class TestLandCoverService(TestWithFullModelRun): def setUp(self): dap_client_factory = DapClientFactory() dap_client_factory.get_land_cover_dap_client = self._mock_get_land_cover_dap_client dap_client_factory.get_soil_properties_dap_client = self._mock_get_soil_properties_dap_client self.land_cover_service = LandCoverService(dap_client_factory=dap_client_factory) self.model_run_service = ModelRunService() self.dataset_service = DatasetService() self.parameter_service = ParameterService() self.clean_database() self.user = self.login() self.create_model_run_ready_for_submit() @staticmethod def _mock_get_land_cover_dap_client(url, key): return MockLandCoverDapClient(url, key) @staticmethod def _mock_get_soil_properties_dap_client(url): return MockSoilPropertiesDapClient(url) def test_GIVEN_land_cover_regions_exist_WHEN_get_land_cover_region_by_id_THEN_land_cover_region_returned(self): model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) land_cover_region = self.add_land_cover_region(model_run) id = land_cover_region.id returned_region = self.land_cover_service.get_land_cover_region_by_id(id) assert_that(returned_region.id, is_(id)) assert_that(returned_region.name, is_("Wales")) def test_GIVEN_land_cover_categories_WHEN_get_land_cover_region_THEN_returned_region_has_category_loaded(self): model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) land_cover_region = self.add_land_cover_region(model_run) id = land_cover_region.id with session_scope() as session: land_cover_cat = LandCoverRegionCategory() land_cover_cat.name = "River Catchments" land_cover_cat.driving_dataset_id = model_run.driving_dataset_id session.add(land_cover_cat) returned_region = self.land_cover_service.get_land_cover_region_by_id(id) assert_that(returned_region.category.name, is_("Countries")) def test_GIVEN_land_cover_values_WHEN_get_land_cover_values_THEN_land_cover_values_returned(self): lc_values = self.land_cover_service.get_land_cover_values(None) assert_that(len(lc_values), is_(9)) names = [lc_value.name for lc_value in lc_values] assert 'Urban' in names assert constants.FRACTIONAL_ICE_NAME in names def test_GIVEN_return_no_ice_WHEN_get_land_cover_values_THEN_land_cover_values_returned(self): lc_values = self.land_cover_service.get_land_cover_values(None, return_ice=False) assert_that(len(lc_values), is_(8)) names = [lc_value.name for lc_value in lc_values] assert 'Urban' in names assert constants.FRACTIONAL_ICE_NAME not in names def test_GIVEN_multiple_land_cover_categories_WHEN_get_categories_THEN_correct_categories_returned(self): model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) datasets = self.dataset_service.get_driving_datasets(self.user) with session_scope() as session: cat1 = LandCoverRegionCategory() cat1.name = "Countries" cat1.driving_dataset_id = model_run.driving_dataset_id region1 = LandCoverRegion() region1.mask_file = "filepath" region1.name = "Wales" region1.category = cat1 cat2 = LandCoverRegionCategory() cat2.name = "Rivers" cat2.driving_dataset_id = datasets[1].id region2 = LandCoverRegion() region2.mask_file = "filepath2" region2.name = "Thames" region2.category = cat2 session.add_all([region1, region2]) categories = self.land_cover_service.get_land_cover_categories(model_run.driving_dataset_id) assert_that(len(categories), is_(1)) assert_that(categories[0].name, is_("Countries")) def test_GIVEN_categories_have_land_cover_regions_WHEN_get_categories_THEN_category_has_regions_loaded(self): model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) with session_scope() as session: cat1 = LandCoverRegionCategory() cat1.name = "Countries" cat1.driving_dataset_id = model_run.driving_dataset_id region1 = LandCoverRegion() region1.mask_file = "filepath" region1.name = "Wales" region1.category = cat1 cat2 = LandCoverRegionCategory() cat2.name = "Rivers" cat2.driving_dataset_id = model_run.driving_dataset_id region2 = LandCoverRegion() region2.mask_file = "filepath2" region2.name = "Thames" region2.category = cat2 session.add_all([region1, region2]) categories = self.land_cover_service.get_land_cover_categories(model_run.driving_dataset_id) assert_that(len(categories[0].regions), is_(1)) assert_that(categories[0].regions[0].name, is_("Wales")) def test_GIVEN_land_cover_actions_WHEN_save_land_cover_actions_THEN_land_cover_actions_saved(self): model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) land_cover_region = self.add_land_cover_region(model_run) self.add_land_cover_actions(land_cover_region, model_run, [(1, 1), (2, 3)], self.land_cover_service) with session_scope() as session: model_run = self.model_run_service._get_model_run_being_created(session, self.user) actions = model_run.land_cover_actions assert_that(len(actions), is_(2)) def test_GIVEN_existing_land_cover_actions_WHEN_save_land_cover_actions_THEN_land_cover_actions_overwritten(self): model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) land_cover_region = self.add_land_cover_region(model_run) self.add_land_cover_actions(land_cover_region, model_run, [(1, 1), (2, 3)], self.land_cover_service) self.add_land_cover_actions(land_cover_region, model_run, [(2, 4)], self.land_cover_service) with session_scope() as session: model_run = self.model_run_service._get_model_run_being_created(session, self.user) actions = model_run.land_cover_actions assert_that(len(actions), is_(1)) assert_that(actions[0].value_id, is_(2)) assert_that(actions[0].order, is_(4)) def test_GIVEN_no_land_cover_actions_WHEN_save_land_cover_actions_THEN_all_land_cover_actions_removed(self): model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) land_cover_region = self.add_land_cover_region(model_run) self.add_land_cover_actions(land_cover_region, model_run, [(1, 1), (2, 3)], self.land_cover_service) self.add_land_cover_actions(land_cover_region, model_run, [], self.land_cover_service) with session_scope() as session: model_run = self.model_run_service._get_model_run_being_created(session, self.user) actions = model_run.land_cover_actions assert_that(len(actions), is_(0)) def test_GIVEN_land_cover_actions_saved_on_model_run_WHEN_get_land_cover_actions_THEN_actions_returned(self): model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) land_cover_region = self.add_land_cover_region(model_run) self.add_land_cover_actions(land_cover_region, model_run, [(1, 1), (2, 3)], self.land_cover_service) actions = self.land_cover_service.get_land_cover_actions_for_model(model_run) assert_that(len(actions), is_(2)) assert_that(actions[0].value_id, is_(1)) assert_that(actions[0].order, is_(1)) assert_that(actions[1].value_id, is_(2)) assert_that(actions[1].order, is_(3)) def test_GIVEN_land_cover_actions_saved_WHEN_get_actions_THEN_actions_have_regions_and_categories_loaded(self): model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) land_cover_region = self.add_land_cover_region(model_run) self.add_land_cover_actions(land_cover_region, model_run, [(1, 1)], self.land_cover_service) action = self.land_cover_service.get_land_cover_actions_for_model(model_run)[0] assert_that(action.region.name, is_("Wales")) assert_that(action.region.category.name, is_("Countries")) def test_GIVEN_land_cover_actions_saved_WHEN_get_actions_THEN_actions_have_values_loaded(self): model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) land_cover_region = self.add_land_cover_region(model_run) self.add_land_cover_actions(land_cover_region, model_run, [(1, 1)], self.land_cover_service) action = self.land_cover_service.get_land_cover_actions_for_model(model_run)[0] assert_that(action.value.name, is_("Broad-leaved Tree")) def test_GIVEN_fractional_string_WHEN_save_fractional_land_cover_for_model_THEN_fractional_cover_saved(self): model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) assert_that(model_run.land_cover_frac, is_(None)) fractional_string = "0\t0\t0\t0\t0\t0\t0\t0\t1" self.land_cover_service.save_fractional_land_cover_for_model(model_run, fractional_string) model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) assert_that(model_run.land_cover_frac, is_(fractional_string)) def test_GIVEN_user_uploaded_driving_data_WHEN_get_default_fractional_cover_THEN_fractional_cover_returned(self): self.clean_database() self.user = self.login() self.create_model_run_with_user_uploaded_driving_data() model_run = self.set_model_run_latlon(self.user, 70, 0) fractional_vals = self.land_cover_service.get_default_fractional_cover(model_run, self.user) assert_that(fractional_vals, is_([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0])) def test_GIVEN_two_matching_datasets_WHEN_get_default_cover_THEN_higher_priority_fractional_cover_returned(self): self.clean_database() self.user = self.login() self.create_model_run_with_user_uploaded_driving_data() model_run = self.set_model_run_latlon(self.user, 0, 0) fractional_vals = self.land_cover_service.get_default_fractional_cover(model_run, self.user) assert_that(fractional_vals, is_([0.02, 0.11, 0.02, 0.05, 0.35, 0.19, 0.22, 0.04, 0.0])) def test_GIVEN_no_matching_datasets_WHEN_get_default_cover_THEN_zeros_returned(self): self.clean_database() self.user = self.login() self.create_model_run_with_user_uploaded_driving_data() model_run = self.set_model_run_latlon(self.user, 88, 0) fractional_vals = self.land_cover_service.get_default_fractional_cover(model_run, self.user) assert_that(fractional_vals, is_([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])) def test_GIVEN_thredds_not_working_WHEN_get_default_cover_THEN_zeros_returned(self): self.clean_database() self.user = self.login() self.create_model_run_with_user_uploaded_driving_data() def _get_broken_dap_client(url, key): return MockLandCoverDapClient("broken_url", key) dap_client_factory = DapClientFactory() dap_client_factory.get_land_cover_dap_client = _get_broken_dap_client self.land_cover_service = LandCoverService(dap_client_factory=dap_client_factory) model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) fractional_vals = self.land_cover_service.get_default_fractional_cover(model_run, self.user) assert_that(fractional_vals, is_([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])) def test_GIVEN_using_provided_driving_data_WHEN_get_default_fractional_cover_THEN_fractional_cover_returned(self): self.clean_database() self.user = self.login() self.create_alternate_model_run() model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) fractional_vals = self.land_cover_service.get_default_fractional_cover(model_run, self.user) assert_that(fractional_vals, is_([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0])) def test_GIVEN_multicell_model_run_WHEN_get_default_fractional_cover_THEN_ServiceException_raised(self): self.clean_database() self.user = self.login() self.create_model_run_ready_for_submit() model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) with self.assertRaises(ServiceException): self.land_cover_service.get_default_fractional_cover(model_run, self.user) def test_GIVEN_user_uploaded_driving_data_WHEN_set_default_soil_properties_THEN_soil_cover_set(self): self.clean_database() self.user = self.login() self.create_model_run_with_user_uploaded_driving_data() model_run = self.set_model_run_latlon(self.user, 51, 0) self.land_cover_service.save_default_soil_properties(model_run, self.user) #self._land_cover_service.dap_client_factory.get_soil_properties_dap_client = _mock_get_soil_props_client model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) nvars = model_run.get_python_parameter_value(constants.JULES_PARAM_SOIL_PROPS_NVARS) var = model_run.get_python_parameter_value(constants.JULES_PARAM_SOIL_PROPS_VAR, is_list=True) use_file = model_run.get_python_parameter_value(constants.JULES_PARAM_SOIL_PROPS_USE_FILE, is_list=True) const_val = model_run.get_python_parameter_value(constants.JULES_PARAM_SOIL_PROPS_CONST_VAL, is_list=True) assert_that(nvars, is_(9)) assert_that(var, is_(['b', 'sathh', 'satcon', 'sm_sat', 'sm_crit', 'sm_wilt', 'hcap', 'hcon', 'albsoil'])) assert_that(use_file, is_(9 * [False])) assert_that(const_val, is_([0.9, 0.0, 0.0, 50.0, 275.0, 278.0, 10.0, 0.0, 0.5])) def test_GIVEN_no_appropriate_driving_data_WHEN_set_default_soil_properties_THEN_values_not_set(self): self.clean_database() self.user = self.login() self.create_model_run_with_user_uploaded_driving_data() model_run = self.set_model_run_latlon(self.user, 90, 0) self.land_cover_service.save_default_soil_properties(model_run, self.user) model_run = self.model_run_service.get_model_being_created_with_non_default_parameter_values(self.user) nvars = model_run.get_python_parameter_value(constants.JULES_PARAM_SOIL_PROPS_NVARS) var = model_run.get_python_parameter_value(constants.JULES_PARAM_SOIL_PROPS_VAR) use_file = model_run.get_python_parameter_value(constants.JULES_PARAM_SOIL_PROPS_USE_FILE, is_list=True) const_val = model_run.get_python_parameter_value(constants.JULES_PARAM_SOIL_PROPS_CONST_VAL, is_list=True) assert_that(nvars, is_(None)) assert_that(var, is_(None)) assert_that(use_file, is_(None)) assert_that(const_val, is_(None)) def set_model_run_latlon(self, user, lat, lon): params_to_save = [[constants.JULES_PARAM_POINTS_FILE, [lat, lon]]] params_to_del = constants.JULES_PARAM_POINTS_FILE self.parameter_service.save_new_parameters(params_to_save, params_to_del, user.id) return self.model_run_service.get_model_being_created_with_non_default_parameter_values(user)
class TestModelRunLandCover(TestController): def setUp(self): self.clean_database() self.user = self.login() self.create_two_driving_datasets() dds = DatasetService().get_driving_datasets(self.user)[0] with session_scope() as session: model_run = ModelRun() model_run.name = "model run" model_run.change_status(session, MODEL_RUN_STATUS_CREATED) model_run.user = self.user model_run.driving_dataset_id = dds.id session.add(model_run) session.commit() self.model_run_service = ModelRunService() model_run = self.model_run_service._get_model_run_being_created(session, self.user) parameter_val = ParameterValue() parameter_val.parameter = self.model_run_service.get_parameter_by_constant(JULES_PARAM_LATLON_REGION) parameter_val.set_value_from_python(True) parameter_val.model_run_id = model_run.id session.add(parameter_val) self.add_land_cover_region(model_run) def test_GIVEN_land_cover_actions_WHEN_post_THEN_land_cover_action_saved_in_database(self): with session_scope() as session: model_run = self.model_run_service._get_model_run_being_created(session, self.user) dds = model_run.driving_dataset categories = LandCoverService().get_land_cover_categories(dds.id) # Need to know the region IDs self.app.post( url(controller='model_run', action='land_cover'), params={ 'submit': u'Next', 'action_1_region': str(categories[0].regions[0].id), 'action_1_value': u'8', 'action_1_order': u'1', 'action_2_region': str(categories[0].regions[0].id), 'action_2_value': u'7', 'action_2_order': u'2' }) with session_scope() as session: model_run = self.model_run_service._get_model_run_being_created(session, self.user) actions = model_run.land_cover_actions assert_that(len(actions), is_(2)) for action in actions: if action.value_id == 8: assert_that(action.order, is_(1)) elif action.value_id == 7: assert_that(action.order, is_(2)) else: assert False def test_GIVEN_invalid_land_cover_actions_WHEN_post_THEN_error_shown_and_stay_on_page(self): # Add some regions to another driving dataset dds = DatasetService().get_driving_datasets(self.user)[1] with session_scope() as session: land_cat = LandCoverRegionCategory() land_cat.driving_dataset = dds land_cat.name = "Category2" land_region = LandCoverRegion() land_region.name = "Region1" land_region.category = land_cat session.add(land_region) response = self.app.post( url(controller='model_run', action='land_cover'), params={ 'submit': u'Next', 'action_1_region': str(land_region.id), 'action_1_value': u'8', 'action_1_order': u'1' }) assert_that(response.normal_body, contains_string("Land Cover")) # Check still on page assert_that(response.normal_body, contains_string("Land Cover Region not valid for the chosen driving data")) def test_GIVEN_land_cover_values_and_regions_exist_WHEN_get_THEN_regions_and_categories_rendered(self): with session_scope() as session: model_run = self.model_run_service._get_model_run_being_created(session, self.user) dds = model_run.driving_dataset session.add_all(self.generate_categories_with_regions(dds)) response = self.app.get(url(controller='model_run', action='land_cover')) assert_that(response.normal_body, contains_string("Rivers")) assert_that(response.normal_body, contains_string("Thames")) assert_that(response.normal_body, contains_string("Itchen")) assert_that(response.normal_body, contains_string("Counties")) assert_that(response.normal_body, contains_string("Hampshire")) assert_that(response.normal_body, contains_string("Oxfordshire")) def test_GIVEN_nothing_WHEN_get_THEN_values_rendered(self): response = self.app.get(url(controller='model_run', action='land_cover')) values = LandCoverService().get_land_cover_values(None, return_ice=False) for value in values: assert_that(response.normal_body, contains_string(str(value.name))) def test_GIVEN_land_cover_action_already_saved_WHEN_get_THEN_action_rendered(self): with session_scope() as session: model_run = self.model_run_service._get_model_run_being_created(session, self.user) dds = model_run.driving_dataset session.add_all(self.generate_categories_with_regions(dds)) action = LandCoverAction() action.model_run = model_run action.region_id = 1 # Thames action.value_id = 5 # Shrub response = self.app.get(url(controller='model_run', action='land_cover')) assert_that(response.normal_body, contains_string("Change <b>Thames (Rivers)</b> to <b>Shrub</b>")) def test_GIVEN_invalid_land_cover_actions_already_saved_WHEN_get_THEN_errors_returned_no_actions_rendered(self): with session_scope() as session: model_run = self.model_run_service._get_model_run_being_created(session, self.user) dds = model_run.driving_dataset session.add_all(self.generate_categories_with_regions(dds)) action = LandCoverAction() action.model_run = model_run action.region_id = 1 # Thames action.value_id = 9 # Ice session.add(action) session.commit() # Set the model run to have a different driving dataset - this should result in an error model_run.driving_dataset = session.query(DrivingDataset).filter(DrivingDataset.name == "driving2").one() response = self.app.get(url(controller='model_run', action='land_cover')) assert_that(response.normal_body, contains_string("Your saved Land Cover edits are not valid for the " "chosen driving data")) assert_that(response.normal_body, is_not(contains_string("Change <b>"))) # Actions start with this def test_GIVEN_multiple_land_cover_actions_saved_out_of_order_WHEN_get_THEN_order_rendered_correctly(self): with session_scope() as session: model_run = self.model_run_service._get_model_run_being_created(session, self.user) dds = model_run.driving_dataset session.add_all(self.generate_categories_with_regions(dds)) action = LandCoverAction() action.model_run = model_run action.region_id = 1 # Thames action.value_id = 5 # Shrub action.order = 5 session.add(action) session.commit() action2 = LandCoverAction() action2.model_run = model_run action2.region_id = 2 # Itchen action2.value_id = 1 # Broad-leaved Tree action2.order = 1 session.add(action2) session.commit() action3 = LandCoverAction() action3.model_run = model_run action3.region_id = 3 # Hampshire action3.value_id = 6 # Urban action3.order = 2 session.add(action3) session.commit() response = self.app.get(url(controller='model_run', action='land_cover')) order1 = response.normal_body.index("Change <b>Itchen (Rivers)</b> to <b>Broad-leaved Tree</b>") order2 = response.normal_body.index("Change <b>Hampshire (Counties)</b> to <b>Urban</b>") order5 = response.normal_body.index("Change <b>Thames (Rivers)</b> to <b>Shrub</b>") assert (order1 < order2 < order5) def generate_categories_with_regions(self, driving_dataset): # Add categories cat1 = LandCoverRegionCategory() cat1.driving_dataset_id = driving_dataset.id cat1.name = "Rivers" cat1.id = 1 region1 = LandCoverRegion() region1.id = 1 region1.name = "Thames" region1.category_id = 1 region1.category = cat1 region2 = LandCoverRegion() region2.id = 2 region2.name = "Itchen" region2.category_id = 1 region2.category = cat1 cat1.regions = [region1, region2] cat2 = LandCoverRegionCategory() cat2.driving_dataset_id = driving_dataset.id cat2.name = "Counties" cat2.id = 2 region3 = LandCoverRegion() region3.id = 3 region3.name = "Hampshire" region3.category_id = 2 region3.category = cat2 region4 = LandCoverRegion() region4.id = 4 region4.name = "Oxfordshire" region4.category_id = 2 region4.category = cat2 cat2.regions = [region3, region4] return [cat1, cat2]