Coverage for tests/api/test_github.py: 100%
75 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-20 22:09 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-20 22:09 +0000
1from os import getenv
2from unittest import TestCase
3from unittest.mock import MagicMock
5from vcr_unittest import VCRTestCase
6from webapp.api.github import GitHub, repository_is_public
7from werkzeug.exceptions import Unauthorized
10class GitHubTest(VCRTestCase):
11 def _get_vcr_kwargs(self):
12 """
13 This removes the authorization header
14 from VCR so we don't record auth parameters
15 """
16 return {"filter_headers": ["Authorization"]}
18 def setUp(self):
19 self.client = GitHub(getenv("TESTS_GITHUB_USER_TOKEN", "secret"))
20 return super(GitHubTest, self).setUp()
22 def test_get_user(self):
23 user = self.client.get_user()
24 self.assertIn("login", user)
25 self.assertIn("name", user)
26 self.assertIn("avatarUrl", user)
28 # Test Unauthorized exception when using bad credentials
29 self.client.access_token = "bad-token"
30 self.assertRaises(Unauthorized, self.client.get_user)
32 def test_get_user_repositories(self):
33 repos = self.client.get_user_repositories()
34 [self.assertIn("name", repo) for repo in repos]
36 # Test Unauthorized exception when using bad credentials
37 self.client.access_token = "bad-token"
38 self.assertRaises(Unauthorized, self.client.get_user_repositories)
40 def test_get_org_repositories(self):
41 repos = self.client.get_org_repositories("canonical-web-and-design")
42 [self.assertIn("name", repo) for repo in repos]
43 [self.assertIn("nameWithOwner", repo) for repo in repos]
44 [self.assertIn("owner", repo) for repo in repos]
46 # Test Unauthorized exception when using bad credentials
47 self.client.access_token = "bad-token"
48 self.assertRaises(Unauthorized, self.client.get_user_repositories)
50 def test_get_orgs(self):
51 orgs = self.client.get_orgs()
52 [self.assertIn("name", org) for org in orgs]
53 [self.assertIn("login", org) for org in orgs]
55 def test_check_permissions_over_repo(self):
56 # The user is the owner of the repo
57 case1 = self.client.check_permissions_over_repo(
58 "build-staging-snapcraft-io", "test1"
59 )
60 self.assertEqual(True, case1)
62 # The user doesn't have permissions for this repo
63 case2 = self.client.check_permissions_over_repo(
64 "canonical-web-and-design", "snapcraft.io"
65 )
66 self.assertEqual(False, case2)
68 def test_get_snapcraft_yaml_location(self):
69 # /snapcraft.yaml is present
70 case1 = self.client.get_snapcraft_yaml_location(
71 "build-staging-snapcraft-io", "test1"
72 )
73 self.assertEqual("snapcraft.yaml", case1)
75 # /.snapcraft.yaml is present
76 case2 = self.client.get_snapcraft_yaml_location(
77 "build-staging-snapcraft-io", "test2"
78 )
79 self.assertEqual(".snapcraft.yaml", case2)
81 # /snap/snapcraft.yaml is present
82 case3 = self.client.get_snapcraft_yaml_location(
83 "build-staging-snapcraft-io", "test3"
84 )
85 self.assertEqual("snap/snapcraft.yaml", case3)
87 # /build-aux/snap/snapcraft.yaml is present
88 case4 = self.client.get_snapcraft_yaml_location(
89 "build-staging-snapcraft-io", "test4"
90 )
91 self.assertEqual("build-aux/snap/snapcraft.yaml", case4)
93 # The repo doesn't contain a valid yaml file
94 case5 = self.client.get_snapcraft_yaml_location(
95 "build-staging-snapcraft-io", "test5"
96 )
97 self.assertEqual(False, case5)
99 def test_get_snapcraft_yaml_data(self):
100 case1 = self.client.get_snapcraft_yaml_data(
101 "build-staging-snapcraft-io", "test1"
102 )
103 self.assertEqual("test1", case1.get("name"))
105 case2 = self.client.get_snapcraft_yaml_data(
106 "build-staging-snapcraft-io", "test5"
107 )
108 self.assertEqual(None, case2.get("name"))
111class RepositoryIsPublicTest(TestCase):
112 """A recipe can outlive the repository it names."""
114 def _session(self, status_code=None, error=None):
115 session = MagicMock()
116 if error:
117 session.head.side_effect = error
118 else:
119 session.head.return_value = MagicMock(status_code=status_code)
120 return session
122 def test_public_repository(self):
123 self.assertTrue(
124 repository_is_public("snapcrafters/mumble", self._session(200))
125 )
127 def test_missing_repository(self):
128 self.assertFalse(repository_is_public("gone/repo", self._session(404)))
130 def test_no_repository(self):
131 session = self._session(200)
132 self.assertTrue(repository_is_public(None, session))
133 # Nothing to check, so nothing requested.
134 session.head.assert_not_called()
136 def test_fails_open_on_error(self):
137 # A timeout must never erase provenance we hold.
138 self.assertTrue(
139 repository_is_public(
140 "snapcrafters/mumble",
141 self._session(error=Exception("read timed out")),
142 )
143 )
145 def test_fails_open_on_rate_limit(self):
146 self.assertTrue(
147 repository_is_public("snapcrafters/mumble", self._session(429))
148 )