From 2f982c34947eeda2a7124265e0ec93d62fb05a9d Mon Sep 17 00:00:00 2001 From: Patryk Szulczewski Date: Mon, 7 Aug 2023 11:08:03 +0200 Subject: [PATCH] Add version constraint to divide into two release trains 1.x and 2.x (#130) Add version constraint to divide into two release trains 1.x and 2.x --- pynautobot/core/api.py | 8 ++++++++ tests/__init__.py | 9 +++++---- tests/conftest.py | 3 ++- tests/integration/test_api_version.py | 2 +- tests/test_api.py | 29 +++++++++++++++++++++------ tests/test_app.py | 5 +++++ 6 files changed, 44 insertions(+), 12 deletions(-) diff --git a/pynautobot/core/api.py b/pynautobot/core/api.py index a48e9af..2294743 100644 --- a/pynautobot/core/api.py +++ b/pynautobot/core/api.py @@ -15,6 +15,7 @@ This file has been modified by NetworktoCode, LLC. """ +from packaging import version import requests from requests.adapters import HTTPAdapter from urllib3 import Retry @@ -109,6 +110,13 @@ def __init__( self.users = App(self, "users") self.plugins = PluginsApp(self) self.graphql = GraphQLQuery(self) + self._validate_version() + + def _validate_version(self): + """Validate API version if eq or ge than 2.0 raise an error.""" + api_version = self.version + if api_version.replace(".", "").isnumeric() and version.parse(api_version) >= version.parse("2.0"): + raise ValueError("Nautobot version 2 detected, please upgrade pynautobot to version 2.x") @property def version(self): diff --git a/tests/__init__.py b/tests/__init__.py index 42b272d..034e971 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -5,10 +5,11 @@ from .util import Response -api = pynautobot.api( - "http://localhost:8000", - token="abc123", -) +with patch("pynautobot.api.version", "1.999"): + api = pynautobot.api( + "http://localhost:8000", + token="abc123", + ) HEADERS = { "accept": "application/json;", diff --git a/tests/conftest.py b/tests/conftest.py index 29218b6..fb7d490 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -46,8 +46,9 @@ def pytest_configure(config): @pytest.fixture -def pynautobot_api(): +def pynautobot_api(monkeypatch): """Factory to create pynautobot api instance.""" + monkeypatch.setattr("pynautobot.api.version", "1.999") return Api(url="https://mocknautobot.example.com", token="1234567890abcdefg") diff --git a/tests/integration/test_api_version.py b/tests/integration/test_api_version.py index 92d7f8b..aaa2fe3 100644 --- a/tests/integration/test_api_version.py +++ b/tests/integration/test_api_version.py @@ -11,7 +11,7 @@ class TestAPIVersioning: def nb_client_1_3(self, nb_client): """Setup a nb_client with API v1.3.""" # Instantiate with a temp url and then replace - nb_api = pynautobot.api("http://localhost", token=nb_client.token, api_version="1.3") + nb_api = pynautobot.api("http://nautobot:8000", token=nb_client.token, api_version="1.3") nb_api.base_url = nb_client.base_url return nb_api diff --git a/tests/test_api.py b/tests/test_api.py index abe94ff..55481ff 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -26,6 +26,7 @@ class ApiTestCase(unittest.TestCase): @patch( "requests.sessions.Session.post", ) + @patch("pynautobot.api.version", "1.999") def test_get(self, *_): api = pynautobot.api(host, **def_kwargs) self.assertTrue(api) @@ -33,6 +34,7 @@ def test_get(self, *_): @patch( "requests.sessions.Session.post", ) + @patch("pynautobot.api.version", "1.999") def test_sanitize_url(self, *_): api = pynautobot.api("http://localhost:8000/", **def_kwargs) self.assertTrue(api) @@ -68,6 +70,19 @@ def test_api_version_not_found(self, *_): ) self.assertEqual(api.version, "") + class ResponseHeadersWithVersion2: + headers = {"API-Version": "2.0"} + ok = True + + @patch( + "requests.sessions.Session.get", + return_value=ResponseHeadersWithVersion2(), + ) + def test_api_version_2(self, *_): + with self.assertRaises(ValueError) as error: + pynautobot.api(host) + self.assertEqual(str(error.exception), "Nautobot version 2 detected, please upgrade pynautobot to version 2.x") + class ApiStatusTestCase(unittest.TestCase): class ResponseWithStatus: @@ -82,6 +97,7 @@ def json(self): "requests.sessions.Session.get", return_value=ResponseWithStatus(), ) + @patch("pynautobot.api.version", "1.999") def test_api_status(self, *_): api = pynautobot.api( host, @@ -106,8 +122,8 @@ def test_api_retry(self, getconn_mock): "http://any.url/", retries=2, ) - - api.version + with patch("pynautobot.api.version", "1.999"): + api.version assert getconn_mock.return_value.request.mock_calls == [ call("GET", "/api/", body=None, headers=ANY), @@ -123,10 +139,11 @@ def test_api_retry_fails(self, getconn_mock): Mock(status=200, msg=HTTPMessage()), ] - api = pynautobot.api( - "http://any.url/", - retries=1, - ) + with patch("pynautobot.api.version", "1.999"): + api = pynautobot.api( + "http://any.url/", + retries=1, + ) with self.assertRaises(RequestErrorFromException): api.version diff --git a/tests/test_app.py b/tests/test_app.py index 36d387e..acbc648 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -17,6 +17,7 @@ class AppCustomFieldsTestCase(unittest.TestCase): "requests.sessions.Session.get", return_value=Response(fixture="extras/custom_fields.json"), ) + @patch("pynautobot.api.version", "1.999") def test_custom_fields(self, session_get_mock): api = pynautobot.api(host, **def_kwargs) cfs = api.extras.custom_fields() @@ -42,6 +43,7 @@ class AppCustomFieldChoicesTestCase(unittest.TestCase): "requests.sessions.Session.get", return_value=Response(fixture="extras/custom_field_choices.json"), ) + @patch("pynautobot.api.version", "1.999") def test_custom_field_choices(self, session_get_mock): api = pynautobot.api(host, **def_kwargs) choices = api.extras.custom_field_choices() @@ -66,6 +68,7 @@ class AppConfigTestCase(unittest.TestCase): "pynautobot.core.query.Request.get", return_value={"tables": {"DeviceTable": {"columns": ["name", "status", "tenant", "tags"]}}}, ) + @patch("pynautobot.api.version", "1.999") def test_config(self, *_): api = pynautobot.api(host, **def_kwargs) config = api.users.config() @@ -81,6 +84,7 @@ class PluginAppCustomChoicesTestCase(unittest.TestCase): "pynautobot.core.query.Request.get", return_value={"Testfield1": {"TF1_1": 1, "TF1_2": 2}, "Testfield2": {"TF2_1": 3, "TF2_2": 4}}, ) + @patch("pynautobot.api.version", "1.999") def test_custom_choices(self, *_): api = pynautobot.api(host, **def_kwargs) choices = api.plugins.test_plugin.custom_fields() @@ -91,6 +95,7 @@ def test_custom_choices(self, *_): "pynautobot.core.query.Request.get", return_value=[{"name": "test_plugin", "package": "netbox_test_plugin"}], ) + @patch("pynautobot.api.version", "1.999") def test_installed_plugins(self, *_): api = pynautobot.api(host, **def_kwargs) plugins = api.plugins.installed_plugins()