diff --git a/pyproject.toml b/pyproject.toml index 88bd1d41..b08273ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,7 +64,6 @@ dev = [ "pytest-cov>=4", "pytest-mock>=3.10.0,<4", "responses>=0.23.1", - "parameterized>=0.9.0,<1", "mypy>=1.5.1,<2", "types-requests>=2.29.0.0,<3", ] @@ -118,5 +117,11 @@ namespace_packages = true explicit_package_bases = true [[tool.mypy.overrides]] -module = ["parameterized", "rich", "attr"] +module = ["rich", "attr"] ignore_missing_imports = true + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = "--cov -rs" +filterwarnings = ["ignore:.*:DeprecationWarning:.*"] +python_classes = ["Test*", "*Tests", "*Test"] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index e72d8a52..00000000 --- a/pytest.ini +++ /dev/null @@ -1,9 +0,0 @@ -[pytest] -testpaths = tests -# Ignore warnings for deprecation -addopts = --cov -rs -filterwarnings= - ; https://docs.python.org/3/library/warnings.html#warning-filter - ; action:message:category:module:line - ; Disable warnings from 3rd party modules - ignore:.*:DeprecationWarning:.* diff --git a/tests/asm/test_api.py b/tests/asm/test_api.py index 1940944f..134832aa 100644 --- a/tests/asm/test_api.py +++ b/tests/asm/test_api.py @@ -3,7 +3,6 @@ import pytest import responses -from parameterized import parameterized from pytest_mock import MockerFixture from requests.models import Response @@ -20,12 +19,6 @@ class CensysAPIBaseTestsNoAsmEnv(unittest.TestCase): @pytest.fixture(autouse=True) def __inject_fixtures(self, mocker: MockerFixture): - """Injects fixtures into the test case. - - Args: - mocker (MockerFixture): pytest-mock fixture. - """ - # Inject mocker fixture self.mocker = mocker def setUp(self): @@ -43,14 +36,14 @@ def test_no_env(self): CensysAsmAPI() -class CensysAsmAPITests(CensysTestCase): - AsmExceptionParams = [(code, exception) for code, exception in CensysExceptionMapper.ASM_EXCEPTIONS.items()] +AsmExceptionParams = [(code, exception) for code, exception in CensysExceptionMapper.ASM_EXCEPTIONS.items()] - def setUp(self): - super().setUp() + +class CensysAsmAPITests(CensysTestCase): + def setup_method(self): self.setUpApi(CensysAsmAPI(self.api_id)) - @parameterized.expand(AsmExceptionParams) + @pytest.mark.parametrize(("status_code", "exception"), AsmExceptionParams) def test_get_exception_class(self, status_code, exception): # Mock mock_response = self.mocker.patch("requests.models.Response.json") @@ -73,7 +66,7 @@ def test_exception_repr(self): repr(exception) == "404 (Error Code: 10014), Unable to Find Seed. [{id: 999}]" # noqa: FS003 ) - @parameterized.expand([("assets")]) + @pytest.mark.parametrize("keyword", ["assets"]) def test_page_keywords(self, keyword): # Mock page_json = { diff --git a/tests/asm/test_assets.py b/tests/asm/test_assets.py index e920fea1..69dc11e3 100644 --- a/tests/asm/test_assets.py +++ b/tests/asm/test_assets.py @@ -1,8 +1,6 @@ -import unittest from urllib.parse import quote import pytest -from parameterized import parameterized_class from pytest_mock import MockerFixture from censys.asm.client import AsmClient @@ -32,37 +30,30 @@ TEST_TAG_COLOR = "#4287f5" TEST_INVALID_TAG_COLOR = "4287f5" +ASSET_PARAMS = [ + ("hosts", "3.12.122.3"), + ( + "certificates", + "0006afc1ddc8431aa57c812adf028ab4f168b25bf5f06e94af86edbafa88dfe0", + ), + ("domains", "amazonaws.com"), + ("subdomains", "s3.amazonaws.com"), + ("web_entities", "www.amazon.com:443"), + ("object_storages", "https://censys-python.s3.us-east-2.amazonaws.com/"), +] -@parameterized_class( - ("asset_type", "test_asset_id"), - [ - ("hosts", "3.12.122.3"), - ( - "certificates", - "0006afc1ddc8431aa57c812adf028ab4f168b25bf5f06e94af86edbafa88dfe0", - ), - ("domains", "amazonaws.com"), - ("subdomains", "s3.amazonaws.com"), - ("web_entities", "www.amazon.com:443"), - ("object_storages", "https://censys-python.s3.us-east-2.amazonaws.com/"), - ], -) -class AssetsUnitTest(unittest.TestCase): - @pytest.fixture(autouse=True) - def __inject_fixtures(self, mocker: MockerFixture): - """Injects fixtures into the test case. - - Args: - mocker (MockerFixture): pytest-mock fixture. - """ - # Inject mocker fixture - self.mocker = mocker +class AssetsUnitTest: """Unit tests for Host, Certificate, and Domain APIs.""" - def setUp(self): + @pytest.fixture(autouse=True, params=ASSET_PARAMS, ids=[p[0] for p in ASSET_PARAMS]) + def _setup(self, request, mocker: MockerFixture): + self.asset_type, self.test_asset_id = request.param + self.mocker = mocker + mocker.patch("time.sleep", return_value=None) self.client = AsmClient() self.resource_type = ASSET_TYPE if self.asset_type != "subdomains" else SUBDOMAIN_ASSET_TYPE + return def get_asset_accessor(self): return getattr(self.client, self.asset_type) diff --git a/tests/asm/test_beta.py b/tests/asm/test_beta.py index 93cf27ca..9e419626 100644 --- a/tests/asm/test_beta.py +++ b/tests/asm/test_beta.py @@ -62,8 +62,7 @@ class BetaUnitTest(CensysTestCase): - def setUp(self): - super().setUp() + def setup_method(self): self.client = Beta(self.api_key) def test_get_logbook_data(self): diff --git a/tests/asm/test_clouds.py b/tests/asm/test_clouds.py index 835e7c3e..9de0a9aa 100644 --- a/tests/asm/test_clouds.py +++ b/tests/asm/test_clouds.py @@ -15,8 +15,7 @@ class CloudsUnitTest(CensysTestCase): - def setUp(self): - super().setUp() + def setup_method(self): self.client = AsmClient(self.api_key) def test_get_host_counts(self): diff --git a/tests/asm/test_inventory.py b/tests/asm/test_inventory.py index cc323c52..3ebed7ab 100644 --- a/tests/asm/test_inventory.py +++ b/tests/asm/test_inventory.py @@ -1,5 +1,5 @@ +import pytest import responses -from parameterized import parameterized from censys.asm.inventory import InventorySearch @@ -36,11 +36,11 @@ class InventoryTests(CensysTestCase): api: InventorySearch - def setUp(self): - super().setUp() + def setup_method(self): self.setUpApi(InventorySearch(self.api_key)) - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "params"), [ ( { @@ -59,7 +59,7 @@ def setUp(self): }, "?workspaces=1&workspaces=2&query=test&pageSize=50", ), - ] + ], ) def test_search(self, kwargs, params): mock_request = self.mocker.patch("censys.asm.api.CensysAsmAPI.get_workspace_id") @@ -79,21 +79,20 @@ def test_search(self, kwargs, params): # Assertions assert res == TEST_INVENTORY_SEARCH_JSON - @parameterized.expand( + @pytest.mark.parametrize( + "kwargs", [ - ( - { - "workspaces": ["1", "2"], - "query": "test", - "aggregation": { - "field": "test", - "size": 50, - "sort": "test", - "order": "test", - }, + { + "workspaces": ["1", "2"], + "query": "test", + "aggregation": { + "field": "test", + "size": 50, + "sort": "test", + "order": "test", }, - ), - ] + }, + ], ) def test_aggregate(self, kwargs): # Setup response @@ -111,7 +110,8 @@ def test_aggregate(self, kwargs): # Assertions assert res == TEST_INVENTORY_AGGREGATE_JSON - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "params"), [ ( { @@ -119,7 +119,7 @@ def test_aggregate(self, kwargs): }, "?fields=host.services.name&fields=host.services.port", ), - ] + ], ) def test_fields(self, kwargs, params): # Setup response diff --git a/tests/asm/test_risks.py b/tests/asm/test_risks.py index f831336d..0d7eefe0 100644 --- a/tests/asm/test_risks.py +++ b/tests/asm/test_risks.py @@ -1,7 +1,7 @@ import urllib.parse +import pytest import responses -from parameterized import parameterized from responses import matchers from censys.asm.risks import Risks @@ -76,11 +76,11 @@ class RisksTests(CensysTestCase): api: Risks - def setUp(self): - super().setUp() + def setup_method(self): self.setUpApi(Risks(self.api_key)) - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "params"), [ ({}, ""), ( @@ -92,7 +92,7 @@ def setUp(self): {"cursor": "eyJhZnRlcklEIjo3NzQwLCJsaW1pdCI6MTAwfQ=="}, "?cursor=eyJhZnRlcklEIjo3NzQwLCJsaW1pdCI6MTAwfQ==", ), - ] + ], ) def test_get_risk_events(self, kwargs, params): # Setup response @@ -107,12 +107,13 @@ def test_get_risk_events(self, kwargs, params): # Assertions assert res == TEST_RISK_EVENTS_JSON - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "params"), [ ({}, ""), ({"include_events": True}, "?includeEvents=True"), ({"include_events": False}, "?includeEvents=False"), - ] + ], ) def test_get_risk_instances(self, kwargs, params): # Setup response @@ -174,12 +175,13 @@ def test_search_risk_instances(self): # Assertions assert res == TEST_RISK_TYPE_JSON - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "params"), [ ({"risk_instance_id": 0}, "0"), ({"risk_instance_id": 1, "include_events": True}, "1?includeEvents=True"), ({"risk_instance_id": 2, "include_events": False}, "2?includeEvents=False"), - ] + ], ) def test_get_risk_instance(self, kwargs, params): # Setup response @@ -215,7 +217,8 @@ def test_patch_risk_instance(self): # Assertions assert res == TEST_PATCH_RISK_INSTANCE_JSON - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "params"), [ ({}, ""), ({"include_events": True}, "?includeEvents=True"), @@ -223,7 +226,7 @@ def test_patch_risk_instance(self): ({"sort": ["severity", "type:asc"]}, "?sort=severity&sort=type:asc"), ({"page": 1, "limit": 10000}, "?page=1&limit=10000"), ({"page": 10}, "?page=10"), - ] + ], ) def test_get_risk_types(self, kwargs, params): # Setup response @@ -238,7 +241,8 @@ def test_get_risk_types(self, kwargs, params): # Assertions assert res == TEST_RISK_TYPES_JSON - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "params"), [ ({"risk_type": TEST_RISK_TYPE}, ESCAPED_TEST_RISK_TYPE), ( @@ -249,7 +253,7 @@ def test_get_risk_types(self, kwargs, params): {"risk_type": TEST_RISK_TYPE, "include_events": False}, ESCAPED_TEST_RISK_TYPE + "?includeEvents=False", ), - ] + ], ) def test_get_risk_type(self, kwargs, params): # Setup respnonse diff --git a/tests/asm/test_saved_queries.py b/tests/asm/test_saved_queries.py index 43fad5b6..9a98654a 100644 --- a/tests/asm/test_saved_queries.py +++ b/tests/asm/test_saved_queries.py @@ -1,5 +1,5 @@ +import pytest import responses -from parameterized import parameterized from censys.asm.saved_queries import SavedQueries @@ -53,11 +53,11 @@ class SavedQueriesTests(CensysTestCase): api: SavedQueries - def setUp(self): - super().setUp() + def setup_method(self): self.setUpApi(SavedQueries(self.api_key)) - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "params"), [ ( { @@ -101,7 +101,7 @@ def setUp(self): "?queryNamePrefix=test-query-name-prefix-6&pageSize=50&page=1", ), ({}, "?pageSize=50&page=1"), - ] + ], ) def test_get_saved_queries(self, kwargs, params): # Setup response @@ -118,13 +118,14 @@ def test_get_saved_queries(self, kwargs, params): # Assertions assert res == TEST_GET_SAVED_QUERIES_JSON - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "body"), [ ( {"query": "test-query-1", "query_name": "test-query-name-1"}, {"query": "test-query-1", "queryName": "test-query-name-1"}, ), - ] + ], ) def test_add_saved_query(self, kwargs, body): # Setup response @@ -142,10 +143,11 @@ def test_add_saved_query(self, kwargs, body): # Assertions assert res == TEST_ADD_SAVED_QUERY_JSON - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "path"), [ ({"query_id": "test-query-id-1"}, "/test-query-id-1"), - ] + ], ) def test_get_saved_query_by_id(self, kwargs, path): # Setup response @@ -162,7 +164,8 @@ def test_get_saved_query_by_id(self, kwargs, path): # Assertions assert res == TEST_GET_SAVED_QUERY_BY_ID_JSON - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "body", "path"), [ ( { @@ -173,7 +176,7 @@ def test_get_saved_query_by_id(self, kwargs, path): {"query": "test-query-1", "queryName": "test-query-name-1"}, "/test-query-id-1", ), - ] + ], ) def test_edit_saved_query_by_id(self, kwargs, body, path): # Setup response @@ -191,10 +194,11 @@ def test_edit_saved_query_by_id(self, kwargs, body, path): # Assertions assert res == TEST_EDIT_SAVED_QUERY_BY_ID_JSON - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "path"), [ ({"query_id": "test-query-id-1"}, "/test-query-id-1"), - ] + ], ) def test_delete_saved_query_by_id(self, kwargs, path): # Setup response diff --git a/tests/cli/test_asm.py b/tests/cli/test_asm.py index f584cfbd..dcb64b38 100644 --- a/tests/cli/test_asm.py +++ b/tests/cli/test_asm.py @@ -244,9 +244,6 @@ class CensysASMCliTest(CensysTestCase): - def setUp(self): - super().setUp() - def test_add_seeds(self): # Mock self.patch_args(["censys", "asm", "add-seeds", "-j", json.dumps(SEEDS_JSON)], asm_auth=True) diff --git a/tests/cli/test_config.py b/tests/cli/test_config.py index 85b05ed2..e6d952e5 100644 --- a/tests/cli/test_config.py +++ b/tests/cli/test_config.py @@ -4,6 +4,7 @@ import pytest import responses +from pytest_mock import MockerFixture from censys.cli import main as cli_main from censys.common.config import ( @@ -38,17 +39,17 @@ def confirm_side_effect(arg, **kwargs): class CensysConfigCliTest(CensysTestCase): - def setUp(self): - super().setUp() - self.mocker.patch("censys.common.config.CONFIG_PATH", TEST_CONFIG_PATH) - self.mock_open = self.mocker.patch( + @pytest.fixture(autouse=True) + def _config_setup(self, mocker: MockerFixture): + mocker.patch("censys.common.config.CONFIG_PATH", TEST_CONFIG_PATH) + self.mock_open = mocker.patch( "builtins.open", - new_callable=self.mocker.mock_open, + new_callable=mocker.mock_open, read_data="[DEFAULT]\napi_id =\napi_secret =\nasm_api_key =", ) - self.mocker.patch("rich.prompt.Prompt.ask", side_effect=prompt_side_effect) - self.mocker.patch("rich.prompt.Confirm.ask", side_effect=confirm_side_effect) - self.mock_chmod = self.mocker.patch("censys.common.config._try_chmod") + mocker.patch("rich.prompt.Prompt.ask", side_effect=prompt_side_effect) + mocker.patch("rich.prompt.Confirm.ask", side_effect=confirm_side_effect) + self.mock_chmod = mocker.patch("censys.common.config._try_chmod") def test_search_config(self): # Mock diff --git a/tests/cli/test_hnri.py b/tests/cli/test_hnri.py index ae19f354..de241e83 100644 --- a/tests/cli/test_hnri.py +++ b/tests/cli/test_hnri.py @@ -15,8 +15,7 @@ class CensysCliHNRITest(CensysTestCase): IPIFY_URL = "https://api.ipify.org?format=json" IP_ADDRESS = "8.8.8.8" - def setUp(self): - super().setUp() + def setup_method(self): self.api = CensysHNRI(self.api_id, self.api_secret) def test_hnri_medium(self): diff --git a/tests/cli/test_search.py b/tests/cli/test_search.py index edb23f7d..411ab897 100644 --- a/tests/cli/test_search.py +++ b/tests/cli/test_search.py @@ -9,7 +9,6 @@ import pytest import responses -from parameterized import parameterized from requests import PreparedRequest from responses import matchers @@ -326,11 +325,12 @@ def test_write_csv_fail(self): ): cli_main() - @parameterized.expand( + @pytest.mark.parametrize( + ("status_code", "json_response"), [ (429, TOO_MANY_REQUESTS_ERROR_JSON), (500, SERVER_ERROR_JSON), - ] + ], ) def test_midway_fail(self, status_code: int, json_response: dict): # Setup response @@ -451,19 +451,20 @@ def test_open_hosts(self): f"https://search.censys.io/search?{query_str}" # noqa: E231 ) - @parameterized.expand( + @pytest.mark.parametrize( + ("index_type", "autocomplete_file", "prefix"), [ - ("hosts", HOSTS_AUTOCOMPLETE), + ("hosts", HOSTS_AUTOCOMPLETE, ""), ("hosts", HOSTS_AUTOCOMPLETE, "service"), - ("certificates", CERTIFICATES_AUTOCOMPLETE), - ("invalid"), - ] + ("certificates", CERTIFICATES_AUTOCOMPLETE, ""), + ("invalid", None, ""), + ], ) def test_fields_completer( self, index_type: str, - autocomplete_file: Optional[Path] = None, - prefix: str = "", + autocomplete_file: Optional[Path], + prefix: str, ): parsed_args = argparse.Namespace(index_type=index_type) if autocomplete_file is None: diff --git a/tests/cli/test_subdomains.py b/tests/cli/test_subdomains.py index cb74fe6d..a5f4491b 100644 --- a/tests/cli/test_subdomains.py +++ b/tests/cli/test_subdomains.py @@ -1,8 +1,8 @@ import contextlib from io import StringIO +import pytest import responses -from parameterized import parameterized from censys.cli import main as cli_main from censys.cli.commands import subdomains @@ -25,11 +25,9 @@ class CensysCliSubdomainsTest(CensysTestCase): - @parameterized.expand( - [ - (True,), - (False,), - ] + @pytest.mark.parametrize( + "test_json_bool", + [True, False], ) def test_print_subdomains( self, diff --git a/tests/cli/test_utils.py b/tests/cli/test_utils.py index d97b9721..797eb082 100644 --- a/tests/cli/test_utils.py +++ b/tests/cli/test_utils.py @@ -2,18 +2,18 @@ from datetime import datetime import pytest -from parameterized import parameterized from censys.cli.utils import valid_datetime_type from tests.utils import CensysTestCase class CensysCliUtilsTest(CensysTestCase): - @parameterized.expand( + @pytest.mark.parametrize( + ("string", "expected"), [ - ["2021-05-20", datetime(2021, 5, 20)], - ["2021-05-20 12:00", datetime(2021, 5, 20, 12, 00)], - ] + ("2021-05-20", datetime(2021, 5, 20)), + ("2021-05-20 12:00", datetime(2021, 5, 20, 12, 00)), + ], ) def test_valid_datetime(self, string, expected): # Actual call @@ -21,11 +21,12 @@ def test_valid_datetime(self, string, expected): # Assertions assert actual == expected - @parameterized.expand( + @pytest.mark.parametrize( + "string", [ - ["2021/05/20"], - ["2021/05/20 12:00"], - ] + "2021/05/20", + "2021/05/20 12:00", + ], ) def test_invalid_datetime(self, string): # Actuall call/error raising diff --git a/tests/search/v1/test_api.py b/tests/search/v1/test_api.py index 3288f508..67be16c3 100644 --- a/tests/search/v1/test_api.py +++ b/tests/search/v1/test_api.py @@ -3,7 +3,6 @@ import pytest import responses -from parameterized import parameterized from requests.models import Response from censys.common.exceptions import ( @@ -26,8 +25,7 @@ class CensysSearchAPITests(CensysTestCase): - def setUp(self): - super().setUp() + def setup_method(self): self.setUpApi(CensysSearchAPIv1(self.api_id, self.api_secret)) def test_account(self): @@ -52,7 +50,7 @@ def test_quota(self): assert res == ACCOUNT_JSON["quota"] - @parameterized.expand(SearchExceptionParams) + @pytest.mark.parametrize(("status_code", "exception"), SearchExceptionParams) def test_get_exception_class(self, status_code, exception): response = Response() response.status_code = status_code diff --git a/tests/search/v1/test_data.py b/tests/search/v1/test_data.py index 571e4902..b910e93a 100644 --- a/tests/search/v1/test_data.py +++ b/tests/search/v1/test_data.py @@ -20,8 +20,7 @@ class CensysDataTest(CensysTestCase): - def setUp(self): - super().setUp() + def setup_method(self): self.setUpApi(SearchClient(self.api_id, self.api_secret).v1.data) def test_get_series(self): diff --git a/tests/search/v2/test_api.py b/tests/search/v2/test_api.py index 55e6955d..3b17571a 100644 --- a/tests/search/v2/test_api.py +++ b/tests/search/v2/test_api.py @@ -3,7 +3,6 @@ import pytest import responses -from parameterized import parameterized from requests.models import Response from censys.common.exceptions import CensysException, CensysExceptionMapper @@ -17,11 +16,10 @@ class CensysSearchAPITests(CensysTestCase): api: CensysSearchAPIv2 - def setUp(self): - super().setUp() + def setup_method(self): self.setUpApi(CensysSearchAPIv2(self.api_id, self.api_secret)) - @parameterized.expand(SearchExceptionParams) + @pytest.mark.parametrize(("status_code", "exception"), SearchExceptionParams) def test_get_exception_class(self, status_code, exception): response = Response() response.status_code = status_code diff --git a/tests/search/v2/test_certs.py b/tests/search/v2/test_certs.py index 4ebf6dc3..7867c04d 100644 --- a/tests/search/v2/test_certs.py +++ b/tests/search/v2/test_certs.py @@ -1,8 +1,8 @@ from datetime import datetime from typing import Any, Optional +import pytest import responses -from parameterized import parameterized from responses import matchers from censys.search import SearchClient @@ -202,8 +202,7 @@ class TestCerts(CensysTestCase): - def setUp(self): - super().setUp() + def setup_method(self): self.setUpApi(SearchClient(self.api_id, self.api_secret).v2.certs) def test_view(self): @@ -216,13 +215,7 @@ def test_view(self): result = self.api.view(TEST_CERT) assert result == VIEW_CERT_JSON["result"] - @parameterized.expand( - [ - ("bulk_post"), - ("bulk"), - ("bulk_view"), - ] - ) + @pytest.mark.parametrize("method_name", ["bulk_post", "bulk", "bulk_view"]) def test_bulk_post(self, method_name: str): self.responses.add( responses.POST, @@ -259,14 +252,15 @@ def test_bulk_get_single(self): result = self.api.bulk_get(TEST_CERT) assert result == BULK_VIEW_CERTS_JSON["result"] - @parameterized.expand( + @pytest.mark.parametrize( + ("method_name", "raw"), [ ("search_post_raw", True), ("raw_search", True), - ("search_post"), - ] + ("search_post", False), + ], ) - def test_search_post(self, method_name: str, raw: bool = False): + def test_search_post(self, method_name: str, raw: bool): self.responses.add( responses.POST, f"{V2_URL}/certificates/search", @@ -280,7 +274,8 @@ def test_search_post(self, method_name: str, raw: bool = False): else: assert result == SEARCH_CERTS_JSON["result"] - @parameterized.expand( + @pytest.mark.parametrize( + ("fields", "sort", "cursor"), [ (None, None, None), (["names", "fingerprint_sha256"], None, None), @@ -291,13 +286,13 @@ def test_search_post(self, method_name: str, raw: bool = False): None, ), (None, None, "nextCursorToken"), - ] + ], ) def test_search( self, - fields: Optional[list[str]] = None, - sort: Optional[list[str]] = None, - cursor: Optional[str] = None, + fields: Optional[list[str]], + sort: Optional[list[str]], + cursor: Optional[str], ): self.responses.add( responses.POST, @@ -308,7 +303,8 @@ def test_search( query = self.api.search(TEST_SEARCH_QUERY, fields=fields, sort=sort, cursor=cursor) assert next(query) == SEARCH_CERTS_JSON["result"]["hits"] - @parameterized.expand( + @pytest.mark.parametrize( + ("params", "expected_params"), [ ({}, {"q": TEST_SEARCH_QUERY, "per_page": 50}), ({"per_page": 1}, {"q": TEST_SEARCH_QUERY, "per_page": 1}), @@ -356,7 +352,7 @@ def test_search( "per_page": 50, }, ), - ] + ], ) def test_search_get(self, params: dict[str, Any], expected_params: dict[str, Any]): self.responses.add( diff --git a/tests/search/v2/test_comments.py b/tests/search/v2/test_comments.py index ef3cb1bc..30b2991f 100644 --- a/tests/search/v2/test_comments.py +++ b/tests/search/v2/test_comments.py @@ -1,5 +1,5 @@ +import pytest import responses -from parameterized import parameterized_class from censys.search.v2 import CensysCerts, CensysHosts from censys.search.v2.api import CensysSearchAPIv2 @@ -45,25 +45,27 @@ }, } +INDEX_PARAMS = [ + {"index": "hosts", "index_cls": CensysHosts, "document_id": "1.0.0.0"}, + { + "index": "certificates", + "index_cls": CensysCerts, + "document_id": "fb444eb8e68437bae06232b9f5091bccff62a768ca09e92eb5c9c2cf9d17c426", + }, +] + -@parameterized_class( - [ - {"index": "hosts", "index_cls": CensysHosts, "document_id": "1.0.0.0"}, - { - "index": "certificates", - "index_cls": CensysCerts, - "document_id": "fb444eb8e68437bae06232b9f5091bccff62a768ca09e92eb5c9c2cf9d17c426", - }, - ] -) class CensysCommentsTests(CensysTestCase): index: str index_cls: CensysSearchAPIv2 document_id: str api: CensysSearchAPIv2 - def setUp(self): - super().setUp() + @pytest.fixture(autouse=True, params=INDEX_PARAMS, ids=["hosts", "certificates"]) + def _index_config(self, request): + self.index = request.param["index"] + self.index_cls = request.param["index_cls"] + self.document_id = request.param["document_id"] self.setUpApi(self.index_cls(self.api_id, self.api_secret)) def test_get_comments(self): diff --git a/tests/search/v2/test_hosts.py b/tests/search/v2/test_hosts.py index 6cecab9a..54449db3 100644 --- a/tests/search/v2/test_hosts.py +++ b/tests/search/v2/test_hosts.py @@ -5,7 +5,6 @@ import pytest import responses -from parameterized import parameterized from responses import matchers from censys.common.exceptions import CensysInternalServerException @@ -179,8 +178,7 @@ class TestHosts(CensysTestCase): api: CensysHosts - def setUp(self): - super().setUp() + def setup_method(self): self.setUpApi(SearchClient(self.api_id, self.api_secret).v2.hosts) def test_view(self): @@ -272,14 +270,15 @@ def test_bulk_view_with_error(self): results = self.api.bulk_view(ips) assert results == expected - @parameterized.expand( + @pytest.mark.parametrize( + ("method_name", "raw"), [ ("search_post_raw", True), ("raw_search", True), - ("search_post"), - ] + ("search_post", False), + ], ) - def test_search_post(self, method_name: str, raw: bool = False): + def test_search_post(self, method_name: str, raw: bool): self.responses.add( responses.POST, f"{V2_URL}/hosts/search", @@ -301,31 +300,23 @@ def test_search_post(self, method_name: str, raw: bool = False): else: assert result == SEARCH_HOSTS_JSON["result"] - @parameterized.expand( + @pytest.mark.parametrize( + ("fields", "sort", "cursor", "virtual_hosts"), [ - (None, None, None), - (["ip", "services.port"], None, None), - (None, "RELEVANCE", None), - ( - ["ip", "services.port"], - "RELEVANCE", - None, - ), - ( - None, - None, - None, - "ONLY", - ), - (None, None, "nextCursorToken"), - ] + (None, None, None, None), + (["ip", "services.port"], None, None, None), + (None, "RELEVANCE", None, None), + (["ip", "services.port"], "RELEVANCE", None, None), + (None, None, None, "ONLY"), + (None, None, "nextCursorToken", None), + ], ) def test_search( self, - fields: Optional[list[str]] = None, - sort: Optional[str] = None, - cursor: Optional[str] = None, - virtual_hosts: Optional[str] = None, + fields: Optional[list[str]], + sort: Optional[str], + cursor: Optional[str], + virtual_hosts: Optional[str], ): self.responses.add( responses.POST, @@ -355,7 +346,8 @@ def test_search_per_page(self): query = self.api.search("services.service_name: HTTP", per_page=test_per_page) assert next(query) == SEARCH_HOSTS_JSON["result"]["hits"] - @parameterized.expand( + @pytest.mark.parametrize( + ("params", "expected_params"), [ ({}, {"q": TEST_SEARCH_QUERY, "per_page": 100}), ({"per_page": 1}, {"q": TEST_SEARCH_QUERY, "per_page": 1}), @@ -393,7 +385,7 @@ def test_search_per_page(self): "per_page": 100, }, ), - ] + ], ) def test_search_get(self, params: dict[str, Any], expected_params: dict[str, Any]): self.responses.add( @@ -785,7 +777,8 @@ def test_view_host_diff(self): results = self.api.view_host_diff(TEST_HOST) assert results == VIEW_HOST_DIFF_JSON["result"] - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "query_params"), [ ({"ip_b": "1.1.1.2"}, "ip_b=1.1.1.2"), ( @@ -795,7 +788,7 @@ def test_view_host_diff(self): }, "at_time=2021-07-01T00%3A00%3A00.000000Z&at_time_b=2021-07-31T00%3A00%3A00.000000Z", ), - ] + ], ) def test_view_host_diff_params(self, kwargs: dict, query_params: str): self.responses.add( @@ -807,7 +800,8 @@ def test_view_host_diff_params(self, kwargs: dict, query_params: str): results = self.api.view_host_diff(TEST_HOST, **kwargs) assert results == VIEW_HOST_DIFF_JSON["result"] - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "query_params"), [ ({}, ""), ({"per_page": 50}, "per_page=50"), @@ -822,7 +816,7 @@ def test_view_host_diff_params(self, kwargs: dict, query_params: str): {"cursor": "nextCursor", "reversed": True}, "cursor=nextCursor&reversed=True", ), - ] + ], ) def test_view_host_events_params(self, kwargs: dict, query_params: str): url = f"{V2_URL}/experimental/hosts/{TEST_HOST}/events" @@ -837,7 +831,8 @@ def test_view_host_events_params(self, kwargs: dict, query_params: str): results = self.api.view_host_events(TEST_HOST, **kwargs) assert results == VIEW_HOST_EVENTS_JSON["result"] - @parameterized.expand( + @pytest.mark.parametrize( + ("kwargs", "query_params"), [ ({}, {"per_page": 100}), ({"per_page": 50}, {"per_page": 50}), @@ -851,7 +846,7 @@ def test_view_host_events_params(self, kwargs: dict, query_params: str): {"cursor": "nextCursor"}, {"per_page": 100, "cursor": "nextCursor"}, ), - ] + ], ) def test_view_host_certificates(self, kwargs: dict, query_params: dict): self.responses.add( diff --git a/tests/search/v2/test_tags.py b/tests/search/v2/test_tags.py index 5df1f502..0eb26271 100644 --- a/tests/search/v2/test_tags.py +++ b/tests/search/v2/test_tags.py @@ -1,6 +1,5 @@ import pytest import responses -from parameterized import parameterized_class from censys.search.v2 import CensysCerts, CensysHosts from censys.search.v2.api import CensysSearchAPIv2 @@ -53,25 +52,27 @@ }, } +INDEX_PARAMS = [ + {"index": "hosts", "index_cls": CensysHosts, "document_id": "1.0.0.0"}, + { + "index": "certificates", + "index_cls": CensysCerts, + "document_id": "fb444eb8e68437bae06232b9f5091bccff62a768ca09e92eb5c9c2cf9d17c426", + }, +] + -@parameterized_class( - [ - {"index": "hosts", "index_cls": CensysHosts, "document_id": "1.0.0.0"}, - { - "index": "certificates", - "index_cls": CensysCerts, - "document_id": "fb444eb8e68437bae06232b9f5091bccff62a768ca09e92eb5c9c2cf9d17c426", - }, - ] -) class CensysTagsTests(CensysTestCase): index: str index_cls: CensysSearchAPIv2 document_id: str api: CensysSearchAPIv2 - def setUp(self): - super().setUp() + @pytest.fixture(autouse=True, params=INDEX_PARAMS, ids=["hosts", "certificates"]) + def _index_config(self, request): + self.index = request.param["index"] + self.index_cls = request.param["index_cls"] + self.document_id = request.param["document_id"] self.setUpApi(self.index_cls(self.api_id, self.api_secret)) def test_list_all_tags(self): diff --git a/tests/test_client.py b/tests/test_client.py index 54062a9b..fcaf20d3 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -9,8 +9,7 @@ class CensysSearchClientTest(CensysTestCase): - def setUp(self): - super().setUp() + def setup_method(self): self.expected_auth = (self.api_id, self.api_secret) def test_api_creds_args(self): diff --git a/tests/test_utils.py b/tests/test_utils.py index 23f4f7c2..d0a4c8e3 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,31 +1,32 @@ import datetime -import unittest -from parameterized import parameterized +import pytest from censys.common.utils import format_iso8601, format_rfc3339 -class UtilsTest(unittest.TestCase): - @parameterized.expand( +class UtilsTest: + @pytest.mark.parametrize( + ("since", "actual"), [ - ["2021-01-01", "2021-01-01"], - [datetime.date(2021, 1, 1), "2021-01-01T00:00:00.000000Z"], - [ + ("2021-01-01", "2021-01-01"), + (datetime.date(2021, 1, 1), "2021-01-01T00:00:00.000000Z"), + ( datetime.datetime(2021, 1, 1, 12, 15, 20, 40), "2021-01-01T12:15:20.000040Z", - ], - ] + ), + ], ) def test_format_rfc3339(self, since, actual): assert format_rfc3339(since) == actual - @parameterized.expand( + @pytest.mark.parametrize( + ("since", "actual"), [ - ["2021-01-01", "2021-01-01"], - [datetime.date(2021, 1, 1), "2021-01-01"], - [datetime.datetime(2021, 1, 1, 12, 15, 20, 40), "2021-01-01"], - ] + ("2021-01-01", "2021-01-01"), + (datetime.date(2021, 1, 1), "2021-01-01"), + (datetime.datetime(2021, 1, 1, 12, 15, 20, 40), "2021-01-01"), + ], ) def test_format_iso8601(self, since, actual): assert format_iso8601(since) == actual diff --git a/tests/utils.py b/tests/utils.py index c0dc3cfa..72d4e220 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,4 +1,3 @@ -import unittest from typing import Optional import pytest @@ -12,7 +11,7 @@ V2_URL = BASE_URL + "/v2" -class CensysTestCase(unittest.TestCase): +class CensysTestCase: api_id = "test-api-id" api_secret = "test-api-secret" api_key = "test-api-key" @@ -30,24 +29,15 @@ class CensysTestCase(unittest.TestCase): mocker: MockerFixture @pytest.fixture(autouse=True) - def __inject_fixtures(self, mocker: MockerFixture): - """Injects fixtures into the test case. - - Args: - mocker (MockerFixture): pytest-mock fixture. - """ - # Inject mocker fixture + def _setup(self, mocker: MockerFixture): self.mocker = mocker - - def setUp(self): - self.responses = responses.RequestsMock() - self.responses.start() - - self.addCleanup(self.responses.stop) - self.addCleanup(self.responses.reset) - - # Mock time.sleep so we don't have to wait in tests - self.mocker.patch("time.sleep", return_value=None) + mocker.patch("time.sleep", return_value=None) + rsps = responses.RequestsMock(assert_all_requests_are_fired=False) + rsps.start() + self.responses = rsps + yield + rsps.stop() + rsps.reset() def setUpApi(self, api: CensysAPIBase): # noqa: N802 self.api = api @@ -59,13 +49,6 @@ def patch_args( search_auth: Optional[bool] = False, asm_auth: Optional[bool] = False, ): - """Patches the arguments of the API. - - Args: - args (List[str]): List of arguments to patch. - search_auth (bool, optional): Whether to patch the search API key. Defaults to False. - asm_auth (bool, optional): Whether to patch the ASM API key. Defaults to False. - """ if search_auth: args.extend(self.cli_args) if asm_auth: diff --git a/uv.lock b/uv.lock index 711fec89..885e307b 100644 --- a/uv.lock +++ b/uv.lock @@ -100,7 +100,6 @@ dependencies = [ dev = [ { name = "mypy", version = "1.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "mypy", version = "1.20.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "parameterized" }, { name = "pytest" }, { name = "pytest-cov" }, { name = "pytest-mock" }, @@ -136,7 +135,6 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ { name = "mypy", specifier = ">=1.5.1,<2" }, - { name = "parameterized", specifier = ">=0.9.0,<1" }, { name = "pytest", specifier = ">=7.3,<9" }, { name = "pytest-cov", specifier = ">=4" }, { name = "pytest-mock", specifier = ">=3.10.0,<4" }, @@ -640,7 +638,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1153,15 +1151,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, ] -[[package]] -name = "parameterized" -version = "0.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/49/00c0c0cc24ff4266025a53e41336b79adaa5a4ebfad214f433d623f9865e/parameterized-0.9.0.tar.gz", hash = "sha256:7fc905272cefa4f364c1a3429cbbe9c0f98b793988efb5bf90aac80f08db09b1", size = 24351, upload-time = "2023-03-27T02:01:11.592Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/00/2f/804f58f0b856ab3bf21617cccf5b39206e6c4c94c2cd227bde125ea6105f/parameterized-0.9.0-py2.py3-none-any.whl", hash = "sha256:4e0758e3d41bea3bbd05ec14fc2c24736723f243b28d702081aef438c9372b1b", size = 20475, upload-time = "2023-03-27T02:01:09.31Z" }, -] - [[package]] name = "pathspec" version = "1.1.1"