From 44b0af933d5dc66e23a6b191bf48b8eb87558c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20P=C3=B6hn?= Date: Tue, 16 Apr 2024 11:35:54 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A1=20add=20unit=20tests=20for=20githu?= =?UTF-8?q?b.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add unittests for our github api calls --- fdroidserver/github.py | 2 +- tests/github.TestCase | 164 +++++++++++++++++++++++++++++++++++++++++ tests/testcommon.py | 12 ++- 3 files changed, 175 insertions(+), 3 deletions(-) create mode 100755 tests/github.TestCase diff --git a/fdroidserver/github.py b/fdroidserver/github.py index 6356c4ae..b7a8ce2a 100644 --- a/fdroidserver/github.py +++ b/fdroidserver/github.py @@ -85,7 +85,7 @@ class GithubApi: with urllib.request.urlopen(req) as resp: refs = json.load(resp) for ref in refs: - r = ref['ref'] + r = ref.get('ref', '') if r.startswith('refs/tags/'): tags.append(r[10:]) return tags diff --git a/tests/github.TestCase b/tests/github.TestCase new file mode 100755 index 00000000..bc5e04a4 --- /dev/null +++ b/tests/github.TestCase @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 + +import inspect +import optparse +import os +import sys +import unittest.mock +import testcommon + +localmodule = os.path.realpath( + os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..') +) +print('localmodule: ' + localmodule) +if localmodule not in sys.path: + sys.path.insert(0, localmodule) + +import fdroidserver.github +import fdroidserver.common + + +class GithubApiTest(unittest.TestCase): + def test__init(self): + api = fdroidserver.github.GithubApi('faketoken', 'fakerepopath') + self.assertEqual(api._api_token, 'faketoken') + self.assertEqual(api._repo_path, 'fakerepopath') + + def test__req(self): + api = fdroidserver.github.GithubApi('faketoken', 'fakerepopath') + r = api._req('https://fakeurl', data='fakedata') + self.assertEqual(r.full_url, 'https://fakeurl') + self.assertEqual(r.data, "fakedata") + self.assertDictEqual( + r.headers, + { + 'Accept': 'application/vnd.github+json', + 'Authorization': 'Bearer faketoken', + 'X-github-api-version': '2022-11-28', + }, + ) + + def test_list_released_tags(self): + api = fdroidserver.github.GithubApi('faketoken', 'fakerepopath') + uomock = testcommon.mock_urlopen( + body='[{"tag_name": "fake"}, {"tag_name": "double_fake"}]' + ) + with unittest.mock.patch("urllib.request.urlopen", uomock): + result = api.list_released_tags() + self.assertListEqual(result, ['fake', 'double_fake']) + + def test_list_unreleased_tags(self): + api = fdroidserver.github.GithubApi('faketoken', 'fakerepopath') + + api.list_all_tags = unittest.mock.Mock(return_value=[1, 2, 3, 4]) + api.list_released_tags = unittest.mock.Mock(return_value=[1, 2]) + + result = api.list_unreleased_tags() + + self.assertListEqual(result, [3, 4]) + + def test_tag_exists(self): + api = fdroidserver.github.GithubApi('faketoken', 'fakerepopath') + uomock = testcommon.mock_urlopen(body='[{"ref": "refs/tags/fake_tag"}]') + with unittest.mock.patch("urllib.request.urlopen", uomock): + result = api.tag_exists('fake_tag') + self.assertTrue(result) + + def test_tag_exists_failure(self): + api = fdroidserver.github.GithubApi('faketoken', 'fakerepopath') + + uomock = testcommon.mock_urlopen(body='[{"error": "failure"}]') + + with unittest.mock.patch("urllib.request.urlopen", uomock): + success = api.tag_exists('fake_tag') + + self.assertFalse(success) + + def test_list_all_tags(self): + api = fdroidserver.github.GithubApi('faketoken', 'fakerepopath') + + uomock = testcommon.mock_urlopen( + body='[{"ref": "refs/tags/fake"}, {"ref": "refs/tags/double_fake"}]' + ) + + with unittest.mock.patch("urllib.request.urlopen", uomock): + result = api.list_all_tags() + + self.assertListEqual(result, ['fake', 'double_fake']) + + def test_create_release(self): + api = fdroidserver.github.GithubApi('faketoken', 'fakerepopath') + + uomock = testcommon.mock_urlopen(body='{"id": "fakeid"}') + api.tag_exists = lambda x: True + api._create_release_asset = unittest.mock.Mock() + + with unittest.mock.patch("urllib.request.urlopen", uomock): + success = api.create_release('faketag', ['file_a', 'file_b']) + self.assertTrue(success) + + req = uomock.call_args_list[0][0][0] + self.assertEqual(1, len(uomock.call_args_list)) + self.assertEqual(2, len(uomock.call_args_list[0])) + self.assertEqual(1, len(uomock.call_args_list[0][0])) + self.assertEqual( + req.full_url, + 'https://api.github.com/repos/fakerepopath/releases', + ) + self.assertEqual(req.data, b'{"tag_name": "faketag"}') + self.assertListEqual( + api._create_release_asset.call_args_list, + [ + unittest.mock.call('fakeid', 'file_a'), + unittest.mock.call('fakeid', 'file_b'), + ], + ) + + def test__create_release_asset(self): + api = fdroidserver.github.GithubApi('faketoken', 'fakerepopath') + uomock = testcommon.mock_urlopen() + + with unittest.mock.patch( + 'fdroidserver.github.open', + unittest.mock.mock_open(read_data=b"fake_content"), + ), unittest.mock.patch("urllib.request.urlopen", uomock): + success = api._create_release_asset('fake_id', 'fake_file') + + self.assertTrue(success) + + req = uomock.call_args_list[0][0][0] + self.assertEqual(1, len(uomock.call_args_list)) + self.assertEqual(2, len(uomock.call_args_list[0])) + self.assertEqual(1, len(uomock.call_args_list[0][0])) + self.assertEqual( + req.full_url, + 'https://uploads.github.com/repos/fakerepopath/releases/fake_id/assets?name=fake_file', + ) + self.assertDictEqual( + req.headers, + { + "Accept": "application/vnd.github+json", + 'Authorization': 'Bearer faketoken', + 'Content-type': 'application/octet-stream', + 'X-github-api-version': '2022-11-28', + }, + ) + self.assertEqual(req.data, b'fake_content') + + +if __name__ == "__main__": + os.chdir(os.path.dirname(__file__)) + + parser = optparse.OptionParser() + parser.add_option( + "-v", + "--verbose", + action="store_true", + default=False, + help="Spew out even more information than normal", + ) + (fdroidserver.common.options, args) = parser.parse_args(["--verbose"]) + + newSuite = unittest.TestSuite() + newSuite.addTest(unittest.makeSuite(GithubApiTest)) + unittest.main(failfast=False) diff --git a/tests/testcommon.py b/tests/testcommon.py index 2ce9f393..f0fd11bd 100644 --- a/tests/testcommon.py +++ b/tests/testcommon.py @@ -19,9 +19,9 @@ import os import sys import tempfile import unittest +import unittest.mock from pathlib import Path -from unittest import mock class TmpCwd: @@ -84,5 +84,13 @@ def parse_args_for_test(parser, args): for arg in args: if arg[0] == '-': flags.append(flags) - with mock.patch('sys.argv', flags): + with unittest.mock.patch('sys.argv', flags): parse_args(parser) + + +def mock_urlopen(status=200, body=None): + resp = unittest.mock.MagicMock() + resp.getcode.return_value = status + resp.read.return_value = body + resp.__enter__.return_value = resp + return unittest.mock.Mock(return_value=resp)