Repository: readthedocs/readthedocs.org

Issue:
Addons: create a suite tests for Addons API endpoint
We need to create a good amount of tests for this API endpoint so we are covered.


Discussion:
Add tests for the HTTP headers and also for the enabled/disabled queryset: https://github.com/readthedocs/readthedocs.org/pull/10733

Resolving patch:
diff --git a/readthedocs/proxito/views/hosting.py b/readthedocs/proxito/views/hosting.py
--- a/readthedocs/proxito/views/hosting.py
+++ b/readthedocs/proxito/views/hosting.py
@@ -233,8 +233,9 @@ def _v0(self, project, version, build, filename, user):
                 .only("slug")
                 .order_by("slug")
             )
-            if version:
-                version_downloads = version.get_downloads(pretty=True).items()
+
+        if version:
+            version_downloads = version.get_downloads(pretty=True).items()
 
         project_translations = (
             project.translations.all().only("language").order_by("language")


Test patch:
diff --git a/readthedocs/proxito/tests/test_headers.py b/readthedocs/proxito/tests/test_headers.py
--- a/readthedocs/proxito/tests/test_headers.py
+++ b/readthedocs/proxito/tests/test_headers.py
@@ -12,7 +12,7 @@
 from readthedocs.builds.models import Version
 from readthedocs.organizations.models import Organization
 from readthedocs.projects.constants import PRIVATE, PUBLIC
-from readthedocs.projects.models import Domain, HTTPHeader
+from readthedocs.projects.models import AddonsConfig, Domain, HTTPHeader
 
 from .base import BaseDocServing
 
@@ -168,6 +168,16 @@ def test_hosting_integrations_header(self):
         self.assertIsNotNone(r.get("X-RTD-Hosting-Integrations"))
         self.assertEqual(r["X-RTD-Hosting-Integrations"], "true")
 
+    def test_force_addons_header(self):
+        fixture.get(AddonsConfig, project=self.project, enabled=True)
+
+        r = self.client.get(
+            "/en/latest/", secure=True, headers={"host": "project.dev.readthedocs.io"}
+        )
+        self.assertEqual(r.status_code, 200)
+        self.assertIsNotNone(r.get("X-RTD-Force-Addons"))
+        self.assertEqual(r["X-RTD-Force-Addons"], "true")
+
     @override_settings(ALLOW_PRIVATE_REPOS=False)
     def test_cors_headers_external_version(self):
         get(
diff --git a/readthedocs/proxito/tests/test_hosting.py b/readthedocs/proxito/tests/test_hosting.py
--- a/readthedocs/proxito/tests/test_hosting.py
+++ b/readthedocs/proxito/tests/test_hosting.py
@@ -10,9 +10,9 @@
 from django.urls import reverse
 
 from readthedocs.builds.constants import LATEST
-from readthedocs.builds.models import Build
-from readthedocs.projects.constants import PUBLIC
-from readthedocs.projects.models import Project
+from readthedocs.builds.models import Build, Version
+from readthedocs.projects.constants import PRIVATE, PUBLIC
+from readthedocs.projects.models import Feature, Project
 
 
 @override_settings(
@@ -123,3 +123,306 @@ def test_get_config_unsupported_version(self):
         )
         assert r.status_code == 400
         assert r.json() == self._get_response_dict("v2")
+
+    def test_disabled_addons_via_feature_flags(self):
+        fixture.get(
+            Feature,
+            projects=[self.project],
+            feature_id=Feature.ADDONS_ANALYTICS_DISABLED,
+        )
+        fixture.get(
+            Feature,
+            projects=[self.project],
+            feature_id=Feature.ADDONS_EXTERNAL_VERSION_WARNING_DISABLED,
+        )
+        fixture.get(
+            Feature,
+            projects=[self.project],
+            feature_id=Feature.ADDONS_NON_LATEST_VERSION_WARNING_DISABLED,
+        )
+        fixture.get(
+            Feature,
+            projects=[self.project],
+            feature_id=Feature.ADDONS_DOC_DIFF_DISABLED,
+        )
+        fixture.get(
+            Feature,
+            projects=[self.project],
+            feature_id=Feature.ADDONS_FLYOUT_DISABLED,
+        )
+        fixture.get(
+            Feature,
+            projects=[self.project],
+            feature_id=Feature.ADDONS_SEARCH_DISABLED,
+        )
+        fixture.get(
+            Feature,
+            projects=[self.project],
+            feature_id=Feature.ADDONS_HOTKEYS_DISABLED,
+        )
+
+        r = self.client.get(
+            reverse("proxito_readthedocs_docs_addons"),
+            {
+                "url": "https://project.dev.readthedocs.io/en/latest/",
+                "client-version": "0.6.0",
+                "api-version": "0.1.0",
+            },
+            secure=True,
+            headers={
+                "host": "project.dev.readthedocs.io",
+            },
+        )
+        assert r.status_code == 200
+        assert r.json()["addons"]["analytics"]["enabled"] is False
+        assert r.json()["addons"]["external_version_warning"]["enabled"] is False
+        assert r.json()["addons"]["non_latest_version_warning"]["enabled"] is False
+        assert r.json()["addons"]["doc_diff"]["enabled"] is False
+        assert r.json()["addons"]["flyout"]["enabled"] is False
+        assert r.json()["addons"]["search"]["enabled"] is False
+        assert r.json()["addons"]["hotkeys"]["enabled"] is False
+
+    def test_non_latest_version_warning_versions(self):
+        fixture.get(
+            Version,
+            project=self.project,
+            privacy_level=PRIVATE,
+            slug="private",
+            verbose_name="private",
+            built=True,
+            active=True,
+        )
+        fixture.get(
+            Version,
+            project=self.project,
+            privacy_level=PUBLIC,
+            slug="public-built",
+            verbose_name="public-built",
+            built=True,
+            active=True,
+        )
+        fixture.get(
+            Version,
+            project=self.project,
+            privacy_level=PUBLIC,
+            slug="public-not-built",
+            verbose_name="public-not-built",
+            built=False,
+            active=True,
+        )
+
+        r = self.client.get(
+            reverse("proxito_readthedocs_docs_addons"),
+            {
+                "url": "https://project.dev.readthedocs.io/en/latest/",
+                "client-version": "0.6.0",
+                "api-version": "0.1.0",
+            },
+            secure=True,
+            headers={
+                "host": "project.dev.readthedocs.io",
+            },
+        )
+        assert r.status_code == 200
+
+        expected = ["latest", "public-built"]
+        assert r.json()["addons"]["non_latest_version_warning"]["versions"] == expected
+
+    def test_flyout_versions(self):
+        fixture.get(
+            Version,
+            project=self.project,
+            privacy_level=PRIVATE,
+            slug="private",
+            verbose_name="private",
+            built=True,
+            active=True,
+        )
+        fixture.get(
+            Version,
+            project=self.project,
+            privacy_level=PUBLIC,
+            slug="public-built",
+            verbose_name="public-built",
+            built=True,
+            active=True,
+        )
+        fixture.get(
+            Version,
+            project=self.project,
+            privacy_level=PUBLIC,
+            slug="public-not-built",
+            verbose_name="public-not-built",
+            built=False,
+            active=True,
+        )
+        fixture.get(
+            Version,
+            project=self.project,
+            privacy_level=PUBLIC,
+            slug="hidden",
+            verbose_name="hidden",
+            built=False,
+            hidden=True,
+            active=True,
+        )
+
+        r = self.client.get(
+            reverse("proxito_readthedocs_docs_addons"),
+            {
+                "url": "https://project.dev.readthedocs.io/en/latest/",
+                "client-version": "0.6.0",
+                "api-version": "0.1.0",
+            },
+            secure=True,
+            headers={
+                "host": "project.dev.readthedocs.io",
+            },
+        )
+        assert r.status_code == 200
+
+        expected = [
+            {"slug": "latest", "url": "/en/latest/"},
+            {"slug": "public-built", "url": "/en/public-built/"},
+        ]
+        assert r.json()["addons"]["flyout"]["versions"] == expected
+
+    def test_flyout_translations(self):
+        fixture.get(
+            Project,
+            slug="translation",
+            main_language_project=self.project,
+            language="ja",
+        )
+
+        r = self.client.get(
+            reverse("proxito_readthedocs_docs_addons"),
+            {
+                "url": "https://project.dev.readthedocs.io/en/latest/",
+                "client-version": "0.6.0",
+                "api-version": "0.1.0",
+            },
+            secure=True,
+            headers={
+                "host": "project.dev.readthedocs.io",
+            },
+        )
+        assert r.status_code == 200
+
+        expected = [
+            {"slug": "ja", "url": "/ja/"},
+        ]
+        assert r.json()["addons"]["flyout"]["translations"] == expected
+
+    def test_flyout_downloads(self):
+        fixture.get(
+            Version,
+            project=self.project,
+            privacy_level=PUBLIC,
+            slug="offline",
+            verbose_name="offline",
+            built=True,
+            has_pdf=True,
+            has_epub=True,
+            has_htmlzip=True,
+            active=True,
+        )
+
+        r = self.client.get(
+            reverse("proxito_readthedocs_docs_addons"),
+            {
+                "url": "https://project.dev.readthedocs.io/en/offline/",
+                "client-version": "0.6.0",
+                "api-version": "0.1.0",
+            },
+            secure=True,
+            headers={
+                "host": "project.dev.readthedocs.io",
+            },
+        )
+        assert r.status_code == 200
+
+        expected = [
+            {
+                "name": "PDF",
+                "url": "//project.dev.readthedocs.io/_/downloads/en/offline/pdf/",
+            },
+            {
+                "name": "HTML",
+                "url": "//project.dev.readthedocs.io/_/downloads/en/offline/htmlzip/",
+            },
+            {
+                "name": "Epub",
+                "url": "//project.dev.readthedocs.io/_/downloads/en/offline/epub/",
+            },
+        ]
+        assert r.json()["addons"]["flyout"]["downloads"] == expected
+
+    def test_flyout_single_version_project(self):
+        self.version.has_pdf = True
+        self.version.has_epub = True
+        self.version.has_htmlzip = True
+        self.version.save()
+
+        self.project.single_version = True
+        self.project.save()
+
+        r = self.client.get(
+            reverse("proxito_readthedocs_docs_addons"),
+            {
+                "url": "https://project.dev.readthedocs.io/",
+                "client-version": "0.6.0",
+                "api-version": "0.1.0",
+            },
+            secure=True,
+            headers={
+                "host": "project.dev.readthedocs.io",
+            },
+        )
+        assert r.status_code == 200
+
+        expected = []
+        assert r.json()["addons"]["flyout"]["versions"] == expected
+
+        expected = [
+            {
+                "name": "PDF",
+                "url": "//project.dev.readthedocs.io/_/downloads/en/latest/pdf/",
+            },
+            {
+                "name": "HTML",
+                "url": "//project.dev.readthedocs.io/_/downloads/en/latest/htmlzip/",
+            },
+            {
+                "name": "Epub",
+                "url": "//project.dev.readthedocs.io/_/downloads/en/latest/epub/",
+            },
+        ]
+        assert r.json()["addons"]["flyout"]["downloads"] == expected
+
+    def test_project_subproject(self):
+        subproject = fixture.get(
+            Project, slug="subproject", repo="https://github.com/readthedocs/subproject"
+        )
+        self.project.add_subproject(subproject)
+
+        r = self.client.get(
+            reverse("proxito_readthedocs_docs_addons"),
+            {
+                "url": "https://project.dev.readthedocs.io/projects/subproject/en/latest/",
+                "client-version": "0.6.0",
+                "api-version": "0.1.0",
+            },
+            secure=True,
+            headers={
+                "host": "project.dev.readthedocs.io",
+            },
+        )
+        assert r.status_code == 200
+
+        assert r.json()["projects"]["current"]["id"] == subproject.pk
+        assert r.json()["projects"]["current"]["slug"] == subproject.slug
+        assert (
+            r.json()["projects"]["current"]["repository"]["url"]
+            == "https://github.com/readthedocs/subproject"
+        )