From dc0e0b722b649fde87ad345c65c30ff1daa501f3 Mon Sep 17 00:00:00 2001 From: Marion Deveaud Date: Thu, 28 Mar 2024 17:22:38 +0100 Subject: [PATCH 1/4] fix(version): use v1 by default until v2 will be released --- README.rst | 12 ++++---- docs-source/conf.py | 2 +- fossology/__init__.py | 10 +++---- fossology/uploads.py | 56 ++++++++++++++++++++++-------------- pyproject.toml | 2 +- tests/conftest.py | 16 +++++------ tests/test_init.py | 28 ++++++++++++++++-- tests/test_items.py | 6 ++-- tests/test_upload_from.py | 60 +++++++++++++++++++++++++++++++++++++++ tests/test_uploads.py | 47 +++++++++++++++++++----------- 10 files changed, 175 insertions(+), 64 deletions(-) diff --git a/README.rst b/README.rst index 11fff55..fe612fd 100644 --- a/README.rst +++ b/README.rst @@ -26,13 +26,13 @@ A simple wrapper for the Fossology REST API. See `the OpenAPI specification `_ used to implement this library. -Current release is compatible with **Fossology version 4.4.0-rc2** - API version 2.0.0 (not all endpoints are supported) +Current release is compatible with **Fossology version 4.4.0** - API version 1.6.1 (not all endpoints are supported) `See release notes `_ for all details. If you miss an API Endpoint, please open a new issue or contribute a pull request. - API v1 is supported too, it needs to be specified explicitly. + API v2 is partially supported too, however the specification is not stable yet and not all endpoints are supported. Documentation ============= @@ -68,14 +68,14 @@ Using the API FOSSOLOGY_PASSWORD = "fossy" TOKEN_NAME = "fossy_token" - # By default version v2 of the token generation API will be used + # By default version v1 of the token generation API will be used token = fossology_token( FOSSOLOGY_SERVER, FOSSOLOGY_USER, FOSSOLOGY_PASSWORD, TOKEN_NAME, TokenScope.WRITE - version="v2" + version="v1" ) - Start using the API: @@ -84,8 +84,8 @@ Using the API from fossology import Fossology - # By default version v2 of the API will be used - foss = Fossology(FOSSOLOGY_SERVER, token, FOSSOLOGY_USER, version="v2") + # By default version v1 of the API will be used + foss = Fossology(FOSSOLOGY_SERVER, token, FOSSOLOGY_USER, version="v1") print(f"Logged in as user {foss.user.name}") diff --git a/docs-source/conf.py b/docs-source/conf.py index a93f4da..02841f9 100644 --- a/docs-source/conf.py +++ b/docs-source/conf.py @@ -22,7 +22,7 @@ copyright = "2021, Siemens AG" # The full version, including major/minor/patch tags -release = "3.2.0" +release = "3.2.1" # -- General configuration --------------------------------------------------- diff --git a/fossology/__init__.py b/fossology/__init__.py index fa716c6..28d2f91 100644 --- a/fossology/__init__.py +++ b/fossology/__init__.py @@ -31,7 +31,7 @@ def fossology_token( token_name, token_scope=TokenScope.READ, token_expire=None, - version="v2", + version="v1", ): """Generate an API token using username/password @@ -41,7 +41,7 @@ def fossology_token( >>> from fossology import fossology_token # doctest: +SKIP >>> from fossology.obj import TokenScope # doctest: +SKIP - >>> token = fossology_token("https://fossology.example.com/repo", "Me", "MyPassword", "MyToken", version="v2") # doctest: +SKIP + >>> token = fossology_token("https://fossology.example.com/repo", "Me", "MyPassword", "MyToken", version="v1") # doctest: +SKIP :param url: the URL of the Fossology server @@ -50,7 +50,7 @@ def fossology_token( :param name: the name of the token :param scope: the scope of the token (default: TokenScope.READ) :param expire: the expire date of the token, e.g. 2019-12-25 (default: max. 30 days) - :param version: the version of the API to use (default: "v2") + :param version: the version of the API to use (default: "v1") :type url: string :type username: string :type password: string @@ -118,7 +118,7 @@ class Fossology( :param url: URL of the Fossology instance :param token: The API token generated using the Fossology UI - :param version: the version of the API to use (default: "v2") + :param version: the version of the API to use (default: "v1") :type url: str :type token: str :type version: str @@ -126,7 +126,7 @@ class Fossology( :raises AuthenticationError: if the user couldn't be authenticated """ - def __init__(self, url, token, version="v2"): + def __init__(self, url, token, version="v1"): self.host = url self.token = token self.users = list() diff --git a/fossology/uploads.py b/fossology/uploads.py index 20b9bf7..119ac67 100644 --- a/fossology/uploads.py +++ b/fossology/uploads.py @@ -156,7 +156,7 @@ def upload_file( >>> from fossology import Fossology >>> from fossology.enums import AccessLevel - >>> foss = Fossology(FOSS_URL, FOSS_TOKEN, username) # doctest: +SKIP + >>> foss = Fossology(FOSS_URL, FOSS_TOKEN) # doctest: +SKIP >>> my_upload = foss.upload_file( ... foss.rootFolder, ... file="my-package.zip", @@ -237,39 +237,53 @@ def upload_file( :raises FossologyApiError: if the REST call failed :raises AuthorizationError: if the REST call is not authorized """ - headers = {"folderId": str(folder.id)} - if description: - headers["uploadDescription"] = description - if access_level: - headers["public"] = access_level.value - if apply_global: - headers["applyGlobal"] = "true" - if ignore_scm: - headers["ignoreScm"] = "true" - if group: + data = { + "folderId": str(folder.id), + "uploadDescription": description, + "public": access_level.value + if access_level + else AccessLevel.PROTECTED.value, + "applyGlobal": apply_global, + "ignoreScm": ignore_scm, + "uploadType": "file", + } + + headers = {} + if "v1" in self.api: + headers = { + k: str(v).lower() if isinstance(v, bool) else v for k, v in data.items() + } # Needed for API v1.x headers["groupName"] = group + endpoint = f"{self.api}/uploads" + else: + if group: + endpoint = f"{self.api}/uploads?groupName={group}" + else: + endpoint = f"{self.api}/uploads" if file: - headers["uploadType"] = "file" + data["uploadType"] = headers["uploadType"] = "file" with open(file, "rb") as fp: files = {"fileInput": fp} response = self.session.post( - f"{self.api}/uploads", files=files, headers=headers + endpoint, files=files, headers=headers, data=data ) elif vcs or url or server: - data = dict if vcs: - headers["uploadType"] = "vcs" - data = {"location": vcs} # type: ignore + data["location"] = vcs + print(data) + data["uploadType"] = headers["uploadType"] = "vcs" elif url: - headers["uploadType"] = "url" - data = {"location": url} # type: ignore + data["location"] = url + data["uploadType"] = headers["uploadType"] = "url" elif server: - headers["uploadType"] = "server" - data = {"location": server} # type: ignore + data["location"] = server + data["uploadType"] = headers["uploadType"] = "server" headers["Content-Type"] = "application/json" response = self.session.post( - f"{self.api}/uploads", data=json.dumps(data), headers=headers + endpoint, + data=json.dumps(data), + headers=headers, ) else: logger.info( diff --git a/pyproject.toml b/pyproject.toml index 77707d5..cf95a89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "fossology" -version = "3.2.0" +version = "3.2.1" description = "A library to automate Fossology from Python scripts" authors = ["Marion Deveaud "] license = "MIT License" diff --git a/tests/conftest.py b/tests/conftest.py index 41af50d..0c01fff 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -175,11 +175,11 @@ def foss(foss_server: str, foss_token: str, foss_agents: Agents) -> fossology.Fo @pytest.fixture(scope="session") -def foss_v1( +def foss_v2( foss_server: str, foss_token: str, foss_agents: Agents ) -> fossology.Fossology: try: - foss = fossology.Fossology(foss_server, foss_token, version="v1") + foss = fossology.Fossology(foss_server, foss_token, version="v2") except (FossologyApiError, AuthenticationError) as error: exit(error.message) @@ -231,20 +231,20 @@ def upload( @pytest.fixture(scope="function") -def upload_v1( - foss_v1: fossology.Fossology, +def upload_v2( + foss_v2: fossology.Fossology, test_file_path: str, ) -> Generator: - upload = foss_v1.upload_file( - foss_v1.rootFolder, + upload = foss_v2.upload_file( + foss_v2.rootFolder, file=test_file_path, description="Test upload via fossology-python lib", access_level=AccessLevel.PUBLIC, wait_time=5, ) - jobs_lookup(foss_v1, upload) + jobs_lookup(foss_v2, upload) yield upload - foss_v1.delete_upload(upload) + foss_v2.delete_upload(upload) time.sleep(5) diff --git a/tests/test_init.py b/tests/test_init.py index cf22e15..62e2278 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -15,12 +15,24 @@ def test_get_info(foss: Fossology): @responses.activate -def test_info_does_not_return_200(foss_server: str, foss: Fossology): +def test_info_v2_does_not_return_200(foss_server: str, foss_v2: Fossology): responses.add( responses.GET, f"{foss_server}/api/v2/info", status=400, ) + with pytest.raises(FossologyApiError) as excinfo: + foss_v2.get_info() + assert "Error while getting API info" in str(excinfo.value) + + +@responses.activate +def test_info_does_not_return_200(foss_server: str, foss: Fossology): + responses.add( + responses.GET, + f"{foss_server}/api/v1/info", + status=400, + ) with pytest.raises(FossologyApiError) as excinfo: foss.get_info() assert "Error while getting API info" in str(excinfo.value) @@ -36,9 +48,21 @@ def test_get_health(foss: Fossology): def test_health_does_not_return_200(foss_server: str, foss: Fossology): responses.add( responses.GET, - f"{foss_server}/api/v2/health", + f"{foss_server}/api/v1/health", status=503, ) with pytest.raises(FossologyApiError) as excinfo: foss.get_health() assert "Error while getting health info" in str(excinfo.value) + + +@responses.activate +def test_health_v2_does_not_return_200(foss_server: str, foss_v2: Fossology): + responses.add( + responses.GET, + f"{foss_server}/api/v2/health", + status=503, + ) + with pytest.raises(FossologyApiError) as excinfo: + foss_v2.get_health() + assert "Error while getting health info" in str(excinfo.value) diff --git a/tests/test_items.py b/tests/test_items.py index 4911a89..fc2eda2 100644 --- a/tests/test_items.py +++ b/tests/test_items.py @@ -16,9 +16,9 @@ def test_item_info(foss: Fossology, upload_with_jobs: Upload): assert info.meta_info -def test_item_info_v1(foss_v1: Fossology, upload_with_jobs: Upload): - files, _ = foss_v1.search(license="BSD") - info: FileInfo = foss_v1.item_info(upload_with_jobs, files[0].uploadTreeId) +def test_item_info_v2(foss_v2: Fossology, upload_with_jobs: Upload): + files, _ = foss_v2.search(license="BSD") + info: FileInfo = foss_v2.item_info(upload_with_jobs, files[0].uploadTreeId) assert info.meta_info diff --git a/tests/test_upload_from.py b/tests/test_upload_from.py index cad2855..30cf43d 100644 --- a/tests/test_upload_from.py +++ b/tests/test_upload_from.py @@ -43,6 +43,27 @@ def test_upload_from_vcs(foss: Fossology): delete_upload(foss, vcs_upload) +def test_upload_from_vcs_v2(foss_v2: Fossology): + vcs = { + "vcsType": "git", + "vcsUrl": "https://github.com/fossology/fossology-python", + "vcsName": "fossology-python-github-master", + "vcsUsername": "", + "vcsPassword": "", + } + vcs_upload = foss_v2.upload_file( + foss_v2.rootFolder, + vcs=vcs, + description="Test upload from github repository via python lib", + access_level=AccessLevel.PUBLIC, + ignore_scm=False, + wait_time=5, + ) + assert vcs_upload.uploadname == vcs["vcsName"] + # Cleanup + delete_upload(foss_v2, vcs_upload) + + def test_upload_from_url(foss: Fossology): url = { "url": "https://github.com/fossology/fossology-python/archive/master.zip", @@ -63,6 +84,26 @@ def test_upload_from_url(foss: Fossology): delete_upload(foss, url_upload) +def test_upload_from_url_v2(foss_v2: Fossology): + url = { + "url": "https://github.com/fossology/fossology-python/archive/master.zip", + "name": "fossology-python-master.zip", + "accept": "zip", + "reject": "", + "maxRecursionDepth": "1", + } + url_upload = foss_v2.upload_file( + foss_v2.rootFolder, + url=url, + description="Test upload from url via python lib", + access_level=AccessLevel.PUBLIC, + wait_time=5, + ) + assert url_upload.uploadname == url["name"] + # Cleanup + delete_upload(foss_v2, url_upload) + + def test_upload_from_server(foss: Fossology): server = { "path": "/tmp/base-files-11", @@ -80,3 +121,22 @@ def test_upload_from_server(foss: Fossology): # Cleanup delete_upload(foss, server_upload) + + +def test_upload_from_server_v2(foss_v2: Fossology): + server = { + "path": "/tmp/base-files-11", + "name": "base-files-11", + } + server_upload = foss_v2.upload_file( + foss_v2.rootFolder, + server=server, + description="Test upload from server via python lib", + access_level=AccessLevel.PUBLIC, + apply_global=True, + wait_time=5, + ) + assert server_upload.uploadname == server["name"] + + # Cleanup + delete_upload(foss_v2, server_upload) diff --git a/tests/test_uploads.py b/tests/test_uploads.py index 8a08c3e..5a2c695 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -30,16 +30,29 @@ def test_upload_sha1(upload: Upload): ) -def test_upload_v1(upload_v1: Upload): - assert upload_v1.uploadname == "base-files_11.tar.xz" - assert upload_v1.hash.sha1 == "D4D663FC2877084362FB2297337BE05684869B00" - assert str(upload_v1) == ( - f"Upload '{upload_v1.uploadname}' ({upload_v1.id}, {upload_v1.hash.size}B, {upload_v1.hash.sha1}) " - f"in folder {upload_v1.foldername} ({upload_v1.folderid})" +def test_upload(upload: Upload): + assert upload.uploadname == "base-files_11.tar.xz" + assert upload.hash.sha1 == "D4D663FC2877084362FB2297337BE05684869B00" + assert str(upload) == ( + f"Upload '{upload.uploadname}' ({upload.id}, {upload.hash.size}B, {upload.hash.sha1}) " + f"in folder {upload.foldername} ({upload.folderid})" + ) + assert str(upload.hash) == ( + f"File SHA1: {upload.hash.sha1} MD5 {upload.hash.md5} " + f"SH256 {upload.hash.sha256} Size {upload.hash.size}B" + ) + + +def test_upload_v2(upload_v2: Upload): + assert upload_v2.uploadname == "base-files_11.tar.xz" + assert upload_v2.hash.sha1 == "D4D663FC2877084362FB2297337BE05684869B00" + assert str(upload_v2) == ( + f"Upload '{upload_v2.uploadname}' ({upload_v2.id}, {upload_v2.hash.size}B, {upload_v2.hash.sha1}) " + f"in folder {upload_v2.foldername} ({upload_v2.folderid})" ) - assert str(upload_v1.hash) == ( - f"File SHA1: {upload_v1.hash.sha1} MD5 {upload_v1.hash.md5} " - f"SH256 {upload_v1.hash.sha256} Size {upload_v1.hash.size}B" + assert str(upload_v2.hash) == ( + f"File SHA1: {upload_v2.hash.sha1} MD5 {upload_v2.hash.md5} " + f"SH256 {upload_v2.hash.sha256} Size {upload_v2.hash.size}B" ) @@ -59,7 +72,7 @@ def test_get_upload_error(foss: Fossology, foss_server: str): upload_id = 100 responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload_id}", + f"{foss_server}/api/v1/uploads/{upload_id}", status=500, ) with pytest.raises(FossologyApiError) as excinfo: @@ -132,7 +145,7 @@ def test_empty_upload(foss: Fossology): def test_upload_error(foss: Fossology, foss_server: str, test_file_path: str): responses.add( responses.POST, - f"{foss_server}/api/v2/uploads", + f"{foss_server}/api/v1/uploads", status=500, ) description = "Test upload API error" @@ -172,7 +185,7 @@ def test_move_upload_error(foss: Fossology, foss_server: str, upload: Upload): folder = Folder(secrets.randbelow(1000), "Folder", "", foss.rootFolder) responses.add( responses.PUT, - f"{foss_server}/api/v2/uploads/{upload.id}", + f"{foss_server}/api/v1/uploads/{upload.id}", status=500, ) with pytest.raises(FossologyApiError): @@ -196,7 +209,7 @@ def test_update_upload_with_unknown_group_raises_error(foss: Fossology, upload: def test_update_upload_error(foss: Fossology, foss_server: str, upload: Upload): responses.add( responses.PATCH, - f"{foss_server}/api/v2/uploads/{upload.id}", + f"{foss_server}/api/v1/uploads/{upload.id}", status=500, ) with pytest.raises(FossologyApiError): @@ -217,7 +230,7 @@ def test_upload_summary(foss: Fossology, upload: Upload): def test_upload_summary_500_error(foss: Fossology, foss_server: str, upload: Upload): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload.id}/summary", + f"{foss_server}/api/v1/uploads/{upload.id}/summary", status=500, ) with pytest.raises(FossologyApiError): @@ -284,7 +297,7 @@ def test_paginated_list_uploads(foss: Fossology, upload: Upload, test_file_path: def test_list_uploads_500_error(foss: Fossology, foss_server: str, upload: Upload): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads", + f"{foss_server}/api/v1/uploads", status=500, ) with pytest.raises(FossologyApiError): @@ -310,7 +323,7 @@ def test_download_upload_authorization_error( ): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload.id}/download", + f"{foss_server}/api/v1/uploads/{upload.id}/download", status=403, ) with pytest.raises(AuthorizationError) as excinfo: @@ -322,7 +335,7 @@ def test_download_upload_authorization_error( def test_download_upload_error(foss_server: str, foss: Fossology, upload: Upload): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload.id}/download", + f"{foss_server}/api/v1/uploads/{upload.id}/download", status=401, ) with pytest.raises(FossologyApiError) as excinfo: From 171332dd96a0776cb76100d1e24ce29a8e26cf7d Mon Sep 17 00:00:00 2001 From: Marion Deveaud Date: Thu, 4 Apr 2024 16:49:17 +0200 Subject: [PATCH 2/4] tests(v1): test v1 by default, add tests for uploads v2 --- tests/test_folders.py | 12 ++++---- tests/test_groups.py | 10 +++---- tests/test_items.py | 12 ++++---- tests/test_jobs.py | 10 +++---- tests/test_license.py | 10 +++---- tests/test_report.py | 12 ++++---- tests/test_search.py | 4 +-- tests/test_upload_licenses_copyrights.py | 14 ++++----- tests/test_upload_permissions.py | 12 ++++---- tests/test_uploads.py | 38 ++++++++++++++++++++++++ tests/test_users.py | 18 +++++------ 11 files changed, 95 insertions(+), 57 deletions(-) diff --git a/tests/test_folders.py b/tests/test_folders.py index 34681e4..ab43408 100644 --- a/tests/test_folders.py +++ b/tests/test_folders.py @@ -14,7 +14,7 @@ @responses.activate def test_list_folders_error(foss_server: str, foss: Fossology): - responses.add(responses.GET, f"{foss_server}/api/v2/folders", status=404) + responses.add(responses.GET, f"{foss_server}/api/v1/folders", status=404) with pytest.raises(FossologyApiError) as excinfo: foss.list_folders() assert f"Unable to get a list of folders for {foss.user.name}" in str(excinfo.value) @@ -69,7 +69,7 @@ def test_create_folder_no_parent(foss: Fossology): def test_create_folder_returns_200_but_folder_does_not_exists( foss_server: str, foss: Fossology ): - responses.add(responses.POST, f"{foss_server}/api/v2/folders", status=200) + responses.add(responses.POST, f"{foss_server}/api/v1/folders", status=200) with pytest.raises(FossologyApiError) as excinfo: foss.create_folder(foss.rootFolder, "NoFolder") assert ( @@ -81,7 +81,7 @@ def test_create_folder_returns_200_but_folder_does_not_exists( @responses.activate def test_create_folder_error(foss_server: str, foss: Fossology): parent = Folder(secrets.randbelow(1000), "NonFolder", "", foss.rootFolder) - responses.add(responses.POST, f"{foss_server}/api/v2/folders", status=404) + responses.add(responses.POST, f"{foss_server}/api/v1/folders", status=404) with pytest.raises(FossologyApiError) as excinfo: foss.create_folder(parent, "TestFolderNoParent") assert "Unable to create folder TestFolderNoParent" in str(excinfo.value) @@ -106,7 +106,7 @@ def test_update_folder(foss: Fossology): def test_update_folder_error(foss_server: str, foss: Fossology): folder = Folder(secrets.randbelow(1000), "Folder", "", foss.rootFolder) responses.add( - responses.PATCH, f"{foss_server}/api/v2/folders/{folder.id}", status=404 + responses.PATCH, f"{foss_server}/api/v1/folders/{folder.id}", status=404 ) with pytest.raises(FossologyApiError) as excinfo: foss.update_folder(folder) @@ -152,7 +152,7 @@ def test_copy_folder(foss: Fossology): def test_put_folder_error(foss_server: str, foss: Fossology): folder = Folder(secrets.randbelow(1000), "Folder", "", foss.rootFolder) responses.add( - responses.PUT, f"{foss_server}/api/v2/folders/{folder.id}", status=404 + responses.PUT, f"{foss_server}/api/v1/folders/{folder.id}", status=404 ) with pytest.raises(FossologyApiError) as excinfo: foss.move_folder(folder, foss.rootFolder) @@ -178,7 +178,7 @@ def test_delete_folder(foss: Fossology): def test_delete_folder_error(foss_server: str, foss: Fossology): folder = Folder(secrets.randbelow(1000), "Folder", "", foss.rootFolder) responses.add( - responses.DELETE, f"{foss_server}/api/v2/folders/{folder.id}", status=404 + responses.DELETE, f"{foss_server}/api/v1/folders/{folder.id}", status=404 ) with pytest.raises(FossologyApiError) as excinfo: foss.delete_folder(folder) diff --git a/tests/test_groups.py b/tests/test_groups.py index dfe48ec..f16ba9b 100644 --- a/tests/test_groups.py +++ b/tests/test_groups.py @@ -33,7 +33,7 @@ def verify_user_group_membership( # Test functions @responses.activate def test_list_groups_error(foss_server: str, foss: fossology.Fossology): - responses.add(responses.GET, f"{foss_server}/api/v2/groups", status=500) + responses.add(responses.GET, f"{foss_server}/api/v1/groups", status=500) with pytest.raises(FossologyApiError) as excinfo: foss.list_groups() assert f"Unable to get a list of groups for {foss.user.name}" in str(excinfo.value) @@ -41,7 +41,7 @@ def test_list_groups_error(foss_server: str, foss: fossology.Fossology): @responses.activate def test_list_group_members_error(foss_server: str, foss: fossology.Fossology): - responses.add(responses.GET, f"{foss_server}/api/v2/groups/42/members", status=500) + responses.add(responses.GET, f"{foss_server}/api/v1/groups/42/members", status=500) with pytest.raises(FossologyApiError) as excinfo: foss.list_group_members(42) assert "Unable to get a list of members for group 42" in str(excinfo.value) @@ -52,7 +52,7 @@ def test_delete_group_member_validation_error( foss_server: str, foss: fossology.Fossology ): responses.add( - responses.DELETE, f"{foss_server}/api/v2/groups/42/user/42", status=400 + responses.DELETE, f"{foss_server}/api/v1/groups/42/user/42", status=400 ) with pytest.raises(FossologyApiError) as excinfo: foss.delete_group_member(42, 42) @@ -64,7 +64,7 @@ def test_delete_group_member_validation_error( @responses.activate def test_delete_group_member_error(foss_server: str, foss: fossology.Fossology): responses.add( - responses.DELETE, f"{foss_server}/api/v2/groups/42/user/42", status=500 + responses.DELETE, f"{foss_server}/api/v1/groups/42/user/42", status=500 ) with pytest.raises(FossologyApiError) as excinfo: foss.delete_group_member(42, 42) @@ -77,7 +77,7 @@ def test_delete_group_member_error(foss_server: str, foss: fossology.Fossology): def test_delete_group_error(foss_server: str, foss: fossology.Fossology): group_id = secrets.randbelow(10) responses.add( - responses.DELETE, f"{foss_server}/api/v2/groups/{group_id}", status=500 + responses.DELETE, f"{foss_server}/api/v1/groups/{group_id}", status=500 ) with pytest.raises(FossologyApiError) as excinfo: foss.delete_group(group_id) diff --git a/tests/test_items.py b/tests/test_items.py index fc2eda2..1a3437b 100644 --- a/tests/test_items.py +++ b/tests/test_items.py @@ -36,7 +36,7 @@ def test_item_info_500_error( ): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload_with_jobs.id}/item/1/info", + f"{foss_server}/api/v1/uploads/{upload_with_jobs.id}/item/1/info", status=500, ) with pytest.raises(FossologyApiError) as excinfo: @@ -69,7 +69,7 @@ def test_item_copyrights_500_error( ): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload_with_jobs.id}/item/1/totalcopyrights", + f"{foss_server}/api/v1/uploads/{upload_with_jobs.id}/item/1/totalcopyrights", status=500, ) with pytest.raises(FossologyApiError) as excinfo: @@ -100,7 +100,7 @@ def test_upload_get_clearing_history_500_error( ): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload_with_jobs.id}/item/1/clearing-history", + f"{foss_server}/api/v1/uploads/{upload_with_jobs.id}/item/1/clearing-history", status=500, ) with pytest.raises(FossologyApiError) as excinfo: @@ -131,7 +131,7 @@ def test_upload_get_bulk_history_500_error( ): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload_with_jobs.id}/item/1/clearing-history", + f"{foss_server}/api/v1/uploads/{upload_with_jobs.id}/item/1/clearing-history", status=500, ) with pytest.raises(FossologyApiError) as excinfo: @@ -172,7 +172,7 @@ def test_schedule_bulk_scan_500_error( ): responses.add( responses.POST, - f"{foss_server}/api/v2/uploads/{upload_with_jobs.id}/item/1/bulk-scan", + f"{foss_server}/api/v1/uploads/{upload_with_jobs.id}/item/1/bulk-scan", status=500, ) with pytest.raises(FossologyApiError) as excinfo: @@ -219,7 +219,7 @@ def test_upload_get_prev_next_500_error( ): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload_with_jobs.id}/item/1/prev-next", + f"{foss_server}/api/v1/uploads/{upload_with_jobs.id}/item/1/prev-next", status=500, ) with pytest.raises(FossologyApiError) as excinfo: diff --git a/tests/test_jobs.py b/tests/test_jobs.py index b3b21dc..df592da 100644 --- a/tests/test_jobs.py +++ b/tests/test_jobs.py @@ -61,7 +61,7 @@ def test_detail_job_wait_completed( @responses.activate def test_schedule_job_error(foss_server: str, foss: Fossology, upload: Upload): - responses.add(responses.POST, f"{foss_server}/api/v2/jobs", status=404) + responses.add(responses.POST, f"{foss_server}/api/v1/jobs", status=404) with pytest.raises(FossologyApiError) as excinfo: foss.schedule_jobs(foss.rootFolder, upload, {}) assert f"Scheduling jobs for upload {upload.uploadname} failed" in str( @@ -71,7 +71,7 @@ def test_schedule_job_error(foss_server: str, foss: Fossology, upload: Upload): @responses.activate def test_list_jobs_error(foss_server: str, foss: Fossology): - responses.add(responses.GET, f"{foss_server}/api/v2/jobs", status=404) + responses.add(responses.GET, f"{foss_server}/api/v1/jobs", status=404) with pytest.raises(FossologyApiError) as excinfo: foss.list_jobs() assert "Unable to retrieve the list of jobs from page 1" in str(excinfo.value) @@ -79,7 +79,7 @@ def test_list_jobs_error(foss_server: str, foss: Fossology): @responses.activate def test_list_all_jobs_access_denied(foss_server: str, foss: Fossology): - responses.add(responses.GET, f"{foss_server}/api/v2/jobs/all", status=403) + responses.add(responses.GET, f"{foss_server}/api/v1/jobs/all", status=403) with pytest.raises(FossologyApiError) as excinfo: foss.list_jobs(all=True) assert "Access denied to /jobs/all endpoint" in str(excinfo.value) @@ -88,8 +88,8 @@ def test_list_all_jobs_access_denied(foss_server: str, foss: Fossology): @responses.activate def test_detail_job_error(foss_server: str, foss: Fossology): job_id = secrets.randbelow(1000) - responses.add(responses.GET, f"{foss_server}/api/v2/jobs/{job_id}", status=404) - responses.add(responses.GET, f"{foss_server}/api/v2/jobs/{job_id}", status=404) + responses.add(responses.GET, f"{foss_server}/api/v1/jobs/{job_id}", status=404) + responses.add(responses.GET, f"{foss_server}/api/v1/jobs/{job_id}", status=404) with pytest.raises(FossologyApiError) as excinfo: foss.detail_job(job_id, wait=True) assert f"Error while getting details for job {job_id}" in str(excinfo.value) diff --git a/tests/test_license.py b/tests/test_license.py index 5d54f85..c74b96a 100644 --- a/tests/test_license.py +++ b/tests/test_license.py @@ -34,7 +34,7 @@ def test_another_license(): @responses.activate def test_detail_license_error(foss_server: str, foss: fossology.Fossology): - responses.add(responses.GET, f"{foss_server}/api/v2/license/Blah", status=500) + responses.add(responses.GET, f"{foss_server}/api/v1/license/Blah", status=500) with pytest.raises(FossologyApiError) as excinfo: foss.detail_license("Blah") assert "Error while getting license Blah" in str(excinfo.value) @@ -48,7 +48,7 @@ def test_detail_license_not_found(foss: fossology.Fossology): @responses.activate def test_list_licenses_error(foss_server: str, foss: fossology.Fossology): - responses.add(responses.GET, f"{foss_server}/api/v2/license", status=500) + responses.add(responses.GET, f"{foss_server}/api/v1/license", status=500) with pytest.raises(FossologyApiError) as excinfo: foss.list_licenses() assert "Unable to retrieve the list of licenses from page 1" in str(excinfo.value) @@ -76,7 +76,7 @@ def test_get_all_candidate_licenses(foss: fossology.Fossology): def test_add_license_error( foss_server: str, foss: fossology.Fossology, test_license: License ): - responses.add(responses.POST, f"{foss_server}/api/v2/license", status=500) + responses.add(responses.POST, f"{foss_server}/api/v1/license", status=500) with pytest.raises(FossologyApiError) as excinfo: foss.add_license(test_license) assert f"Error while adding new license {test_license.shortName}" in str( @@ -93,7 +93,7 @@ def test_add_license_already_exists( ): mocked_logger = MagicMock() monkeypatch.setattr("fossology.license.logger", mocked_logger) - responses.add(responses.POST, f"{foss_server}/api/v2/license", status=409) + responses.add(responses.POST, f"{foss_server}/api/v1/license", status=409) foss.add_license(test_license) mocked_logger.info.assert_called_once() @@ -125,7 +125,7 @@ def test_patch_license_error( foss_server: str, foss: fossology.Fossology, test_license: License ): responses.add( - responses.PATCH, f"{foss_server}/api/v2/license/License-1.0", status=500 + responses.PATCH, f"{foss_server}/api/v1/license/License-1.0", status=500 ) with pytest.raises(FossologyApiError) as excinfo: foss.update_license(test_license.shortName) diff --git a/tests/test_report.py b/tests/test_report.py index 2ec7022..b3a25ad 100644 --- a/tests/test_report.py +++ b/tests/test_report.py @@ -51,11 +51,11 @@ def test_generate_report(foss: Fossology, upload: Upload): def test_report_error(foss_server: str, foss: Fossology, upload: Upload): responses.add( responses.GET, - f"{foss_server}/api/v2/report", + f"{foss_server}/api/v1/report", status=503, headers={"Retry-After": "1"}, ) - responses.add(responses.GET, f"{foss_server}/api/v2/report", status=404) + responses.add(responses.GET, f"{foss_server}/api/v1/report", status=404) with pytest.raises(FossologyApiError) as excinfo: foss.generate_report(upload) assert f"Report generation for upload {upload.uploadname} failed" in str( @@ -68,7 +68,7 @@ def test_download_report_error(foss_server: str, foss: Fossology): report_id = secrets.randbelow(1000) responses.add( responses.GET, - f"{foss_server}/api/v2/report/{report_id}", + f"{foss_server}/api/v1/report/{report_id}", status=500, ) with pytest.raises(FossologyApiError) as excinfo: @@ -81,7 +81,7 @@ def test_download_report_filename_without_quotes(foss_server: str, foss: Fossolo report_id = "1" responses.add( responses.GET, - f"{foss_server}/api/v2/report/{report_id}", + f"{foss_server}/api/v1/report/{report_id}", status=200, headers={"Content-Disposition": "attachment; filename=Report_FileName.docx"}, ) @@ -94,7 +94,7 @@ def test_download_report_filename_with_quotes(foss_server: str, foss: Fossology) report_id = "1" responses.add( responses.GET, - f"{foss_server}/api/v2/report/{report_id}", + f"{foss_server}/api/v1/report/{report_id}", status=200, headers={"Content-Disposition": 'attachment; filename="Report_FileName.docx"'}, ) @@ -107,7 +107,7 @@ def test_download_report_filename_with_single_quotes(foss_server: str, foss: Fos report_id = "1" responses.add( responses.GET, - f"{foss_server}/api/v2/report/{report_id}", + f"{foss_server}/api/v1/report/{report_id}", status=200, headers={"Content-Disposition": "attachment; filename='Report_FileName.docx'"}, ) diff --git a/tests/test_search.py b/tests/test_search.py index 182061f..2e5a389 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -74,7 +74,7 @@ def test_search_upload_does_not_exist(foss: Fossology): @responses.activate def test_search_error(foss_server: str, foss: Fossology): - responses.add(responses.GET, f"{foss_server}/api/v2/search", status=404) + responses.add(responses.GET, f"{foss_server}/api/v1/search", status=404) with pytest.raises(FossologyApiError) as excinfo: foss.search() assert "Unable to get a result with the given search criteria" in str(excinfo.value) @@ -108,7 +108,7 @@ def test_filesearch_nogroup(foss: Fossology): @responses.activate def test_filesearch_error(foss_server: str, foss: Fossology): - responses.add(responses.POST, f"{foss_server}/api/v2/filesearch", status=404) + responses.add(responses.POST, f"{foss_server}/api/v1/filesearch", status=404) with pytest.raises(FossologyApiError) as excinfo: foss.filesearch() assert "Unable to get a result with the given filesearch criteria" in str( diff --git a/tests/test_upload_licenses_copyrights.py b/tests/test_upload_licenses_copyrights.py index 6e019ec..95d0a18 100644 --- a/tests/test_upload_licenses_copyrights.py +++ b/tests/test_upload_licenses_copyrights.py @@ -51,7 +51,7 @@ def test_upload_licenses_with_unknown_group_raises_authorization_error( def test_upload_licenses_412_error(foss: Fossology, foss_server: str, upload: Upload): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload.id}/licenses", + f"{foss_server}/api/v1/uploads/{upload.id}/licenses", status=412, ) with pytest.raises(FossologyApiError) as excinfo: @@ -66,7 +66,7 @@ def test_upload_licenses_412_error(foss: Fossology, foss_server: str, upload: Up def test_upload_licenses_503_error(foss: Fossology, foss_server: str, upload: Upload): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload.id}/licenses", + f"{foss_server}/api/v1/uploads/{upload.id}/licenses", status=503, ) with pytest.raises(RetryError): @@ -77,7 +77,7 @@ def test_upload_licenses_503_error(foss: Fossology, foss_server: str, upload: Up def test_upload_licenses_500_error(foss: Fossology, foss_server: str, upload: Upload): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload.id}/licenses", + f"{foss_server}/api/v1/uploads/{upload.id}/licenses", status=500, ) with pytest.raises(FossologyApiError) as excinfo: @@ -97,7 +97,7 @@ def test_upload_copyrights(foss: Fossology, upload_with_jobs: Upload): def test_upload_copyrights_403_error(foss: Fossology, foss_server: str, upload: Upload): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload.id}/copyrights", + f"{foss_server}/api/v1/uploads/{upload.id}/copyrights", status=403, ) with pytest.raises(AuthorizationError) as excinfo: @@ -112,7 +112,7 @@ def test_upload_copyrights_403_error(foss: Fossology, foss_server: str, upload: def test_upload_copyrights_412_error(foss: Fossology, foss_server: str, upload: Upload): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload.id}/copyrights", + f"{foss_server}/api/v1/uploads/{upload.id}/copyrights", status=412, ) with pytest.raises(FossologyApiError) as excinfo: @@ -127,7 +127,7 @@ def test_upload_copyrights_412_error(foss: Fossology, foss_server: str, upload: def test_upload_copyrights_503_error(foss: Fossology, foss_server: str, upload: Upload): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload.id}/copyrights", + f"{foss_server}/api/v1/uploads/{upload.id}/copyrights", status=503, ) with pytest.raises(RetryError): @@ -138,7 +138,7 @@ def test_upload_copyrights_503_error(foss: Fossology, foss_server: str, upload: def test_upload_copyrights_500_error(foss: Fossology, foss_server: str, upload: Upload): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload.id}/copyrights", + f"{foss_server}/api/v1/uploads/{upload.id}/copyrights", status=500, ) with pytest.raises(FossologyApiError) as excinfo: diff --git a/tests/test_upload_permissions.py b/tests/test_upload_permissions.py index 5a28e31..d1f3722 100644 --- a/tests/test_upload_permissions.py +++ b/tests/test_upload_permissions.py @@ -58,7 +58,7 @@ def test_get_upload_permissions_if_api_returns_403_raises_authorization_error( ): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload.id}/perm-groups", + f"{foss_server}/api/v1/uploads/{upload.id}/perm-groups", status=403, ) with pytest.raises(AuthorizationError) as excinfo: @@ -74,7 +74,7 @@ def test_get_upload_permissions_if_api_returns_500_raises_fossology_error( ): responses.add( responses.GET, - f"{foss_server}/api/v2/uploads/{upload.id}/perm-groups", + f"{foss_server}/api/v1/uploads/{upload.id}/perm-groups", status=500, ) with pytest.raises(FossologyApiError) as excinfo: @@ -108,7 +108,7 @@ def test_change_upload_permissions_if_api_returns_400_raises_fossology_error( ): responses.add( responses.PUT, - f"{foss_server}/api/v2/uploads/{upload.id}/permissions", + f"{foss_server}/api/v1/uploads/{upload.id}/permissions", status=400, ) with pytest.raises(FossologyApiError) as excinfo: @@ -124,7 +124,7 @@ def test_change_upload_permissions_if_api_returns_403_raises_authorization_error ): responses.add( responses.PUT, - f"{foss_server}/api/v2/uploads/{upload.id}/permissions", + f"{foss_server}/api/v1/uploads/{upload.id}/permissions", status=403, ) with pytest.raises(AuthorizationError) as excinfo: @@ -140,7 +140,7 @@ def test_change_upload_permissions_if_api_returns_500_raises_fossology_error( ): responses.add( responses.PUT, - f"{foss_server}/api/v2/uploads/{upload.id}/permissions", + f"{foss_server}/api/v1/uploads/{upload.id}/permissions", status=500, ) with pytest.raises(FossologyApiError) as excinfo: @@ -157,7 +157,7 @@ def test_change_upload_permissions_if_api_returns_503_raises_fossology_error( ): responses.add( responses.PUT, - f"{foss_server}/api/v2/uploads/{upload.id}/permissions", + f"{foss_server}/api/v1/uploads/{upload.id}/permissions", status=503, ) with pytest.raises(FossologyApiError) as excinfo: diff --git a/tests/test_uploads.py b/tests/test_uploads.py index 5a2c695..c9d4db3 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -43,6 +43,44 @@ def test_upload(upload: Upload): ) +def test_upload_for_group(foss: Fossology, test_file_path: str): + foss.create_group("upload_access") + groups = foss.list_groups() + group_access = [group for group in groups if group.name == "upload_access"][0] + upload = foss.upload_file( + foss.rootFolder, + file=test_file_path, + description="Test upload via fossology-python lib", + access_level=AccessLevel.PUBLIC, + group="upload_access", + wait_time=5, + ) + assert upload.uploadname == "base-files_11.tar.xz" + uploads = foss.list_uploads(group="upload_access") + assert uploads[0][0].uploadname == "base-files_11.tar.xz" + foss.delete_upload(upload) + foss.delete_group(group_access.id) + + +def test_upload_for_group_v2(foss_v2: Fossology, test_file_path: str): + foss_v2.create_group("upload_access") + groups = foss_v2.list_groups() + group_access = [group for group in groups if group.name == "upload_access"][0] + upload = foss_v2.upload_file( + foss_v2.rootFolder, + file=test_file_path, + description="Test upload via fossology-python lib", + access_level=AccessLevel.PUBLIC, + group="upload_access", + wait_time=5, + ) + assert upload.uploadname == "base-files_11.tar.xz" + uploads = foss_v2.list_uploads(group="upload_access") + assert uploads[0][0].uploadname == "base-files_11.tar.xz" + foss_v2.delete_upload(upload) + foss_v2.delete_group(group_access.id) + + def test_upload_v2(upload_v2: Upload): assert upload_v2.uploadname == "base-files_11.tar.xz" assert upload_v2.hash.sha1 == "D4D663FC2877084362FB2297337BE05684869B00" diff --git a/tests/test_users.py b/tests/test_users.py index 559cbf8..72e9b0e 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -50,7 +50,7 @@ def test_generate_token_too_long(foss_server: str): def test_generate_token_if_receiving_connection_error_exits(foss_server: str): responses.add( responses.POST, - f"{foss_server}/api/v2/tokens", + f"{foss_server}/api/v1/tokens", body=requests.exceptions.ConnectionError("Test Exception"), ) with pytest.raises(SystemExit) as excinfo: @@ -73,7 +73,7 @@ def test_generate_token_if_receiving_authentication_error_raises_api_error_( ): responses.add( responses.POST, - f"{foss_server}/api/v2/tokens", + f"{foss_server}/api/v1/tokens", status=404, ) with pytest.raises(AuthenticationError) as excinfo: @@ -104,7 +104,7 @@ def test_list_users(foss: Fossology): def test_get_self_error(foss_server: str, foss: Fossology): responses.add( responses.GET, - f"{foss_server}/api/v2/users/self", + f"{foss_server}/api/v1/users/self", status=500, ) with pytest.raises(FossologyApiError): @@ -117,7 +117,7 @@ def test_get_self_with_agents( ): user = foss_user responses.add( - responses.GET, f"{foss_server}/api/v2/users/self", status=200, json=user + responses.GET, f"{foss_server}/api/v1/users/self", status=200, json=user ) user_from_api = foss.get_self() assert user_from_api.agents.to_dict() == foss_user_agents @@ -129,7 +129,7 @@ def test_detail_user_with_agents( ): user = foss_user responses.add( - responses.GET, f"{foss_server}/api/v2/users/{user['id']}", status=200, json=user + responses.GET, f"{foss_server}/api/v1/users/{user['id']}", status=200, json=user ) user_from_api = foss.detail_user(user["id"]) assert user_from_api.agents.to_dict() == foss_user_agents @@ -140,14 +140,14 @@ def test_list_users_with_agents( foss_server: str, foss: Fossology, foss_user: dict, foss_user_agents: dict ): users = [foss_user] - responses.add(responses.GET, f"{foss_server}/api/v2/users", status=200, json=users) + responses.add(responses.GET, f"{foss_server}/api/v1/users", status=200, json=users) users_from_api = foss.list_users() assert users_from_api[0].agents.to_dict() == foss_user_agents @responses.activate def test_list_users_error(foss_server: str, foss: Fossology): - responses.add(responses.GET, f"{foss_server}/api/v2/users", status=404) + responses.add(responses.GET, f"{foss_server}/api/v1/users", status=404) with pytest.raises(FossologyApiError) as excinfo: foss.list_users() assert f"Unable to get a list of users from {foss_server}" in str(excinfo.value) @@ -164,8 +164,8 @@ def test_detail_user(foss: Fossology): @responses.activate def test_delete_user(foss_server: str, foss: Fossology): user = Mock(name="Test User", id=secrets.randbelow(1000)) - responses.add(responses.DELETE, f"{foss_server}/api/v2/users/{user.id}", status=202) - responses.add(responses.DELETE, f"{foss_server}/api/v2/users/{user.id}", status=404) + responses.add(responses.DELETE, f"{foss_server}/api/v1/users/{user.id}", status=202) + responses.add(responses.DELETE, f"{foss_server}/api/v1/users/{user.id}", status=404) assert not foss.delete_user(user) with pytest.raises(FossologyApiError) as excinfo: foss.delete_user(user) From 4ae209cd65ef9aaeb87ed279b50fab0d47aa2e45 Mon Sep 17 00:00:00 2001 From: Marion Deveaud Date: Thu, 4 Apr 2024 16:53:50 +0200 Subject: [PATCH 3/4] chore(types): fix type check errors --- fossology/uploads.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fossology/uploads.py b/fossology/uploads.py index 119ac67..6cdd901 100644 --- a/fossology/uploads.py +++ b/fossology/uploads.py @@ -237,7 +237,7 @@ def upload_file( :raises FossologyApiError: if the REST call failed :raises AuthorizationError: if the REST call is not authorized """ - data = { + data: dict = { "folderId": str(folder.id), "uploadDescription": description, "public": access_level.value @@ -270,14 +270,13 @@ def upload_file( ) elif vcs or url or server: if vcs: - data["location"] = vcs - print(data) + data["location"] = vcs # type: ignore data["uploadType"] = headers["uploadType"] = "vcs" elif url: - data["location"] = url + data["location"] = url # type: ignore data["uploadType"] = headers["uploadType"] = "url" elif server: - data["location"] = server + data["location"] = server # type: ignore data["uploadType"] = headers["uploadType"] = "server" headers["Content-Type"] = "application/json" response = self.session.post( From 91c9ca69dafc0e084f0e4393eaf0ec03fb0c9b43 Mon Sep 17 00:00:00 2001 From: Marion Deveaud Date: Thu, 4 Apr 2024 17:13:36 +0200 Subject: [PATCH 4/4] chore(image): test against latest fossology build --- .github/workflows/fossologytests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/fossologytests.yml b/.github/workflows/fossologytests.yml index 038829c..2984774 100644 --- a/.github/workflows/fossologytests.yml +++ b/.github/workflows/fossologytests.yml @@ -10,7 +10,7 @@ on: jobs: test-latest: - name: Integration Tests (latest Fossology - 4.4.0-rc2) + name: Integration Tests (Fossology - Latest) runs-on: ubuntu-latest container: @@ -20,7 +20,7 @@ jobs: services: fossology: - image: fossology/fossology:4.4.0-rc2 + image: fossology/fossology:latest ports: - 8081:80 volumes: