def test_GIVEN_user_uploaded_driving_data_previously_WHEN_page_submit_THEN_moved_to_next_page(self):
        # 1. User visits driving data page and chooses 'upload'
        # 2. They upload their data
        # 3. They click submit (the driving data is now stored).
        # 4. They return to the driving data page and submit again without changing anything
        # This is acceptable, they should be moved on. In fact no database saves need to occur.
        self._add_model_run_being_created(self.user)

        self.upload_valid_user_driving_data()
        data_service = DatasetService()
        ds_id = data_service.get_id_for_user_upload_driving_dataset()
        response = self.app.post(
            url(controller='model_run', action='driving_data'),
            params={
                'driving_dataset': ds_id,
                'submit': u'Next',
                'lat': u'1800',
                'lon': u'-181',
                'dt_start': u'2011-02-02 11:00',
                'dt_end': u'2017-02-02 11:00',
                'driving-file': u''
            })
        assert_that(response.status_code, is_(302), "Response is redirect")
        assert_that(urlparse(response.response.location).path,
                    is_(url(controller='model_run', action='extents')), "url")
 def create_model_run_ready_for_submit(self):
     # Set up the model as if we'd gone through all the previous pages
     # The Create page
     self.model_name = u'name'
     self.model_description = u'This is a description'
     self.science_config = self.model_run_service.get_scientific_configurations()[0]
     model_science_config_id = self.science_config['id']
     response = self.app.post(url=url(controller='model_run', action='create'),
                              params={
                                  'name': self.model_name,
                                  'science_configuration': str(model_science_config_id),
                                  'description': self.model_description
                              })
     assert response.status_code == 302
     # The Driving Data page
     self.create_two_driving_datasets()
     dataset_service = DatasetService()
     driving_datasets = dataset_service.get_driving_datasets(self.user)
     self.driving_data = [dds for dds in driving_datasets if dds.name == "driving1"][0]
     response = self.app.post(url(controller='model_run', action='driving_data'),
                              params={
                                  'driving_dataset': self.driving_data.id,
                                  'submit': u'Next'
                              })
     assert response.status_code == 302
     # The Extents page
     self.lat_n, self.lat_s = 40, 0
     self.lon_w, self.lon_e = -15, 15
     self.date_start = datetime.datetime(1980, 1, 1, 0, 0, 0)
     self.date_end = datetime.datetime(1980, 1, 1, 0, 0, 0)
     response = self.app.post(url(controller='model_run', action='extents'),
                              params={
                                  'submit': u'Next',
                                  'site': u'multi',
                                  'lat_n': self.lat_n,
                                  'lat_s': self.lat_s,
                                  'lon_e': self.lon_e,
                                  'lon_w': self.lon_w,
                                  'start_date': self.date_start.strftime("%Y-%m-%d"),
                                  'end_date': self.date_end.strftime("%Y-%m-%d")
                              })
     assert response.status_code == 302
     # The Output Variables page
     response = self.app.post(url(controller='model_run', action='output'),
                              params={
                                  'submit': u'Next',
                                  'ov_select_1': 1,
                                  'ov_hourly_1': 1,
                                  'ov_select_10': 1,
                                  'ov_yearly_10': 1,
                                  'ov_monthly_10': 1
                              })
     assert response.status_code == 302
 def upload_valid_user_driving_data(self):
     data_service = DatasetService()
     ds_id = data_service.get_id_for_user_upload_driving_dataset()
     return self.app.post(
         url(controller='model_run', action='driving_data'),
         params={
             'driving_dataset': ds_id,
             'submit': u'Upload',
             'lat': u'55',
             'lon': u'45',
             'dt_start': u'2000-01-01 00:00',
             'dt_end': u'2000-01-01 02:00'},
         upload_files=[('driving-file', 'file.txt', self.sample_file_contents)]
     )
 def test_GIVEN_user_driving_data_but_invalid_dates_WHEN_upload_data_THEN_errors_returned(self):
     self._add_model_run_being_created(self.user)
     data_service = DatasetService()
     ds_id = data_service.get_id_for_user_upload_driving_dataset()
     response = self.app.post(
         url(controller='model_run', action='driving_data'),
         params={
             'driving_dataset': ds_id,
             'submit': u'Upload',
             'lat': u'45',
             'lon': u'55',
             'dt_start': u'2017-02-02 11:00',
             'dt_end': u'this-is-not-a-date'},
         upload_files=[('driving-file', 'file.txt', self.sample_file_contents)]
     )
     assert_that(response.normal_body, contains_string('Enter date as YYYY-MM-DD HH:MM'))
 def test_GIVEN_no_user_driving_data_uploaded_WHEN_upload_THEN_errors_shown(self):
     self._add_model_run_being_created(self.user)
     data_service = DatasetService()
     ds_id = data_service.get_id_for_user_upload_driving_dataset()
     response = self.app.post(
         url(controller='model_run', action='driving_data'),
         params={
             'driving_dataset': ds_id,
             'submit': u'Upload',
             'lat': u'1800',
             'lon': u'-181',
             'dt_start': u'2011-02-02 11:00',
             'dt_end': u'2017-02-02 11:00',
             'driving-file': u''
         })
     assert_that(response.normal_body, contains_string('You must select a driving data file'))
 def test_GIVEN_user_driving_data_but_invalid_lat_lon_WHEN_upload_data_THEN_errors_returned(self):
     self._add_model_run_being_created(self.user)
     data_service = DatasetService()
     ds_id = data_service.get_id_for_user_upload_driving_dataset()
     response = self.app.post(
         url(controller='model_run', action='driving_data'),
         params={
             'driving_dataset': ds_id,
             'submit': u'Upload',
             'lat': u'1800',
             'lon': u'-181',
             'dt_start': u'2011-02-02 11:00',
             'dt_end': u'2017-02-02 11:00'},
         upload_files=[('driving-file', 'file.txt', self.sample_file_contents)]
     )
     assert_that(response.normal_body, contains_string('Latitude must be between -90 and 90'))
     assert_that(response.normal_body, contains_string('Longitude must be between -180 and 180'))
    def test_GIVEN_valid_driving_data_chosen_WHEN_go_back_THEN_create_page_rendered(self):
        self._add_model_run_being_created(self.user)
        self.create_two_driving_datasets()

        dataset_service = DatasetService()
        driving_data = dataset_service.get_driving_datasets(self.user)
        ds_id = driving_data[0].id
        response = self.app.post(
            url(controller='model_run', action='driving_data'),
            params={
                'driving_dataset': ds_id,
                'submit': u'Back'
            })

        assert_that(response.status_code, is_(302), "Response is redirect")
        assert_that(urlparse(response.response.location).path,
                    is_(url(controller='model_run', action='create')), "url")
    def test_GIVEN_valid_driving_data_chosen_WHEN_post_THEN_driving_data_stored_against_model_run(self):
        self._add_model_run_being_created(self.user)
        self.create_two_driving_datasets()

        dataset_service = DatasetService()
        driving_data = dataset_service.get_driving_datasets(self.user)
        ds_id = driving_data[0].id
        self.app.post(
            url(controller='model_run', action='driving_data'),
            params={
                'driving_dataset': ds_id,
                'submit': u'Next'
            })

        model_run_service = ModelRunService()
        model_run = model_run_service.get_model_being_created_with_non_default_parameter_values(self.user)
        param_val = model_run.get_python_parameter_value(constants.JULES_PARAM_DRIVE_FILE)
        assert_that(param_val, is_('testFileName'))
 def test_GIVEN_valid_user_driving_data_selected_WHEN_page_submit_THEN_proceeds_to_next_page(self):
     self._add_model_run_being_created(self.user)
     self.upload_valid_user_driving_data()
     data_service = DatasetService()
     ds_id = data_service.get_id_for_user_upload_driving_dataset()
     response = self.app.post(
         url(controller='model_run', action='driving_data'),
         params={
             'driving_dataset': ds_id,
             'submit': u'Next',
             'lat': u'55',
             'lon': u'45',
             'dt_start': u'2000-01-01 00:00',
             'dt_end': u'2000-01-01 03:00'},
         upload_files=[('driving-file', 'file.txt', self.sample_file_contents)]
     )
     assert_that(response.status_code, is_(302), "Response is redirect")
     assert_that(urlparse(response.response.location).path,
                 is_(url(controller='model_run', action='extents')), "url")
 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()
 def test_GIVEN_upload_dataset_chosen_but_no_uploaded_dataset_WHEN_page_submit_THEN_error_shown(self):
     # 1. User visits driving data page
     # 2. User chooses upload data but doesn't actually upload anything
     # 3. User clicks submit
     # This is bad and an error should appear
     self._add_model_run_being_created(self.user)
     data_service = DatasetService()
     ds_id = data_service.get_id_for_user_upload_driving_dataset()
     response = self.app.post(
         url(controller='model_run', action='driving_data'),
         params={
             'driving_dataset': ds_id,
             'submit': u'Next',
             'lat': u'1800',
             'lon': u'-181',
             'dt_start': u'2011-02-02 11:00',
             'dt_end': u'2017-02-02 11:00',
             'driving-file': u''
         })
     assert_that(response.normal_body, contains_string('You must upload a driving data file'))
    def test_GIVEN_user_driving_data_previously_selected_then_changed_on_page_WHEN_page_submit_THEN_data_not_changed(
            self):
        # This is understood to be the correct action - unless the 'upload' button is clicked, the user
        # driving data does not get processed.
        self._add_model_run_being_created(self.user)
        self.upload_valid_user_driving_data()

        self.app.get(
            url(controller='model_run', action='driving_data'))
        data_service = DatasetService()
        ds_id = data_service.get_id_for_user_upload_driving_dataset()
        self.app.post(
            url(controller='model_run', action='driving_data'),
            params={
                'driving_dataset': ds_id,
                'submit': u'Next',
                'lat': u'12',
                'lon': u'17',
                'dt_start': u'1990-01-01 00:00',
                'dt_end': u'1990-01-01 03:00'},
            upload_files=[('driving-file', 'file2.txt', self.sample_file_contents)]
        )
        self.check_valid_user_driving_data_params_stored()
    def test_GIVEN_user_quota_exceeded_WHEN_navigate_post_to_driving_data_THEN_navigate_to_error_page(self):
        """
        On a post of data the quota should not be checked, the data should just be saved as normal
        """
        user = self.login()
        self.create_run_model(storage_in_mb=user.storage_quota_in_gb * 1024 + 1, name="big_run", user=user)

        self._add_model_run_being_created(self.user)
        self.create_two_driving_datasets()

        dataset_service = DatasetService()
        driving_data = dataset_service.get_driving_datasets(user)
        ds_id = driving_data[0].id
        response = self.app.post(
            url(controller='model_run', action='driving_data'),
            params={
                'driving_dataset': ds_id,
                'submit': u'Next'
            })

        assert_that(response.status_code, is_(302), "Response is redirect")
        assert_that(urlparse(response.response.location).path,
                    is_(url(controller='model_run', action='index')), "url")
    def test_GIVEN_valid_data_WHEN_create_new_THEN_new_set_created(self):

        self.login(access_level=constants.USER_ACCESS_LEVEL_ADMIN)

        valid_params = self.create_valid_post_values()

        response = self.app.post(
            url=url(controller='driving_data', action='edit'),
            params=valid_params,
            expect_errors=True
        )

        assert_that(response.status_code, is_(302), "no redirect after successful post got %s" % response.normal_body)

        with session_scope() as session:
            driving_dataset_id = session\
                .query(DrivingDataset)\
                .filter(DrivingDataset.name == self.new_driving_dataset.name)\
                .one().id
            driving_dataset = DatasetService().get_driving_dataset_by_id(driving_dataset_id)

        assert_that(driving_dataset.name, is_(self.new_driving_dataset.name), "name")
        assert_that(driving_dataset.description, is_(self.new_driving_dataset.description), "description")
        assert_that(driving_dataset.geographic_region, is_(self.new_driving_dataset.geographic_region), "geographic_region")
        assert_that(driving_dataset.spatial_resolution, is_(self.new_driving_dataset.spatial_resolution), "spatial_resolution")
        assert_that(driving_dataset.temporal_resolution, is_(self.new_driving_dataset.temporal_resolution), "temporal_resolution")
        assert_that(driving_dataset.boundary_lat_north, is_(self.new_driving_dataset.boundary_lat_north), "boundary_lat_north")
        assert_that(driving_dataset.boundary_lat_south, is_(self.new_driving_dataset.boundary_lat_south), "boundary_lat_south")
        assert_that(driving_dataset.boundary_lon_east, is_(self.new_driving_dataset.boundary_lon_east), "boundary_lon_east")
        assert_that(driving_dataset.boundary_lon_west, is_(self.new_driving_dataset.boundary_lon_west), "boundary_lon_west")
        assert_that(driving_dataset.view_order_index, is_(self.new_driving_dataset.view_order_index), "view_order_index")
        assert_that(driving_dataset.usage_order_index, is_(self.new_driving_dataset.usage_order_index), "usage_order_index")
        assert_that(driving_dataset.time_start, is_(self.new_driving_dataset.time_start), "start time")
        assert_that(driving_dataset.time_end, is_(self.new_driving_dataset.time_end), "end time")

        assert_that(driving_dataset.get_python_parameter_value(constants.JULES_PARAM_DRIVE_DATA_START),
                    is_(self.new_driving_dataset.time_start), "start time")
        assert_that(driving_dataset.get_python_parameter_value(constants.JULES_PARAM_DRIVE_DATA_END),
                    is_(self.new_driving_dataset.time_end), "end time")
        assert_that(driving_dataset.get_python_parameter_value(constants.JULES_PARAM_INPUT_GRID_NX),
                    is_(valid_params["drive_nx"]), "nx")
        assert_that(driving_dataset.get_python_parameter_value(constants.JULES_PARAM_DRIVE_NVARS),
                    is_(valid_params["drive_nvars"]), "drive_nvars")
        assert_that(driving_dataset.get_python_parameter_value(constants.JULES_PARAM_DRIVE_VAR),
                    is_(self.drive_var), "vars")
        assert_that(len(driving_dataset.locations), is_(2), "number of locations")
 def create_model_run_with_user_uploaded_driving_data(self):
     # Set up the model as if we'd gone through all the previous pages
     # and uploaded our own driving data
     # The Create page
     self.model_name = u'Run with my own driving data'
     self.model_description = u'This is a description of a model_run'
     self.science_config = self.model_run_service.get_scientific_configurations()[0]
     model_science_config_id = self.science_config['id']
     response = self.app.post(url=url(controller='model_run', action='create'),
                              params={
                                  'name': self.model_name,
                                  'science_configuration': str(model_science_config_id),
                                  'description': self.model_description
                              })
     assert response.status_code == 302
     # The Driving Data page
     self.sample_file_contents = "# solar   long  rain  snow    temp   wind     press      humid\n" \
                                 "# sw_down   lw_down  tot_rain  tot_snow    t   wind     pstar      q\n" \
                                 "# i   i  i  i    i   i     i      i\n" \
                                 "3.3  187.8   0.0   0.0  259.10  3.610  102400.5  1.351E-03\n" \
                                 "89.5  185.8   0.0   0.0  259.45  3.140  102401.9  1.357E-03\n" \
                                 "142.3  186.4   0.0   0.0  259.85  2.890  102401.0  1.369E-03\n" \
                                 "# ----- data for later times ----"
     data_service = DatasetService()
     self.create_two_driving_datasets()
     ds_id = data_service.get_id_for_user_upload_driving_dataset()
     response = self.app.post(
         url(controller='model_run', action='driving_data'),
         params={
             'driving_dataset': ds_id,
             'submit': u'Upload',
             'lat': u'55',
             'lon': u'45',
             'dt_start': u'2000-01-01 00:00',
             'dt_end': u'2000-01-01 02:00'},
         upload_files=[('driving-file', 'file.txt', self.sample_file_contents)]
     )
     assert response.status_code == 302
     # The Extents page
     self.lat_n, self.lat_s = 55, 55
     self.lon_w, self.lon_e = 45, 45
     self.date_start = datetime.datetime(2000, 1, 1, 0, 0, 0)
     self.date_end = datetime.datetime(2000, 1, 1, 0, 2, 0)
     response = self.app.post(url(controller='model_run', action='extents'),
                              params={
                                  'submit': u'Next',
                                  'site': u'single',
                                  'lat': self.lat_n,
                                  'lon': self.lon_e,
                                  'start_date': self.date_start.strftime("%Y-%m-%d"),
                                  'end_date': self.date_end.strftime("%Y-%m-%d")
                              })
     assert response.status_code == 302
     # The Output Variables page
     response = self.app.post(url(controller='model_run', action='output'),
                              params={
                                  'submit': u'Next',
                                  'ov_select_6': 1,
                                  'ov_hourly_6': 1,
                                  'ov_monthly_6': 1,
                                  'ov_select_11': 1,
                                  'ov_yearly_11': 1,
                                  'ov_monthly_11': 1
                              })
     assert response.status_code == 302
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)
    def test_GIVEN_valid_data_with_extra_parameters_WHEN_update_THEN_parameters_are_updated(self):

        with session_scope(Session) as session:
            original_count = session\
                .query(DrivingDataset).count()

            parameter_value = DrivingDatasetParameterValue(ModelRunService(), self.driving_dataset, 23, "old value")
            param_id_to_delete = 1
            parameter_value = DrivingDatasetParameterValue(ModelRunService(), self.driving_dataset, param_id_to_delete,
                                                           "to be deleted")

        self.login(access_level=constants.USER_ACCESS_LEVEL_ADMIN)

        valid_params = self.create_valid_post_values()
        valid_params["params_count"] = 1
        parameter_id = 23
        valid_params["param-0.id"] = str(parameter_id)
        valid_params["param-0.value"] = "expected extra parameter value"

        valid_params["mask_count"] = 1
        valid_params["region-0.name"] = "a value"
        valid_params["region-0.category"] = "a value"
        valid_params["region-0.path"] = "a value"
        valid_params["region-0.id"] = ""

        expected_nvars = len(self.drive_var) + 1
        last_index = len(self.drive_var) + 4
        valid_params["drive_nvars"] = last_index + 1
        valid_params["drive_var_-{}.vars".format(last_index)] = 'blah'
        valid_params["drive_var_-{}.names".format(last_index)] = 'blah'
        valid_params["drive_var_-{}.templates".format(last_index)] = 'blah'
        valid_params["drive_var_-{}.interps".format(last_index)] = 'blah'

        response = self.app.post(
            url=url(controller='driving_data', action='edit', id=str(self.driving_dataset.id)),
            params=valid_params,
            expect_errors=True
        )

        assert_that(response.status_code, is_(302), "status code for page")

        with session_scope(Session) as session:
            final_count = session\
                .query(DrivingDataset).count()

        assert_that(final_count, is_(original_count), "number of driving datasets (before and after update)")

        with session_scope(Session) as session:
            driving_dataset = DatasetService().get_driving_dataset_by_id(self.driving_dataset.id)
        regions = LandCoverService().get_land_cover_regions(self.driving_dataset.id)

        assert_that(driving_dataset.name, is_(self.new_driving_dataset.name), "name has changed")
        value = [parameter_value for parameter_value in driving_dataset.parameter_values if parameter_value.parameter_id == parameter_id]
        assert_that(len(value), is_(1), "number of parameter values")
        assert_that(value[0].value, is_(valid_params["param-0.value"]), "parameter value")


        assert_that(driving_dataset.get_python_parameter_value(constants.JULES_PARAM_DRIVE_NVARS), is_(expected_nvars), "nvars")

        for parameter_value in driving_dataset.parameter_values:
            if parameter_value.parameter_id == param_id_to_delete:
                self.fail("Parameter should have been deleted but wasn't")


        assert_that(len(regions), is_(1), "number of regions")
        assert_that(regions[0].name, is_(valid_params["region-0.name"]), "name of region")
        assert_that(regions[0].category.name, is_(valid_params["region-0.category"]), "category of region")
        assert_that(regions[0].mask_file, is_(valid_params["region-0.path"]), "path of region")

        assert_that(len(driving_dataset.locations), is_(expected_nvars), 'driving dataset locations')
