def prepare_post_body_data(request, adcm_api_fs: ADCMTestApiWrapper): """ Fixture for preparing test data for POST request, depending on generated test datasets """ test_data_list: List[TestDataWithPreparedBody] = request.param valid_request_data = DbFiller( adcm=adcm_api_fs).generate_valid_request_data( endpoint=test_data_list[0].test_data.request.endpoint, method=Methods.POST) final_test_data_list: List[TestDataWithPreparedBody] = [] for test_data_with_prepared_values in test_data_list: test_data, prepared_field_values = test_data_with_prepared_values test_data.request.data = deepcopy(valid_request_data["data"]) for field in get_fields(test_data.request.endpoint.data_class): if field.name in prepared_field_values: if not prepared_field_values[field.name].drop_key: valid_field_value = None if field.name in test_data.request.data: valid_field_value = test_data.request.data[field.name] test_data.request.data[field.name] = prepared_field_values[ field.name].return_value(valid_field_value) else: if field.name in test_data.request.data: del test_data.request.data[field.name] final_test_data_list.append( TestDataWithPreparedBody(test_data, prepared_field_values)) return adcm_api_fs, final_test_data_list
def generate_body_for_checks(test_data: TestDataWithPreparedBody): """ Generate expected response fields values by test data """ test_data, prepared_field_values = test_data body = ExpectedBody() for field in get_fields(test_data.request.endpoint.data_class): body.fields[field.name] = not_set if is_fk_field(field): # TODO add fk field check continue if field.default_value == AUTO_VALUE: continue if test_data.request.method == Methods.POST: continue if isinstance(body.fields[field.name], list): # TODO implement list checks with sorting continue if (test_data.request.method == Methods.PATCH and not field.changeable and field.name in prepared_field_values and prepared_field_values[field.name].generated_value): body.fields[field.name] = NotEqual( test_data.request.data.get(field.name)) elif is_password_field(field): body.fields[field.name] = field.f_type.placeholder elif expected_field_value := test_data.request.data.get(field.name): body.fields[field.name] = expected_field_value
def prepare_patch_body_data(request, adcm_api_fs: ADCMTestApiWrapper): """ Fixture for preparing test data for PATCH request, depending on generated test datasets """ test_data_list: List[TestDataWithPreparedBody] = request.param dbfiller = DbFiller(adcm=adcm_api_fs) valid_data = dbfiller.generate_valid_request_data( endpoint=test_data_list[0].test_data.request.endpoint, method=Methods.PATCH) full_item = deepcopy(valid_data["full_item"]) changed_fields = deepcopy(valid_data["changed_fields"]) final_test_data_list: List[TestDataWithPreparedBody] = [] for test_data_with_prepared_values in test_data_list: test_data, prepared_field_values = deepcopy( test_data_with_prepared_values) for field in get_fields(test_data.request.endpoint.data_class): if (field.name in prepared_field_values ) and not prepared_field_values[field.name].drop_key: current_field_value = full_item[field.name] if prepared_field_values[field.name].unchanged_value is False: changed_field_value = changed_fields.get(field.name, None) test_data.request.data[field.name] = prepared_field_values[ field.name].return_value(dbfiller, current_field_value, changed_field_value) else: test_data.request.data[field.name] = current_field_value test_data.request.object_id = valid_data["object_id"] final_test_data_list.append( TestDataWithPreparedBody(test_data, prepared_field_values)) return adcm_api_fs, final_test_data_list
def generate_valid_request_data(self, endpoint: Endpoints, method: Methods) -> dict: """ Return valid request body and url params for endpoint and method combination """ if method == Methods.POST: return { "data": self._get_or_create_data_for_endpoint( endpoint=endpoint, force=True, prepare_data_only=True, )[0], "url_params": {}, } if method == Methods.LIST: self._get_or_create_multiple_data_for_endpoint(endpoint=endpoint, count=3) return {"data": None, "url_params": {}} full_item = get_object_data( adcm=self.adcm, endpoint=endpoint, object_id=self._get_or_create_data_for_endpoint(endpoint=endpoint)[0]['id'], ) if method in (Methods.GET, Methods.DELETE): return {"data": None, "url_params": {}, "object_id": full_item["id"]} if method in (Methods.PUT, Methods.PATCH): changed_fields = {} for field in get_fields(endpoint.data_class, predicate=lambda x: x.changeable): if isinstance(field.f_type, ForeignKey): fk_data = self._get_or_create_data_for_endpoint( endpoint=Endpoints.get_by_data_class(field.f_type.fk_link), force=True ) if isinstance(field.f_type, ForeignKeyM2M): changed_fields[field.name] = [{"id": el["id"]} for el in fk_data] elif isinstance(field.f_type, ObjectForeignKey): changed_fields[field.name] = {"id": fk_data[0]["id"]} else: changed_fields[field.name] = fk_data[0]["id"] elif field.name != "id": changed_fields[field.name] = self._generate_field_value( field=field, old_value=full_item[field.name] ) if getattr(endpoint.data_class, 'dependable_fields_sync', None): changed_fields = endpoint.data_class.dependable_fields_sync(self.adcm, changed_fields) result = { "full_item": full_item.copy(), "changed_fields": changed_fields, "url_params": {}, "object_id": full_item["id"], } full_item.update(changed_fields) result["data"] = full_item return result raise ValueError(f"No such method {method}")
def _prepare_data_for_object_creation(self, endpoint: Endpoints = None, force=False): data = {} for field in get_fields(data_class=endpoint.data_class, predicate=lambda x: x.postable): if field.name in data: continue if field.f_type.relates_on: data_with_relates, field = self._solve_field_relations(endpoint, data, field, force) data.update(data_with_relates) data[field.name] = self._prepare_field_value_for_object_creation(field, force) return data
def get_child_endpoint_by_fk_name( self, field_name: str) -> Optional["Endpoints"]: """Get child endpoint instance by data class""" for field in get_fields(self.value.data_class): # pylint: disable=no-member if field.name == field_name: try: return self.get_by_data_class(field.f_type.fk_link) except AttributeError: raise ValueError( f"Field {field_name} must be a Foreign Key field type" ) from AttributeError return None
def _get_special_body_datasets(endpoint: Endpoints, desc, method: Methods, positive_case: bool) -> (list, str): """Get datasets with based on special values for fields""" datasets = [] special_values = {} field_condition = False for field in get_fields(endpoint.data_class): if method == Methods.POST: field_condition = field.postable if method in [Methods.PATCH, Methods.PUT]: field_condition = field.changeable if field_condition: if positive_case: special_values[field.name] = field.f_type.get_positive_values() else: # Since Json does not have an invalid value, # in case when this is the only field in a negative case, # we do not include it in the tests. # For example: PATCH and PUT methods in MountPoint negative_values = get_fields( endpoint.data_class, predicate=lambda x: x.f_type.get_negative_values() and (x.changeable if method in [Methods.PATCH, Methods.PUT] else x.postable), # noqa: W504 ) if negative_values: special_values[field.name] = ( field.f_type.get_negative_values() if field.f_type.get_negative_values() else [ PreparedFieldValue(generated_value=True, f_type=field.f_type) ]) if special_values: fill_lists_by_longest(special_values.values()) for name, values in special_values.copy().items(): special_values[name] = [{name: value} for value in values] for values in zip(*special_values.values()): datasets.append(dict(ChainMap(*values))) return datasets, desc
def prepare_put_body_data(request, adcm_api_fs: ADCMTestApiWrapper): """ Fixture for preparing test data for PUT request, depending on generated test datasets """ test_data_list: List[TestDataWithPreparedBody] = request.param dbfiller = DbFiller(adcm=adcm_api_fs) endpoint = test_data_list[0].test_data.request.endpoint valid_data = dbfiller.generate_valid_request_data(endpoint=endpoint, method=Methods.PUT) full_item = deepcopy(valid_data["full_item"]) changed_fields = deepcopy(valid_data["changed_fields"]) final_test_data_list: List[TestDataWithPreparedBody] = [] for test_data_with_prepared_values in test_data_list: test_data, prepared_field_values = deepcopy( test_data_with_prepared_values) test_data.request.data = deepcopy(full_item) for field in get_fields(test_data.request.endpoint.data_class): if field.name in prepared_field_values: if not prepared_field_values[field.name].drop_key: if prepared_field_values[ field.name].unchanged_value is False: current_field_value = full_item[field.name] changed_field_value = changed_fields.get( field.name, None) test_data.request.data[ field.name] = prepared_field_values[ field.name].return_value( dbfiller, current_field_value, changed_field_value) else: if field.name in test_data.request.data: del test_data.request.data[field.name] else: # When we want to drop some fields, but leave others with: # - changed value if fields are changeable # - value as is if field.name in changed_fields: test_data.request.data[field.name] = changed_fields[ field.name] test_data.request.object_id = valid_data["object_id"] if getattr(endpoint.data_class, 'dependable_fields_sync', None): test_data.request.data = endpoint.data_class.dependable_fields_sync( adcm_api_fs, test_data.request.data) final_test_data_list.append( TestDataWithPreparedBody(test_data, prepared_field_values)) return adcm_api_fs, final_test_data_list
def _add_child_fk_values_to_available_fkeys(self, fk_ids: list, fk_data_class): """Add information about child FK values to metadata for further consistency""" for child_fk_field in get_fields(data_class=fk_data_class, predicate=is_fk_field): fk_field_name = get_field_name_by_fk_dataclass( data_class=fk_data_class, fk_data_class=child_fk_field.f_type.fk_link ) for fk_id in fk_ids: fk_data = get_object_data( adcm=self.adcm, endpoint=Endpoints.get_by_data_class(fk_data_class), object_id=fk_id, ) if isinstance(child_fk_field.f_type, ForeignKeyM2M): self._available_fkeys[child_fk_field.f_type.fk_link.__name__].update( [el["id"] for el in fk_data[fk_field_name]] ) elif isinstance(child_fk_field.f_type, ForeignKey): self._available_fkeys[child_fk_field.f_type.fk_link.__name__].add(fk_data[fk_field_name])
def _get_datasets( endpoint: Endpoints, desc, field_conditions, value_properties: dict, ) -> (list, str): """Generic dataset creator for editing request data later""" dataset = {} if "generated_value" in value_properties and "value" in value_properties: raise ValueError( "'generated_value', 'value' properties are not compatible") for field in get_fields(endpoint.data_class): if field_conditions(field): dataset[field.name] = PreparedFieldValue( value=value_properties.get("value", None), unchanged_value=value_properties.get("unchanged_value", False), generated_value=value_properties.get("generated_value", False), error_messages=[value_properties.get("error_message", None)], drop_key=value_properties.get("drop_key", False), f_type=field.f_type, ) return [dataset] if dataset else [], desc
def get_data_for_params_check(method=Methods.GET, fields_predicate=None): """ Get test data for GET-request params check, such as flex fields, filtering and ordering """ test_data = [] for endpoint in Endpoints: if endpoint.technical: continue if method not in endpoint.methods: continue if not get_fields(endpoint.data_class, predicate=fields_predicate): continue request = Request(method=method, endpoint=endpoint) response = ExpectedResponse(status_code=method.default_success_code) test_data.append( _fill_pytest_param( [TestData(request=request, response=response)], endpoint=endpoint, method=method, positive=True, )) return test_data