def get_custom_algo(http_request, customized_algo_id, query_dict): """ Reads the CustomizedAlgo specified :param http_request: the request :type http_request: HttpRequest :param customized_algo_id: the database ID of the CustomizedAlgo :type customized_algo_id: str of int :param query_dict: the query parameters :type query_dict: QueryDict :return: the Json response (nominal or error). :rtype: JsonResponse """ # Builds the response in blocks try: or except: response_builder = DjangoHttpResponseFactory() try: # info-level is used to adapt the returned content of resource my_level = HttpCommonsIkats.get_info_level(http_request, query_dict) my_id = CustomizedAlgoDao.parse_dao_id(customized_algo_id) buzz_custom_algo = CustomizedAlgoDao.find_business_elem_with_key( primary_key=my_id) LOG_WS_CUSTOM.info("Found customized algo with id=%s: %s", customized_algo_id, buzz_custom_algo) # CustomizedAlgoWs is wrapping the business resource # => manages the user rendering: json format, according to info-level ws_custom_algo = CustomizedAlgoWs(buzz_custom_algo) dict_custom_algo = ws_custom_algo.to_dict(level=my_level) my_response = JsonResponse(dict_custom_algo, safe=False) except CustomizedAlgoDao.DoesNotExist: # Example: customized_algo_id=99999999 is not matching a resource in database msg = "Does not exist: customized algo with id=%s" % customized_algo_id LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_not_found( ikats_error=msg) except IkatsInputError as err: # Example: invalid info_level value in query params ... LOG_WS_CUSTOM.exception(err) msg = "Bad request in get_custom_algo with id={}".format( customized_algo_id) LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_bad_request( ikats_error=msg, exception=err) except Exception as err: # Any unexpected error: database crash ... LOG_WS_CUSTOM.exception(err) msg = "Unexpected server error in get_custom_algo with id={}".format( customized_algo_id) LOG_WS_CUSTOM.error(msg) my_response = response_builder.get_json_response_internal_server_error( ikats_error=msg) return my_response
def test_check_err_create_bad_dom(self): """ Tests that CheckEngine produces expected CheckStatus, when checking domain error exists with the CustomizedAlgo creation Rest service. """ # Re-activate checking rules CheckEngine.set_checking_rules( FactoryCatalogue.TYPE_CHECKING_FUNCTIONS) my_custom_outside_domain = self.init_rsrc_outside_domain() http_req = self.request_factory.post( path=reverse('pattern_custom_algos_dummy'), data=CustomizedAlgoWs(my_custom_outside_domain).to_json(), content_type="application/json_util") http_response = create_custom_algo(http_req) # Display the check result result = json_io.decode_json_from_http_response(http_response) self.info("response loaded={}".format(result)) self.info("response status={}".format(http_response.status_code)) self.assertTrue(http_response.status_code == HttpResponseFactory.BAD_REQUEST_HTTP_STATUS)
def test_custo_create_200(self): """ Tests the nominal Creation of CustomizedAlgo: we prepare the data and then submit creation """ # Preparing the data ... my_new_custom_algo = self.init_resource_named( name="custom algo for create seq3", save_in_db=False) data = CustomizedAlgoWs(my_new_custom_algo).to_json() # ... testing the service http_req = self.request_factory.post( path=reverse('pattern_custom_algos_dummy'), data=data, content_type="application/json_util") http_response = create_custom_algo(http_req) result = json_io.decode_json_from_http_response(http_response) self.info("!!! response loaded={} !!!".format(result)) self.info("!!! response status={} !!!".format( http_response.status_code)) self.assertTrue(http_response.status_code == HttpResponseFactory.CREATED_HTTP_STATUS)
def test_load_from_dict_seq4(self): """ Nominal test of load_from_dict() """ my_custom_ws = CustomizedAlgoWs(self.my_custom_algo_in_DB) normal_dict = my_custom_ws.to_dict(level=LevelInfo.NORMAL) self.info( "- Evaluating my_custom_algo_in_DB => CustomizedAlgoWs.load_from_dict(...)" ) loaded_ws_resource = CustomizedAlgoWs.load_from_dict(normal_dict) my_business_custo = loaded_ws_resource.get_customized_algo() self.info(" - uploaded custom_algo={}".format(my_business_custo)) self.assertTrue(my_business_custo == self.my_custom_algo_in_DB)
def convert_to_ws_custom_algo(cls, business_custom_algo, level=LevelInfo.NORMAL): """ Returns the json-friendly dictionary matching the content view of - one CustomizedAlgo resource - according to specified level :param business_custom_algo: the business resource CustomizedAlgo :type business_custom_algo: CustomizedAlgo :param level: the specified level: optional, default value is NORMAL :type level: LevelInfo :return the json-friendly dictionary :rtype: dict """ my_rest_api_dto = CustomizedAlgoWs(business_custom_algo) return my_rest_api_dto.to_dict(level=level)
def test_to_dict_summary_seq3(self): """ Tests the building of SUMMARY-leveled json view """ my_custom_ws = CustomizedAlgoWs(self.my_custom_algo_2_in_DB) self.info( "- Evaluating my_custom_algo_2_in_DB => to_dict(level=LevelInfo.SUMMARY): " ) summary_dict = my_custom_ws.to_dict(level=LevelInfo.SUMMARY) ref_summary_dict = { "description": "Custo2 description", "label": "Custo2", "parent": { "description": "Python tan from math::my_tan", "label": "TestCustomizedAlgoWs ORM impl for CustomizedAlgo", "id": 11, "name": "TestCustomizedAlgoWs ORM impl for CustomizedAlgo" }, "name": "TestCustomizedAlgoWs Custo2 of my_pseudo_impl_from_db", "family": "TestCustomizedAlgoWs tested family", "is_customized": True, "id": 5, "algo": "TestCustomizedAlgoWsmy algo", "visibility": True } self.info(json.dumps(obj=summary_dict, indent=2)) self.assertEqual(summary_dict['parent']['id'], self.my_custom_algo_2_in_DB.implementation.db_id) self.assertEqual(summary_dict['id'], self.my_custom_algo_2_in_DB.db_id) # Needed before comparing dict: # change hard-coded ID values: # hard-coded IDS can be different from IDs from prepared DB # ref_summary_dict['parent']['id'] = summary_dict['parent']['id'] ref_summary_dict['id'] = summary_dict['id'] self.assertDictEqual(ref_summary_dict, summary_dict)
def convert_to_ws_list_custom_algo(cls, custom_algo_list, level=LevelInfo.SUMMARY): """ Returns the list of json-friendly dictionaries: each dictionary is matching the content view of - each CustomizedAlgo resource from custom_algo_list - according to specified level :param custom_algo_list: the list of business resources CustomizedAlgo :type custom_algo_list: list :param level: the specified level: optional, default value is SUMMARY :type level: LevelInfo :return: the json string coding the list of customized algo resources :rtype: list """ my_rest_api_list = [] for custom in custom_algo_list: my_ws = CustomizedAlgoWs(custom) my_rest_api_list.append(my_ws.to_dict(level=level)) return my_rest_api_list
def test_checked_exec_errors_seq2(self): """ Test run with - customized algo inconsistent with its implementation: 2 wrong specified values - run args: angle (no value overriding) => CheckEngine detects errors Note: this unit test is testing the expected error code. """ angle = 1.58 # Wrong type : string for factor # # Wrong value for phase: 5.0 is outside of the domain defined in # my_pseudo_impl_with_domain_from_db: [0, 1.1, 2 ] # # ... checking rule are not activated here: my_custom = self.init_resource_named("Custom for created at {}".format(time.time()), save_in_db=True, implem=self.my_pseudo_impl_with_domain_from_db, factor="3", phase=5.0) my_id = my_custom.name my_async = False my_opts = {'async': my_async, 'custo_algo': True, 'debug': True} # case where # => no parameter value is redefined # => only argument angle is specified my_args = {'angle': angle} my_data = {'opts': my_opts, 'args': my_args} # self.info("- Implem ={}".format( my_custom.implementation ) ) self.info("- Custom ={}".format(CustomizedAlgoWs(my_custom).to_json(indent=2, level=LevelInfo.DETAIL))) self.info("- data ={}".format(json.dumps(obj=my_data, indent=2))) http_req = self.request_factory.post(path=reverse(viewname='algo_run', args=[my_id]), data=json.dumps(my_data), content_type="application/json") self.info("- data ={}".format(json.dumps(obj=my_data, indent=2))) http_response = views_algo_run(http_req, my_id) # Display the check result result = json_io.decode_json_from_http_response(http_response) self.info("response loaded={}".format(result)) self.info("response status={}".format(http_response.status_code)) self.assertTrue(http_response.status_code == HttpResponseFactory.BAD_REQUEST_HTTP_STATUS)
def test_custo_create_409(self): """ Tests the Creation failure case: CONFLICT_HTTP_STATUS """ http_req = self.request_factory.post( path=reverse('pattern_custom_algos_dummy'), data=CustomizedAlgoWs(self.my_custom_algo_in_DB).to_json(), content_type="application/json_util") http_response = create_custom_algo(http_req) self.assertTrue(http_response.status_code == HttpResponseFactory.CONFLICT_HTTP_STATUS)
def test_custo_update_404(self): """ Tests the not found case, updating a CustomizedAlgo resource - returned status is 404 """ my_ws_modif = CustomizedAlgoWs(self.my_custom_algo_in_DB).to_dict() unknown = 99999 my_ws_modif['id'] = unknown my_json_data = json.dumps(obj=my_ws_modif) client = Client() http_response_bis = client.put( '/ikats/algo/custom/custom_algos/{}'.format(unknown), data=my_json_data) self.assertTrue(http_response_bis.status_code == HttpResponseFactory.NOT_FOUND_HTTP_STATUS)
def test_custo_update_400(self): """ Tests the CustomizedAlgo Update failure case with BAD_REQUEST_HTTP_STATUS: - case when the CustomizedAlgo ID is unknown by database """ # TEST: bad id in the URL => input error my_modif = self.my_custom_algo_in_DB http_req = self.request_factory.put( path=reverse(viewname='pattern_custom_algos_with_id', args=["9999999"]), data=CustomizedAlgoWs(my_modif).to_json(), content_type="application/json_util") http_response = update_custom_algo(http_request=http_req, customized_algo_id="9999999") self.assertTrue(http_response.status_code == HttpResponseFactory.BAD_REQUEST_HTTP_STATUS)
def test_custo_update_200(self): """ Tests the nominal Update of CustomizedAlgo """ my_modif = self.my_custom_algo_in_DB my_modif.label = "Modified label" http_req = self.request_factory.put( path=reverse(viewname='pattern_custom_algos_with_id', args=[my_modif.db_id]), data=CustomizedAlgoWs(my_modif).to_json(), content_type="application/json_util") http_response = update_custom_algo(http_req, customized_algo_id=my_modif.db_id) self.assertTrue( http_response.status_code == HttpResponseFactory.OK_HTTP_STATUS)
def test_custo_read_200(self): """ Tests the nominal reading of resource initialized in test DB: self.my_custom_algo_in_DB """ my_id = self.my_custom_algo_in_DB.db_id http_response = get_custom_algo(http_request=HttpRequest(), customized_algo_id=my_id, query_dict=None) self.assertTrue( http_response.status_code == HttpResponseFactory.OK_HTTP_STATUS) # Check result content: ... self.my_custom_algo_in_DB == biz_result dict_result = json_io.decode_json_from_http_response(http_response) ws_result = CustomizedAlgoWs.load_from_dict(dict_result) biz_result = ws_result.get_customized_algo() self.assertTrue(self.my_custom_algo_in_DB == biz_result)
def test_checked_exec_nominal_seq1(self): """ Tests that the nominal execution on one CustomizedAlgo consistent with its Implementation: - is executed in nominal mode (no tests about Python execution: tested by another Test unit) Note: this unit test is testing the expected error code. TODO: complete this test: evaluate that response body is empty """ angle = 1.58 my_custom = self.init_resource_named("Custom for created at {}".format(time.time()), save_in_db=True) my_name = my_custom.name my_async = False my_opts = {'async': my_async, 'custo_algo': my_name, 'debug': True} my_args = {'angle': angle} my_data = {'opts': my_opts, 'args': my_args} # self.info("- Implem ={}".format( my_custom.implementation ) ) self.info("- Custom ={}".format(CustomizedAlgoWs(my_custom).to_json(indent=2, level=LevelInfo.DETAIL))) self.info("- data ={}".format(json.dumps(obj=my_data, indent=2))) http_req = self.request_factory.post(path=reverse(viewname='algo_run', args=[my_name]), data=json.dumps(my_data), content_type="application/json") self.info("- data ={}".format(json.dumps(obj=my_data, indent=2))) http_response = views_algo_run(http_req, my_name) # Display the check result result = json_io.decode_json_from_http_response(http_response) self.info("response loaded={}".format(result)) self.info("response status={}".format(http_response.status_code)) self.assertTrue(http_response.status_code == HttpResponseFactory.OK_HTTP_STATUS)
def convert_to_business_custo_algo(cls, custom_algo_from_json): """ Returns the business CustomizedAlgo resource from the equivalent json string. the customized algorithm :param custom_algo_from_json: json input encoding the resource :type custom_algo_from_json: str or equivalent json-friendly dict :return: the business resource CustomizedAlgo :rtype: CustomizedAlgo """ if type(custom_algo_from_json) is str: my_dict = json.loads(custom_algo_from_json) elif type(custom_algo_from_json) is dict: my_dict = custom_algo_from_json else: msg = "Unexpected type={} for arg custom_algo_from_json in convert_to_business_custo_algo()" raise IkatsException( msg.format(type(custom_algo_from_json).__name__)) my_ws_custo_algo = CustomizedAlgoWs.load_from_dict(my_dict) return my_ws_custo_algo.get_customized_algo()
def test_to_dict_normal_seq1(self): """ Tests the building of Normal-leveled json view of CustomizedAlgoWs """ my_custom_ws = CustomizedAlgoWs(self.my_custom_algo_in_DB) self.info( "- Evaluating my_custom_ws => to_dict(level=LevelInfo.NORMAL): ") normal_dict = my_custom_ws.to_dict(level=LevelInfo.NORMAL) my_dict_str = json.dumps(obj=normal_dict, indent=2) self.info(my_dict_str) # Hard-defined reference: a bit long # --> start definition of ref_normal_dict ... ref_normal_dict = { "is_customized": True, "name": "Custo1 of my_pseudo_impl_from_db", "description": "Custo1 description", "inputs": [{ "domain": None, "name": "angle", "description": "angle (rad)", "type": None, "label": "angle", "order_index": 0 }], "parameters": [{ "domain": None, "name": "factor", "description": "factor on angle", "default_value": None, "type": "number", "label": "factor", "value": 0.5, "order_index": 1 }, { "domain": None, "name": "phase", "description": "added phase constant", "default_value": 0, "type": "number", "label": "phase", "value": 1.5, "order_index": 2 }], "label": "Custo1", "family": "TestCustomizedAlgoWs tested family", "parent": { "label": "TestCustomizedAlgoWs ORM impl for CustomizedAlgo", "name": "TestCustomizedAlgoWs ORM impl for CustomizedAlgo", "description": "Python tan from math::my_tan", "id": 11 }, "outputs": [{ "domain": None, "name": "result", "description": "tan(factor*angle+phase)", "type": None, "label": "result", "order_index": 0 }], "algo": "TestCustomizedAlgoWsmy algo", "id": 4, "visibility": True } # ... end definition of ref_normal_dict self.assertEqual(normal_dict['parent']['id'], self.my_custom_algo_in_DB.implementation.db_id) self.assertEqual(normal_dict['id'], self.my_custom_algo_in_DB.db_id) # Needed before comparing dict: # change hard-coded ID values: hard-coded values may be different from IDs from prepared DB # ref_normal_dict['parent']['id'] = normal_dict['parent']['id'] ref_normal_dict['id'] = normal_dict['id'] self.assertDictEqual(ref_normal_dict, normal_dict)
def test_to_dict_detailed_seq2(self): """ Tests the building of DETAIL-leveled json view """ my_custom_ws = CustomizedAlgoWs(self.my_custom_algo_2_in_DB) self.info( "- Evaluating my_custom_algo_2_in_DB => to_dict(level=LevelInfo.DETAIL): " ) detailed_dict = my_custom_ws.to_dict(level=LevelInfo.DETAIL) my_dict_str = json.dumps(obj=detailed_dict, indent=2) self.info(my_dict_str) # Hard-defined reference: a bit long # --> start definition of ref_dict ... ref_dict = { "is_customized": True, "execution_plugin": "apps.algo.execute.models.business.python_local_exec_engine::PythonLocalExecEngine", "outputs": [{ "label": "result", "domain": None, "type": None, "name": "result", "order_index": 0, "description": "tan(factor*angle+phase)" }], "family": "TestCustomizedAlgoWs tested family", "label": "Custo2", "library_address": "ikats.processing.ikats_processing.tests.test_contrib::my_tan", "name": "TestCustomizedAlgoWs Custo2 of my_pseudo_impl_from_db", "algo": "TestCustomizedAlgoWsmy algo", "inputs": [{ "label": "angle", "domain": None, "type": None, "name": "angle", "order_index": 0, "description": "angle (rad)" }], "parameters": [{ "label": "factor", "value": 0.885, "default_value": None, "domain": None, "type": "number", "name": "factor", "order_index": 1, "description": "factor on angle" }, { "label": "phase", "value": 0.33, "default_value": 0, "domain": None, "type": "number", "name": "phase", "order_index": 2, "description": "added phase constant" }], "id": 5, "description": "Custo2 description", "visibility": True, "parent": { "id": 11, "label": "TestCustomizedAlgoWs ORM impl for CustomizedAlgo", "name": "TestCustomizedAlgoWs ORM impl for CustomizedAlgo", "description": "Python tan from math::my_tan" } } # ... end definition of ref_dict self.assertEqual(detailed_dict['parent']['id'], self.my_custom_algo_2_in_DB.implementation.db_id) self.assertEqual(detailed_dict['id'], self.my_custom_algo_2_in_DB.db_id) # Needed before comparing dict: # change hard-coded ID values: # hard-coded IDS can be different from IDs from prepared DB # ref_dict['parent']['id'] = detailed_dict['parent']['id'] ref_dict['id'] = detailed_dict['id'] self.assertDictEqual(ref_dict, detailed_dict)