class TestDatasetService(TestController):
    """
    Test for the dataset service
    """

    def setUp(self):
        super(TestDatasetService, self).setUp()
        self.dataset_service = DatasetService()
        self.clean_database()

    def test_GIVEN_two_driving_datasets_WHEN_get_driving_datasets_THEN_both_driving_datasets_returned(self):
        user = self.login()
        self.create_two_driving_datasets()
        driving_datasets = self.dataset_service.get_driving_datasets(user)
        assert_that(len(driving_datasets), is_(2 + 1))  # Have to also count the 'user upload driving dataset'
        assert_that(driving_datasets[0].name, is_("driving1"))
        assert_that(driving_datasets[1].description, is_("driving 2 description"))

    def test_GIVEN_two_driving_datasets_WHEN_get_spatial_extent_THEN_correct_spatial_extent_returned(self):
        user = self.login()
        self.create_two_driving_datasets()
        driving_datasets = self.dataset_service.get_driving_datasets(user)
        id = driving_datasets[0].id
        spatial_extent = self.dataset_service.get_spatial_extent(id)
        assert_that(spatial_extent._bound_lat_n, is_(50))
        assert_that(spatial_extent._bound_lat_s, is_(-10))
        assert_that(spatial_extent._bound_lon_w, is_(-15))
        assert_that(spatial_extent._bound_lon_e, is_(30))

    def test_GIVEN_driving_dataset_with_parameter_values_THEN_when_get_driving_dataset_by_id_THEN_namelist_parameters_loaded(self):
        user = self.login()
        self.create_two_driving_datasets()
        driving_datasets = self.dataset_service.get_driving_datasets(user)
        id = driving_datasets[0].id
        dataset = self.dataset_service.get_driving_dataset_by_id(id)
        parameter_values = dataset.parameter_values
        for param_val in parameter_values:
            parameter = param_val.parameter
            namelist = parameter.namelist

    def test_GIVEN_driving_dataset_THEN_when_view_by_non_admin_THEN_not_shown(self):
        user = self.login()
        self.clean_database()
        with session_scope() as session:
            self.create_driving_dataset(session, is_restricted_to_admins=True)

        driving_datasets = self.dataset_service.get_driving_datasets(user)

        assert_that(len(driving_datasets), is_(1), "Driving dataset count (just the single cell one)")

    def test_GIVEN_driving_dataset_THEN_when_view_by_admin_THEN_shown(self):
        user = self.login(access_level=constants.USER_ACCESS_LEVEL_ADMIN)
        self.clean_database()
        n_dd = len(self.dataset_service.get_driving_datasets(user))
        with session_scope() as session:
            self.create_driving_dataset(session, is_restricted_to_admins=True)

        driving_datasets = self.dataset_service.get_driving_datasets(user)

        assert_that(len(driving_datasets), is_(n_dd + 1), "Driving dataset count")

    def test_GIVEN_driving_dataset_with_max_less_than_min_THEN_when_view_THEN_max_is_set_at_twice_min(self):
        # If the range is incorrect then THREDDS refuses to show the data so make sure this never happens
        user = self.login()
        self.clean_database()
        with session_scope() as session:
            dataset_id = self.create_dataset(session, data_range_from=10, data_range_to=5)

        dataset = self.dataset_service.get_dataset_by_id(dataset_id, user.id)

        assert_that(dataset.data_range_from, less_than(dataset.data_range_to), "Driving dataset data ranges must be in correct order")
 def setUp(self):
     super(TestDatasetService, self).setUp()
     self.dataset_service = DatasetService()
     self.clean_database()