class JobTest(ResourceTestCase): def setUp(self): super(JobTest, self).setUp() self.client = TestApiClient() self.endpoint = '/api/v1/jobs/' self.format = 'json' # Create one user self.user = User(username="******") self.user.save() # Create on token self.token = UserToken(user=self.user) self.token.save() # create a job self.job = Job(user=self.user, application=Application.objects.all()[0]) self.job.save() def test_get_job_list(self): url = "%s?token=%s" % (self.endpoint, self.token.token) request = self.client.get(url, self.format) self.assertValidJSONResponse(request) def test_get_job_detail(self): url = "%s%d/?token=%s" % (self.endpoint, self.job.id, self.token.token) request = self.client.get(url, self.format) self.assertValidJSONResponse(request) def test_post_job(self): data = {"application" : "/api/v1/apps/1/"} url = "%s?token=%s" % (self.endpoint, self.token.token) self.assertHttpCreated(self.client.post(url, self.format, data=data)) def test_patch_job(self): job = Job(user=self.user, application=Application.objects.all()[0]) job.save() data = {"progress":"50"} url = "%s%d/?token=%s" % (self.endpoint, job.id, self.token.token) resp = self.client.patch(url, self.format, data=data) self.assertHttpAccepted(resp) def test_delete_job(self): job = Job(user=self.user, application=Application.objects.all()[0]) job.save() url = "%s%d/?token=%s" % (self.endpoint, job.id, self.token.token) self.assertHttpAccepted(self.client.delete(url, self.format))
class EncounterParticipantResourceTest(ResourceTestCase): fixtures = ['testing_users.json', 'testing_data.json'] def setUp(self): super(EncounterParticipantResourceTest, self).setUp() self.api_client = TestApiClient() self.username = '******' self.password = '******' self.user = User.objects.create_superuser(self.username, '*****@*****.**', self.password) self.encounter_participant = EncounterParticipant.objects.get(id=1) def get_credentials(self): return self.api_client.client.login(username=self.username, password=self.password) def test_pc_initiative_save_unauthenticated(self): self.assertHttpUnauthorized(self.api_client.patch('/dm/api/v1/encounter_participant/1/', format='json', data={'initiative': 5})) def test_pc_initiative_save(self): """ Should save initiative for PC """ resp = self.api_client.patch('/dm/api/v1/encounter_participant/1/', authorization=self.get_credentials(), format='json', data={'initiative': 5}) self.assertHttpAccepted(resp) resp = self.api_client.get('/dm/api/v1/encounter_participant/1/', format='json', authentication=self.get_credentials()) self.assertEqual(self.deserialize(resp)['initiative'], 5)
def mock_request(obj, method, url, **kwargs): client = TestApiClient() authentication = 'Basic %s' % base64.b64encode(':'.join([ get_setting('SUPERUSER_USERNAME', None), get_setting('SUPERUSER_PASSWORD', None), ])) if method == 'GET': data = kwargs.get('params', {}) djresponse = client.get(url, data=data, authentication=authentication) elif method == 'POST': data = json.loads(kwargs.get('data', '{}')) djresponse = client.post(url, data=data, authentication=authentication) elif method == 'PUT': data = json.loads(kwargs.get('data', '{}')) djresponse = client.put(url, data=data, authentication=authentication) elif method == 'PATCH': data = json.loads(kwargs.get('data', '{}')) djresponse = client.patch(url, data=data, authentication=authentication) elif method == 'DELETE': data = kwargs.get('params', {}) djresponse = client.delete(url, data=data, authentication=authentication) # convert django.http.HttpResponse to requests.models.Response response = requests.models.Response() response.status_code = djresponse.status_code response.headers = {} try: response.headers['content-type'] = djresponse['content-type'] response.headers['location'] = djresponse['location'] except: pass response.encoding = requests.utils.get_encoding_from_headers(response.headers) response._content = djresponse.content return response
class ApiResourceTestCase(ResourceTestCase): # TODO: Using the regular ROOT_URLCONF avoids a problem where failing tests print useless error messages, # because the 500.html error template includes a {% url %} lookup that isn't included in api.urls. # There could be a better way to handle this. # url_base = "/v1" url_base = "/api/v1" server_domain = "perma.dev" server_port = 8999 serve_files = [] rejected_status_code = 401 # Unauthorized # reduce wait times for testing perma.tasks.ROBOTS_TXT_TIMEOUT = perma.tasks.AFTER_LOAD_TIMEOUT = 1 @classmethod def setUpClass(cls): if len(cls.serve_files): cls.start_server() @classmethod def tearDownClass(cls): if getattr(cls, "_server_process", None): cls.kill_server() def setUp(self): super(ApiResourceTestCase, self).setUp() self.api_client = TestApiClient(serializer=MultipartSerializer()) self._media_org = settings.MEDIA_ROOT self._media_tmp = settings.MEDIA_ROOT = tempfile.mkdtemp() try: self.list_url = "{0}/{1}".format(self.url_base, self.resource.Meta.resource_name) except: pass def tearDown(self): settings.MEDIA_ROOT = self._media_org shutil.rmtree(self._media_tmp) def get_credentials(self, user=None): user = user or self.user return "ApiKey %s" % user.api_key.key @classmethod def start_server(cls): """ Set up a server with some known files to run captures against. Example: with run_server_in_temp_folder([ 'test/assets/test.html', 'test/assets/test.pdf', ['test/assets/test.html', 'some_other_url.html']): assert(requests.get("http://localhost/test.html") == contents_of_file("test.html")) assert(requests.get("http://localhost/some_other_url.html") == contents_of_file("test.html")) """ assert socket.gethostbyname(cls.server_domain) in ('0.0.0.0', '127.0.0.1'), "Please add `127.0.0.1 " + cls.server_domain + "` to your hosts file before running this test." # Run in temp dir. # We have to (implicitly) cwd to this so SimpleHTTPRequestHandler serves the files for us. cwd = os.getcwd() cls._server_tmp = tempfile.mkdtemp() os.chdir(cls._server_tmp) # Copy over files to current temp dir, stripping paths. for source_file in cls.serve_files: # handle single strings if isinstance(source_file, basestring): target_url = os.path.basename(source_file) # handle tuple like (source_file, target_url) else: source_file, target_url = source_file copy_file_or_dir(os.path.join(cwd, source_file), target_url) # start server cls._httpd = TestHTTPServer(('', cls.server_port), SimpleHTTPRequestHandler) cls._httpd._BaseServer__is_shut_down = multiprocessing.Event() cls._server_process = Process(target=cls._httpd.serve_forever) cls._server_process.start() # once the server is started, we can return to our working dir # and the server thread will continue to server from the tmp dir os.chdir(cwd) return cls._server_process @classmethod def kill_server(cls): # If you don't close the server before terminating # the thread the port isn't freed up. cls._httpd.server_close() cls._server_process.terminate() shutil.rmtree(cls._server_tmp) @contextmanager def serve_file(self, src): if not getattr(self.__class__, "_server_process", None): self.__class__.start_server() dst = os.path.join(self._server_tmp, os.path.basename(src)) try: copy_file_or_dir(src, dst) yield finally: os.remove(dst) @cached_property def server_url(self): return "http://" + self.server_domain + ":" + str(self.server_port) @contextmanager def header_timeout(self, timeout): prev_t = models.HEADER_CHECK_TIMEOUT try: models.HEADER_CHECK_TIMEOUT = timeout yield finally: models.HEADER_CHECK_TIMEOUT = prev_t def assertValidJSONResponse(self, resp): # Modified from tastypie to allow 201's as well # https://github.com/toastdriven/django-tastypie/blob/master/tastypie/test.py#L448 try: self.assertHttpOK(resp) except AssertionError: self.assertHttpCreated(resp) self.assertTrue(resp['Content-Type'].startswith('application/json')) self.assertValidJSON(force_text(resp.content)) def detail_url(self, obj): return "{0}/{1}".format(self.list_url, obj.pk) def get_req_kwargs(self, kwargs): req_kwargs = {} if kwargs.get('format', None): req_kwargs['format'] = kwargs['format'] if kwargs.get('user', None): req_kwargs['authentication'] = self.get_credentials(kwargs['user']) return req_kwargs def successful_get(self, url, data=None, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) resp = self.api_client.get(url, data=data, **req_kwargs) self.assertHttpOK(resp) self.assertValidJSONResponse(resp) data = self.deserialize(resp) if kwargs.get('fields', None): self.assertKeys(data, kwargs['fields']) if kwargs.get('count', None): self.assertEqual(len(data['objects']), kwargs['count']) return data def rejected_get(self, url, expected_status_code=None, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) resp = self.api_client.get(url, **req_kwargs) self.assertEqual(resp.status_code, expected_status_code or self.rejected_status_code) return resp def successful_post(self, url, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) count = self.resource._meta.queryset.count() resp = self.api_client.post(url, data=kwargs['data'], **req_kwargs) self.assertHttpCreated(resp) self.assertValidJSONResponse(resp) # Make sure the count changed self.assertEqual(self.resource._meta.queryset.count(), count+1) return self.deserialize(resp) def rejected_post(self, url, expected_status_code=None, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) count = self.resource._meta.queryset.count() resp = self.api_client.post(url, data=kwargs['data'], **req_kwargs) self.assertEqual(resp.status_code, expected_status_code or self.rejected_status_code) self.assertEqual(self.resource._meta.queryset.count(), count) return resp def successful_put(self, url, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) if kwargs.get('data', None): req_kwargs['data'] = kwargs['data'] count = self.resource._meta.queryset.count() resp = self.api_client.put(url, **req_kwargs) self.assertHttpAccepted(resp) # Make sure the count hasn't changed self.assertEqual(self.resource._meta.queryset.count(), count) def rejected_put(self, url, expected_status_code=None, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) if kwargs.get('data', None): req_kwargs['data'] = kwargs['data'] count = self.resource._meta.queryset.count() resp = self.api_client.put(url, **req_kwargs) self.assertEqual(resp.status_code, expected_status_code or self.rejected_status_code) # Make sure the count hasn't changed self.assertEqual(self.resource._meta.queryset.count(), count) def successful_patch(self, url, check_results=True, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) if check_results: # Fetch the existing data for comparison. resp = self.api_client.get(url, **req_kwargs) self.assertHttpOK(resp) self.assertValidJSONResponse(resp) old_data = self.deserialize(resp) new_data = dict(old_data, **kwargs['data']) else: new_data = kwargs['data'] count = self.resource._meta.queryset.count() patch_resp = self.api_client.patch(url, data=new_data, **req_kwargs) self.assertHttpAccepted(patch_resp) # Make sure the count hasn't changed & we did an update. self.assertEqual(self.resource._meta.queryset.count(), count) if check_results: fresh_data = self.deserialize(self.api_client.get(url, **req_kwargs)) for attr in kwargs['data'].keys(): try: # Make sure the data actually changed self.assertNotEqual(fresh_data[attr], old_data[attr]) # Make sure the data changed to what we specified self.assertEqual(fresh_data[attr], new_data[attr]) except AssertionError: # If we specified a nested ID, we'll be getting back an object if str(new_data[attr]).isdigit() and isinstance(fresh_data[attr], dict): self.assertEqual(new_data[attr], fresh_data[attr]['id']) else: raise except KeyError: pass return fresh_data else: return self.deserialize(patch_resp) def rejected_patch(self, url, expected_status_code=None, expected_data=None, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) old_data = self.deserialize(self.api_client.get(url, **req_kwargs)) # User might not have GET access to grab initial data if old_data: new_data = old_data.copy() new_data.update(kwargs['data']) else: new_data = kwargs['data'] count = self.resource._meta.queryset.count() resp = self.api_client.patch(url, data=new_data, **req_kwargs) self.assertEqual(resp.status_code, expected_status_code or self.rejected_status_code) if expected_data: self.assertDictEqual(self.deserialize(resp), expected_data) self.assertEqual(self.resource._meta.queryset.count(), count) self.assertEqual(self.deserialize(self.api_client.get(url, **req_kwargs)), old_data) return resp def successful_delete(self, url, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) count = self.resource._meta.queryset.count() self.assertHttpOK( self.api_client.get(url, **req_kwargs)) self.assertHttpAccepted( self.api_client.delete(url, **req_kwargs)) self.assertEqual(self.resource._meta.queryset.count(), count-1) self.assertHttpNotFound( self.api_client.get(url, **req_kwargs)) def rejected_delete(self, url, expected_status_code=None, expected_data=None, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) count = self.resource._meta.queryset.count() delete_resp = self.api_client.delete(url, **req_kwargs) self.assertEqual(delete_resp.status_code, expected_status_code or self.rejected_status_code) if expected_data: self.assertDictEqual(self.deserialize(delete_resp), expected_data) self.assertEqual(self.resource._meta.queryset.count(), count) resp = self.api_client.get(url, **req_kwargs) try: # If the user doesn't have access, that's okay - # we were testing delete from an unauthorized user self.assertHttpUnauthorized(resp) except AssertionError: # Check for OK last so that this is the assertion # that shows up as the failure if it doesn't pass self.assertHttpOK(resp) return delete_resp
class PilotJobResourceTest(ResourceTestCase): fixtures = ['local_site.json'] def setUp(self): super(PilotJobResourceTest, self).setUp() self.client = TestApiClient() self.endpoint = '/api/v1/dispatcher/' self.format = 'json' # Create one user self.user = User(username="******") self.user.save() # create a job self.job = Job(user=self.user, application=Application.objects.all()[0]) self.job.maxtime = 30 self.job.save() self.site = Site.objects.get(pk=1) self.pilot = self.site.submit_pilot_based_on_job(self.job) def test_submit_pilot(self): pilot = self.site.submit_pilot_based_on_job(self.job) self.assertEqual(type(pilot), type(Pilot())) def test_pilot_post_job(self): self.job.status = 'P' self.job.save() data = {"time_left": 60} token = self.pilot.token url = "%s?token=%s" % (self.endpoint, token) request = self.client.post(url, self.format, data=data) self.assertHttpCreated(request) def test_pilot_get_job(self): self.job.status = 'R' self.job.pilot = self.pilot self.job.save() token = self.pilot.token url = "%s%d/?token=%s" % (self.endpoint, self.job.id, token) request = self.client.get(url, self.format) self.assertValidJSONResponse(request) def test_wrong_token(self): url = "%s%d/?token=%s" % (self.endpoint, self.job.id, "not-a-valid-token") request = self.client.get(url, self.format) self.assertHttpUnauthorized(request) def test_no_token(self): url = "%s%d/" % (self.endpoint, self.job.id) request = self.client.get(url, self.format) self.assertHttpUnauthorized(request) def test_pilot_patch_job(self): self.job.status = 'R' self.job.pilot = self.pilot self.job.save() data = {"progress": 50} token = self.pilot.token url = "%s%d/?token=%s" % (self.endpoint, self.job.id, token) request = self.client.patch(url, self.format, data=data) self.assertHttpAccepted(request)
class AnswerCreationResource(ResourceTestCase): def setUp(self): super(AnswerCreationResource, self).setUp() call_command('loaddata', 'example_data', verbosity=0) self.outbound_message = OutboundMessage.objects.all()[0] self.identifier = OutboundMessageIdentifier.objects.get(outbound_message=self.outbound_message) self.api_client = TestApiClient() self.user = User.objects.all()[0] self.data = {'format': 'json', 'username': self.user.username, 'api_key':self.user.api_key.key} def get_credentials(self): credentials = self.create_apikey(username=self.user.username, api_key=self.user.api_key.key) return credentials def test_I_can_create_an_answer_with_only_an_identifier_and_a_content(self): url = '/api/v1/create_answer/' content = 'Fiera tiene una pulga' answer_data = { 'key':self.identifier.key, 'content':content } previous_answers = Answer.objects.count() response = self.api_client.post(url, data = answer_data, format='json', authentication=self.get_credentials()) self.assertHttpCreated(response) answers_count = Answer.objects.count() self.assertEquals(answers_count, previous_answers + 1) def test_authorization_using_api_key(self): url = '/api/v1/create_answer/' content = 'una sola' answer_data = { 'key':self.identifier.key, 'content':content } response = self.api_client.post(url, data = answer_data, format='json') self.assertHttpUnauthorized(response) def test_only_the_owner_can_create_an_answer(self): not_the_owner = User.objects.create(username='******') his_api_key = not_the_owner.api_key credentials = self.create_apikey(username=not_the_owner.username, api_key=his_api_key.key) url = '/api/v1/create_answer/' content = 'una sola' answer_data = { 'key':self.identifier.key, 'content':content } response = self.api_client.post(url, data = answer_data, format='json', authentication=credentials) self.assertHttpUnauthorized(response) def test_only_post_endpoint(self): url = '/api/v1/create_answer/' content = 'una sola' answer_data = { 'key':self.identifier.key, 'content':content } response = self.api_client.get(url) self.assertHttpMethodNotAllowed(response) response = self.api_client.put(url, data = answer_data) self.assertHttpMethodNotAllowed(response) response = self.api_client.patch(url, data = answer_data) self.assertHttpMethodNotAllowed(response)
class ApiResourceTestCaseMixin(SimpleTestCase): # TODO: Using the regular ROOT_URLCONF avoids a problem where failing tests print useless error messages, # because the 500.html error template includes a {% url %} lookup that isn't included in api.urls. # There could be a better way to handle this. # url_base = "/v1" url_base = "/api/v1" server_domain = "perma.dev" server_port = 8999 serve_files = [] rejected_status_code = 401 # Unauthorized # reduce wait times for testing perma.tasks.ROBOTS_TXT_TIMEOUT = perma.tasks.AFTER_LOAD_TIMEOUT = 1 @classmethod def setUpClass(cls): super(ApiResourceTestCaseMixin, cls).setUpClass() if len(cls.serve_files): cls.start_server() @classmethod def tearDownClass(cls): if getattr(cls, "_server_process", None): cls.kill_server() def setUp(self): super(ApiResourceTestCaseMixin, self).setUp() self.api_client = TestApiClient(serializer=MultipartSerializer()) self._media_org = settings.MEDIA_ROOT self._media_tmp = settings.MEDIA_ROOT = tempfile.mkdtemp() try: self.list_url = "{0}/{1}".format(self.url_base, self.resource.Meta.resource_name) except: pass def tearDown(self): settings.MEDIA_ROOT = self._media_org shutil.rmtree(self._media_tmp) def get_credentials(self, user=None): user = user or self.user return "ApiKey %s" % user.api_key.key @classmethod def start_server(cls): """ Set up a server with some known files to run captures against. Example: with run_server_in_temp_folder([ 'test/assets/test.html', 'test/assets/test.pdf', ['test/assets/test.html', 'some_other_url.html']): assert(requests.get("http://localhost/test.html") == contents_of_file("test.html")) assert(requests.get("http://localhost/some_other_url.html") == contents_of_file("test.html")) """ assert socket.gethostbyname(cls.server_domain) in ( '0.0.0.0', '127.0.0.1' ), "Please add `127.0.0.1 " + cls.server_domain + "` to your hosts file before running this test." # Run in temp dir. # We have to (implicitly) cwd to this so SimpleHTTPRequestHandler serves the files for us. cwd = os.getcwd() cls._server_tmp = tempfile.mkdtemp() os.chdir(cls._server_tmp) # Copy over files to current temp dir, stripping paths. for source_file in cls.serve_files: # handle single strings if isinstance(source_file, basestring): target_url = os.path.basename(source_file) # handle tuple like (source_file, target_url) else: source_file, target_url = source_file copy_file_or_dir(os.path.join(cwd, source_file), target_url) # start server cls._httpd = TestHTTPServer(('', cls.server_port), SimpleHTTPRequestHandler) cls._httpd._BaseServer__is_shut_down = multiprocessing.Event() cls._server_process = Process(target=cls._httpd.serve_forever) cls._server_process.start() # once the server is started, we can return to our working dir # and the server thread will continue to server from the tmp dir os.chdir(cwd) return cls._server_process @classmethod def kill_server(cls): # If you don't close the server before terminating # the thread the port isn't freed up. cls._httpd.server_close() cls._server_process.terminate() shutil.rmtree(cls._server_tmp) @contextmanager def serve_file(self, src): if not getattr(self.__class__, "_server_process", None): self.__class__.start_server() dst = os.path.join(self._server_tmp, os.path.basename(src)) try: copy_file_or_dir(src, dst) yield finally: os.remove(dst) @cached_property def server_url(self): return "http://" + self.server_domain + ":" + str(self.server_port) @contextmanager def header_timeout(self, timeout): prev_t = models.HEADER_CHECK_TIMEOUT try: models.HEADER_CHECK_TIMEOUT = timeout yield finally: models.HEADER_CHECK_TIMEOUT = prev_t def assertValidJSONResponse(self, resp): # Modified from tastypie to allow 201's as well # https://github.com/toastdriven/django-tastypie/blob/master/tastypie/test.py#L448 try: self.assertHttpOK(resp) except AssertionError: self.assertHttpCreated(resp) self.assertTrue(resp['Content-Type'].startswith('application/json')) self.assertValidJSON(force_text(resp.content)) def detail_url(self, obj): return "{0}/{1}".format(self.list_url, obj.pk) def get_req_kwargs(self, kwargs): req_kwargs = {} if kwargs.get('format', None): req_kwargs['format'] = kwargs['format'] if kwargs.get('user', None): req_kwargs['authentication'] = self.get_credentials(kwargs['user']) return req_kwargs def successful_get(self, url, data=None, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) resp = self.api_client.get(url, data=data, **req_kwargs) self.assertHttpOK(resp) self.assertValidJSONResponse(resp) data = self.deserialize(resp) if kwargs.get('fields', None): self.assertKeys(data, kwargs['fields']) if kwargs.get('count', None): self.assertEqual(len(data['objects']), kwargs['count']) return data def rejected_get(self, url, expected_status_code=None, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) resp = self.api_client.get(url, **req_kwargs) self.assertEqual(resp.status_code, expected_status_code or self.rejected_status_code) return resp def successful_post(self, url, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) count = self.resource._meta.queryset.count() resp = self.api_client.post(url, data=kwargs['data'], **req_kwargs) self.assertHttpCreated(resp) self.assertValidJSONResponse(resp) # Make sure the count changed self.assertEqual(self.resource._meta.queryset.count(), count + 1) return self.deserialize(resp) def rejected_post(self, url, expected_status_code=None, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) count = self.resource._meta.queryset.count() resp = self.api_client.post(url, data=kwargs['data'], **req_kwargs) self.assertEqual(resp.status_code, expected_status_code or self.rejected_status_code) self.assertEqual(self.resource._meta.queryset.count(), count) return resp def successful_put(self, url, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) if kwargs.get('data', None): req_kwargs['data'] = kwargs['data'] count = self.resource._meta.queryset.count() resp = self.api_client.put(url, **req_kwargs) self.assertHttpAccepted(resp) # Make sure the count hasn't changed self.assertEqual(self.resource._meta.queryset.count(), count) def rejected_put(self, url, expected_status_code=None, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) if kwargs.get('data', None): req_kwargs['data'] = kwargs['data'] count = self.resource._meta.queryset.count() resp = self.api_client.put(url, **req_kwargs) self.assertEqual(resp.status_code, expected_status_code or self.rejected_status_code) # Make sure the count hasn't changed self.assertEqual(self.resource._meta.queryset.count(), count) def successful_patch(self, url, check_results=True, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) new_data = kwargs['data'] if check_results: # Fetch the existing data for comparison. resp = self.api_client.get(url, **req_kwargs) self.assertHttpOK(resp) self.assertValidJSONResponse(resp) old_data = self.deserialize(resp) count = self.resource._meta.queryset.count() patch_resp = self.api_client.patch(url, data=new_data, **req_kwargs) self.assertHttpAccepted(patch_resp) # Make sure the count hasn't changed & we did an update. self.assertEqual(self.resource._meta.queryset.count(), count) if check_results: fresh_data = self.deserialize( self.api_client.get(url, **req_kwargs)) for attr in kwargs['data'].keys(): try: # Make sure the data actually changed self.assertNotEqual(fresh_data[attr], old_data[attr]) # Make sure the data changed to what we specified self.assertEqual(fresh_data[attr], new_data[attr]) except AssertionError: # If we specified a nested ID, we'll be getting back an object if str(new_data[attr]).isdigit() and isinstance( fresh_data[attr], dict): self.assertEqual(new_data[attr], fresh_data[attr]['id']) else: raise except KeyError: pass return fresh_data else: return self.deserialize(patch_resp) def rejected_patch(self, url, expected_status_code=None, expected_data=None, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) old_data = self.deserialize(self.api_client.get(url, **req_kwargs)) new_data = kwargs['data'] count = self.resource._meta.queryset.count() resp = self.api_client.patch(url, data=new_data, **req_kwargs) self.assertEqual(resp.status_code, expected_status_code or self.rejected_status_code) if expected_data: self.assertDictEqual(self.deserialize(resp), expected_data) self.assertEqual(self.resource._meta.queryset.count(), count) self.assertEqual( self.deserialize(self.api_client.get(url, **req_kwargs)), old_data) return resp def successful_delete(self, url, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) count = self.resource._meta.queryset.count() self.assertHttpOK(self.api_client.get(url, **req_kwargs)) self.assertHttpAccepted(self.api_client.delete(url, **req_kwargs)) self.assertEqual(self.resource._meta.queryset.count(), count - 1) self.assertHttpNotFound(self.api_client.get(url, **req_kwargs)) def rejected_delete(self, url, expected_status_code=None, expected_data=None, **kwargs): req_kwargs = self.get_req_kwargs(kwargs) count = self.resource._meta.queryset.count() delete_resp = self.api_client.delete(url, **req_kwargs) self.assertEqual(delete_resp.status_code, expected_status_code or self.rejected_status_code) if expected_data: self.assertDictEqual(self.deserialize(delete_resp), expected_data) self.assertEqual(self.resource._meta.queryset.count(), count) resp = self.api_client.get(url, **req_kwargs) try: # If the user doesn't have access, that's okay - # we were testing delete from an unauthorized user self.assertHttpUnauthorized(resp) except AssertionError: # Check for OK last so that this is the assertion # that shows up as the failure if it doesn't pass self.assertHttpOK(resp) return delete_resp
class AnswerCreationResource(ResourceTestCase): def setUp(self): super(AnswerCreationResource, self).setUp() call_command('loaddata', 'example_data', verbosity=0) self.outbound_message = OutboundMessage.objects.get(id=1) self.identifier = OutboundMessageIdentifier.objects.get( outbound_message=self.outbound_message) self.api_client = TestApiClient() self.user = User.objects.get(id=1) self.data = { 'format': 'json', 'username': self.user.username, 'api_key': self.user.api_key.key } def get_credentials(self): credentials = self.create_apikey(username=self.user.username, api_key=self.user.api_key.key) return credentials def test_I_can_create_an_answer_with_only_an_identifier_and_a_content( self): url = '/api/v1/create_answer/' content = 'Fiera tiene una pulga' answer_data = { 'key': self.identifier.key, 'content': content, } previous_answers = Answer.objects.count() response = self.api_client.post(url, data=answer_data, format='json', authentication=self.get_credentials()) self.assertHttpCreated(response) answers_count = Answer.objects.count() self.assertEquals(answers_count, previous_answers + 1) answer_json = self.deserialize(response) self.assertEquals(answer_json['content'], content) self.assertIn('id', answer_json.keys()) def test_authorization_using_api_key(self): url = '/api/v1/create_answer/' content = 'una sola' answer_data = { 'key': self.identifier.key, 'content': content, } response = self.api_client.post(url, data=answer_data, format='json') self.assertHttpUnauthorized(response) def test_only_the_owner_can_create_an_answer(self): not_the_owner = User.objects.create(username='******') his_api_key = not_the_owner.api_key credentials = self.create_apikey(username=not_the_owner.username, api_key=his_api_key.key) url = '/api/v1/create_answer/' content = 'una sola' answer_data = { 'key': self.identifier.key, 'content': content, } response = self.api_client.post(url, data=answer_data, format='json', authentication=credentials) self.assertHttpUnauthorized(response) def test_only_post_endpoint(self): url = '/api/v1/create_answer/' content = 'una sola' answer_data = { 'key': self.identifier.key, 'content': content, } response = self.api_client.get(url) self.assertHttpMethodNotAllowed(response) response = self.api_client.put(url, data=answer_data) self.assertHttpMethodNotAllowed(response) response = self.api_client.patch(url, data=answer_data) self.assertHttpMethodNotAllowed(response)
def test_2api_init(self): print '***================ super: db test_2api_init =============== ' super(TestApiInit, self).test_2api_init() print '***================ local: db test_2api_init =============== ' serializer=CSVSerializer() # todo: doesn't work for post, see TestApiClient.post() method, it is # incorrectly "serializing" the data before posting testApiClient = TestApiClient(serializer=serializer) filename = os.path.join(self.db_directory,'api_init_actions.csv') with open(filename) as input_file: api_init_actions = serializer.from_csv(input_file.read(), root=None) bootstrap_files = [ 'metahash_resource_data.csv', 'vocabularies_data.csv'] for action in api_init_actions: print '\n++++=========== processing action', json.dumps(action) command = action['command'].lower() resource = action['resource'].lower() resource_uri = BASE_REPORTS_URI + '/' + resource if command == 'delete': resp = testApiClient.delete( resource_uri, authentication=self.get_credentials()) self.assertHttpAccepted(resp) else: filename = os.path.join(self.db_directory,action['file']) search_excludes = [] # exclude 'resource_uri' from equivalency check during # bootstrap, because resource table needs to be loaded for # the uri generation if action['file'] in bootstrap_files: search_excludes = ['resource_uri'] logger.info(str(('+++++++++++processing file', filename))) with open(filename) as data_file: input_data = serializer.from_csv(data_file.read()) if command == 'put': resp = testApiClient.put( resource_uri, format='csv', data=input_data, authentication=self.get_credentials() ) logger.debug(str(('action: ', json.dumps(action), 'response: ' , resp.status_code))) self.assertTrue( resp.status_code in [200], str((resp.status_code, resp))) # now see if we can get these objects back resp = testApiClient.get( resource_uri, format='json', authentication=self.get_credentials(), data={ 'limit': 999 }) self.assertTrue( resp.status_code in [200], str((resp.status_code, resp))) # self.assertValidJSONResponse(resp) new_obj = self.deserialize(resp) result, msgs = find_all_obj_in_list( input_data['objects'], new_obj['objects'], excludes=search_excludes) self.assertTrue( result, str((command, 'input file', filename, msgs, new_obj['objects'])) ) elif command == 'patch': resp = testApiClient.patch( resource_uri, format='csv', data=input_data, authentication=self.get_credentials() ) # self.assertHttpAccepted(resp) self.assertTrue(resp.status_code in [202, 204], str(( 'response not accepted, resource_uri:', resource_uri, 'response', resp))) resp = testApiClient.get( resource_uri, format='json', authentication=self.get_credentials(), data={ 'limit': 999 } ) self.assertTrue( resp.status_code in [200], str((resp.status_code, resp))) # self.assertValidJSONResponse(resp) new_obj = self.deserialize(resp) with open(filename) as f2: input_data2 = serializer.from_csv(f2.read()) result, msgs = find_all_obj_in_list( input_data2['objects'], new_obj['objects'], excludes=search_excludes) self.assertTrue( result, str(( command, 'input file', filename, msgs )) ) elif command == 'post': self.fail(( 'resource entry: ' + json.dumps(action) + '; ' 'cannot POST multiple objects to tastypie; ' 'therefore the "post" command is invalid with ' 'the initialization scripts')) else: self.fail('unknown command: ' + command + ', ' + json.dumps(action))
def test_2api_init(self): print '***================ super: db test_2api_init =============== ' super(TestApiInit, self).test_2api_init() print '***================ local: db test_2api_init =============== ' serializer = CSVSerializer() # todo: doesn't work for post, see TestApiClient.post() method, it is # incorrectly "serializing" the data before posting testApiClient = TestApiClient(serializer=serializer) filename = os.path.join(self.db_directory, 'api_init_actions.csv') with open(filename) as input_file: api_init_actions = serializer.from_csv(input_file.read(), root=None) bootstrap_files = [ 'metahash_resource_data.csv', 'vocabularies_data.csv' ] for action in api_init_actions: print '\n++++=========== processing action', json.dumps(action) command = action['command'].lower() resource = action['resource'].lower() resource_uri = BASE_REPORTS_URI + '/' + resource if command == 'delete': resp = testApiClient.delete( resource_uri, authentication=self.get_credentials()) self.assertHttpAccepted(resp) else: filename = os.path.join(self.db_directory, action['file']) search_excludes = [] # exclude 'resource_uri' from equivalency check during # bootstrap, because resource table needs to be loaded for # the uri generation if action['file'] in bootstrap_files: search_excludes = ['resource_uri'] logger.info(str(('+++++++++++processing file', filename))) with open(filename) as data_file: input_data = serializer.from_csv(data_file.read()) if command == 'put': resp = testApiClient.put( resource_uri, format='csv', data=input_data, authentication=self.get_credentials()) logger.debug( str(('action: ', json.dumps(action), 'response: ', resp.status_code))) self.assertTrue(resp.status_code in [200], str((resp.status_code, resp))) # now see if we can get these objects back resp = testApiClient.get( resource_uri, format='json', authentication=self.get_credentials(), data={'limit': 999}) self.assertTrue(resp.status_code in [200], str((resp.status_code, resp))) # self.assertValidJSONResponse(resp) new_obj = self.deserialize(resp) result, msgs = find_all_obj_in_list( input_data['objects'], new_obj['objects'], excludes=search_excludes) self.assertTrue( result, str((command, 'input file', filename, msgs, new_obj['objects']))) elif command == 'patch': resp = testApiClient.patch( resource_uri, format='csv', data=input_data, authentication=self.get_credentials()) # self.assertHttpAccepted(resp) self.assertTrue( resp.status_code in [202, 204], str(('response not accepted, resource_uri:', resource_uri, 'response', resp))) resp = testApiClient.get( resource_uri, format='json', authentication=self.get_credentials(), data={'limit': 999}) self.assertTrue(resp.status_code in [200], str((resp.status_code, resp))) # self.assertValidJSONResponse(resp) new_obj = self.deserialize(resp) with open(filename) as f2: input_data2 = serializer.from_csv(f2.read()) result, msgs = find_all_obj_in_list( input_data2['objects'], new_obj['objects'], excludes=search_excludes) self.assertTrue( result, str((command, 'input file', filename, msgs))) elif command == 'post': self.fail(( 'resource entry: ' + json.dumps(action) + '; ' 'cannot POST multiple objects to tastypie; ' 'therefore the "post" command is invalid with ' 'the initialization scripts')) else: self.fail('unknown command: ' + command + ', ' + json.dumps(action))
class PilotJobResourceTest(ResourceTestCase): fixtures = ['local_site.json'] def setUp(self): super(PilotJobResourceTest, self).setUp() self.client = TestApiClient() self.endpoint = '/api/v1/dispatcher/' self.format = 'json' # Create one user self.user = User(username="******") self.user.save() # create a job self.job = Job(user=self.user, application=Application.objects.all()[0]) self.job.maxtime = 30 self.job.save() self.site = Site.objects.get(pk=1) self.pilot = self.site.submit_pilot_based_on_job(self.job) def test_submit_pilot(self): pilot = self.site.submit_pilot_based_on_job(self.job) self.assertEqual(type(pilot), type(Pilot())) def test_pilot_post_job(self): self.job.status='P' self.job.save() data = {"time_left": 60} token = self.pilot.token url = "%s?token=%s" % (self.endpoint, token) request = self.client.post(url, self.format, data=data) self.assertHttpCreated(request) def test_pilot_get_job(self): self.job.status='R' self.job.pilot = self.pilot self.job.save() token = self.pilot.token url = "%s%d/?token=%s" % (self.endpoint, self.job.id, token) request = self.client.get(url, self.format) self.assertValidJSONResponse(request) def test_wrong_token(self): url = "%s%d/?token=%s" % (self.endpoint, self.job.id, "not-a-valid-token") request = self.client.get(url, self.format) self.assertHttpUnauthorized(request) def test_no_token(self): url = "%s%d/" % (self.endpoint, self.job.id) request = self.client.get(url, self.format) self.assertHttpUnauthorized(request) def test_pilot_patch_job(self): self.job.status='R' self.job.pilot = self.pilot self.job.save() data = {"progress": 50} token = self.pilot.token url = "%s%d/?token=%s" % (self.endpoint, self.job.id, token) request = self.client.patch(url, self.format, data=data) self.assertHttpAccepted(request)
class Private_v1__PhotoResourceTest(ResourceTestCase): fixtures = [ 'packages.json', 'api_accounts_and_keys.json', 'accounts_and_users.json', 'events.json', 'photos.json' ] def setUp(self): super(Private_v1__PhotoResourceTest, self).setUp() # we need a custom serializer for multipart uploads self.api_client = TestApiClient(serializer=MultipartSerializer()) self.api_key = 'key123' self.api_secret = 'sec123' # The data we'll send on POST requests. filename = 'trashcat.jpg' filepath = os.path.join(settings.PROJECT_PATH, 'api', 'assets', filename) f = open(filepath, 'rb') self.post_data = { 'event': '/private_v1/event/1/', 'caption': 'My super awesome caption!', 'type': '/private_v1/type/1/', 'image': { 'filename': filename, 'data': f.read(), } } def get_credentials(self, method, uri): return DatabaseAuthentication.create_signature(self.api_key, self.api_secret, method, uri) def test_post_photo(self): uri = '/private_v1/photo/' resp = self.api_client.post(uri, data=self.post_data, format='multipart', authentication=self.get_credentials( 'POST', uri)) data = self.deserialize(resp) # make sure the resource was created self.assertHttpCreated(resp) # test to make sure all the keys are in the response self.assertKeys(self.deserialize(resp), [ 'author_name', 'caption', 'created_at', 'event', 'guest', 'image', 'is_streamable', 'resource_uri', 'streamable', 'timestamp', 'type', ]) # make sure the timestamp is in the format we want (ISO8601) without micro # expected format: 2013-01-21T18:12:45 self.assertTrue( re.search('^\d{4}-(\d{2}-?){2}T(\d{2}:?){3}$', data['timestamp'])) def test_post_photo_noimage(self): uri = '/private_v1/photo/' del (self.post_data['image']) resp = self.api_client.post(uri, data=self.post_data, format='multipart', authentication=self.get_credentials( 'POST', uri)) data = self.deserialize(resp) # make sure the resource was created self.assertHttpBadRequest(resp) def test_put_photo(self): uri = '/private_v1/photo/1/' put_data = {'caption': 'awesome'} resp = self.api_client.put(uri, data=put_data, format='json', authentication=self.get_credentials( 'PUT', uri)) data = self.deserialize(resp) # make sure the resource has a valid response self.assertHttpOK(resp) # test to make sure all the keys are in the response self.assertEqual(data['caption'], put_data['caption']) def test_patch_photo(self): uri = '/private_v1/photo/1/' patch_data = {'is_streamable': False} resp = self.api_client.patch(uri, data=patch_data, format='json', authentication=self.get_credentials( 'PATCH', uri)) data = self.deserialize(resp) # make sure the resource has a valid response self.assertHttpAccepted(resp) # test to make sure all the keys are in the response self.assertEqual(data['is_streamable'], patch_data['is_streamable']) def test_delete_photo(self): uri = '/private_v1/photo/1/' resp = self.api_client.delete(uri, format='json', authentication=self.get_credentials( 'DELETE', uri)) self.assertHttpAccepted(resp)
class Private_v1__EventResourceTest(ResourceTestCase): fixtures = ['packages.json', 'api_accounts_and_keys.json', 'accounts_and_users.json', 'events.json', 'photos.json'] def setUp(self): super(Private_v1__EventResourceTest, self).setUp() # we need a custom serializer for multipart uploads self.api_client = TestApiClient(serializer=SnapSerializer()) self.api_key = 'key123' self.api_secret = 'sec123' # Fetch the objects we'll use in testing. # Note that we aren't using PKs because they can change depending # on what other tests are running. self.event_1 = Event.objects.all()[0] self.post_data = { 'account': '/private_v1/account/3/', # account 3 has no users 'end': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(time.time() + 60*60)), 'start': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), 'title': 'My awesome test event', 'url': 'awesome-test-event', 'tz_offset': 0, } self.old_date_data = { 'are_photos_streamable': True, 'end': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(time.time() + 60*60)), 'is_public': False, 'start': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime()), 'title': 'Wedding Republic & Snapable Office Party', 'url': 'wr-snap-party', } self.patch_data = { 'are_photos_streamable': True, 'end_at': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(time.time() + 60*60)), 'is_public': False, 'start_at': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), 'title': 'Wedding Republic & Snapable Office Party', 'url': 'wr-snap-party', } def get_credentials(self, method, uri): return DatabaseAuthentication.create_signature(self.api_key, self.api_secret, method, uri) def test_get_event(self): uri = '/private_v1/event/{0}/'.format(self.event_1.pk) resp = self.api_client.get(uri, format='json', authentication=self.get_credentials('GET', uri)) # make sure the resource was created self.assertValidJSONResponse(resp) # test to make sure all the keys are in the response self.assertKeys(self.deserialize(resp), [ 'account', 'addons', 'addresses', 'are_photos_streamable', 'cover', 'created', 'created_at', 'creation_date', 'enabled', 'end', 'end_at', 'is_enabled', 'is_public', 'package', 'photo_count', 'pin', 'public', 'resource_uri', 'start', 'start_at', 'title', 'type', 'tz_offset', 'url', 'user', 'uuid' ]) def test_get_events(self): uri = '/private_v1/event/' data_get = {'start_at__gte': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(time.time() - 60))} resp = self.api_client.get(uri, data=data_get, format='json', authentication=self.get_credentials('GET', uri)) # make sure the resource was created self.assertValidJSONResponse(resp) count = self.deserialize(resp)['meta']['total_count'] self.assertTrue(count >= 0) self.assertTrue(count < Event.objects.count()) def test_get_event_cover(self): # this event doesn't have any data in cloud files uri = '/private_v1/event/{0}/'.format(self.event_1.pk) resp = self.api_client.get(uri, format='jpeg', authentication=self.get_credentials('GET', uri)) self.assertHttpNotFound(resp) def test_get_events_search(self): uri_post = '/private_v1/event/' uri_get = '/private_v1/event/search/' data_get = {'q': 'event', 'enabled': 'true', 'order_by': 'end'} events = Event.objects.all() events_count = events.count() # count() checks database, not queryset, so we save now resp_post = self.api_client.post(uri_post, data=self.post_data, format='json', authentication=self.get_credentials('POST', uri_post)) # make sure the resource was created self.assertHttpCreated(resp_post) resp_get = self.api_client.get(uri_get, data=data_get, format='json', authentication=self.get_credentials('GET', uri_get)) # make sure the response is valid self.assertValidJSONResponse(resp_get) # make sure we have some search results self.assertTrue(self.deserialize(resp_get)['meta']['total_count'] > 0) # we should have n+1 where n is existing events (+ 1 new) self.assertEqual(self.deserialize(resp_get)['meta']['total_count'], events_count + 1) # the first should be the new event url self.assertEqual(self.deserialize(resp_get)['objects'][0]['url'], self.post_data['url']) # the second should be the first event url self.assertEqual(self.deserialize(resp_get)['objects'][1]['url'], self.event_1.url) def test_put_event(self): uri_put = '/private_v1/event/{0}/'.format(self.event_1.pk) resp = self.api_client.put(uri_put, data=self.patch_data, format='json', authentication=self.get_credentials('PUT', uri_put)) event = Event.objects.get(pk=self.event_1.pk) event_start = event.start_at.strftime('%Y-%m-%dT%H:%M:%SZ') self.assertEqual(event_start, self.patch_data['start_at']) # deprecated code test resp = self.api_client.put(uri_put, data=self.old_date_data, format='json', authentication=self.get_credentials('PUT', uri_put)) event = Event.objects.get(pk=self.event_1.pk) event_start = event.start_at.strftime('%Y-%m-%d %H:%M:%S') self.assertEqual(event_start, self.old_date_data['start']) def test_patch_event(self): uri_patch = '/private_v1/event/{0}/'.format(self.event_1.pk) resp = self.api_client.patch(uri_patch, data=self.patch_data, format='json', authentication=self.get_credentials('PATCH', uri_patch)) event = Event.objects.get(pk=self.event_1.pk) event_start = event.start_at.strftime('%Y-%m-%dT%H:%M:%SZ') self.assertEqual(event_start, self.patch_data['start_at']) # deprecated code test resp = self.api_client.patch(uri_patch, data=self.old_date_data, format='json', authentication=self.get_credentials('PATCH', uri_patch)) event = Event.objects.get(pk=self.event_1.pk) event_start = event.start_at.strftime('%Y-%m-%d %H:%M:%S') self.assertEqual(event_start, self.old_date_data['start'])