Repository: deis/deis

Issue:
Controller: Domain remove, removes always the latest domain
(deis):~/mozilla/deis-apps/masterfirefoxos-dev$ deis domains:list
=== masterfirefoxos-dev Domains
dev.masterfirefoxos.com
(deis):~/mozilla/deis-apps/masterfirefoxos-dev$ deis domains:add foo.example.com
Adding foo.example.com to masterfirefoxos-dev... done 
(deis):~/mozilla/deis-apps/masterfirefoxos-dev$ deis domains:list
=== masterfirefoxos-dev Domains
dev.masterfirefoxos.com
foo.example.com
(deis):~/mozilla/deis-apps/masterfirefoxos-dev$ deis domains:remove dev.masterfirefoxos.com
Removing dev.masterfirefoxos.com from masterfirefoxos-dev... done 
(deis):~/mozilla/deis-apps/masterfirefoxos-dev$ deis domains:list
=== masterfirefoxos-dev Domains
dev.masterfirefoxos.com



Discussion:
I believe this is because `get_queryset` ignores `kwargs` https://github.com/deis/deis/blob/master/controller/api/views.py#L76-78

I ran into this same problem. Kinda. If you add multiple domains to an app, and then delete one, you may not end up actually deleting the domain you thought you did. It's some kind of weird off-by-one bug.

I can reproduce it with the following unit test:

```
def test_delete_domain_does_not_remove_latest(self):
    """https://github.com/deis/deis/issues/3239"""
    url = '/v1/apps/{app_id}/domains'.format(app_id=self.app_id)
    test_domains = [
        'test-domain.example.com',
        'django.paas-sandbox',
    ]
    for domain in test_domains:
        body = {'domain': domain}
        response = self.client.post(url, json.dumps(body), content_type='application/json',
                                    HTTP_AUTHORIZATION='token {}'.format(self.token))
        self.assertEqual(response.status_code, 201)
    url = '/v1/apps/{app_id}/domains/{domain}'.format(domain=test_domains[0],
                                                      app_id=self.app_id)
    response = self.client.delete(url, content_type='application/json',
                                  HTTP_AUTHORIZATION='token {}'.format(self.token))
    self.assertEqual(response.status_code, 204)
    with self.assertRaises(Domain.DoesNotExist):
        Domain.objects.get(domain=test_domains[0])
```

Working on a fix.


Resolving patch:
diff --git a/controller/api/views.py b/controller/api/views.py
--- a/controller/api/views.py
+++ b/controller/api/views.py
@@ -218,6 +218,9 @@ class DomainViewSet(AppResourceViewSet):
     model = models.Domain
     serializer_class = serializers.DomainSerializer
 
+    def get_object(self, **kwargs):
+        return self.get_queryset(**kwargs)
+
 
 class KeyViewSet(BaseDeisViewSet):
     """A viewset for interacting with Key objects."""


Test patch:
diff --git a/controller/api/tests/test_domain.py b/controller/api/tests/test_domain.py
--- a/controller/api/tests/test_domain.py
+++ b/controller/api/tests/test_domain.py
@@ -12,6 +12,8 @@
 from django.test import TestCase
 from rest_framework.authtoken.models import Token
 
+from api.models import Domain
+
 
 class DomainTest(TestCase):
 
@@ -78,6 +80,26 @@ def test_manage_domain(self):
                                        HTTP_AUTHORIZATION='token {}'.format(self.token))
             self.assertEqual(0, response.data['count'], msg)
 
+    def test_delete_domain_does_not_remove_latest(self):
+        """https://github.com/deis/deis/issues/3239"""
+        url = '/v1/apps/{app_id}/domains'.format(app_id=self.app_id)
+        test_domains = [
+            'test-domain.example.com',
+            'django.paas-sandbox',
+        ]
+        for domain in test_domains:
+            body = {'domain': domain}
+            response = self.client.post(url, json.dumps(body), content_type='application/json',
+                                        HTTP_AUTHORIZATION='token {}'.format(self.token))
+            self.assertEqual(response.status_code, 201)
+        url = '/v1/apps/{app_id}/domains/{domain}'.format(domain=test_domains[0],
+                                                          app_id=self.app_id)
+        response = self.client.delete(url, content_type='application/json',
+                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
+        self.assertEqual(response.status_code, 204)
+        with self.assertRaises(Domain.DoesNotExist):
+            Domain.objects.get(domain=test_domains[0])
+
     def test_manage_domain_invalid_app(self):
         url = '/v1/apps/{app_id}/domains'.format(app_id="this-app-does-not-exist")
         body = {'domain': 'test-domain.example.com'}