Repository: mozmeao/snippets-service

Issue:
Return empty json for empty bundles in ASR
Return empty json for empty bundles in ASR. Unclear whether ASR can handle 204 responses so let's default to empty json. 

See also https://bugzilla.mozilla.org/show_bug.cgi?id=1511640

History:
 - https://github.com/mozmeao/snippets-service/commit/4936f2371e341690def9be40a72abdd32205b0c9
 - https://github.com/mozmeao/snippets-service/commit/cb0fc0ca63af4ed3786342e17c2f50d2fc6dc5c4


Discussion:

Resolving patch:
diff --git a/snippets/base/views.py b/snippets/base/views.py
--- a/snippets/base/views.py
+++ b/snippets/base/views.py
@@ -51,6 +51,11 @@ def fetch_snippets(request, **kwargs):
         bundle = SnippetBundle(client)
     if bundle.empty:
         statsd.incr('bundle.empty')
+
+        if client.startpage_version == 6:
+            # Return valid JSON for Activity Stream Router
+            return HttpResponse(status=200, content='{}')
+
         # This is not a 204 because Activity Stream expects content, even if
         # it's empty.
         return HttpResponse(status=200, content='')


Test patch:
diff --git a/snippets/base/tests/test_views.py b/snippets/base/tests/test_views.py
--- a/snippets/base/tests/test_views.py
+++ b/snippets/base/tests/test_views.py
@@ -188,6 +188,18 @@ def setUp(self):
             ('distribution', 'default'),
             ('distribution_version', 'default_version'),
         ])
+        self.asrclient_kwargs = OrderedDict([
+            ('startpage_version', 6),
+            ('name', 'Firefox'),
+            ('version', '64.0'),
+            ('appbuildid', '20190110041606'),
+            ('build_target', 'Darwin_Universal-gcc3'),
+            ('locale', 'en-US'),
+            ('channel', 'release'),
+            ('os_version', 'Darwin 10.8.0'),
+            ('distribution', 'default'),
+            ('distribution_version', 'default_version'),
+        ])
 
     def test_normal(self):
         with patch.object(views, 'SnippetBundle') as SnippetBundle:
@@ -206,6 +218,23 @@ def test_normal(self):
         # Do not generate bundle when not expired.
         self.assertTrue(not SnippetBundle.return_value.generate.called)
 
+    def test_normal_asr(self):
+        with patch.object(views, 'ASRSnippetBundle') as ASRSnippetBundle:
+            bundle = ASRSnippetBundle.return_value
+            bundle.url = '/foo/bar'
+            bundle.empty = False
+            bundle.cached = True
+            response = views.fetch_snippets(self.request, **self.asrclient_kwargs)
+
+        self.assertEqual(response.status_code, 302)
+        self.assertEqual(response['Location'], '/foo/bar')
+
+        # Check for correct client.
+        self.assertEqual(ASRSnippetBundle.call_args[0][0].locale, 'en-US')
+
+        # Do not generate bundle when not expired.
+        self.assertTrue(not ASRSnippetBundle.return_value.generate.called)
+
     def test_regenerate(self):
         """If the bundle has expired, re-generate it."""
         with patch.object(views, 'SnippetBundle') as SnippetBundle:
@@ -222,7 +251,7 @@ def test_regenerate(self):
         self.assertTrue(SnippetBundle.return_value.generate.called)
 
     def test_empty(self):
-        """If the bundle is empty return 200. """
+        """If the bundle is empty return 200 and empty string."""
         with patch.object(views, 'SnippetBundle') as SnippetBundle:
             bundle = SnippetBundle.return_value
             bundle.empty = True
@@ -231,6 +260,16 @@ def test_empty(self):
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.content, b'')
 
+    def test_empty_asr(self):
+        """If the bundle is empty return 200 and valid JSON for ASR."""
+        with patch.object(views, 'ASRSnippetBundle') as ASRSnippetBundle:
+            bundle = ASRSnippetBundle.return_value
+            bundle.empty = True
+            response = views.fetch_snippets(self.request, **self.asrclient_kwargs)
+
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.content, b'{}')
+
     @patch('snippets.base.views.Client', wraps=Client)
     def test_client_construction(self, ClientMock):
         """