def testUsingCache_RandomEncodingsSubstituteEmptyResponses(self, mockGet): """ Random encodings are returned by getBitmap() and duplicate requests prevented """ # Arrange. bogusTerm = "bogus" mockGet.__name__ = "get" # Mock an empty response, regardless of bogus term mockGet.return_value = Mock(status_code=200, content='[]') cacheDir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, cacheDir) # Act. Make two identical calls. client = cortipy.CorticalClient(apiKey="fakeKey", useCache=True, cacheDir=cacheDir) result1 = client.getBitmap(bogusTerm) result2 = client.getBitmap(bogusTerm) # Assert. Assert only one request made, both responses equal, and only one # cache file created self.assertEqual(mockGet.call_count, 1) self.assertDictEqual(result1, result2) self.assertEqual(result1["fingerprint"], client._placeholderFingerprint(bogusTerm)) self.assertEqual( len(os.listdir(cacheDir)), 1, "More than one cache file generated for duplicate " "requests")
def testCompare(self): """ Tests client.createClassification(). Asserts the returned object has fields with expected values for both the classifciation name and bitmap. """ client = cortipy.CorticalClient(useCache=False) bitmap1 = client.getBitmap("one")["fingerprint"]["positions"] bitmap2 = client.getBitmap("two")["fingerprint"]["positions"] distances = client.compare(bitmap1, bitmap2) types = [ "cosineSimilarity", "euclideanDistance", "jaccardDistance", "overlappingAll", "overlappingLeftRight", "overlappingRightLeft", "sizeLeft", "sizeRight", "weightedScoring" ] self.assertIsInstance(distances, dict, "The returned object is not a dictionary") for t in types: self.assertIn(t, distances, "No \'{}\' field in the distances".format(t)) for t in types: self.assertIsInstance(distances[t], (float, int), "No \'{}\' field in the distances".format(t))
def testNotUsingCache_ApiCallsDontReadFromCache(self, mockGet): """ When not using the cache, API calls do not write responses to the cache. """ mockGet.__name__ = "get" mockGet.return_value = Mock(status_code=200, content='{"dummy": "mock body"}') resourcePath = "/mockResourcePath" method = "GET" queryParams = {} postData = "mock postData" cacheDir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, cacheDir) # Act. Make two identical calls. client = cortipy.CorticalClient(apiKey="fakeKey", useCache=False) result1 = client._queryAPI(method, resourcePath, queryParams, postData=postData) result2 = client._queryAPI(method, resourcePath, queryParams, postData=postData) # Assert. Assert only one request made, both responses equal self.assertEqual(mockGet.call_count, 2) self.assertDictEqual(result1, result2)
def testCompareOrthogonalFPs(self): """ Tests client.Compare() for fingerprints with orthogonal SDRs, asserting the method returns distances reflecting the maximum. """ # Arrange: mock JSON response from API, mock out the API endpoint we expect # to be called, init identical FPs. mockResponseString = getMockApiData("compare_orthogonalSDRs.json") httpretty.register_uri(httpretty.POST, "http://api.cortical.io/rest/compare", body=mockResponseString, content_type="application/json") fp1 = [0] fp2 = [13] # Act: create the client object we'll be testing. client = cortipy.CorticalClient( apiKey="fakeKey", verbosity=0, useCache=False) distances = client.compare(fp1, fp2) # Assert: expected distance metrics are returned, and result should reflect # maximum distances. self.assertTrue({"cosineSimilarity", "overlappingAll", "jaccardDistance", "weightedScoring", "sizeRight", "sizeLeft", "overlappingLeftRight", "euclideanDistance", "overlappingRightLeft"} == set(distances), "The returned dictionary does not contain the expected distance metrics.") self.assertEqual(distances["euclideanDistance"], 1.0, "Euclidean distance is incorrect. Expected 1.0 but received %0.1f" % distances["euclideanDistance"]) self.assertEqual(distances["overlappingAll"], 0, "Overlap count is incorrect. Expected 0 but received %d" % distances["overlappingAll"])
def testUsingCache_CachedRandomEncodingsAreUnique(self, mockGet): """ Random encodings are returned by getBitmap() and unique for unique terms """ # Arrange. bogusTerm = "bogus" mockGet.__name__ = "get" # Mock an empty response, regardless of bogus term mockGet.return_value = Mock(status_code=200, content='[]') cacheDir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, cacheDir) # Act. Make two identical calls. client = cortipy.CorticalClient(apiKey="fakeKey", useCache=True, cacheDir=cacheDir) result1 = client.getBitmap(bogusTerm) result2 = client.getBitmap(bogusTerm[::-1]) # Assert. Assert only one request made, both responses equal, and only one # cache file created self.assertEqual(mockGet.call_count, 2) self.assertNotEqual(result1, result2)
def testNotUsingCache_ApiCallsDontWriteToCache(self, mockExists): """ When not using the cache, API calls do not write responses to the cache. """ # Arrange. mockOpen = mock_open() httpretty.register_uri(httpretty.GET, "http://api.cortical.io/rest/mockResourcePath", body='{"dummy":"mock body"}', status=200, content_type="application/json") resourcePath = "/mockResourcePath" method = "GET" queryParams = "mock queryParams" postData = "mock postData" # Patching file open with patch('__builtin__.open', mockOpen, create=True): # Act. client = cortipy.CorticalClient(apiKey="fakeKey", useCache=False) client._queryAPI(method, resourcePath, queryParams, postData=postData) # Assert. self.assertEqual(0, mockOpen.call_count, "Caching was attempted when useCache=False.")
def testNotUsingCache_CacheDirIsNotCreated(self, mockMkDirs, _mockPathExists): """ When using not using the cache, a cache directory is not created when querying the API. """ # Arrange. mockOpen = mock_open() httpretty.register_uri(httpretty.GET, "http://api.cortical.io/rest/mockResourcePath", body='{"dummy":"mock body"}', status=200, content_type="application/json") resourcePath = "/mockResourcePath" method = "GET" queryParams = "mock queryParams" postData = "mock postData" # Patching file open with patch('__builtin__.open', mockOpen, create=False): # Act. client = cortipy.CorticalClient(apiKey="fakeKey", useCache=False) client._queryAPI(method, resourcePath, queryParams, postData=postData) # Assert. assert (mockMkDirs.call_count == 0)
def testGetContextReturnFields(self): """ Tests client.getContext() for a sample term. Asserts the returned object contains the correct fields and have contents as expected. """ # Arrange: mock JSON response from API, mock out the API endpoint we expect # to be called. mockResponseString = getMockApiData("context_android.json") httpretty.register_uri(httpretty.GET, "http://api.cortical.io/rest/terms/contexts", body=mockResponseString, content_type="application/json") # Act: create the client object we'll be testing. client = cortipy.CorticalClient(apiKey="fakeKey", verbosity=0, useCache=False) contexts = client.getContext("android") # Assert: check the result object. self.assertTrue(isinstance(contexts, list), "Returned object is not of type list as expected.") self.assertTrue( ("context_label" and "fingerprint" and "context_id") in contexts[0], "Data structure returned by getContext() does not contain" " the required fields.") self.assertTrue(isinstance(contexts[0]["context_label"], str), "The \'context_label\' field is not of type string.") self.assertEqual(contexts[0]["context_id"], 0, "The top context does not have ID of zero.")
def testUsingCache_CacheDirIsLazilyCreated(self, mockMkDirs, _mockPathExists): """ When using cache, a cache directory is created on the first call to query the API if it does not exist. """ # Arrange. mockOpen = mock_open() httpretty.register_uri(httpretty.GET, "http://api.cortical.io/rest/mockResourcePath", body='{"dummy":"mock body"}', status=200, content_type="application/json") resourcePath = "/mockResourcePath" method = "GET" queryParams = "mock queryParams" postData = "mock postData" # Patching file open with patch('__builtin__.open', mockOpen, create=True): # Act. client = cortipy.CorticalClient(apiKey="fakeKey", useCache=True) client._queryAPI(method, resourcePath, queryParams, postData=postData) # Assert. mockMkDirs.assert_called_once_with("/tmp/cortipy")
def testUsingCache_ApiCallsReadFromCache(self, _mockExists): """ When using the cache, API calls that are already cached are read from the cache instead of making a new API call. """ # Arrange. mockOpen = mock_open(read_data='{"dummy": "mock body"}') resourcePath = "/mockResourcePath" method = "GET" queryParams = "mock queryParams" postData = "mock postData" # Patching file open with patch('__builtin__.open', mockOpen, create=True): # Act. client = cortipy.CorticalClient(apiKey="fakeKey", useCache=True) result = client._queryAPI(method, resourcePath, queryParams, postData=postData) expectedCacheString = hashlib.sha224( json.dumps( [resourcePath, method, json.dumps(queryParams), postData])).hexdigest() expectedCachePath = "/tmp/cortipy/" + expectedCacheString + ".json" # Assert. mockOpen.assert_called_once_with(expectedCachePath, "r") self.assertEqual({"dummy": "mock body"}, result)
def testGetBitmap(self): """ Tests client.getBitmap(). Asserts the proper query parameters are passed to the API, returns a complete JSON string in response, and asserts that string is converted into the expected result object for the client code. """ # Arrange: mock JSON response from API, mock out the API endpoint we expect # to be called. mockResponseString = getMockApiData("terms_owl.json") httpretty.register_uri(httpretty.GET, "http://api.cortical.io/rest/terms", body=mockResponseString, content_type="application/json") # Act: create the client object we'll be testing. client = cortipy.CorticalClient(apiKey="fakeKey", verbosity=0, useCache=False, retina="en_synonymous") bitmap = client.getBitmap("owl") # Assert: check the result object. self.assertTrue("term" in bitmap, "No \'term\' field in the returned object.") self.assertEqual(bitmap["term"], "owl", "The returned term is incorrect.") self.assertIsInstance( bitmap["fingerprint"], dict, "The returned object does not contain a \'fingerprint'\ dictionary." ) self.assertTrue( "positions" in bitmap["fingerprint"], "The returned object does not contain a \'positions\' field for the " "\'fingerprint\'.") self.assertIsInstance( bitmap["fingerprint"]["positions"], list, "The returned object does not contain a \'positions\' list within its " " \'fingerprint\' dictionary.") # Assert: get the request sent to the API and check it. request = httpretty.last_request() self.assertEqual(request.method, 'GET', "Incorrect request method.") self.assertEqual(request.headers['content-type'], 'application/json', "Incorrect request headers.") self.assertTrue(hasattr(request, 'querystring'), "The request field \'queryString\' does not exist") self.assertEqual( request.querystring, { "retina_name": ["en_synonymous"], "term": ["owl"], "start_index": ["0"], "max_results": ["10"], "get_fingerprint": ["True"] }, "The request field \'queryString\' does not have the expected values." )
def testGetContext(self): """ Tests client.getContext() for a sample term. Asserts the returned object contains the correct fields and have contents as expected. """ # Act: create the client object we'll be testing. client = cortipy.CorticalClient(useCache=False) contexts = client.getContext("android") self._checkValidContexts(contexts)
def testWhenConstructingClientProperDefaultPropertiesAreSet(self): client = cortipy.CorticalClient(apiKey="fakeKey") self.assertEqual(client.apiUrl, "http://api.cortical.io/rest", "Wrong default API URL") self.assertEqual(client.cacheDir, "/tmp/cortipy", "Wrong default cache directory") self.assertEqual(client.verbosity, 0, "Wrong default verbosity") self.assertEqual(client.retina, "en_synonymous", "Wrong default retina") self.assertEqual(client.useCache, True, "Wrong default cache on/off setting")
def testCreateClassification(self): """ Tests client.createClassification(). Asserts the returned object has fields with expected values for both the classifciation name and bitmap. """ # Arrange: mock JSON response from API, mock out the API endpoint we expect # to be called. mockResponseString = getMockApiData("dfw_category.json") httpretty.register_uri( httpretty.POST, "http://api.cortical.io/rest/classify/create_category_filter", body=mockResponseString, content_type="application/json") # Act: create the client object we'll be testing. client = cortipy.CorticalClient( apiKey="fakeKey", verbosity=0, useCache=False, retina="en_synonymous") positives = ["The truth will set you free. But not until it is finished \ with you.", "You will become way less concerned with what other people \ think of you when you realize how seldom they do."] negatives = ["It was the best of times, it was the worst of times, it was \ the age of wisdom, it was the age of foolishness, it was the epoch of \ belief, it was the epoch of incredulity, it was the season of Light, \ it was the season of Darkness, it was the spring of hope, it was the \ winter of despair, we had everything before us, we had nothing before \ us, we were all going direct to Heaven, we were all going direct the \ other way -- in short, the period was so far like the present period, \ that some of its noisiest authorities insisted on its being received, \ for good or for evil, in the superlative degree of comparison only."] response = client.createClassification("dfw", positives, negatives) # Assert: check the result object. self.assertTrue("positions" in response, "No \'positions\' field in the returned object.") self.assertTrue("categoryName" in response, "No \'categoryName\' field in the returned object.") self.assertEqual(response["categoryName"], "dfw", "The returned category name is incorrect.") self.assertIsInstance(response["positions"], list, "The returned object does not contain a \'positions\' list.") # Assert: get the request sent to the API and check it. request = httpretty.last_request() self.assertEqual(request.method, 'POST', "Incorrect request method.") self.assertEqual(request.headers['content-type'], 'application/json', "Incorrect request headers.") self.assertTrue(hasattr(request, 'querystring'), "The request field \'queryString\' does not exist") self.assertEqual(request.querystring, {"retina_name": ["en_synonymous"], "filter_name": ["dfw"]}, "The request field \'queryString\' does not have the expected values.")
def testGetContextFromOneText(self): """ Tests client.getContextFromText() for a sample text. Asserts the returned object contains the correct fields and have contents as expected. """ # Act: create the client object we'll be testing. client = cortipy.CorticalClient(useCache=False) text = "The jaguar is a big cat, a feline in the Panthera genus." bitmaps = [client.getTextBitmap(text)["fingerprint"]["positions"]] contexts = client.getContextFromText(bitmaps) self._checkValidContexts(contexts)
def testUsingCache_ApiPostCallsWriteToCache(self, mockPathExists): """ When using the cache, POST API response is written to the cache directory in a new JSON file, using a cache key created by the hashed request string. """ # Arrange. mockOpen = mock_open() httpretty.register_uri(httpretty.POST, "http://api.cortical.io/rest/mockResourcePath", body='{"dummy":"mock body"}', status=200, content_type="application/json") resourcePath = "/mockResourcePath" method = "POST" queryParams = '{"get_fingerprint": true, \ "retina_name": "en_synonymous", \ "max_results": 10, \ "term": "cat", \ "start_index": 0}' postData = "dummy post data" # os.path.exists() will be called twice. First to see if the cache path to # the resource being fetched exists (we'll return False), and the 2nd time # after the API call to decide whether to lazily create the cache directory. # To this call we'll return True so it doesn't try to create it. def existsSideEffect(arg): if arg == "/tmp/cortipy": return True mockPathExists.side_effect = existsSideEffect # Patching file open with patch('__builtin__.open', mockOpen, create=True): # Act. client = cortipy.CorticalClient(apiKey="fakeKey", useCache=True) client._queryAPI(method, resourcePath, queryParams, postData=postData) expectedCacheString = hashlib.sha224( json.dumps( [resourcePath, method, json.dumps(queryParams), postData])).hexdigest() expectedCachePath = "/tmp/cortipy/" + expectedCacheString + ".json" # Assert. mockOpen.assert_called_once_with(expectedCachePath, "w") handle = mockOpen() handle.write.assert_called_once_with('{"dummy": "mock body"}')
def testAPICannotEncodeError(self, mockPost): """ Tests the client receiving an HTTP error code from the API, asserting we receive a UnsuccessfulEncodingError. """ mockPost.return_value = Mock( content='{"dummy": "mock body"}', status_code=400) # Act: client = cortipy.CorticalClient(apiKey="fakeKey") # Assert: with self.assertRaises(UnsuccessfulEncodingError): client._queryAPI("GET", "path", {})
def testPostQueryToAPI(self, mockPost): """ Tests the client can send a 'POST' query to the API, asserting we receive an HTTP status code reflecting successful operation. """ mockPost.return_value = Mock( content='{"dummy": "mock body"}', status_code=200) # Act: client = cortipy.CorticalClient(apiKey="fakeKey") response = client._queryAPI("POST", "path", {}) # Assert: self.assertEqual({"dummy": "mock body"}, response)
def testGetContextReturnFields(self): """ Tests client.getContext() for a sample term. Asserts the returned object contains the correct fields and have contents as expected. """ # Act: create the client object we'll be testing. client = cortipy.CorticalClient(useCache=False) keywords = client.extractKeywords("This is about food") # Assert: check the result object. self.assertIsInstance( keywords, list, "Returned object is not of type list as expected.")
def testBadQueryMethodToAPI(self, mockPost): """ Tests the client sending an invalid query method to the API, asserting we receive a RequestMethodError. """ mockPost.return_value = Mock(content='{"dummy": "mock body"}', status_code=None) # Act: client = cortipy.CorticalClient(apiKey="fakeKey") # Assert: with self.assertRaises(RequestMethodError): client._queryAPI("BAD_METHOD", "path", {})
def testGetQueryToAPI(self, mockGet): """ Tests the client can send a 'GET' query to the API, asserting we receive an HTTP status code reflecting successful operation. """ # Arrange: patch the request in cortipy.CorticalClient._queryAPI(). # with patch.object(requests, 'get', return_value=) as mock_get: mockGet.return_value = Mock( content='{"dummy": "mock body"}', status_code=200) # Act: client = cortipy.CorticalClient(apiKey="fakeKey", useCache=False) response = client._queryAPI("GET", "/path", {}) # Assert: self.assertEqual({"dummy": "mock body"}, response)
def testForIdenticalPlaceholderFingerprints(self): """ Tests client._placeholderFingerprint() returns the same bitmap for when repeatedly called for the same input term. """ # Arrange: term = "Rosen" # Act: client = cortipy.CorticalClient(apiKey="fakeKey") fp1 = client._placeholderFingerprint(term, option="random") fp2 = client._placeholderFingerprint(term, option="random") # Assert: self.assertEqual(fp1, fp2, "The generated bitmaps are different, but should be identical.")
def testGracefulHandlingOfAPIError(self, mockGet): """ Tests the client receiving an HTTP error code from the API returns an empty encoding. """ mockGet.__name__ = "get" mockGet.return_value = Mock(content='{"dummy": "mock body"}', status_code=400) # Act: client = cortipy.CorticalClient(apiKey="fakeKey") # Assert: result = client._queryAPI("GET", "path", {}) self.assertEqual(result, [])
def testForUniquePlaceholderFingerprints(self): """ Tests client._placeholderFingerprint() returns different random bitmaps for different input terms. """ # Arrange: term1 = "Deckard" term2 = "Holden" # Act: client = cortipy.CorticalClient(apiKey="fakeKey") fp1 = client._placeholderFingerprint(term1, option="random") fp2 = client._placeholderFingerprint(term2, option="random") # Assert: self.assertNotEqual(fp1, fp2, "The generated bitmaps are identical, but should be different.")
def testGetSDRFromNullFingerprint(self): """ Tests client.getSDR(). Asserts the correct binary string is returned for an empty bitmap. """ # Arrange: fp = {"width": 4, "height": 4, "fingerprint": {"positions": []}} # Act: client = cortipy.CorticalClient(apiKey="fakeKey") sdr = client.getSDR(fp) # Assert: self.assertIsInstance(sdr, str, "Result is not of type string as expected.") self.assertEqual( sdr, '0000000000000000', "The resulting SDR does not match the input bitmap. Expected " "[0000000000000000] but instead received [%s]" % sdr)
def testCreateClassificationOnlyPositives(self): """ Tests client.createClassification(). Asserts the returned object has fields with expected values for both the classifciation name and bitmap. """ client = cortipy.CorticalClient(useCache=False) name = "programming languages" positives = [ "Always code as if the guy who ends up maintaining your code will be a \ violent psychopath who knows where you live.", "To iterate is human, to recurse divine.", "First learn computer science and all the theory. Next develop a \ programming style. Then forget all that and just hack." ] response = client.createClassification(name, positives) self._checkValidResponse(response, name)
def testCompareSimilarFPs(self): """ Tests client.Compare() for similar SDRs, with overlapping bits, and for dissimilar SDRs, asserting the method returns distances reflecting the similar SDRs are closer than the dissimilar SDRs. """ # Arrange: mock JSON response from API, mock out the API endpoint we expect # to be called, init identical FPs. mockResponseStringSimilar = getMockApiData("compare_similarSDRs.json") mockResponseStringDissimilar = getMockApiData( "compare_dissimilarSDRs.json") httpretty.register_uri(httpretty.POST, "http://api.cortical.io/rest/compare", body=mockResponseStringSimilar, content_type="application/json") fp1 = [0, 1] fp2 = [1, 3] fp3 = [10, 11] # Act: create the client object we'll be testing. client = cortipy.CorticalClient(apiKey="fakeKey", verbosity=0, useCache=False) distances_similar = client.compare(fp1, fp2) httpretty.register_uri(httpretty.POST, "http://api.cortical.io/rest/compare", body=mockResponseStringDissimilar, content_type="application/json") distances_dissimilar = client.compare(fp1, fp3) # Assert: result should reflect distances = 0. self.assertTrue( (distances_similar["euclideanDistance"] < distances_dissimilar["euclideanDistance"]), ("Euclidean for " "dissimilar SDRs is incorrectly less than that of similar SDRs.")) self.assertTrue( (distances_similar["overlappingAll"] > distances_dissimilar["overlappingAll"]), ("Overlap for dissimilar " "SDRs is incorrectly less than that of similar SDRs."))
def testUsingCache_ApiCallsReadFromCache(self, mockGet): """ When using the cache, API calls that are already cached are read from the cache instead of making a new API call. """ # Arrange. #mockOpen = mock_open(read_data='{"dummy": "mock body"}') mockGet.__name__ = "get" mockGet.return_value = Mock(status_code=200, content='{"dummy": "mock body"}') resourcePath = "/mockResourcePath" method = "GET" queryParams = {} postData = "mock postData" cacheDir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, cacheDir) # Act. Make two identical calls. client = cortipy.CorticalClient(apiKey="fakeKey", useCache=True, cacheDir=cacheDir) result1 = client._queryAPI(method, resourcePath, queryParams, postData=postData) result2 = client._queryAPI(method, resourcePath, queryParams, postData=postData) # Assert. Assert only one request made, both responses equal, and only one # cache file created self.assertEqual(mockGet.call_count, 1) self.assertDictEqual(result1, result2) self.assertEqual( len(os.listdir(cacheDir)), 1, "More than one cache file generated for duplicate " "requests")
def testUsingCache_RandomEncodingsSubstituteErrors(self, mockGet): """ Random encodings are returned by getBitmap() and unique for unique terms """ # Arrange. bogusTerm = "bogus" mockGet.__name__ = "get" # Mock a broken response which would otherwise cause json.loads() to fail, # regardless of bogus term mockGet.return_value = Mock(status_code=200, content='[') cacheDir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, cacheDir) # Act. Make two identical calls. client = cortipy.CorticalClient(apiKey="fakeKey", useCache=True, cacheDir=cacheDir) with warnings.catch_warnings(record=True) as allWarnings: result1 = client.getBitmap(bogusTerm) result2 = client.getBitmap(bogusTerm) # Assert. Assert only one request made, both responses equal, and only one # cache file created self.assertEqual(mockGet.call_count, 1) self.assertDictEqual(result1, result2) self.assertEqual(result1["fingerprint"], client._placeholderFingerprint(bogusTerm)) self.assertEqual( len(os.listdir(cacheDir)), 1, "More than one cache file generated for duplicate " "requests") for warning in allWarnings: if str(warning.message).startswith( "Suppressing error in parsing response"): break else: self.fail("Warning not raised as expected")
def testNotUsingCache_ApiCallsDontReadFromCache(self, _mockExists): """ When not using the cache, API calls that are already cached are not read from the cache instead. """ # Arrange. mockOpen = mock_open() httpretty.register_uri(httpretty.GET, "http://api.cortical.io/rest/mockResourcePath", body='{"dummy":"mock body"}', status=200, content_type="application/json") resourcePath = "/mockResourcePath" method = "GET" queryParams = "mock queryParams" postData = "mock postData" client = cortipy.CorticalClient(apiKey="fakeKey", useCache=False) client._queryAPI(method, resourcePath, queryParams, postData=postData) # Assert. self.assertEqual(0, mockOpen.call_count, "Caching was attempted when useCache=False.")