def test_get_user_secrets(self): """Vanilla test case for get_user_secrets Utility function for reading user secrets from configured location """ # Setting up config object tc = UtilsTestConfig() with tempfile.NamedTemporaryFile(mode="w", suffix=".json") as temp_secrets_file, \ tempfile.NamedTemporaryFile(mode="w", suffix=".json") as temp_user_secrets_file: json.dump(self.test_secrets, temp_secrets_file) json.dump(self.test_user_secrets, temp_user_secrets_file) temp_secrets_file.flush() temp_user_secrets_file.flush() tc.SECRETS_FILE = temp_secrets_file.name tc.USER_SECRETS_FILE = temp_user_secrets_file.name # *not* reusing the temp file tc.USER_SECRETS_SALT_KEY = self.test_secret_key current_app.config.from_object(tc) util.flush_caches() util.get_secrets(flush_cache=True) util.get_user_secrets(flush_cache=True) util.secure_mode(flush_cache=True) user_secrets = util.get_user_secrets() self.assertDictEqual(user_secrets, self.test_user_secrets, "User secrets not loaded correctly")
def test_get_secrets(self): """Vanilla test case for get_secrets Utility function for reading secrets from configured location """ # Setting up config object tc = UtilsTestConfig() with tempfile.NamedTemporaryFile(mode="w", suffix=".json") as temp_secrets_file: json.dump(self.test_secrets, temp_secrets_file) temp_secrets_file.flush() tc.SECRETS_FILE = temp_secrets_file.name current_app.config.from_object(tc) util.flush_caches() secrets = util.get_secrets() secrets2 = util.get_secrets() secrets3 = util.get_secrets(flush_cache=True) self.assertDictEqual( secrets, self.test_secrets, "get_secrets not reading secrets from configured location") # Checking that cache (and its flush) is working as expected self.assertIs(secrets, secrets2, "get_secrets cache is not working as expected") self.assertIsNot(secrets, secrets3, "get_secrets cache flush is not happening")
def setUp(self) -> None: credentials = base64.b64encode(b"test_user:test_password").decode('utf-8') self.authorisation_headers = {"Authorization": "Basic {}".format(credentials)} # Setting up the GeoLookup data files tc = GeoLookupTestConfig() self.temp_dir = tempfile.TemporaryDirectory() tc.GEOLOOKUP_DATASET_DIR = self.temp_dir.name temp_geojson = { "type": "FeatureCollection", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [0.0, 0.0] }, "properties": { "temp_id": "centre_of_the_world" }}] } temp_layer_file_path = self.temp_dir.name + "temp_layer.geojson" with open(temp_layer_file_path, "w") as temp_layer_file: json.dump(temp_geojson, temp_layer_file) tc.GEOLOOKUP_DATASET_CONFIG = { "temp_layer": (temp_layer_file.name, "temp_id") } current_app.config.from_object(tc) util.flush_caches()
def setUp(self) -> None: credentials = base64.b64encode(b"test_user:test_password").decode( 'utf-8') self.authorisation_headers = { "Authorization": "Basic {}".format(credentials) } current_app.config.from_object(ScrubTestConfig) util.flush_caches()
def test_configurable_geocoders(self): """Testing get_geocoders sets up a configurable geocoder correctly. This test does double duty, as the config mechanism is shared with get_scrubbers. Configurable geocoders are geocoders that need additional config (e.g. secrets) """ # Setting up config object tc = UtilsTestConfig() random_value = random.random() tc.SOME_RANDOM_VALUE = random_value tc.GEOCODERS = ((test_geocode_controller.MockGeocoder, { "proxy_url": [config.ConfigNamespace.CONFIG, "SOME_RANDOM_VALUE"] }), (test_geocode_controller.MockGeocoder, { "proxy_url": [config.ConfigNamespace.SECRETS, self.test_secret_key] }), (test_geocode_controller.MockGeocoder, { "proxy_url": [config.ConfigNamespace.CONFIG, "SOME_OTHER_RANDOM_VALUE"] })) # Setting secrets values with tempfile.NamedTemporaryFile(mode="w", suffix=".json") as temp_secrets_file: json.dump(self.test_secrets, temp_secrets_file) temp_secrets_file.flush() tc.SECRETS_FILE = temp_secrets_file.name tc.USER_SECRETS_FILE = temp_secrets_file.name # reusing the temp file tc.USER_SECRETS_SALT_KEY = self.test_secret_key # Actually configuring the app current_app.config.from_object(tc) util.flush_caches() # Testing the configuration from config namespace works gc, *_ = util.get_geocoders(flush_cache=True) self.assertIsInstance( gc, test_geocode_controller.MockGeocoder, "Configurable geocoder using config namespace not being returned" ) self.assertEqual( gc.proxy_url, random_value, "Configurable geocoder using config namespace not being configured correctly" ) _, gc2, *_ = util.get_geocoders() self.assertIsInstance( gc, test_geocode_controller.MockGeocoder, "Configurable geocoder using secrets namespace not being returned" ) self.assertEqual( gc2.proxy_url, self.test_secret_value, "Configurable geocoder using secrets namespace not being configured correctly" ) self.assertEqual(len(util.get_geocoders(flush_cache=True)), 2, "Wrong number of geocoders being returned")
def test_secure_auth(self): """Tests for auth in secure mode Service should only allow valid usernames to call """ # Setting up config object tc = AuthorizationTestConfig() with tempfile.NamedTemporaryFile(mode="w", suffix=".json") as temp_secrets_file, \ tempfile.NamedTemporaryFile(mode="w", suffix=".json") as temp_user_secrets_file: json.dump(self.test_secrets, temp_secrets_file) json.dump(self.test_user_secrets, temp_user_secrets_file) temp_secrets_file.flush() temp_user_secrets_file.flush() tc.SECRETS_FILE = temp_secrets_file.name tc.USER_SECRETS_FILE = temp_user_secrets_file.name tc.USER_SECRETS_SALT_KEY = self.test_secret_key current_app.config.from_object(tc) util.flush_caches() current_app.logger.info(f"**Happy Case Test**") query_string = [('address', 'address_example')] # Testing the happy case response = self.client.open( '/v1/scrub', method='GET', query_string=query_string, headers=self.authorisation_headers ) self.assert200(response, 'Response body is : ' + response.data.decode('utf-8')) # Testing the unhappy case (no creds) current_app.logger.info(f"**Unhappy Case Test**") response2 = self.client.open( '/v1/scrub', method='GET', query_string=query_string, ) self.assert401(response2, 'Response body is : ' + response2.data.decode('utf-8')) # Testing the unhappy case (bad creds) current_app.logger.info(f"**Unhappy Case Test 2**") credentials = base64.b64encode(b"Fanny:your aunt").decode('utf-8') authorisation_headers2 = {"Authorization": "Basic {}".format(credentials)} response3 = self.client.open( '/v1/scrub', method='GET', query_string=query_string, headers=authorisation_headers2 ) self.assert401(response3, 'Response body is : ' + response3.data.decode('utf-8'))
def test_geocode(self): """Vanilla test case for geocode Translate a free form address into a spatial coordinate """ tc = GeocoderTestConfig() tc.GEOCODERS = [ ( MockGeocoder, {} ), ] current_app.config.from_object(tc) util.flush_caches() query_string = [('address', 'address_example')] response = self.client.open( '/v1/geocode', method='GET', query_string=query_string, headers=self.authorisation_headers ) self.assert200(response, 'Response body is : ' + response.data.decode('utf-8')) # Asserting that we get back the results we expect data_dict = json.loads(response.data) self.assertIn("results", data_dict) results = data_dict["results"] self.assertEqual(2, len(data_dict["results"]), "Geocoder is not returning the expected number of test results") # Inspecting the result itself result, *_ = results self.assertEqual(result["geocoder_id"], MockGeocoder.__name__, "Geocode ID not mapped through correctly") self.assertEqual(result["confidence"], 1, "Geocoder confidence not mapped through correctly") result_dict = json.loads(result["geocoded_value"]) self.assertDictEqual( {"features": [ {"geometry": {"coordinates": [0.000, 0.0001], "type": "Point"}, "properties": {"address": "address_example"}, "type": "Feature"}], "type": "FeatureCollection"}, result_dict, "Geocoded value not mapped through correctly" ) # Inspecting the second result (the combined result) *_, result2 = results result_dict2 = json.loads(result2["geocoded_value"]) self.assertDictEqual( {"features": [ {"geometry": {"coordinates": [0.0, 0.0001], "type": "Point"}, "properties": {"geocoders": ["MockGeocoder"]}, "type": "Feature"}], "type": "FeatureCollection"}, result_dict2, "Combined geocoded value not mapped through correctly" )
def setUp(self) -> None: self.test_secret_key = "Bob" self.test_secret_value = "your uncle" self.test_secrets = {self.test_secret_key: self.test_secret_value} self.test_user_secrets = { '3d224707797b570fe4523f6ff4b9d68be72815d80c19530000919efad9e6cfe2': # sha256("Bob" + "your uncle") '037525e1e2b6f9f169c483caf4aba43bc50885fdb9a2efe023635cd9534999ab' # sha256("your uncle" + "your uncle") } cred_string = f"{self.test_secret_key}:{self.test_secret_value}" credentials = base64.b64encode(cred_string.encode('utf-8')).decode('utf-8') self.authorisation_headers = {"Authorization": "Basic {}".format(credentials)} current_app.logger.debug(f"self.authorisation_headers={self.authorisation_headers}") current_app.config.from_object(AuthorizationTestConfig) util.flush_caches()
def test_bad_gecode(self): """Testing the behaviour around failed geocoding AKA SAD CASE TESTS """ tc = GeocoderTestConfig() tc.GEOCODERS = [ ( MockGeocoder, {} ), ( BadMockGeocoder, {} ), ] current_app.config.from_object(tc) util.flush_caches() query_string = [('address', 'address_example')] response = self.client.open( '/v1/geocode', method='GET', query_string=query_string, headers=self.authorisation_headers ) data_dict = json.loads(response.data) results = data_dict["results"] # For now, the expected behaviour is just to pass through failed geocodes with null values. self.assertEqual(3, len(results), "Geocoder is not returning the expected number of test results") _, bad_result, _ = results self.assertEqual(bad_result["confidence"], 0, "Failed geocoder confidence not mapped through correctly") result = json.loads(bad_result["geocoded_value"]) self.assertIsNone(result, "Failed geocoder not returning a null result") *_, combined_result = results result_dict = json.loads(combined_result["geocoded_value"]) self.assertDictEqual( {"features": [ {"geometry": {"coordinates": [0.0, 0.0001], "type": "Point"}, "properties": {"geocoders": ["MockGeocoder"]}, "type": "Feature"}], "type": "FeatureCollection"}, result_dict, "Combined geocoded value not excluding bad geocoder properly" )
def test_secure_mode(self): """Vanilla test case for secure_mode Utility function for determining whether the app should start in secure mode """ # Setting up config object tc = UtilsTestConfig() with tempfile.NamedTemporaryFile(mode="w", suffix=".json") as temp_secrets_file: json.dump(self.test_secrets, temp_secrets_file) temp_secrets_file.flush() tc.SECRETS_FILE = temp_secrets_file.name tc.USER_SECRETS_FILE = temp_secrets_file.name # reusing the temp file tc.USER_SECRETS_SALT_KEY = self.test_secret_key current_app.config.from_object(tc) util.flush_caches() secure_mode = util.secure_mode() self.assertTrue(secure_mode, "Secure mode not correctly detected") # The user secrets file shouldn't exist at this point secure_mode2 = util.secure_mode(flush_cache=True) self.assertFalse( secure_mode2, "Secure mode *shouldn't* be detected because the user secrets doesn't exist" ) # Testing that the salt not existing is tc.USER_SECRETS_SALT_KEY = "doesn't-exist" current_app.config.from_object(tc) util.flush_caches() secure_mode2 = util.secure_mode(flush_cache=False) self.assertFalse( secure_mode2, "Secure mode *shouldn't* be detected because the user secrets salt doesn't exist" )
def test_auth_user(self): """Vanilla test case for auth_user Utility function for confirming that user matches what is in the records """ # Setting up config object tc = UtilsTestConfig() with tempfile.NamedTemporaryFile(mode="w", suffix=".json") as temp_secrets_file, \ tempfile.NamedTemporaryFile(mode="w", suffix=".json") as temp_user_secrets_file: json.dump(self.test_secrets, temp_secrets_file) json.dump(self.test_user_secrets, temp_user_secrets_file) temp_secrets_file.flush() temp_user_secrets_file.flush() tc.SECRETS_FILE = temp_secrets_file.name tc.USER_SECRETS_FILE = temp_user_secrets_file.name # *not* reusing the temp file tc.USER_SECRETS_SALT_KEY = self.test_secret_key current_app.config.from_object(tc) util.flush_caches() util.get_secrets(flush_cache=True) util.get_user_secrets(flush_cache=True) util.secure_mode(flush_cache=True) user_auth_check = util.auth_user(self.test_secret_key, self.test_secret_value) self.assertTrue(user_auth_check, "User auth not successful") user_auth_check2 = util.auth_user(self.test_secret_key, "blah") self.assertFalse( user_auth_check2, "User auth successful despite the password being wrong!") user_auth_check3 = util.auth_user("foo", self.test_secret_value) self.assertFalse( user_auth_check2, "User auth successful despite the username being wrong!")
def test_combined_gecode(self): """Testing that combined geocode result is blended into results """ tc = GeocoderTestConfig() tc.GEOCODERS = [ ( MockGeocoder, {} ), ( MockGeocoder2, {} ), ] current_app.config.from_object(tc) util.flush_caches() query_string = [('address', 'address_example')] response = self.client.open( '/v1/geocode', method='GET', query_string=query_string, headers=self.authorisation_headers ) data_dict = json.loads(response.data) results = data_dict["results"] self.assertEqual(3, len(results), "Geocoder is not returning the expected number of test results") *_, combined_result = results result_dict = json.loads(combined_result["geocoded_value"]) self.assertDictEqual( {"features": [ {"geometry": {"coordinates": [0.00005, 0.0001], "type": "Point"}, "properties": {"geocoders": ["MockGeocoder", "MockGeocoder2"]}, "type": "Feature"}], "type": "FeatureCollection"}, result_dict, "Combined geocoded value not mapped through correctly" )
def test_get_geocoders(self): """Vanilla test case for get_geocoders Utility function for setting up and configuring geocoder objects """ # Setting up config object tc = UtilsTestConfig() tc.GEOCODERS = ((test_geocode_controller.MockGeocoder, {}), ) current_app.config.from_object(tc) # Testing that we get back an instance of the configured geocoder gc, *_ = util.get_geocoders() self.assertIsInstance( gc, test_geocode_controller.MockGeocoder, "config is not plumbing through to get_geocoders correctly") # Checking that the cache is working gc2, *_ = util.get_geocoders() self.assertIs(gc, gc2, "get_geocoders cache is not working as expected") # Flushing the cache and checking we get a new geocoder instance gc3, *_ = util.get_geocoders(flush_cache=True) self.assertIsNot(gc, gc3, "get_geocoders cache flush is not happening") # Checking that that the min geocoders check works tc = UtilsTestConfig() tc.GEOCODERS = [] tc.GEOCODERS_MIN = 1 current_app.config.from_object(tc) with self.assertRaises( AssertionError, msg="get_geocoders did not raise an assertion error as expected" ): util.flush_caches()