コード例 #1
0
ファイル: pourag.py プロジェクト: imouton/pourag
def seed():
  wipe()
  if not UserModel.exists():
    UserModel.create_table(read_capacity_units=1, write_capacity_units=1, wait=True)
  if not Connection.exists():
    Connection.create_table(read_capacity_units=1, write_capacity_units=1, wait=True)
  return "Done!"
コード例 #2
0
 def insert_into_user(cls, username, fname, lname):
     conn = Connection()
     query = "INSERT INTO User (FName, LName, Username) VALUES('{fname}', '{lname}', '{username}')".format(fname=fname, lname=lname, username=username)
     cur = conn.get_cursor()
     cur.execute(query)
     conn.connection.commit()
     conn.close_connection()
コード例 #3
0
 def insert_into_password_analytics(cls, aggregate, count, password_id):
     conn = Connection()
     query = "INSERT INTO PasswordAnalytics (Aggregate, Count, PasswordID) VALUES ({aggregate}, {count}, " \
             "{password_id})".format(aggregate=aggregate, count=count, password_id=password_id)
     cur = conn.get_cursor()
     cur.execute(query)
     conn.connection.commit()
     conn.close_connection()
コード例 #4
0
ファイル: notify.py プロジェクト: Fairbrook/proyecto-SBD
 def __init__(self, app, channel):
     super(Worker, self).__init__()
     self.app = app
     conn = Connection().connect()
     conn.set_isolation_level(
         psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
     cur = conn.cursor()
     cur.execute(f'Listen {channel};')
     self.conn = conn
コード例 #5
0
    def fetch_by_username(cls, username):
        conn = Connection()
        query = "SELECT * FROM User WHERE Username = '******'".format(uname=username)
        cur = conn.get_cursor()
        cur.execute(query)
        user_row_dict = cur.fetchone()

        conn.close_connection()

        if user_row_dict:
            return User(id=user_row_dict['ID'], username=user_row_dict['Username'], fname=user_row_dict['FName'],
                        lname=user_row_dict['LName'])
コード例 #6
0
    def fetch_by_userid(cls, userid, password):
        conn = Connection()
        query = "SELECT * FROM Passwords WHERE Userid = {userid} AND Password = '******'".format(
            userid=userid, password=password)
        cur = conn.get_cursor()
        cur.execute(query)

        passwords_row_dict = cur.fetchone()

        conn.close_connection()

        if passwords_row_dict:
            return Password(id=passwords_row_dict['ID'], userid=passwords_row_dict['UserID'])
コード例 #7
0
    def update_analytics(self, sample_aggregate, sample_count):
        conn = Connection()

        # Update for all passwords of userid iscurrent=False
        query = "UPDATE PasswordAnalytics SET Aggregate = {0}, Count={1} WHERE PasswordID = {2}".format(
            self.aggregate+sample_aggregate, self.count+sample_count, self.passwordid)

        cur = conn.get_cursor()
        cur.execute(query)
        conn.connection.commit()

# Get mean

# Update Total and Count
コード例 #8
0
    def insert_into_passwords(cls, password, userid):
        conn = Connection()

        # Update for all passwords of userid iscurrent=False
        query = "UPDATE Passwords SET IsCurrent = False WHERE UserID = {userid}".format(userid=userid)

        cur = conn.get_cursor()
        cur.execute(query)
        conn.connection.commit()

        query = "INSERT INTO Passwords (IsCurrent, Password, UserID) VALUES({iscurrent}, '{password}', {userid})".format(
            iscurrent=True, password=password, userid=userid)
        cur.execute(query)
        conn.connection.commit()
        conn.close_connection()
コード例 #9
0
    def fetch_by_password_id(cls, password_id):
        conn = Connection()
        query = "SELECT * FROM PasswordAnalytics WHERE PasswordID = {password_id}".format(password_id=password_id)
        cur = conn.get_cursor()
        cur.execute(query)

        passwordanalytics_row_dict = cur.fetchone()

        conn.close_connection()

        if passwordanalytics_row_dict:
            return PasswordAnalytics(id=passwordanalytics_row_dict['ID'],
                                     aggregate=passwordanalytics_row_dict['Aggregate'],
                                     count=passwordanalytics_row_dict['Count'],
                                     passwordid=passwordanalytics_row_dict['PasswordID'])
コード例 #10
0
def connection_handler():
    connection = Connection()
    connection.settings = "conf/config.ini"
    connection.user_name = "User"
    connection.password = "******"
    connection.email = "User"
    connection.driver = connection.settings.get('SYSTEM', 'WebDriverPath')

    return connection
コード例 #11
0
    def getAllProjects(con: Connection) -> List['Project']:
        """
        Get all existing projects in Knora

        :param con: Connection instance
        :return:
        """
        result = con.get('/admin/projects')
        if 'projects' not in result:
            raise BaseError("Request got no projects!")
        return list(
            map(lambda a: Project.fromJsonObj(con, a), result['projects']))
コード例 #12
0
    def getAllLists(con: Connection, project_iri: str) -> List['ListNode']:
        """
        Get all lists of the specified project

        :param con: Connection instance
        :param project_iri: Iri/id of project
        :return: list of ListNodes
        """
        result = con.get('/admin/lists?projectIri=' + quote_plus(project_iri))
        if 'lists' not in result:
            raise BaseError("Request got no lists!")
        return list(map(lambda a: ListNode.fromJsonObj(con, a), result['lists']))
コード例 #13
0
    def getAllUsers(con: Connection) -> List[Any]:
        """
        Get a list of all users (static method)

        :param con: Connection instance
        :return: List of users
        """

        result = con.get('/admin/users')
        if 'users' not in result:
            raise BaseError("Request got no users!")
        return list(map(lambda a: User.fromJsonObj(con, a), result['users']))
コード例 #14
0
    def import_connection_data(self, data):
        try:
            id = data['id']
            name = data['name']
            if 'start_time' in data.keys():
                start = data['start_time']
            if 'end_time' in data.keys():
                end = data['end_time']
            ingress = data['ingress_port']
            egress = data['egress_port']
        except KeyError as e:
            raise MissingAttributeException(e.args[0], e.args[0])

        connection = Connection(id=id,
                                name=name,
                                start_time=start,
                                end_time=end,
                                ingress_port=ingress,
                                egress_port=egress)

        return connection
コード例 #15
0
 def getProjectOntologies(con: Connection, project_id: str) -> List['Ontology']:
     if project_id is None:
         raise BaseError('Project ID must be defined!')
     result = con.get('/v2/ontologies/metadata/' + quote_plus(project_id))
     return Ontology.allOntologiesFromJsonObj(con, result)
コード例 #16
0
__author__ = 'phoehne'

import time
from requests.auth import HTTPDigestAuth
from models.database import Database
from models.connection import Connection
from models.server import HttpServer


conn = Connection("localhost", HTTPDigestAuth("admin", "admin"))

srvr = HttpServer.lookup("test-one-http", conn)
if srvr:
    srvr.remove(conn)

# TODO determine if the server is restarted
time.sleep(30)


db = Database.lookup("test-one", conn)
db.remove(conn)

mod = Database.lookup("test-one-modules", conn)
mod.remove(conn)
コード例 #17
0
def program(args):
    #
    # parse the arguments of the command line
    #
    parser = argparse.ArgumentParser()
    parser.add_argument("datamodelfile", help="path to data model file")
    parser.add_argument("-s",
                        "--server",
                        type=str,
                        default="http://0.0.0.0:3333",
                        help="URL of the Knora server")
    parser.add_argument("-u",
                        "--user",
                        default="*****@*****.**",
                        help="Username for Knora")
    parser.add_argument("-p",
                        "--password",
                        default="test",
                        help="The password for login")
    parser.add_argument(
        "-V",
        "--validate",
        action='store_true',
        help="Do only validation of JSON, no upload of the ontology")
    parser.add_argument("-l",
                        "--lists",
                        action='store_true',
                        help="Only create the lists")
    parser.add_argument("-v",
                        "--verbose",
                        action="store_true",
                        help="Verbose feedback")
    args = parser.parse_args(args)

    current_dir = os.path.dirname(os.path.realpath(__file__))

    # let's read the schema for the data model definition
    if args.lists:
        with open(os.path.join(current_dir, 'knora-schema-lists.json')) as s:
            schema = json.load(s)
    else:
        with open(os.path.join(current_dir, 'knora-schema.json')) as s:
            schema = json.load(s)

    # read the data model definition
    with open(args.datamodelfile) as f:
        datamodel = json.load(f)

    # validate the data model definition in order to be sure that it is correct
    validate(datamodel, schema)
    print("data model is syntactically correct and passed validation!")

    if args.validate:
        exit(0)

    #
    # Connect to the DaSCH Service Platform API
    #
    con = Connection(args.server)
    con.login(args.user, args.password)

    # --------------------------------------------------------------------------
    # let's read the prefixes of external ontologies that may be used
    #
    context = Context(datamodel["prefixes"])

    # --------------------------------------------------------------------------
    # Let's create the project...
    #
    project = None
    if not args.lists:
        #
        # Deal with the project info
        #
        try:
            # we try to read the project to see if it's existing....
            project = Project(
                con=con,
                shortcode=datamodel["project"]["shortcode"],
            ).read()
            #
            # we got it, update the project data if necessary...
            #
            if project.shortname != datamodel["project"]["shortname"]:
                project.shortname = datamodel["project"]["shortname"]
            if project.longname != datamodel["project"]["longname"]:
                project.longname == datamodel["project"]["longname"]
            project.description = datamodel["project"].get("descriptions")
            project.keywords = set(datamodel["project"].get("keywords"))
            nproject = project.update()
            if nproject is not None:
                project = nproject
            if args.verbose:
                print("Modified project:")
                project.print()
        except:
            #
            # The project doesn't exist yet – let's create it
            #
            try:
                project = Project(
                    con=con,
                    shortcode=datamodel["project"]["shortcode"],
                    shortname=datamodel["project"]["shortname"],
                    longname=datamodel["project"]["longname"],
                    description=LangString(
                        datamodel["project"].get("descriptions")),
                    keywords=set(datamodel["project"].get("keywords")),
                    selfjoin=False,
                    status=True).create()
            except BaseError as err:
                print("Creating project failed: " + err.message)
                exit(100)
            if args.verbose:
                print("Created project:")
                project.print()
    else:
        project = Project(
            con=con,
            shortcode=datamodel["project"]["shortcode"],
        ).read()
    assert project is not None

    # --------------------------------------------------------------------------
    # now let's create the lists
    #
    if args.verbose is not None:
        print("Creating lists...")
    lists = datamodel["project"].get('lists')
    listrootnodes = {}
    if lists is not None:
        for rootnode in lists:
            if args.verbose is not None:
                print("  Creating list:" + rootnode['name'])
            root_list_node = ListNode(con=con,
                                      project=project,
                                      label=rootnode['labels'],
                                      comment=rootnode.get('comments'),
                                      name=rootnode['name']).create()
            listnodes = list_creator(con, project, root_list_node,
                                     rootnode['nodes'])
            listrootnodes[rootnode['name']] = {
                "id": root_list_node.id,
                "nodes": listnodes
            }

    with open('lists.json', 'w', encoding="utf-8") as fp:
        json.dump(listrootnodes, fp, indent=3, sort_keys=True)
        print(
            "The definitions of the node-id's can be found in \"lists.json\"!")

    if args.lists:
        exit(0)

    # --------------------------------------------------------------------------
    # now let's add the groups (if there are groups defined...)
    #
    if args.verbose is not None:
        print("Adding groups...")

    new_groups = {}
    groups = datamodel["project"].get('groups')
    if groups is not None:
        for group in groups:
            new_group = None
            try:
                new_group = Group(
                    con=con,
                    name=group["name"],
                    description=group["description"],
                    project=project,
                    status=group["status"]
                    if group.get("status") is not None else True,
                    selfjoin=group["selfjoin"]
                    if group.get("selfjoin") is not None else False).create()
            except BaseError as err:
                print("Creating group failed: " + err.message)
                exit(101)
            new_groups[new_group.name] = new_group
            if args.verbose is not None:
                new_group.print()

    # --------------------------------------------------------------------------
    # now let's add the users (if there are users defined...)
    #
    if args.verbose is not None:
        print("Adding users...")
    all_groups: List[Group] = []
    all_projects: List[Project] = []
    users = datamodel["project"].get('users')
    if users is not None:
        for user in users:
            sysadmin = False
            group_ids: Set[str] = set()
            for groupname in user["groups"]:
                #
                # First we determine the groups the user is in because we can do this in one call
                # groupname has the form [proj_shortname]:groupname|"SystemAdmin" (projectname omitted = current project)
                #
                tmp = groupname.split(':')
                if len(tmp) > 1:
                    group = None
                    if tmp[0] and tmp[0] != '':
                        # we have 'proj_shortname:groupname
                        if not all_groups:
                            all_groups = Group.getAllGroups(con)
                        tmp_group = list(
                            filter(
                                lambda g: g.project.shortname == tmp[0] and g.
                                name == tmp[1], all_groups))
                        assert len(tmp_group) == 1
                        group = tmp_group[0]
                    else:
                        # we have ':groupname' and add to current project
                        group = new_groups.get(tmp[1])
                        assert group is not None
                    group_ids.add(group.id)
                else:
                    if tmp[0] == "SystemAdmin":
                        sysadmin = True

            project_infos: Dict[str, bool] = {}
            for projectname in user["projects"]:
                #
                # now we determine the project memberships of the user
                # projectname has the form [projectname]:"member"|"admin" (projectname omitted = current project)
                #
                tmp = projectname.split(':')
                assert len(tmp) == 2
                if tmp[0]:
                    # we have 'proj_shortname:"member"|"admin"'
                    if not all_projects:
                        all_projects = project.getAllProjects(con)
                    tmp_project = list(
                        filter(lambda g: g.shortname == tmp[0], all_projects))
                    assert len(tmp_project) == 1
                    in_project = tmp_project[0]
                else:
                    # we have ':"member"|"admin"'
                    in_project = project
                if tmp[1] == "admin":
                    project_infos[in_project.id] = True
                else:
                    project_infos[in_project.id] = False
            user_existing = False
            tmp_user = None
            try:
                tmp_user = User(con, username=user["username"]).read()
            except Error as err:
                pass
            if tmp_user is None:
                try:
                    tmp_user = User(con, email=user["email"]).read()
                except Error as err:
                    pass
            if tmp_user:
                #
                # The user is already in the database – let's update its settings
                #
                if tmp_user.username != user["username"]:
                    tmp_user.username = user["username"]
                if tmp_user.email != user["email"]:
                    tmp_user.email = user["email"]
                if tmp_user.givenName != user["givenName"]:
                    tmp_user.givenName = user["givenName"]
                if tmp_user.familyName != user["familyName"]:
                    tmp_user.familyName = user["familyName"]
                if tmp_user.password != user["password"]:
                    tmp_user.password = user["password"]
                if user.get("status") and tmp_user.status != user["status"]:
                    tmp_user.status = user["status"]
                if user.get("lang") and tmp_user.lang != user["lang"]:
                    tmp_user.lang = user["lang"]
                if tmp_user.sysadmin != sysadmin:
                    tmp_user.sysadmin = sysadmin
                try:
                    tmp_user.update()
                except Error as err:
                    pprint(tmp_user)
                    print("Updating user failed: " + err.message)
                    exit(103)
                #
                # now we update group and project membership
                # Note: we do NOT remove any mambership here, we just add!
                #
                tmp_in_groups = tmp_user.in_groups
                add_groups = group_ids - tmp_in_groups
                for g in add_groups:
                    User.addToGroup(g)
                rm_groups = tmp_in_groups - group_ids
                # we do no remove a user from a group here!
                tmp_in_projects = tmp_user.in_projects
                for p in project_infos.items():
                    if tmp_in_projects.get(
                            p[0]) and tmp_in_projects[p[0]] == p[1]:
                        continue
                    User.addToProject(p[0], p[1])
            else:
                #
                # The user does not exist yet, let's create a new one
                #
                try:
                    new_user = User(con=con,
                                    username=user["username"],
                                    email=user["email"],
                                    givenName=user["givenName"],
                                    familyName=user["familyName"],
                                    password=user["password"],
                                    status=user["status"] if user.get("status")
                                    is not None else True,
                                    lang=user["lang"]
                                    if user.get("lang") is not None else "en",
                                    sysadmin=sysadmin,
                                    in_projects=project_infos,
                                    in_groups=group_ids).create()
                except Error as err:
                    print("Creating user failed: " + err.message)
                    exit(104)
            if args.verbose is not None:
                new_user.print()

    # --------------------------------------------------------------------------
    # now let's create the ontologies
    #
    ontologies = datamodel["project"]["ontologies"]
    for ontology in ontologies:
        last_modification_date, newontology = Ontology(
            con=con,
            project=project,
            label=ontology["label"],
            name=ontology["name"]).create()
        if args.verbose is not None:
            newontology.print()

        #
        # First we create the empty resource classes
        #
        resclasses = ontology["resources"]
        newresclasses: Dict[str, ResourceClass] = {}
        for resclass in resclasses:
            resname = resclass.get("name")
            super_classes = resclass.get("super")
            if isinstance(super_classes, str):
                super_classes = [super_classes]
            reslabel = LangString(resclass.get("labels"))
            rescomment = resclass.get("comment")
            if rescomment is not None:
                rescomment = LangString(rescomment)
            try:
                last_modification_date, newresclass = ResourceClass(
                    con=con,
                    context=newontology.context,
                    ontology_id=newontology.id,
                    name=resname,
                    superclasses=super_classes,
                    label=reslabel,
                    comment=rescomment).create(last_modification_date)
            except Error as err:
                print("Creating resource class failed: " + err.message)
                exit(105)
            newresclasses[newresclass.id] = newresclass
            if args.verbose is not None:
                newresclass.print()

        #
        # Then we create the property classes
        #
        propclasses = ontology["properties"]
        newpropclasses: Dict[str, ResourceClass] = {}
        for propclass in propclasses:
            propname = propclass.get("name")
            proplabel = LangString(propclass.get("labels"))
            #
            # get the super-property/ies if defined. Valid forms are:
            #   - "prefix:superproperty" : fully qualified name of property in another ontology. The prefix has to
            #     be defined in the prefixes part.
            #   - "superproperty" : Use of super-property defined in the knora-api ontology
            #  if omitted, automatically "knora-api:hasValue" is assumed
            #
            if propclass.get("super") is not None:
                super_props = list(
                    map(lambda a: a
                        if ':' in a else "knora-api:" + a, propclass["super"]))
            else:
                super_props = ["knora-api:hasValue"]
            #
            # now we get the "object" if defined. Valid forms are:
            #  - "prefix:object_name" : fully qualified object. The prefix has to be defined in the prefixes part.
            #  - ":object_name" : The object is defined in the current ontology.
            #  - "object_name" : The object is defined in "knora-api"
            #
            if propclass.get("object") is not None:
                tmp = propclass["object"].split(':')
                if len(tmp) > 1:
                    if tmp[0]:
                        object = propclass["object"]  # fully qualified name
                    else:
                        object = newontology.name + ':' + tmp[1]
                else:
                    object = "knora-api:" + propclass["object"]
            else:
                object = None

            if propclass.get("subject") is not None:
                subject = propclass["subject"]
            else:
                subject = None
            gui_element = propclass.get("gui_element")
            gui_attributes = propclass.get("gui_attributes")
            if gui_attributes is not None and gui_attributes.get(
                    "hlist") is not None:
                gui_attributes['hlist'] = "<" + listrootnodes[
                    gui_attributes['hlist']]["id"] + ">"
            propcomment = propclass.get("comment")
            if propcomment is not None:
                propcomment = LangString(propcomment)
            else:
                propcomment = "no comment given"
            try:
                last_modification_date, newpropclass = PropertyClass(
                    con=con,
                    context=newontology.context,
                    label=proplabel,
                    name=propname,
                    ontology_id=newontology.id,
                    superproperties=super_props,
                    object=object,
                    subject=subject,
                    gui_element="salsah-gui:" + gui_element,
                    gui_attributes=gui_attributes,
                    comment=propcomment).create(last_modification_date)
            except Error as err:
                print("Creating property class failed: " + err.message)
                exit(105)
            newpropclasses[newpropclass.id] = newpropclass
            if args.verbose is not None:
                newpropclass.print()

        #
        # Add cardinalities
        #
        switcher = {
            "1": Cardinality.C_1,
            "0-1": Cardinality.C_0_1,
            "0-n": Cardinality.C_0_n,
            "1-n": Cardinality.C_1_n
        }
        for resclass in resclasses:
            for cardinfo in resclass["cardinalities"]:
                rc = newresclasses.get(newontology.id + '#' + resclass["name"])
                cardinality = switcher[cardinfo["cardinality"]]
                tmp = cardinfo["propname"].split(':')
                if len(tmp) > 1:
                    if tmp[0]:
                        propid = cardinfo["propname"]  # fully qualified name
                    else:
                        propid = newontology.name + ':' + tmp[1]
                else:
                    propid = "knora-api:" + cardinfo["propname"]
                last_modification_date = rc.addProperty(
                    propid, cardinality, last_modification_date)
コード例 #18
0
 def getAllGroups(con: Connection) -> List['Group']:
     result = con.get('/admin/groups')
     if 'groups' not in result:
         raise BaseError("Request got no groups!")
     return list(map(lambda a: Group.fromJsonObj(con, a), result['groups']))
コード例 #19
0
def program(args):
    #
    # parse the arguments of the command line
    #
    parser = argparse.ArgumentParser()
    #parser.add_argument("datamodelfile", help="path to data model file")
    parser.add_argument("-s",
                        "--server",
                        type=str,
                        default="http://0.0.0.0:3333",
                        help="URL of the Knora server")
    parser.add_argument("-u",
                        "--user",
                        type=str,
                        default="*****@*****.**",
                        help="Username for Knora")
    parser.add_argument("-p",
                        "--password",
                        type=str,
                        default="test",
                        help="The password for login")
    parser.add_argument("-c",
                        "--shortcode",
                        type=str,
                        help="Shortcode of the project")
    parser.add_argument("-n",
                        "--shortname",
                        type=str,
                        help="Shortname of the project")
    parser.add_argument("-i", "--iri", type=str, help="Project iri")
    args = parser.parse_args(args)

    current_dir = os.path.dirname(os.path.realpath(__file__))

    #
    # Connect to the DaSCH Service Platform API
    #
    con = Connection(args.server)
    #con.login(args.user, args.password)

    #
    # First we get the project information...
    #
    if args.shortcode:
        project = Project(con=con, shortcode=args.shortcode)
    elif args.shortname:
        project = Project(con=con, shortname=args.shortname)
    elif args.iri:
        project = Project(con=con, shortname=args.iri)
    else:
        print("ERROR")
        exit(-1)
    project = project.read()

    projectobj = project.createDefinitionFileObj()

    #
    # now collect the lists
    #
    listroots = ListNode.getAllLists(con=con, project_iri=project.id)
    listobj = []
    for listroot in listroots:
        complete_list = listroot.getAllNodes()
        listobj.append(complete_list.createDefinitionFileObj())
    projectobj["lists"] = listobj

    projectobj["ontologies"] = []
    for ontology in project.ontologies:
        oparts = ontology.split("/")
        name = oparts[len(oparts) - 1]
        shortcode = oparts[len(oparts) - 2]
        lastmoddate, ontology = Ontology.getOntologyFromServer(
            con=con, shortcode=shortcode, name=name)
        projectobj["ontologies"].append(ontology.createDefinitionFileObj())

    umbrella = {
        "prefixes": ontology.context.get_externals_used(),
        "project": projectobj
    }

    with open('data.json', 'w', encoding='utf8') as outfile:
        json.dump(umbrella, outfile, indent=3, ensure_ascii=False)

    print(ontology.context)
コード例 #20
0
ファイル: pourag.py プロジェクト: imouton/pourag
def wipe():
  if UserModel.exists():
    UserModel.delete_table()
  if Connection.exists():
    Connection.delete_table()
  return "Done!"
コード例 #21
0
        else:
            print('  Description: None')
        if self._keywords is not None:
            print('  Keywords:   {}'.format(' '.join(self._keywords)))
        else:
            print('  Keywords:   None')
        if self._ontologies is not None:
            print('  Ontologies: {}'.format(' '.join(self._ontologies)))
        else:
            print('  Ontologies: None')
        print('  Selfjoin:   {}'.format(self._selfjoin))
        print('  Status:     {}'.format(self._status))


if __name__ == '__main__':
    con = Connection('http://0.0.0.0:3333')
    con.login('*****@*****.**', 'test')

    projects = Project.getAllProjects(con)

    for project in projects:
        project.print()

    print('==============================================================')

    new_project = Project(con=con,
                          shortcode='F11F',
                          shortname='mytest3',
                          longname='A Test beloning to me',
                          description=LangString(
                              {Languages.EN: 'My Tests description'}),