def setUp(self): for class_ in self.doc.parsed_classes: if class_ not in self.doc.collections: dummy_obj = gen_dummy_object(class_, self.doc) crud.insert(dummy_obj, id_=str(uuid.uuid4()), session=self.session)
def put(self, type_): """Add item to ItemCollection.""" if get_authentication(): if request.authorization is None: return failed_authentication() else: try: auth = check_authorization(request, get_session()) if auth is False: return failed_authentication() except Exception as e: status_code, message = e.get_HTTP() return set_response_headers(jsonify(message), status_code=status_code) if checkEndpoint("PUT", type_): object_ = json.loads(request.data.decode('utf-8')) # Collections if type_ in get_doc().collections: collection = get_doc().collections[type_]["collection"] obj_type = collection.class_.title if validObject(object_): if object_["@type"] == obj_type: try: object_id = crud.insert(object_=object_, session=get_session()) headers_ = [{"Location": get_hydrus_server_url()+get_api_name()+"/"+type_+"/"+str(object_id)}] response = {"message": "Object with ID %s successfully deleted" % (object_id)} return set_response_headers(jsonify(response), headers=headers_, status_code=201) except Exception as e: status_code, message = e.get_HTTP() return set_response_headers(jsonify(message), status_code=status_code) return set_response_headers(jsonify({400: "Data is not valid"}), status_code=400) # Non Collection classes elif type_ in get_doc().parsed_classes and type_+"Collection" not in get_doc().collections: obj_type = getType(type_, "PUT") if object_["@type"] == obj_type: if validObject(object_): try: object_id = crud.insert(object_=object_, session=get_session()) headers_ = [{"Location": get_hydrus_server_url()+get_api_name()+"/"+type_+"/"}] response = {"message": "Object successfully added"} return set_response_headers(jsonify(response), headers=headers_, status_code=201) except Exception as e: status_code, message = e.get_HTTP() return set_response_headers(jsonify(message), status_code=status_code) return set_response_headers(jsonify({400: "Data is not valid"}), status_code=400) abort(405)
def init_db_for_app_tests(doc, constants, session, add_doc_classes_and_properties_to_db): """ Initalze the database for testing app in tests/functional/test_app.py. """ for class_ in doc.parsed_classes: class_title = doc.parsed_classes[class_]['class'].title dummy_obj = gen_dummy_object(class_title, doc) crud.insert(dummy_obj, id_=str(uuid.uuid4()), session=session) # If it's a collection class then add an extra object so # we can test pagination thoroughly. if class_ in doc.collections: crud.insert(dummy_obj, id_=str(uuid.uuid4()), session=session)
def test_insert_used_id(drone_doc_parsed_classes, drone_doc, session): """Test CRUD insert when used ID is given.""" object_ = gen_dummy_object(random.choice(drone_doc_parsed_classes), drone_doc) id_ = str(uuid.uuid4()) insert_response = crud.insert(object_=object_, id_=id_, session=session) response_code = None try: insert_response = crud.insert(object_=object_, id_=id_, session=session) except Exception as e: error = e.get_HTTP() response_code = error.code assert 400 == response_code
def test_get_for_nested_obj(drone_doc_parsed_classes, drone_doc, session, constants): """Test CRUD get operation for object that can contain other objects.""" expanded_base_url = DocUrl.doc_url for class_ in drone_doc_parsed_classes: for prop in drone_doc.parsed_classes[class_][ 'class'].supportedProperty: if not isinstance(prop.prop, HydraLink): if expanded_base_url in prop.prop: dummy_obj = gen_dummy_object(class_, drone_doc) nested_class = prop.prop.split(expanded_base_url)[1] obj_id = str(uuid.uuid4()) response = crud.insert(object_=dummy_obj, id_=obj_id, session=session) object_ = crud.get(id_=obj_id, type_=class_, session=session, api_name='api') assert prop.title in object_ nested_obj_id = object_[prop.title] nested_obj = crud.get(id_=nested_obj_id, type_=nested_class, session=session, api_name='api') assert nested_obj['@id'].split('/')[-1] == nested_obj_id break
def put(self, id_: str, path: str) -> Response: """Add new object_ optional <id_> parameter using HTTP PUT. :param id_ - ID of Item to be updated :param path - Path for Item type( Specified in APIDoc @id) to be updated """ id_ = str(id_) auth_response = check_authentication_response() if isinstance(auth_response, Response): return auth_response class_type = get_doc().collections[path]["collection"].class_.title if checkClassOp(class_type, "PUT"): # Check if class_type supports PUT operation object_ = json.loads(request.data.decode('utf-8')) obj_type = getType(class_type, "PUT") # Load new object and type if validObject(object_) and object_["@type"] == obj_type: try: # Add the object with given ID object_id = crud.insert(object_=object_, id_=id_, session=get_session()) headers_ = [{"Location": "{}{}/{}/{}".format( get_hydrus_server_url(), get_api_name(), path, object_id)}] response = { "message": "Object with ID {} successfully added".format(object_id)} return set_response_headers( jsonify(response), headers=headers_, status_code=201) except (ClassNotFound, InstanceExists, PropertyNotFound) as e: status_code, message = e.get_HTTP() return set_response_headers(jsonify(message), status_code=status_code) else: return set_response_headers(jsonify({400: "Data is not valid"}), status_code=400) else: abort(405)
def items_put_check_support(id_, class_path, path, is_collection): """Check if class_type supports PUT operation""" object_ = json.loads(request.data.decode('utf-8')) collections, parsed_classes = get_collections_and_parsed_classes() if path in parsed_classes: class_path = path obj_type = getType(path, "PUT") elif path in collections: collection = collections[path]["collection"] class_path = collection.path obj_type = collection.name link_props, link_type_check = get_link_props(class_path, object_) # Load new object and type if (validate_object(object_, obj_type, class_path) and link_type_check): if is_collection: object_ = parse_collection_members(object_) try: # Add the object with given ID object_id = crud.insert(object_=object_, id_=id_, session=get_session(), collection=is_collection) headers_ = [{"Location": f"{get_hydrus_server_url()}" f"{get_api_name()}/{path}/{object_id}"}] status_description = f"Object with ID {object_id} successfully added" status = HydraStatus(code=201, title="Object successfully added.", desc=status_description) return set_response_headers( jsonify(status.generate()), headers=headers_, status_code=status.code) except (ClassNotFound, InstanceExists, PropertyNotFound) as e: error = e.get_HTTP() return error_response(error) else: error = HydraError(code=400, title="Data is not valid") return error_response(error)
def init_db_for_socket_tests(doc, add_doc_classes_and_properties_to_db, session): """ Initalze the database for testing app in tests/functional/test_socket.py. """ for class_ in doc.parsed_classes: class_title = doc.parsed_classes[class_]["class"].title dummy_obj = gen_dummy_object(class_title, doc) crud.insert(dummy_obj, id_=str(uuid.uuid4()), session=session) # If it's a collection class then add an extra object so # we can test pagination thoroughly. if class_ in doc.collections: crud.insert(dummy_obj, id_=str(uuid.uuid4()), session=session) # Add two dummy modification records crud.insert_modification_record(method="POST", resource_url="", session=session) crud.insert_modification_record(method="DELETE", resource_url="", session=session)
def test_insert(self): """Test CRUD insert.""" object_ = gen_dummy_object(random.choice(self.doc_collection_classes), self.doc) response = crud.insert(object_=object_, id_="1", session=self.session) assert isinstance(response, str)
def test_get(self): """Test CRUD get.""" object_ = gen_dummy_object("dummyClass", self.doc) id_ = 2 response = crud.insert(object_=object_, id_=id_, session=self.session) object_ = crud.get(id_=id_, type_=object_["@type"], session=self.session, api_name="api") assert type(response) is int assert int(object_["@id"].split("/")[-1]) == id_
def on_put(self, req, resp, id_: int, type_: str): """Add new object_ optional <id_> parameter using HTTP PUT. :param id_ - ID of Item to be updated :param type_ - Type(Class name) of Item to be updated """ if get_authentication(resp): if req.auth is None: return failed_authentication(resp) else: try: auth = check_authorization(req, get_session(resp)) if auth is False: return failed_authentication(resp) except Exception as e: status_code, message = e.get_HTTP() # type: ignore resp.media = message return set_response_headers(resp, status_code=status_code) class_type = get_doc( resp).collections[type_]["collection"].class_.title if checkClassOp(resp, class_type, "PUT"): # Check if class_type supports PUT operation object_ = req.media obj_type = getType(resp, class_type, "PUT") # Load new object and type if validObject(object_): if object_["@type"] == obj_type: try: # Add the object with given ID object_id = crud.insert(object_=object_, id_=id_, session=get_session(resp)) headers_ = [{ "Location": get_hydrus_server_url(resp) + get_api_name(resp) + "/" + type_ + "/" + str(object_id) }] response = { "message": "Object with ID %s successfully added" % (object_id) } resp.media = response return set_response_headers( resp, headers=headers_[0], status_code=falcon.HTTP_201) except Exception as e: status_code, message = e.get_HTTP() resp.media = message return set_response_headers(resp, status_code=status_code) return set_response_headers(resp, status_code=falcon.HTTP_400) resp.status = falcon.HTTP_405
def test_crud_insert_response_is_str(drone_doc_parsed_classes, drone_doc, session, init_db_for_crud_tests): """Test CRUD insert response is string""" object_ = gen_dummy_object(random.choice(drone_doc_parsed_classes), drone_doc) id_ = str(uuid.uuid4()) response = crud.insert(object_=object_, id_=id_, session=session) assert isinstance(response, str)
def test_insert_id(self): """Test CRUD insert when used ID is given.""" object_ = gen_dummy_object("dummyClass", self.doc) id_ = 1 response_code = None try: insert_response = crud.insert(object_=object_, id_=id_, session=self.session) except Exception as e: response_code, message = e.get_HTTP() assert 400 == response_code
def gen_dummy_object(class_title, doc): """ Create a dummy object based on the definitions in the API Doc. :param class_title: Title of the class whose object is being created. :param doc: ApiDoc. :return: A dummy object of class `class_title`. """ object_ = { "@type": class_title } expanded_base_url = DocUrl.doc_url for class_path in doc.collections: if class_title == doc.collections[class_path]["collection"].name: members = list() manages_class_titles = list() collection_manages = doc.collections[class_title]["collection"].manages if type(collection_manages) is dict: # only one manages block manages_class = collection_manages['object'].split(expanded_base_url)[1] manages_class_titles.append(manages_class) elif type(collection_manages) is list: # multiple manages block for manages_block in collection_manages: manages_class = collection_manages['object'].split(expanded_base_url)[1] manages_class_titles.append(manages_class) for _ in range(3): member_class = random.choice(manages_class_titles) member = gen_dummy_object(member_class, doc) member_id = crud.insert(object_=member, session=get_session(), collection=False) member_class_path = get_path_from_type(member_class) member_api_path = f'/{get_api_name()}/{member_class_path}/{member_id}' members.append({ "@id": member_api_path, "@type": member_class, }) object_['members'] = members return object_ for class_path in doc.parsed_classes: if class_title == doc.parsed_classes[class_path]["class"].title: for prop in doc.parsed_classes[class_path]["class"].supportedProperty: if prop.write is False: continue if isinstance(prop.prop, HydraLink): object_[prop.title] = ''.join(random.choice( string.ascii_uppercase + string.digits) for _ in range(6)) pass elif expanded_base_url in prop.prop: prop_class = prop.prop.split(expanded_base_url)[1] object_[prop.title] = gen_dummy_object(prop_class, doc) else: object_[prop.title] = ''.join(random.choice( string.ascii_uppercase + string.digits) for _ in range(6)) return object_
def insert_data(objects): """ Insert a list of obejcts to the database.""" insertion_ids = [] for object_ in objects: try: id_ = insert(object_) insertion_ids.append(id_) except: print("Error occured, skipping object.") return insertion_ids
def test_insert_type(self): """Test CRUD insert when wrong/undefined class is given.""" object_ = gen_dummy_object("dummyClass", self.doc) id_ = 7 object_["@type"] = "otherClass" response_code = None try: insert_response = crud.insert(object_=object_, id_=id_, session=self.session) except Exception as e: response_code, message = e.get_HTTP() assert 400 == response_code
def test_searching_over_collection_elements(drone_doc_parsed_classes, drone_doc, session): """Test searching over collection elements.""" expanded_base_url = DocUrl.doc_url for class_ in drone_doc_parsed_classes: target_property_1 = '' target_property_2 = '' for prop in drone_doc.parsed_classes[class_][ 'class'].supportedProperty: if isinstance(prop.prop, HydraLink): continue # Find nested object so we can test searching of elements by # properties of nested objects. if expanded_base_url in prop.prop: object_ = gen_dummy_object(class_, drone_doc) # Setting property of a nested object as target for property_ in object_[prop.title]: if property_ != '@type': object_[prop.title][property_] = 'target_1' target_property_1 = '{}[{}]'.format( prop.title, property_) break break elif target_property_1 is not '': for property_ in object_: if property_ != '@type': object_[property_] = 'target_2' target_property_2 = property_ break break if target_property_1 is not '' and target_property_2 is not '': # Set search parameters search_params = { target_property_1: 'target_1', target_property_2: 'target_2' } obj_id = str(uuid.uuid4()) response = crud.insert(object_=object_, id_=obj_id, session=session) search_result = crud.get_collection( API_NAME='api', type_=class_, session=session, paginate=True, page_size=5, search_params=search_params) assert len(search_result['members']) > 0 search_item_id = search_result['members'][0]['@id'].split( '/')[-1] assert search_item_id == obj_id break
def test_get_for_nested_obj(self): """Test get operation for object that can contain other objects.""" for class_ in self.doc_collection_classes: for prop in self.doc.parsed_classes[class_][ "class"].supportedProperty: if isinstance(prop.prop, HydraLink) or "vocab:" in prop.prop: link_props = {} dummy_obj = gen_dummy_object(class_, self.doc) if isinstance(prop.prop, HydraLink): nested_class = prop.prop.range.replace("vocab:", "") for collection_path in self.doc.collections: coll_class = self.doc.collections[collection_path][ 'collection'].class_.title if nested_class == coll_class: id_ = str(uuid.uuid4()) crud.insert(gen_dummy_object( nested_class, self.doc), id_=id_, session=self.session) link_props[prop.title] = id_ dummy_obj[prop.title] = "{}/{}/{}".format( self.API_NAME, collection_path, id_) else: nested_class = prop.prop.replace("vocab:", "") obj_id = str(uuid.uuid4()) response = crud.insert(object_=dummy_obj, id_=obj_id, link_props=link_props, session=self.session) object_ = crud.get(id_=obj_id, type_=class_, session=self.session, api_name="api") assert prop.title in object_ nested_obj_id = object_[prop.title] nested_obj = crud.get(id_=nested_obj_id, type_=nested_class, session=self.session, api_name="api") assert nested_obj["@id"].split("/")[-1] == nested_obj_id break
def test_update(self): """Test CRUD update.""" object_ = gen_dummy_object("dummyClass", self.doc) new_object = gen_dummy_object("dummyClass", self.doc) id_ = 30 insert_response = crud.insert(object_=object_, id_=id_, session=self.session) update_response = crud.update(id_=id_, type_=object_["@type"], object_=new_object, session=self.session, api_name="api") test_object = crud.get(id_=id_, type_=object_["@type"], session=self.session, api_name="api") assert type(insert_response) is int assert type(update_response) is int assert insert_response == update_response assert int(test_object["@id"].split("/")[-1]) == id_
def test_get(self): """Test CRUD get.""" object_ = gen_dummy_object(random.choice(self.doc_collection_classes), self.doc) id_ = "2" response = crud.insert(object_=object_, id_=id_, session=self.session) object_ = crud.get(id_=id_, type_=object_["@type"], session=self.session, api_name="api") assert isinstance(response, str) assert object_["@id"].split("/")[-1] == id_
def put(self, id_: int, type_: str) -> Response: """Add new object_ optional <id_> parameter using HTTP PUT.""" if get_authentication(): if request.authorization is None: return failed_authentication() else: try: auth = check_authorization(request, get_session()) if auth is False: return failed_authentication() except Exception as e: status_code, message = e.get_HTTP() # type: ignore return set_response_headers(jsonify(message), status_code=status_code) class_type = get_doc().collections[type_]["collection"].class_.title if checkClassOp(class_type, "PUT"): object_ = json.loads(request.data.decode('utf-8')) obj_type = getType(class_type, "PUT") if validObject(object_): if object_["@type"] == obj_type: try: object_id = crud.insert(object_=object_, id_=id_, session=get_session()) headers_ = [{ "Location": get_hydrus_server_url() + get_api_name() + "/" + type_ + "/" + str(object_id) }] response = { "message": "Object with ID %s successfully added" % (object_id) } return set_response_headers(jsonify(response), headers=headers_, status_code=201) except Exception as e: status_code, message = e.get_HTTP() # type: ignore return set_response_headers(jsonify(message), status_code=status_code) return set_response_headers(jsonify({400: "Data is not valid"}), status_code=400) abort(405)
def test_searching(self): """Test searching over collection elements.""" for class_ in self.doc_collection_classes: target_property_1 = "" target_property_2 = "" for prop in self.doc.parsed_classes[class_][ "class"].supportedProperty: if isinstance(prop.prop, HydraLink): continue # Find nested object so we can test searching of elements by # properties of nested objects. if "vocab:" in prop.prop: object_ = gen_dummy_object(class_, self.doc) # Setting property of a nested object as target for property_ in object_[prop.title]: if property_ != "@type": object_[prop.title][property_] = "target_1" target_property_1 = "{}[{}]".format( prop.title, property_) break break elif target_property_1 is not "": for property_ in object_: if property_ != "@type": object_[property_] = "target_2" target_property_2 = property_ break break if target_property_1 is not "" and target_property_2 is not "": # Set search parameters search_params = { target_property_1: "target_1", target_property_2: "target_2" } obj_id = str(uuid.uuid4()) response = crud.insert(object_=object_, id_=obj_id, session=self.session) search_result = crud.get_collection( API_NAME="api", type_=class_, session=self.session, paginate=True, page_size=5, search_params=search_params) assert len(search_result["members"]) > 0 search_item_id = search_result["members"][0]["@id"].split( '/')[-1] assert search_item_id == obj_id break
def test_delete_id(self): """Test CRUD delete when wrong/undefined ID is given.""" object_ = gen_dummy_object("dummyClass", self.doc) id_ = 6 insert_response = crud.insert(object_=object_, id_=id_, session=self.session) response_code = None try: delete_response = crud.delete(id_=999, type_=object_["@type"], session=self.session) except Exception as e: response_code, message = e.get_HTTP() assert 404 == response_code assert type(insert_response) is int assert insert_response == id_
def test_crud_get_returns_correct_object(drone_doc_parsed_classes, drone_doc, session): """Test CRUD get returns correct object""" object_ = gen_dummy_object(random.choice(drone_doc_parsed_classes), drone_doc) id_ = str(uuid.uuid4()) response = crud.insert(object_=object_, id_=id_, session=session) object_ = crud.get(id_=id_, type_=object_['@type'], session=session, api_name='api') assert isinstance(response, str) assert object_['@id'].split('/')[-1] == id_
def test_delete(self): """Test CRUD delete.""" object_ = gen_dummy_object("dummyClass", self.doc) id_ = 4 insert_response = crud.insert(object_=object_, id_=id_, session=self.session) delete_response = crud.delete(id_=id_, type_=object_["@type"], session=self.session) assert type(insert_response) is int response_code = None try: get_response = crud.get(id_=id_, type_=object_["@type"], session=self.session, api_name="api") except Exception as e: response_code, message = e.get_HTTP() assert 404 == response_code
def item_collection_put_response(path: str) -> Response: """ Handles PUT operation on item collection classes. :param path: Path for Item Collection :type path: str :return: Appropriate response for the PUT operation. :rtype: Response """ object_ = json.loads(request.data.decode('utf-8')) collections, parsed_classes = get_collections_and_parsed_classes() is_collection = False if path in parsed_classes: class_path = path is_collection = False obj_type = getType(path, "PUT") elif path in collections: collection = collections[path]["collection"] class_path = collection.path obj_type = collection.name is_collection = True if validate_object(object_, obj_type, class_path): # If Item in request's JSON is a valid object ie. @type is a key in object_ # and the right Item type is being added to the collection if is_collection: object_ = parse_collection_members(object_) try: # Insert object and return location in Header object_id = crud.insert(object_=object_, session=get_session(), collection=is_collection) headers_ = [{ "Location": f"{get_hydrus_server_url()}{get_api_name()}/{path}/{object_id}" }] status_description = f"Object with ID {object_id} successfully added" status = HydraStatus(code=201, title="Object successfully added", desc=status_description) return set_response_headers(jsonify(status.generate()), headers=headers_, status_code=status.code) except (ClassNotFound, InstanceExists, PropertyNotFound, PropertyNotGiven) as e: error = e.get_HTTP() return error_response(error) else: error = HydraError(code=400, title="Data is not valid") return error_response(error)
def test_delete_type(self): """Test CRUD delete when wrong/undefined class is given.""" object_ = gen_dummy_object("dummyClass", self.doc) id_ = 50 insert_response = crud.insert( object_=object_, id_=id_, session=self.session) assert isinstance(insert_response, int) assert insert_response == id_ response_code = None try: delete_response = crud.delete( id_=id_, type_="otherClass", session=self.session) except Exception as e: response_code, message = e.get_HTTP() assert 400 == response_code
def test_insert_on_wrong_type(drone_doc_parsed_classes, drone_doc, session): """Test CRUD insert when wrong/undefined class is given.""" object_ = gen_dummy_object(random.choice(drone_doc_parsed_classes), drone_doc) id_ = str(uuid.uuid4()) object_['@type'] = 'otherClass' response_code = None try: insert_response = crud.insert(object_=object_, id_=id_, session=session) except Exception as e: error = e.get_HTTP() response_code = error.code assert 400 == response_code
def test_insert_type(self): """Test CRUD insert when wrong/undefined class is given.""" object_ = gen_dummy_object(random.choice(self.doc_collection_classes), self.doc) id_ = str(uuid.uuid4()) object_["@type"] = "otherClass" response_code = None try: insert_response = crud.insert(object_=object_, id_=id_, session=self.session) except Exception as e: error = e.get_HTTP() response_code = error.code assert 400 == response_code
def put(self, id_: int, type_: str) -> Response: """Add new object_ optional <id_> parameter using HTTP PUT. :param id_ - ID of Item to be updated :param type_ - Type(Class name) of Item to be updated """ auth_response = check_authentication_response() if type(auth_response) == Response: return auth_response class_type = get_doc().collections[type_]["collection"].class_.title if checkClassOp(class_type, "PUT"): # Check if class_type supports PUT operation object_ = json.loads(request.data.decode('utf-8')) obj_type = getType(class_type, "PUT") # Load new object and type if validObject(object_): if object_["@type"] == obj_type: try: # Add the object with given ID object_id = crud.insert(object_=object_, id_=id_, session=get_session()) headers_ = [{ "Location": get_hydrus_server_url() + get_api_name() + "/" + type_ + "/" + str(object_id) }] response = { "message": "Object with ID %s successfully added" % (object_id) } return set_response_headers(jsonify(response), headers=headers_, status_code=201) except (ClassNotFound, InstanceExists, PropertyNotFound) as e: status_code, message = e.get_HTTP() return set_response_headers(jsonify(message), status_code=status_code) return set_response_headers(jsonify({400: "Data is not valid"}), status_code=400) abort(405)