ApplicationOAuth.py
1 ############################ Copyrights and license ############################ 2 # # 3 # Copyright 2019 Rigas Papathanasopoulos <rigaspapas@gmail.com> # 4 # # 5 # This file is part of PyGithub. # 6 # http://pygithub.readthedocs.io/ # 7 # # 8 # PyGithub is free software: you can redistribute it and/or modify it under # 9 # the terms of the GNU Lesser General Public License as published by the Free # 10 # Software Foundation, either version 3 of the License, or (at your option) # 11 # any later version. # 12 # # 13 # PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY # 14 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # 15 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # 16 # details. # 17 # # 18 # You should have received a copy of the GNU Lesser General Public License # 19 # along with PyGithub. If not, see <http://www.gnu.org/licenses/>. # 20 # # 21 ################################################################################ 22 23 from datetime import datetime, timezone 24 from unittest import mock 25 26 import github 27 from github.ApplicationOAuth import ApplicationOAuth as aoa 28 29 from . import Framework 30 31 32 class ApplicationOAuth(Framework.TestCase): 33 def setUp(self): 34 super().setUp() 35 self.CLIENT_ID = "client_id_removed" 36 self.CLIENT_SECRET = "client_secret_removed" 37 self.app = self.g.get_oauth_application(self.CLIENT_ID, self.CLIENT_SECRET) 38 39 def testLoginURL(self): 40 BASE_URL = "https://github.com/login/oauth/authorize" 41 sample_uri = "https://myapp.com/some/path" 42 sample_uri_encoded = "https%3A%2F%2Fmyapp.com%2Fsome%2Fpath" 43 self.assertEqual(self.app.get_login_url(), f"{BASE_URL}?client_id={self.CLIENT_ID}") 44 self.assertTrue(f"redirect_uri={sample_uri_encoded}" in self.app.get_login_url(redirect_uri=sample_uri)) 45 self.assertTrue(f"client_id={self.CLIENT_ID}" in self.app.get_login_url(redirect_uri=sample_uri)) 46 self.assertTrue("state=123abc" in self.app.get_login_url(state="123abc", login="user")) 47 self.assertTrue("login=user" in self.app.get_login_url(state="123abc", login="user")) 48 self.assertTrue(f"client_id={self.CLIENT_ID}" in self.app.get_login_url(state="123abc", login="user")) 49 50 def testGetAccessToken(self): 51 access_token = self.app.get_access_token("oauth_code_removed", state="state_removed") 52 # Test string representation 53 self.assertEqual( 54 str(access_token), 55 'AccessToken(type="bearer", token="acces...", scope="", ' 56 "refresh_token_expires_in=None, refresh_token=None, expires_in=None)", 57 ) 58 self.assertEqual(access_token.token, "access_token_removed") 59 self.assertEqual(access_token.type, "bearer") 60 self.assertEqual(access_token.scope, "") 61 self.assertIsNone(access_token.expires_in) 62 self.assertIsNone(access_token.expires_at) 63 self.assertIsNone(access_token.refresh_token) 64 self.assertIsNone(access_token.refresh_expires_in) 65 self.assertIsNone(access_token.refresh_expires_at) 66 67 def testGetAccessTokenWithExpiry(self): 68 with mock.patch("github.AccessToken.datetime") as dt: 69 dt.now = mock.Mock(return_value=datetime(2023, 6, 7, 12, 0, 0, 123, tzinfo=timezone.utc)) 70 access_token = self.app.get_access_token("oauth_code_removed", state="state_removed") 71 # Test string representation 72 self.assertEqual( 73 str(access_token), 74 'AccessToken(type="bearer", token="acces...", scope="", ' 75 'refresh_token_expires_in=15811200, refresh_token="refre...", expires_in=28800)', 76 ) 77 self.assertEqual(access_token.token, "access_token_removed") 78 self.assertEqual(access_token.type, "bearer") 79 self.assertEqual(access_token.scope, "") 80 self.assertEqual(access_token.expires_in, 28800) 81 self.assertEqual( 82 access_token.expires_at, 83 datetime(2023, 6, 7, 20, 0, 0, 123, tzinfo=timezone.utc), 84 ) 85 self.assertEqual(access_token.refresh_token, "refresh_token_removed") 86 self.assertEqual(access_token.refresh_expires_in, 15811200) 87 self.assertEqual( 88 access_token.refresh_expires_at, 89 datetime(2023, 12, 7, 12, 0, 0, 123, tzinfo=timezone.utc), 90 ) 91 92 def testRefreshAccessToken(self): 93 access_token = self.app.get_access_token("oauth_code_removed", state="state_removed") 94 95 with mock.patch("github.AccessToken.datetime") as dt: 96 dt.now = mock.Mock(return_value=datetime(2023, 6, 7, 12, 0, 0, 123, tzinfo=timezone.utc)) 97 refreshed = self.app.refresh_access_token(access_token.refresh_token) 98 99 self.assertNotEqual(refreshed.token, access_token.token) 100 self.assertNotEqual(refreshed.refresh_token, access_token.refresh_token) 101 self.assertNotEqual(refreshed.created, access_token.created) 102 # Test string representation 103 self.assertEqual( 104 str(refreshed), 105 'AccessToken(type="bearer", token="anoth...", scope="", ' 106 'refresh_token_expires_in=15811200, refresh_token="anoth...", expires_in=28800)', 107 ) 108 self.assertEqual(refreshed.token, "another_access_token_removed") 109 self.assertEqual(refreshed.type, "bearer") 110 self.assertEqual(refreshed.scope, "") 111 self.assertEqual( 112 refreshed.created, 113 datetime(2023, 6, 7, 12, 0, 0, 123, tzinfo=timezone.utc), 114 ) 115 self.assertEqual(refreshed.expires_in, 28800) 116 self.assertEqual( 117 refreshed.expires_at, 118 datetime(2023, 6, 7, 20, 0, 0, 123, tzinfo=timezone.utc), 119 ) 120 self.assertEqual(refreshed.refresh_token, "another_refresh_token_removed") 121 self.assertEqual(refreshed.refresh_expires_in, 15811200) 122 self.assertEqual( 123 refreshed.refresh_expires_at, 124 datetime(2023, 12, 7, 12, 0, 0, 123, tzinfo=timezone.utc), 125 ) 126 127 def testGetAccessTokenBadCode(self): 128 with self.assertRaises(github.BadCredentialsException) as exc: 129 self.app.get_access_token("oauth_code_removed", state="state_removed") 130 self.assertEqual(exc.exception.status, 200) 131 self.assertIn("error", exc.exception.data) 132 self.assertEqual(exc.exception.data["error"], "bad_verification_code") 133 134 def testGetAccessTokenUnknownError(self): 135 with self.assertRaises(github.GithubException) as exc: 136 self.app.get_access_token("oauth_code_removed", state="state_removed") 137 self.assertEqual(exc.exception.status, 200) 138 self.assertIn("error", exc.exception.data) 139 self.assertEqual(exc.exception.data["error"], "some_unknown_error") 140 141 def testRefreshAccessTokenBadCode(self): 142 with self.assertRaises(github.BadCredentialsException) as exc: 143 self.app.refresh_access_token("oauth_code_removed") 144 self.assertEqual(exc.exception.status, 200) 145 self.assertIn("error", exc.exception.data) 146 self.assertEqual(exc.exception.data["error"], "bad_verification_code") 147 148 def testRefreshAccessTokenUnknownError(self): 149 with self.assertRaises(github.GithubException) as exc: 150 self.app.refresh_access_token("oauth_code_removed") 151 self.assertEqual(exc.exception.status, 200) 152 self.assertIn("error", exc.exception.data) 153 self.assertEqual(exc.exception.data["error"], "some_unknown_error") 154 155 def testCheckError(self): 156 expected_header = {"header": True} 157 expected_data = {"data": True} 158 159 header, data = aoa._checkError(expected_header, None) 160 self.assertEqual(header, expected_header) 161 self.assertIsNone(data) 162 163 header, data = aoa._checkError(expected_header, expected_data) 164 self.assertEqual(header, expected_header) 165 self.assertEqual(data, expected_data) 166 167 with self.assertRaises(github.BadCredentialsException) as exc: 168 aoa._checkError({}, {"error": "bad_verification_code"}) 169 self.assertEqual(exc.exception.status, 200) 170 self.assertIn("error", exc.exception.data) 171 self.assertEqual(exc.exception.data["error"], "bad_verification_code") 172 173 with self.assertRaises(github.GithubException) as exc: 174 aoa._checkError({}, {"error": "other"}) 175 self.assertEqual(exc.exception.status, 200) 176 self.assertIn("error", exc.exception.data) 177 self.assertEqual(exc.exception.data["error"], "other")