From 1cd988390ccc68195a9e18892d46ae26b8246d9d Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Thu, 19 Oct 2023 13:13:17 -0400 Subject: [PATCH] add integration test suite for control plane operations --- .../control/test_configure_index.py | 76 +++++++++++++++++ .../integration/control/test_create_index.py | 82 +++++++++++++++++++ .../control/test_describe_index.py | 42 ++++++++++ .../integration/control/test_list_indexes.py | 30 +++++++ tests/test_helpers.py | 12 +++ 5 files changed, 242 insertions(+) create mode 100644 tests/integration/control/test_configure_index.py create mode 100644 tests/integration/control/test_create_index.py create mode 100644 tests/integration/control/test_describe_index.py create mode 100644 tests/integration/control/test_list_indexes.py create mode 100644 tests/test_helpers.py diff --git a/tests/integration/control/test_configure_index.py b/tests/integration/control/test_configure_index.py new file mode 100644 index 00000000..bb2c796f --- /dev/null +++ b/tests/integration/control/test_configure_index.py @@ -0,0 +1,76 @@ +import pytest +import pinecone +import os +import tests.test_helpers as test_helpers + + +class TestConfigureIndex: + @pytest.fixture(autouse=True) + def setup_and_teardown(self): + # setup + api_key = os.getenv("PINECONE_API_KEY") + environment = os.getenv("PINECONE_ENVIRONMENT") + + self.index_name = test_helpers.generate_index_name() + self.pinecone = pinecone + self.pinecone.init(api_key=api_key, environment=environment) + self.pinecone.create_index(name=self.index_name, dimension=5, replicas=2, timeout=-1) + self.enable_teardown = True + + # run test + yield + + # teardown + if self.enable_teardown: + self.pinecone.delete_index(name=self.index_name) + + # region: error-handling + + def test_configure_index_name_invalid(self): + with pytest.raises(pinecone.core.client.exceptions.NotFoundException) as excinfo: + self.pinecone.configure_index(name="nonexistant", replicas=2) + + exception_msg = str(excinfo.value) + assert "Reason: Not Found" in exception_msg + assert "HTTP response body: 404: Not Found" in exception_msg + + def test_configure_index_exceeds_quota(self): + with pytest.raises(pinecone.core.client.exceptions.ApiException) as excinfo: + self.pinecone.configure_index(name=self.index_name, replicas=10) + + exception_msg = str(excinfo.value) + assert "Reason: Bad Request" in exception_msg + assert "HTTP response body: The index exceeds the project quota of 5 pods by 5 pods." in exception_msg + + # endregion error-handling + + def test_configure_index_scale_replicas(self): + index = self.pinecone.describe_index(name=self.index_name) + assert index.replicas == 2 + + # scale up + self.pinecone.configure_index(name=self.index_name, replicas=3) + index = self.pinecone.describe_index(name=self.index_name) + assert index.replicas == 3 + + # scale down + self.pinecone.configure_index(name=self.index_name, replicas=1) + index = self.pinecone.describe_index(name=self.index_name) + assert index.replicas == 1 + + def test_configure_index_scale_pod_type(self): + index = self.pinecone.describe_index(name=self.index_name) + assert index.pod_type == "p1.x1" + + # scale up + self.pinecone.configure_index(name=self.index_name, pod_type="p1.x2") + index = self.pinecone.describe_index(name=self.index_name) + assert index.pod_type == "p1.x2" + + # scale down (expected error) + with pytest.raises(pinecone.core.client.exceptions.ApiException) as excinfo: + self.pinecone.configure_index(name=self.index_name, pod_type="p1.x1") + + exception_msg = str(excinfo.value) + assert "Reason: Bad Request" in exception_msg + assert "HTTP response body: scaling down pod type is not supported" in exception_msg diff --git a/tests/integration/control/test_create_index.py b/tests/integration/control/test_create_index.py new file mode 100644 index 00000000..52213837 --- /dev/null +++ b/tests/integration/control/test_create_index.py @@ -0,0 +1,82 @@ +import pytest +import pinecone +import os +import tests.test_helpers as test_helpers + + +class TestCreateIndex: + @pytest.fixture(autouse=True) + def setup_and_teardown(self): + # setup + api_key = os.getenv("PINECONE_API_KEY") + environment = os.getenv("PINECONE_ENVIRONMENT") + + self.index_name = test_helpers.generate_index_name() + self.pinecone = pinecone + self.pinecone.init(api_key=api_key, environment=environment) + self.enable_teardown = True + + # run test + yield + + # teardown + if self.enable_teardown: + pinecone.delete_index(name=self.index_name, timeout=-1) + + # region: error handling + + def test_create_index_invalid_name(self): + self.enable_teardown = False + + with pytest.raises(pinecone.core.client.exceptions.ApiException) as excinfo: + self.pinecone.create_index(name=self.index_name + "-", dimension=5) + + exception_msg = str(excinfo.value) + assert "Reason: Bad Request" in exception_msg + assert "must be an empty string or consist of alphanumeric characters" in exception_msg + + def test_create_index_nonexistant_collection(self): + self.enable_teardown = False + + with pytest.raises(pinecone.core.client.exceptions.ApiException) as excinfo: + self.pinecone.create_index(name=self.index_name, dimension=5, source_collection="nonexistant") + + exception_msg = str(excinfo.value) + assert "Reason: Bad Request" in exception_msg + assert "HTTP response body: failed to fetch source collection nonexistant" in exception_msg + + def test_create_index_insufficient_quota(self): + self.enable_teardown = False + + with pytest.raises(pinecone.core.client.exceptions.ApiException) as excinfo: + self.pinecone.create_index(name=self.index_name, dimension=5, replicas=20) + + exception_msg = str(excinfo.value) + assert "Reason: Bad Request" in exception_msg + assert "HTTP response body: The index exceeds the project quota of 5 pods by 15 pods." in exception_msg + + # endregion + + def test_create_index(self): + self.pinecone.create_index(name=self.index_name, dimension=10, timeout=-1) + index = self.pinecone.describe_index(name=self.index_name) + + assert index.name == self.index_name + assert index.dimension == 10 + assert index.metric == "cosine" + assert index.pods == 1 + assert index.replicas == 1 + assert index.shards == 1 + + def test_create_index_with_options(self): + self.pinecone.create_index( + name=self.index_name, dimension=10, metric="euclidean", replicas=2, pod_type="p1.x2", timeout=-1 + ) + index = self.pinecone.describe_index(name=self.index_name) + + assert index.name == self.index_name + assert index.dimension == 10 + assert index.metric == "euclidean" + assert index.pods == 2 + assert index.replicas == 2 + assert index.shards == 1 diff --git a/tests/integration/control/test_describe_index.py b/tests/integration/control/test_describe_index.py new file mode 100644 index 00000000..3a128198 --- /dev/null +++ b/tests/integration/control/test_describe_index.py @@ -0,0 +1,42 @@ +import pytest +import pinecone +import os +import tests.test_helpers as test_helpers + + +class TestDescribeIndex: + @pytest.fixture(autouse=True) + def setup_and_teardown(self): + # setup + api_key = os.getenv("PINECONE_API_KEY") + environment = os.getenv("PINECONE_ENVIRONMENT") + + self.index_name = test_helpers.generate_index_name() + self.pinecone = pinecone + self.pinecone.init(api_key=api_key, environment=environment) + self.pinecone.create_index(name=self.index_name, dimension=5, timeout=-1) + self.enable_teardown = True + + # run test + yield + + # teardown + if self.enable_teardown: + self.pinecone.delete_index(name=self.index_name, timeout=-1) + + def test_describe_index(self): + description = self.pinecone.describe_index(name=self.index_name) + assert description.name == self.index_name + assert description.dimension == 5 + assert description.metric == "cosine" + assert description.pods == 1 + assert description.replicas == 1 + assert description.shards == 1 + + def test_describe_index_invalid_name(self): + with pytest.raises(pinecone.core.client.exceptions.NotFoundException) as excinfo: + self.pinecone.describe_index(name="invalid-index-name") + + exception_msg = str(excinfo.value) + assert "Reason: Not Found" in exception_msg + assert "HTTP response body: 404: Not Found" in exception_msg diff --git a/tests/integration/control/test_list_indexes.py b/tests/integration/control/test_list_indexes.py new file mode 100644 index 00000000..2111c3df --- /dev/null +++ b/tests/integration/control/test_list_indexes.py @@ -0,0 +1,30 @@ +import pytest +import pinecone +import os +import tests.test_helpers as test_helpers + + +class TestListIndexes: + @pytest.fixture(autouse=True) + def setup_and_teardown(self): + # setup + api_key = os.getenv("PINECONE_API_KEY") + environment = os.getenv("PINECONE_ENVIRONMENT") + pinecone.init(api_key=api_key, environment=environment) + + self.index_name = test_helpers.generate_index_name() + self.pinecone = pinecone + self.pinecone.create_index(name=self.index_name, dimension=5, timeout=-1) + + # run test + yield + + # teardown + pinecone.delete_index(name=self.index_name, timeout=-1) + + def test_list_indexes(self): + indexes = self.pinecone.list_indexes() + + assert indexes is not None + assert len(indexes) > 0 + assert self.index_name in indexes diff --git a/tests/test_helpers.py b/tests/test_helpers.py new file mode 100644 index 00000000..5300a1cc --- /dev/null +++ b/tests/test_helpers.py @@ -0,0 +1,12 @@ +import random + +def generate_random_string(length: int): + letters = "abcdefghijklmnopqrstuvwxyz0123456789" + return ''.join(random.choice(letters) for i in range(length)) + +def generate_index_name(): + return f"python-index-{generate_random_string(10)}" + + +# generate records +# generate sparse values \ No newline at end of file