def test_correct_setup(self): request = MockRequest() request.GET = {'format': 'json'} request.method = 'GET' # Verify the explicit 'through' relationships has been created correctly resource = api.canonical_resource_for('taggabletag') resp = resource.wrap_view('dispatch_detail')(request, pk=self.taggabletag_1.pk) data = json.loads(resp.content) self.assertEqual(resp.status_code, 200) self.assertEqual(data['tag'], '/v1/tag/1/') self.assertEqual(data['taggable'], '/v1/taggable/1/') resource = api.canonical_resource_for('taggable') resp = resource.wrap_view('dispatch_detail')(request, pk=self.taggable_1.pk) data = json.loads(resp.content) self.assertEqual(resp.status_code, 200) self.assertEqual(data['name'], 'exam') resource = api.canonical_resource_for('tag') request.path = "/v1/tag/%(pk)s/" % {'pk': self.tag_1.pk} resp = resource.wrap_view('dispatch_detail')(request, pk=self.tag_1.pk) data = json.loads(resp.content) self.assertEqual(resp.status_code, 200) self.assertEqual(data['name'], 'important') # and check whether the extradata is present self.assertEqual(data['extradata']['name'], u'additional')
def patch_details(resource, pk, **kwargs): # Post the extradata element which is attached to a "reverse" OneToOne request = MockRequest() request.method = "PATCH" request.body = json.dumps(kwargs) response = resource.patch_detail(request, pk=pk) return response
def test_create_similar(self): # We submit to job with the related payment included. # Note that on the resource, the payment related resource is defined # On the model, the Job class does not have a payment field, # but it has a reverse relationship defined by the Payment class resource = JobResource() data = { 'name': 'OtherJob', 'payment': { 'scheduled': self.some_time_str } } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.set_body(json.dumps(data)) resp = resource.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Job.objects.count(), 2) self.assertEqual(Payment.objects.count(), 2) new_job = Job.objects.all().order_by('-id')[0] new_payment = Payment.objects.all().order_by('-id')[0] self.assertEqual(new_job.name, 'OtherJob') self.assertEqual(new_job, new_payment.job)
def test_read_tag_content_object_full(self): request = MockRequest() request.GET = {'format': 'json'} request.method = 'GET' # set the content_object field to full mode resource = api.canonical_resource_for('generictag') resource.fields['content_object'].full = True # check for self.tag_1 and self.category_1 resp = resource.wrap_view('dispatch_detail')(request, pk=self.tag_1.pk) self.assertEqual(resp.status_code, 200) data = json.loads(resp.content) self.assertEqual(data['content_object'], CategoryResource().full_dehydrate( CategoryResource().build_bundle(obj=self.category_1, request=request)).data) # now for self.tag_2 and self.taggable_1 resp = resource.wrap_view('dispatch_detail')(request, pk=self.tag_2.pk) self.assertEqual(resp.status_code, 200) data = json.loads(resp.content) self.assertEqual(data['content_object'], TaggableResource().full_dehydrate( TaggableResource().build_bundle(obj=self.taggable_1, request=request)).data)
def test_related_resource_authorization(self): resource = api.canonical_resource_for("notes") request = MockRequest() request.GET = {"format": "json"} request.method = "POST" request.set_body( '{"content": "The cat is back. The dog coughed him up out back.", "created": "2010-04-03 20:05:00", "is_active": true, "slug": "cat-is-back", "title": "The Cat Is Back", "updated": "2010-04-03 20:05:00", "author": null}' ) resp = resource.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(User.objects.get(id=self.user.id).username, "testy_mctesterson") request = MockRequest() request.GET = {"format": "json"} request.method = "POST" request.set_body( '{"content": "The cat is back. The dog coughed him up out back.", "created": "2010-04-03 20:05:00", "is_active": true, "slug": "cat-is-back-2", "title": "The Cat Is Back", "updated": "2010-04-03 20:05:00", "author": {"id": %s, "username": "******"}}' % self.user.id ) resp = resource.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(User.objects.get(id=self.user.id).username, "foobar")
def test_correct_setup(self): request = MockRequest() request.GET = {'format': 'json'} request.method = 'GET' # Verify the explicit 'through' relationships has been created correctly resource = api.canonical_resource_for('taggabletag') resp = resource.wrap_view('dispatch_detail')(request, pk=self.taggabletag_1.pk) data = json.loads(resp.content) self.assertEqual(resp.status_code, 200) self.assertEqual(data['tag'], '/v1/tag/1/') self.assertEqual(data['taggable'], '/v1/taggable/1/') resource = api.canonical_resource_for('taggable') resp = resource.wrap_view('dispatch_detail')(request, pk=self.taggable_1.pk) data = json.loads(resp.content) self.assertEqual(resp.status_code, 200) self.assertEqual(data['name'], 'exam') resource = api.canonical_resource_for('tag') resp = resource.wrap_view('dispatch_detail')(request, pk=self.tag_1.pk) data = json.loads(resp.content) self.assertEqual(resp.status_code, 200) self.assertEqual(data['name'], 'important') # and check whether the extradata is present self.assertEqual(data['extradata']['name'], u'additional')
def test_one_to_many(self): # Sanity checks. self.assertEqual(Note.objects.count(), 2) self.assertEqual(MediaBit.objects.count(), 0) fnr = FreshNoteResource() data = { "title": "Create with related URIs", "slug": "create-with-related-uris", "content": "Some content here", "is_active": True, "media_bits": [{"title": "Picture #1"}], } request = MockRequest() request.GET = {"format": "json"} request.method = "POST" request.body = json.dumps(data) resp = fnr.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Note.objects.count(), 3) note = Note.objects.latest("created") self.assertEqual(note.media_bits.count(), 1) self.assertEqual(note.media_bits.all()[0].title, u"Picture #1")
def test_correct_setup(self): request = MockRequest() request.GET = {"format": "json"} request.method = "GET" # Verify the explicit 'through' relationships has been created correctly resource = api.canonical_resource_for("taggabletag") resp = resource.wrap_view("dispatch_detail")(request, pk=self.taggabletag_1.pk) data = json.loads(resp.content) self.assertEqual(resp.status_code, 200) self.assertEqual(data["tag"], "/v1/tag/1/") self.assertEqual(data["taggable"], "/v1/taggable/1/") resource = api.canonical_resource_for("taggable") resp = resource.wrap_view("dispatch_detail")(request, pk=self.taggable_1.pk) data = json.loads(resp.content) self.assertEqual(resp.status_code, 200) self.assertEqual(data["name"], "exam") resource = api.canonical_resource_for("tag") resp = resource.wrap_view("dispatch_detail")(request, pk=self.tag_1.pk) data = json.loads(resp.content) self.assertEqual(resp.status_code, 200) self.assertEqual(data["name"], "important") # and check whether the extradata is present self.assertEqual(data["extradata"]["name"], u"additional")
def test_incorrect_uri(self): self.assertEqual(Note.objects.count(), 2) nr = NoteResource() # For this test, we need a ``User`` with the same PK as a ``Note``. note_1 = Note.objects.latest('created') User.objects.create( id=note_1.pk, username='******', email='*****@*****.**', password='******' ) data = { # This URI is flat-out wrong (wrong resource). # This should cause the request to fail. 'author': '/v1/notes/{0}/'.format( note_1.pk ), 'title': 'Nopenopenope', 'slug': 'invalid-request', 'content': "This shouldn't work.", 'is_active': True, } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.set_body(json.dumps(data)) with self.assertRaises(NotFound) as cm: nr.post_list(request) self.assertEqual(str(cm.exception), "An incorrect URL was provided '/v1/notes/2/' for the 'UserResource' resource.") self.assertEqual(Note.objects.count(), 2)
def test_incorrect_uri(self): self.assertEqual(Note.objects.count(), 2) nr = NoteResource() # For this test, we need a ``User`` with the same PK as a ``Note``. note_1 = Note.objects.latest("created") user_2 = User.objects.create(id=note_1.pk, username="******", email="*****@*****.**", password="******") data = { # This URI is flat-out wrong (wrong resource). # This should cause the request to fail. "author": "/v1/notes/{0}/".format(note_1.pk), "title": "Nopenopenope", "slug": "invalid-request", "content": "This shouldn't work.", "is_active": True, } request = MockRequest() request.GET = {"format": "json"} request.method = "POST" request.set_body(json.dumps(data)) with self.assertRaises(NotFound) as cm: nr.post_list(request) self.assertEqual( str(cm.exception), "An incorrect URL was provided '/v1/notes/2/' for the 'UserResource' resource." ) self.assertEqual(Note.objects.count(), 2)
def test_related_resource_authorization(self): resource = api.canonical_resource_for('notes') request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.body = '{"content": "The cat is back. The dog coughed him up out back.", "created": "2010-04-03 20:05:00", "is_active": true, "slug": "cat-is-back", "title": "The Cat Is Back", "updated": "2010-04-03 20:05:00", "author": null}' resp = resource.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual( User.objects.get(id=self.user.id).username, 'testy_mctesterson') request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.body = '{"content": "The cat is back. The dog coughed him up out back.", "created": "2010-04-03 20:05:00", "is_active": true, "slug": "cat-is-back-2", "title": "The Cat Is Back", "updated": "2010-04-03 20:05:00", "author": {"id": %s, "username": "******"}}' % self.user.id try: resource.post_list(request) except ImmediateHttpResponse as resp: self.assertEqual(resp.response.status_code, 400) else: self.fail("post_list should raise an ImmediateHttpResponse error") # self.assertEqual(resp.status_code, 201) self.assertEqual( User.objects.get(id=self.user.id).username, 'testy_mctesterson', "User resource is GET-only and so should not be updatable")
def test_one_to_many(self): # Sanity checks. self.assertEqual(Note.objects.count(), 2) self.assertEqual(MediaBit.objects.count(), 0) fnr = FreshNoteResource() data = { 'title': 'Create with related URIs', 'slug': 'create-with-related-uris', 'content': 'Some content here', 'is_active': True, 'media_bits': [{ 'title': 'Picture #1' }] } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.raw_post_data = json.dumps(data) resp = fnr.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Note.objects.count(), 3) note = Note.objects.latest('created') self.assertEqual(note.media_bits.count(), 1) self.assertEqual(note.media_bits.all()[0].title, u'Picture #1')
def test_one_to_many(self): # Sanity checks. self.assertEqual(Note.objects.count(), 2) self.assertEqual(MediaBit.objects.count(), 0) fnr = FreshNoteResource() data = { 'title': 'Create with related URIs', 'slug': 'create-with-related-uris', 'content': 'Some content here', 'is_active': True, 'media_bits': [ { 'title': 'Picture #1' } ] } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.set_body(json.dumps(data)) resp = fnr.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Note.objects.count(), 3) note = Note.objects.latest('created') self.assertEqual(note.media_bits.count(), 1) self.assertEqual(note.media_bits.all()[0].title, u'Picture #1')
def test_related_resource_fk_lookup(self): resource = api.canonical_resource_for('tag') request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.raw_post_data = '{"extradata": {"non_existent_field": "foobar"}, "taggabletags": [ ]}' response = resource.post_list(request) self.assertEqual(response.status_code, 201)
def test_one_to_many(self): """ Test a related ToOne resource with a nested full ToMany resource """ self.assertEqual(Person.objects.count(), 0) self.assertEqual(Company.objects.count(), 0) self.assertEqual(Product.objects.count(), 0) pr = PersonResource() data = { 'name': 'Joan Rivers', 'company': { 'name': 'Yum Yum Pie Factory!', 'products': [ { 'name': 'Tasty Pie' } ] } } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' setattr(request, self.body_attr, json.dumps(data)) resp = pr.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Person.objects.count(), 1) self.assertEqual(Company.objects.count(), 1) self.assertEqual(Product.objects.count(), 1) pk = Person.objects.all()[0].pk request = MockRequest() request.method = 'GET' request.path = reverse('api_dispatch_detail', kwargs={'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name}) resp = pr.get_detail(request, pk=pk) self.assertEqual(resp.status_code, 200) person = json.loads(resp.content) self.assertEqual(person['name'], 'Joan Rivers') company = person['company'] self.assertEqual(company['name'], 'Yum Yum Pie Factory!') self.assertEqual(len(company['products']), 1) product = company['products'][0] self.assertEqual(product['name'], 'Tasty Pie') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.path = reverse('api_dispatch_detail', kwargs={'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name}) setattr(request, self.body_attr, json.dumps(person)) resp = pr.put_detail(request, pk=pk) self.assertEqual(resp.status_code, 204)
def test_many_to_one(self): """ Test a related ToMany resource with a nested full ToOne resource """ self.assertEqual(Person.objects.count(), 0) self.assertEqual(Dog.objects.count(), 0) self.assertEqual(DogHouse.objects.count(), 0) pr = PersonResource() data = { 'name': 'Joan Rivers', 'dogs': [ { 'name': 'Snoopy', 'house': { 'color': 'Red' } } ] } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' setattr(request, self.body_attr, json.dumps(data)) resp = pr.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Person.objects.count(), 1) self.assertEqual(Dog.objects.count(), 1) self.assertEqual(DogHouse.objects.count(), 1) pk = Person.objects.all()[0].pk request = MockRequest() request.method = 'GET' request.path = reverse('api_dispatch_detail', kwargs={'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name}) resp = pr.get_detail(request, pk=pk) self.assertEqual(resp.status_code, 200) person = json.loads(resp.content) self.assertEqual(person['name'], 'Joan Rivers') self.assertEqual(len(person['dogs']), 1) dog = person['dogs'][0] self.assertEqual(dog['name'], 'Snoopy') house = dog['house'] self.assertEqual(house['color'], 'Red') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' setattr(request, self.body_attr, json.dumps(person)) request.path = reverse('api_dispatch_detail', kwargs={'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name}) resp = pr.put_detail(request, pk=pk) self.assertEqual(resp.status_code, 204)
def test_related_resource_partial_update(self): note = Note.objects.create(author=self.user, content="Note Content", title="Note Title", slug="note-title") resource = api.canonical_resource_for('notes') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.raw_post_data = '{"content": "The note has been changed"}' resp = resource.put_detail(request, pk=note.pk) self.assertEqual(resp.status_code, 201) self.assertEqual(Note.objects.get(id=note.id).content, "The note has been changed")
def test_related_resource_authorization(self): resource = api.canonical_resource_for('notes') request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.raw_post_data = '{"content": "The cat is back. The dog coughed him up out back.", "created": "2010-04-03 20:05:00", "is_active": true, "slug": "cat-is-back", "title": "The Cat Is Back", "updated": "2010-04-03 20:05:00", "author": {"id": %s, "username": "******"}}' % self.user.id resp = resource.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(User.objects.get(id=self.user.id).username, 'foobar')
def test_cannot_access_user_resource(self): resource = api.canonical_resource_for('users') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.raw_post_data = '{"username": "******"}' resp = resource.wrap_view('dispatch_detail')(request, pk=self.user.pk) self.assertEqual(resp.status_code, 405) self.assertEqual(User.objects.get(id=self.user.id).username, self.user.username)
def test_cannot_access_user_resource(self): resource = api.canonical_resource_for("users") request = MockRequest() request.GET = {"format": "json"} request.method = "PUT" request.body = '{"username": "******"}' resp = resource.wrap_view("dispatch_detail")(request, pk=self.user.pk) self.assertEqual(resp.status_code, 405) self.assertEqual(User.objects.get(id=self.user.id).username, self.user.username)
def test_cannot_access_user_resource(self): resource = api.canonical_resource_for('users') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' setattr(request, self.body_attr, '{"username": "******"}') resp = resource.wrap_view('dispatch_detail')(request, pk=self.user.pk) self.assertEqual(resp.status_code, 405) self.assertEqual(User.objects.get(id=self.user.id).username, self.user.username)
def test_many_to_many(self): """ Test a related ToMany resource with a nested full ToMany resource """ self.assertEqual(Person.objects.count(), 0) self.assertEqual(Dog.objects.count(), 0) self.assertEqual(Bone.objects.count(), 0) pr = PersonResource() data = { 'name': 'Joan Rivers', 'dogs': [ { 'name': 'Snoopy', 'bones': [ { 'color': 'white' } ] } ] } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.raw_post_data = json.dumps(data) resp = pr.post_list(request) self.assertEqual(resp.status_code, 201) pk = Person.objects.all()[0].pk request = MockRequest() request.method = 'GET' resp = pr.get_detail(request, pk=pk) self.assertEqual(resp.status_code, 200) person = json.loads(resp.content) self.assertEqual(person['name'], 'Joan Rivers') self.assertEqual(len(person['dogs']), 1) dog = person['dogs'][0] self.assertEqual(dog['name'], 'Snoopy') self.assertEqual(len(dog['bones']), 1) bone = dog['bones'][0] self.assertEqual(bone['color'], 'white') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.raw_post_data = resp.content resp = pr.put_detail(request, pk=pk) self.assertEqual(resp.status_code, 204)
def test_one_query_for_post_list(self): """ Posting a new detail with no related objects should require one query to save the object """ resource = api.canonical_resource_for("category") request = MockRequest() body = json.dumps({"name": "Foo", "parent": None}) request.set_body(body) with self.assertNumQueries(1): resp = resource.post_list(request)
def test_resource_passes_request(self): note = Note.objects.create( title='All aboard the rest train', content='Sometimes it is just better to lorem ipsum') uri = '/api/v1/notes/1/' request = MockRequest() request.GET = {'format': 'json'} request.method = 'GET' result = self.resource.get_via_uri(uri, request=request) self.assertEqual(result, note)
def test_apifielderror_missing_not_null_field(self): """ Posting a new detail with no related objects should require one query to save the object """ resource = api.canonical_resource_for('product') request = MockRequest() body = json.dumps({}) request.set_body(body) with self.assertRaises(ApiFieldError): resource.post_list(request)
def test_one_query_for_post_list(self): """ Posting a new detail with no related objects should require one query to save the object """ resource = api.canonical_resource_for('category') request = MockRequest() body = json.dumps({'name': 'Foo', 'parent': None}) request.set_body(body) with self.assertNumQueries(1): resource.post_list(request)
def test_post_by_data_requires_content_type(self): """Make sure 400 (BadRequest) is the response if an attempt is made to post with data for the GenericForeignKey without providing a content_type """ request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.raw_post_data = '{"name": "Photoshop", "content_object": %s}' % '{"name": "Design"}' resource = api.canonical_resource_for('generictag') resp = resource.wrap_view('dispatch_list')(request) self.assertTrue(resp.status_code, 400)
def test_resource_passes_request(self): note = Note.objects.create( title='All aboard the rest train', content='Sometimes it is just better to lorem ipsum' ) uri = '/api/v1/notes/1/' request = MockRequest() request.GET = {'format': 'json'} request.method = 'GET' result = self.resource.get_via_uri(uri, request=request) self.assertEqual(result, note)
def test_related_resource_partial_update(self): note = Note.objects.create(author=self.user, content="Note Content", title="Note Title", slug="note-title") resource = api.canonical_resource_for('notes') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.raw_post_data = '{"content": "The note has been changed"}' resp = resource.put_detail(request, pk=note.pk) self.assertEqual(resp.status_code, 201) self.assertEqual( Note.objects.get(id=note.id).content, "The note has been changed")
def test_one_to_one(self): """ Test a related ToOne resource with a nested full ToOne resource """ self.assertEqual(Person.objects.count(), 0) self.assertEqual(Company.objects.count(), 0) self.assertEqual(Address.objects.count(), 0) pr = PersonResource() data = { 'name': 'Joan Rivers', 'company': { 'name': 'Yum Yum Pie Factory!', 'address': { 'line': 'Somewhere, Utah' } } } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' setattr(request, self.body_attr, json.dumps(data)) resp = pr.post_list(request) self.assertEqual(resp.status_code, 201) pk = Person.objects.all()[0].pk request = MockRequest() request.method = 'GET' request.path = reverse('api_dispatch_detail', kwargs={'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name}) resp = pr.get_detail(request, pk=pk) self.assertEqual(resp.status_code, 200) person = json.loads(resp.content) self.assertEqual(person['name'], 'Joan Rivers') company = person['company'] self.assertEqual(company['name'], 'Yum Yum Pie Factory!') address = company['address'] self.assertEqual(address['line'], 'Somewhere, Utah') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.path = reverse('api_dispatch_detail', kwargs={'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name}) setattr(request, self.body_attr, resp.content) resp = pr.put_detail(request, pk=pk) self.assertEqual(resp.status_code, 204)
def test_put_null(self): resource = api.canonical_resource_for('category') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.raw_post_data = '{"parent": null, "name": "Son"}' # Before the PUT, there should be a parent. self.assertEqual(Category.objects.get(pk=self.child_cat_1.pk).parent.pk, self.parent_cat_1.pk) # After the PUT, the parent should be ``None``. resp = resource.put_detail(request, pk=self.child_cat_1.pk) self.assertEqual(resp.status_code, 204) self.assertEqual(Category.objects.get(pk=self.child_cat_1.pk).name, 'Son') self.assertEqual(Category.objects.get(pk=self.child_cat_1.pk).parent, None)
def test_put_null(self): resource = api.canonical_resource_for('category') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' setattr(request, self.body_attr, '{"parent": null, "name": "Son"}') # Before the PUT, there should be a parent. self.assertEqual(Category.objects.get(pk=self.child_cat_1.pk).parent.pk, self.parent_cat_1.pk) # After the PUT, the parent should be ``None``. resp = resource.put_detail(request, pk=self.child_cat_1.pk) self.assertEqual(resp.status_code, 204) self.assertEqual(Category.objects.get(pk=self.child_cat_1.pk).name, 'Son') self.assertEqual(Category.objects.get(pk=self.child_cat_1.pk).parent, None)
def test_put_null(self): resource = api.canonical_resource_for("category") request = MockRequest() request.GET = {"format": "json"} request.method = "PUT" request.body = '{"parent": null, "name": "Son"}' # Before the PUT, there should be a parent. self.assertEqual(Category.objects.get(pk=self.child_cat_1.pk).parent.pk, self.parent_cat_1.pk) # After the PUT, the parent should be ``None``. resp = resource.put_detail(request, pk=self.child_cat_1.pk) self.assertEqual(resp.status_code, 204) self.assertEqual(Category.objects.get(pk=self.child_cat_1.pk).name, "Son") self.assertEqual(Category.objects.get(pk=self.child_cat_1.pk).parent, None)
def test_depth_limits(self): self.grandchild_cat = Category.objects.create(parent=self.child_cat_1, name='Grandson') self.great_grandchild_cat = Category.objects.create(parent=self.grandchild_cat, name='Great-Grandson') resource = api.canonical_resource_for('depth-category') request = MockRequest() request.GET = {'format': 'json'} request.method = 'GET' resp = resource.wrap_view('dispatch_detail')(request, pk=self.great_grandchild_cat.pk) self.assertEqual(resp.status_code, 200) data = json.loads(resp.content) self.assertEqual(data['name'], 'Great-Grandson') self.assertEqual(data['parent']['name'], 'Grandson') self.assertEqual(data['parent']['parent']['name'], 'Son') self.assertEqual(data['parent']['parent']['parent'], '/v1/depth-category/1/')
def test_two_queries_for_post_list(self): """ Posting a new detail with one related object, referenced via its ``resource_uri`` should require two queries: one to save the object, and one to lookup the related object. """ parent = Category.objects.create(name="Bar") resource = api.canonical_resource_for("category") request = MockRequest() body = json.dumps({"name": "Foo", "parent": resource.get_resource_uri(parent)}) request.set_body(body) with self.assertNumQueries(2): resp = resource.post_list(request)
def test_patch_detail_dont_update_related_without_permission(self): """ When fields are excluded the value of the field should not be set to a default value if updated by bmga. """ resource = NoteResource() note = Note.objects.create(author_id=1) user = User.objects.get(pk=1) self.assertEqual(user.password, 'this_is_not_a_valid_password_string') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PATCH' request.path = "/v1/note/%(pk)s/" % {'pk': note.pk} data = { 'author': { 'id': 1, 'username': '******', 'email': '*****@*****.**', } } request.set_body(json.dumps(data)) resp = resource.patch_detail(request, pk=note.pk) self.assertEqual(resp.status_code, 202) user2 = User.objects.get(pk=1) self.assertEqual(user2.email, '*****@*****.**') self.assertEqual(user2.password, 'this_is_not_a_valid_password_string')
def test_many_to_many(self): """ Test a related ToMany resource with a nested full ToMany resource """ self.assertEqual(Person.objects.count(), 0) self.assertEqual(Dog.objects.count(), 0) self.assertEqual(Bone.objects.count(), 0) pr = PersonResource() data = {"name": "Joan Rivers", "dogs": [{"name": "Snoopy", "bones": [{"color": "white"}]}]} request = MockRequest() request.GET = {"format": "json"} request.method = "POST" request.raw_post_data = json.dumps(data) resp = pr.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Person.objects.count(), 1) self.assertEqual(Dog.objects.count(), 1) self.assertEqual(Bone.objects.count(), 1) pk = Person.objects.all()[0].pk request = MockRequest() request.method = "GET" resp = pr.get_detail(request, pk=pk) self.assertEqual(resp.status_code, 200) person = json.loads(resp.content) self.assertEqual(person["name"], "Joan Rivers") self.assertEqual(len(person["dogs"]), 1) dog = person["dogs"][0] self.assertEqual(dog["name"], "Snoopy") self.assertEqual(len(dog["bones"]), 1) bone = dog["bones"][0] self.assertEqual(bone["color"], "white") request = MockRequest() request.GET = {"format": "json"} request.method = "PUT" request.raw_post_data = json.dumps(person) resp = pr.put_detail(request, pk=pk) self.assertEqual(resp.status_code, 204)
def test_reverse_items_relationship(self): order_resource = OrderResource() data = { 'name': 'order1', 'items': [{ 'name': 'car', }, { 'name': 'yacht', }] } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.path = reverse('api_dispatch_list', kwargs={ 'resource_name': order_resource._meta.resource_name, 'api_name': order_resource._meta.api_name }) request.set_body(json.dumps(data)) resp = order_resource.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Order.objects.count(), 1) self.assertEqual(OrderItem.objects.count(), 2)
def test_patch_to_one(self): resource = FullCategoryResource() cat1 = Category.objects.create(name='Dad') cat2 = Category.objects.create(parent=cat1, name='Child') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PATCH' request.path = "/v1/category/%(pk)s/" % {'pk': cat2.pk} data = { 'name': 'Kid' } request.set_body(json.dumps(data)) self.assertEqual(cat2.name, 'Child') resp = resource.patch_detail(request, pk=cat2.pk) self.assertEqual(resp.status_code, 202) cat2 = Category.objects.get(pk=2) self.assertEqual(cat2.name, 'Kid')
def test_ok_not_null_field_included(self): """ Posting a new detail with no related objects should require one query to save the object """ company = Company.objects.create() resource = api.canonical_resource_for('product') request = MockRequest() body = json.dumps({ 'producer': {'pk': company.pk}, }) request.set_body(body) resp = resource.post_list(request) self.assertEqual(resp.status_code, 201)
def test_resource_from_uri(self): note_2 = Note.objects.create(title='Generic and such', content='Sometimes it is to lorem ipsum') gfk_field = GenericForeignKeyField( { Note: NoteResource, Quote: QuoteResource }, 'nofield') request = MockRequest() request.GET = {'format': 'json'} request.method = 'GET' self.assertEqual( gfk_field.resource_from_uri(gfk_field.to_class(), '/api/v1/notes/%s/' % note_2.pk, request).obj, note_2)
def test_post_by_uri(self): """Create a new GenericTag item using POST request. Point content_object to a category by it's uri""" new_category = Category.objects.create(name="Design") self.assertEqual(new_category.name, "Design") request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.raw_post_data = '{"name": "Photoshop", "content_object": "%s"}' % CategoryResource().get_resource_uri(new_category) resource = api.canonical_resource_for('generictag') resp = resource.wrap_view('dispatch_list')(request) self.assertEqual(resp.status_code, 201) # get newly created object via headers.locaion self.assertTrue(resp.has_header('location')) location = resp['location'] resp = self.client.get(location, data={"format": "json"}) self.assertEqual(resp.status_code, 200) data = json.loads(resp.content) self.assertEqual(data['name'], 'Photoshop') self.assertEqual(data['content_object'], CategoryResource().get_resource_uri(new_category)) # now try doing this with a TaggableObject instead new_taggable = Taggable.objects.create(name="Design Post") request.raw_post_data = '{"name": "UX", "content_object": "%s"}' % TaggableResource().get_resource_uri(new_taggable) resp = resource.wrap_view('dispatch_list')(request) self.assertEqual(resp.status_code, 201) self.assertTrue(resp.has_header('location')) location = resp['location'] resp = self.client.get(location, data={"format" : "json"}) self.assertEqual(resp.status_code, 200) data = json.loads(resp.content) self.assertEqual(data['name'], 'UX') self.assertEqual(data['content_object'], TaggableResource().get_resource_uri(new_taggable))
def test_two_queries_for_post_list(self): """ Posting a new detail with one related object, referenced via its ``resource_uri`` should require two queries: one to save the object, and one to lookup the related object. """ parent = Category.objects.create(name='Bar') resource = api.canonical_resource_for('category') request = MockRequest() body = json.dumps({ 'name': 'Foo', 'parent': resource.get_resource_uri(parent) }) request.set_body(body) with self.assertNumQueries(2): resource.post_list(request)
def test_correct_relation(self): resource = api.canonical_resource_for('category') request = MockRequest() request.GET = {'format': 'json'} request.method = 'GET' resp = resource.wrap_view('dispatch_detail')(request, pk=self.parent_cat_1.pk) self.assertEqual(resp.status_code, 200) data = json.loads(resp.content.decode('utf-8')) self.assertEqual(data['parent'], None) self.assertEqual(data['name'], 'Dad') # Now try a child. resp = resource.wrap_view('dispatch_detail')(request, pk=self.child_cat_2.pk) self.assertEqual(resp.status_code, 200) data = json.loads(resp.content.decode('utf-8')) self.assertEqual(data['parent'], '/v1/category/2/') self.assertEqual(data['name'], 'Daughter')
def test_reverse_one_to_one_post(self): ed = ExtraData.objects.create(name='ed_name') resource = TagResource() # Post the extradata element which is attached to a "reverse" OneToOne request = MockRequest() request.method = "POST" request.body = json.dumps({ "name": "tag_name", "tagged": [], "extradata": "/v1/extradata/%s/" % ed.pk }) resp = resource.post_list(request) # Assert that the status code is CREATED self.assertEqual(resp.status_code, 201) tag = Tag.objects.get(pk=int(resp['Location'].split("/")[-2])) self.assertEqual(tag.extradata, ed)
def test_post_new_tag(self): resource = api.canonical_resource_for('tag') request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.raw_post_data = '{"name": "school", "taggabletags": [ ]}' # Prior to the addition of ``blank=True``, this would # fail badly. resp = resource.wrap_view('dispatch_list')(request) self.assertEqual(resp.status_code, 201) # GET the created object (through its headers.location) self.assertTrue(resp.has_header('location')) location = resp['Location'] resp = self.client.get(location, data={'format': 'json'}) self.assertEqual(resp.status_code, 200) deserialized = json.loads(resp.content) self.assertEqual(len(deserialized), 5) self.assertEqual(deserialized['name'], 'school')
def test_incorrect_uri(self): self.assertEqual(Note.objects.count(), 2) nr = NoteResource() # For this test, we need a ``User`` with the same PK as a ``Note``. note_1 = Note.objects.latest('created') User.objects.create(id=note_1.pk, username='******', email='*****@*****.**', password='******') data = { # This URI is flat-out wrong (wrong resource). # This should cause the request to fail. 'author': '/v1/notes/{0}/'.format(note_1.pk), 'title': 'Nopenopenope', 'slug': 'invalid-request', 'content': "This shouldn't work.", 'is_active': True, } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.set_body(json.dumps(data)) with self.assertRaises(NotFound) as cm: nr.post_list(request) self.assertEqual( str(cm.exception), "An incorrect URL was provided '/v1/notes/2/' for the 'UserResource' resource." ) self.assertEqual(Note.objects.count(), 2)
def test_no_save_m2m_related(self): """ When saving an object with a M2M field, don't save that related object's related objects. """ cg1 = ContactGroup.objects.create(name='The Inebriati') cg2 = ContactGroup.objects.create(name='The Stone Cutters') c1 = Contact.objects.create(name='foo') c2 = Contact.objects.create(name='bar') c2.groups.add(cg1, cg2) c3 = Contact.objects.create(name='baz') c3.groups.add(cg1) self.assertEqual(list(c1.groups.all()), []) self.assertEqual(list(c2.groups.all()), [cg1, cg2]) self.assertEqual(list(c3.groups.all()), [cg1]) data = { 'name': c1.name, 'groups': [reverse('api_dispatch_detail', kwargs={'api_name': 'v1', 'resource_name': 'contactgroup', 'pk': cg1.pk})], } resource = api.canonical_resource_for('contact') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request._load_post_and_files = lambda *args, **kwargs: None request.set_body(json.dumps(data)) with self.withAssertNumQueriesLessThan(9): response = resource.wrap_view('dispatch_detail')(request, pk=c1.pk) self.assertEqual(response.status_code, 204, response.content) new_contacts = Contact.objects.all() new_c1 = new_contacts[0] new_c2 = new_contacts[1] new_c3 = new_contacts[2] self.assertEqual(new_c1.name, c1.name) self.assertEqual(new_c1.id, c1.id) self.assertEqual(list(new_c1.groups.all()), [cg1]) self.assertEqual(new_c2.id, c2.id) self.assertEqual(list(new_c2.groups.all()), [cg1, cg2]) self.assertEqual(new_c3.id, c3.id) self.assertEqual(list(new_c3.groups.all()), [cg1]) new_cg1 = ContactGroup.objects.get(id=cg1.id) new_cg2 = ContactGroup.objects.get(id=cg2.id) self.assertEqual(list(new_cg1.members.all()), [new_c1, new_c2, new_c3]) self.assertEqual(list(new_cg2.members.all()), [new_c2])
def setUp(self): self.resource = NoteResource() self.request = MockRequest() self.request.path = '/api/v1/notes/' self.request.GET = {'limit': '100'} user = User.objects.create_user('foo', 'pass') for i in range(0, 200): Note.objects.create(author=user, title='Note #%s' % i, slug='note-%s' % i) super(ResourceProfilingTestCase, self).setUp()
def test_no_save_m2m_unchanged(self): """ Posting a new detail with a related m2m object shouldn't save the m2m object unless the m2m object is provided inline. """ def _save_fails_test(sender, **kwargs): self.fail("Should not have saved Label") pre_save.connect(_save_fails_test, sender=Label) l1 = Label.objects.get(name='coffee') resource = api.canonical_resource_for('post') label_resource = api.canonical_resource_for('label') request = MockRequest() body = json.dumps({ 'name': 'test post', 'label': [label_resource.get_resource_uri(l1)], }) request.set_body(body) resource.post_list(request) # _save_fails_test will explode if Label is saved
def test_save_m2m_changed(self): """ Posting a new or updated detail object with a related m2m object should save the m2m object if it's included inline. """ resource = api.canonical_resource_for('tag') request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' body_dict = { 'name': 'school', 'taggabletags': [{'extra': 7}] } request.set_body(json.dumps(body_dict)) with self.assertNumQueries(4): resp = resource.wrap_view('dispatch_list')(request) self.assertEqual(resp.status_code, 201) # 'extra' should have been set tag = Tag.objects.all()[0] taggable_tag = tag.taggabletags.all()[0] self.assertEqual(taggable_tag.extra, 7) body_dict['taggabletags'] = [{'extra': 1234}] request.set_body(json.dumps(body_dict)) request.path = reverse('api_dispatch_detail', kwargs={ 'pk': tag.pk, 'resource_name': resource._meta.resource_name, 'api_name': resource._meta.api_name }) with self.assertNumQueries(5): resource.put_detail(request) # 'extra' should have changed tag = Tag.objects.all()[0] taggable_tag = tag.taggabletags.all()[0] self.assertEqual(taggable_tag.extra, 1234)
def test_m2m_put_prefetch(self): resource = api.canonical_resource_for('forum') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' forum = Forum.objects.create() user_data_1 = { 'username': '******', 'email': '*****@*****.**', 'password': '******', } user_data_2 = { 'username': '******', 'email': '*****@*****.**', 'password': '******', } user_data_3 = { 'username': '******', 'email': '*****@*****.**', 'password': '******', } forum_data = { 'members': [ user_data_1, user_data_2, ], 'moderators': [ user_data_3, ] } request.set_body(json.dumps(forum_data)) request.path = reverse('api_dispatch_detail', kwargs={ 'pk': forum.pk, 'resource_name': resource._meta.resource_name, 'api_name': resource._meta.api_name }) response = resource.put_detail(request) self.assertEqual(response.status_code, 200) data = json.loads(response.content.decode('utf-8')) # Check that the query does what it's supposed to and only the return value is wrong self.assertEqual(User.objects.count(), 3) self.assertEqual(len(data['members']), 2) self.assertEqual(len(data['moderators']), 1)
def test_no_save_m2m_unchanged_existing_data_persists(self): """ Data should persist when posting an updated detail object with unchanged reverse related objects. """ person = Person.objects.create(name='Ryan') dog = Dog.objects.create(name='Wilfred', owner=person) bone1 = Bone.objects.create(color='White', dog=dog) bone2 = Bone.objects.create(color='Grey', dog=dog) self.assertEqual(dog.bones.count(), 2) resource = api.canonical_resource_for('dog') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request._load_post_and_files = lambda *args, **kwargs: None body_dict = { 'id': dog.id, 'name': 'Wilfred', 'bones': [{ 'id': bone1.id, 'color': bone1.color }, { 'id': bone2.id, 'color': bone2.color }] } request.set_body(json.dumps(body_dict)) with self.assertNumQueries(13 if django.VERSION >= (1, 9) else 14): resp = resource.wrap_view('dispatch_detail')(request, pk=dog.pk) self.assertEqual(resp.status_code, 204) dog = Dog.objects.all()[0] dog_bones = dog.bones.all() self.assertEqual(len(dog_bones), 2) self.assertEqual(dog_bones[0], bone1) self.assertEqual(dog_bones[1], bone2)
def make_request(self, method): request = MockRequest() request.GET = {'format': 'json'} request.method = method request.set_body(json.dumps({ 'members': [ self.user_data[0], self.user_data[1], ], 'moderators': [self.user_data[2]], })) request.path = reverse('api_dispatch_detail', kwargs={ 'pk': self.forum.pk, 'resource_name': self.resource._meta.resource_name, 'api_name': self.resource._meta.api_name }) return request
def test_many_to_many(self): """ Test a related ToMany resource with a nested full ToMany resource """ self.assertEqual(Person.objects.count(), 0) self.assertEqual(Dog.objects.count(), 0) self.assertEqual(Bone.objects.count(), 0) pr = PersonResource() data = { 'name': 'Joan Rivers', 'dogs': [{ 'name': 'Snoopy', 'bones': [{ 'color': 'white' }] }] } request = MockRequest() request.GET = {'format': 'json'} request.method = 'POST' request.path = reverse('api_dispatch_list', kwargs={ 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name }) request.raw_post_data = json.dumps(data) resp = pr.post_list(request) self.assertEqual(resp.status_code, 201) self.assertEqual(Person.objects.count(), 1) self.assertEqual(Dog.objects.count(), 1) self.assertEqual(Bone.objects.count(), 1) pk = Person.objects.all()[0].pk request = MockRequest() request.method = 'GET' request.path = reverse('api_dispatch_detail', kwargs={ 'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name }) resp = pr.get_detail(request, pk=pk) self.assertEqual(resp.status_code, 200) person = json.loads(resp.content) self.assertEqual(person['name'], 'Joan Rivers') self.assertEqual(len(person['dogs']), 1) dog = person['dogs'][0] self.assertEqual(dog['name'], 'Snoopy') self.assertEqual(len(dog['bones']), 1) bone = dog['bones'][0] self.assertEqual(bone['color'], 'white') request = MockRequest() request.GET = {'format': 'json'} request.method = 'PUT' request.raw_post_data = json.dumps(person) request.path = reverse('api_dispatch_detail', kwargs={ 'pk': pk, 'resource_name': pr._meta.resource_name, 'api_name': pr._meta.api_name }) resp = pr.put_detail(request, pk=pk) self.assertEqual(resp.status_code, 204)