From 3ea964b6e2303d88f8b58089f4f124c1d3b00f3d Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Tue, 13 Feb 2024 20:53:18 -0500 Subject: [PATCH 01/22] add collections calls to PineconeControlPlaneClient, add new integration tests for collections, add new helpers for new collections tests --- build.gradle | 64 +++++++ .../java/io/pinecone/helpers/AssertRetry.java | 15 +- .../io/pinecone/helpers/IndexManager.java | 69 +++++++ .../controlPlane/pod/CollectionErrorTest.java | 143 ++++++++++++++ .../controlPlane/pod/CollectionTest.java | 180 ++++++++++++++++++ .../{index => }/pod/ConfigureIndexTest.java | 2 +- .../CreateDescribeListAndDeleteIndexTest.java | 2 +- .../CreateDescribeListAndDeleteIndexTest.java | 2 +- .../pinecone/PineconeControlPlaneClient.java | 56 +++++- .../pinecone/exceptions/HttpErrorMapper.java | 2 +- 10 files changed, 515 insertions(+), 20 deletions(-) create mode 100644 src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java create mode 100644 src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java rename src/integration/java/io/pinecone/integration/controlPlane/{index => }/pod/ConfigureIndexTest.java (99%) rename src/integration/java/io/pinecone/integration/controlPlane/{index => }/pod/CreateDescribeListAndDeleteIndexTest.java (97%) rename src/integration/java/io/pinecone/integration/controlPlane/{index => }/serverless/CreateDescribeListAndDeleteIndexTest.java (96%) diff --git a/build.gradle b/build.gradle index dd01b849..aea0cca5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,6 @@ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat; +import org.gradle.api.tasks.testing.logging.TestLogEvent; + plugins { id 'com.github.johnrengelman.shadow' version '6.1.0' id 'java-library' @@ -93,6 +96,36 @@ tasks.named('build') { test { useJUnitPlatform() + + + testLogging { + events = [TestLogEvent.FAILED, TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.STANDARD_OUT] + exceptionFormat = TestExceptionFormat.FULL + showExceptions = true + showCauses = true + showStackTraces = true + + debugOptions { + events = [ + TestLogEvent.STARTED, + TestLogEvent.FAILED, + TestLogEvent.PASSED, + TestLogEvent.SKIPPED, + TestLogEvent.STANDARD_ERROR, + TestLogEvent.STANDARD_OUT + ] + exceptionFormat = TestExceptionFormat.FULL + } + + afterSuite { desc, result -> + if (!desc.parent) { + def output = "Results: ${result.resultType} (${result.testCount}) tests, ${result.successfulTestCount} successful, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped." + def startItem = "| ", endItem = " |" + def repeatLength = startItem.length() + output.length() + endItem.length() + println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength)) + } + } + } } task integrationTest(type: Test) { @@ -100,6 +133,37 @@ task integrationTest(type: Test) { testClassesDirs = sourceSets.integrationTest.output.classesDirs classpath = sourceSets.integrationTest.runtimeClasspath outputs.upToDateWhen { false } + + + testLogging { + events = [TestLogEvent.FAILED, TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.STANDARD_OUT] + exceptionFormat = TestExceptionFormat.FULL + showExceptions = true + showCauses = true + showStackTraces = true + + debugOptions { + events = [ + TestLogEvent.STARTED, + TestLogEvent.FAILED, + TestLogEvent.PASSED, + TestLogEvent.SKIPPED, + TestLogEvent.STANDARD_ERROR, + TestLogEvent.STANDARD_OUT + ] + exceptionFormat = TestExceptionFormat.FULL + + } + + afterSuite { desc, result -> + if (!desc.parent) { + def output = "Results: ${result.resultType} (${result.testCount}) tests, ${result.successfulTestCount} successful, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped." + def startItem = "| ", endItem = " |" + def repeatLength = startItem.length() + output.length() + endItem.length() + println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength)) + } + } + } } // Configure Auto Relocation diff --git a/src/integration/java/io/pinecone/helpers/AssertRetry.java b/src/integration/java/io/pinecone/helpers/AssertRetry.java index 1212893f..16f4c6cf 100644 --- a/src/integration/java/io/pinecone/helpers/AssertRetry.java +++ b/src/integration/java/io/pinecone/helpers/AssertRetry.java @@ -1,18 +1,21 @@ package io.pinecone.helpers; +import io.pinecone.exceptions.PineconeException; + import java.io.IOException; import java.util.concurrent.ExecutionException; public class AssertRetry { private static final int maxRetry = 4; - private static int delay = 1500; + private static final int delay = 1500; - public static void assertWithRetry(AssertionRunnable assertionRunnable) throws InterruptedException { + public static void assertWithRetry(AssertionRunnable assertionRunnable) throws InterruptedException, PineconeException { assertWithRetry(assertionRunnable, 2); } - public static void assertWithRetry(AssertionRunnable assertionRunnable, int backOff) throws InterruptedException { + public static void assertWithRetry(AssertionRunnable assertionRunnable, int backOff) throws InterruptedException, PineconeException { int retryCount = 0; + int delayCount = delay; boolean success = false; while (retryCount < maxRetry && !success) { @@ -21,14 +24,14 @@ public static void assertWithRetry(AssertionRunnable assertionRunnable, int back success = true; } catch (AssertionError | ExecutionException | IOException e) { retryCount++; - delay*=backOff; - Thread.sleep(delay); + Thread.sleep(delayCount); + delayCount*=backOff; } } } @FunctionalInterface public interface AssertionRunnable { - void run() throws AssertionError, ExecutionException, InterruptedException, IOException; + void run() throws AssertionError, ExecutionException, InterruptedException, IOException, PineconeException; } } diff --git a/src/integration/java/io/pinecone/helpers/IndexManager.java b/src/integration/java/io/pinecone/helpers/IndexManager.java index c99818a9..577b2688 100644 --- a/src/integration/java/io/pinecone/helpers/IndexManager.java +++ b/src/integration/java/io/pinecone/helpers/IndexManager.java @@ -1,12 +1,15 @@ package io.pinecone.helpers; import io.pinecone.*; +import io.pinecone.exceptions.PineconeException; import org.openapitools.client.model.*; import java.io.IOException; import java.util.List; import static io.pinecone.helpers.AssertRetry.assertWithRetry; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; public class IndexManager { private static PineconeClientConfig config; @@ -79,6 +82,72 @@ private static String createNewIndex(PineconeControlPlaneClient controlPlaneClie return indexName; } + public static IndexModel waitUntilIndexIsReady(PineconeControlPlaneClient controlPlaneClient, String indexName, Integer totalMsToWait) throws InterruptedException { + IndexModel index = controlPlaneClient.describeIndex(indexName); + int waitedTimeMs = 0; + int intervalMs = 1500; + + while (!index.getStatus().getReady()) { + index = controlPlaneClient.describeIndex(indexName); + if (waitedTimeMs >= totalMsToWait) { + System.out.println("Index " + indexName + " not ready after " + waitedTimeMs + "ms"); + break; + } + if (index.getStatus().getReady()) { + Thread.sleep(3000); + System.out.println("Index " + indexName + " is ready after " + waitedTimeMs + 3000 + "ms"); + break; + } + Thread.sleep(intervalMs); + waitedTimeMs += intervalMs; + } + return index; + } + + public static IndexModel waitUntilIndexIsReady(PineconeControlPlaneClient controlPlaneClient, String indexName) throws InterruptedException { + return waitUntilIndexIsReady(controlPlaneClient, indexName, 120000); + } + + public static PineconeConnection createNewIndexAndConnect(PineconeControlPlaneClient controlPlaneClient, String indexName, int dimension, IndexMetric metric, CreateIndexRequestSpec spec) throws InterruptedException, PineconeException { + CreateIndexRequest createIndexRequest = new CreateIndexRequest().name(indexName).dimension(dimension).metric(metric).spec(spec); + controlPlaneClient.createIndex(createIndexRequest); + + // Wait until index is ready + waitUntilIndexIsReady(controlPlaneClient, indexName, 200000); + String host = controlPlaneClient.describeIndex(indexName).getHost(); + + PineconeClientConfig specificConfig = new PineconeClientConfig().withApiKey(System.getenv("PINECONE_API_KEY")); + PineconeClient dataPlaneClient = new PineconeClient(specificConfig); + + return dataPlaneClient.connect( + new PineconeConnectionConfig() + .withConnectionUrl("https://" + host)); + } + + public static CollectionModel createCollection(PineconeControlPlaneClient controlPlaneClient, String collectionName, String indexName, boolean waitUntilReady) throws InterruptedException { + CreateCollectionRequest createCollectionRequest = new CreateCollectionRequest().name(collectionName).source(indexName); + CollectionModel collection = controlPlaneClient.createCollection(createCollectionRequest); + + assertEquals(collection.getStatus(), CollectionModel.StatusEnum.INITIALIZING); + + // Wait until collection is ready + int timeWaited = 0; + CollectionModel.StatusEnum collectionReady = collection.getStatus(); + while (collectionReady != CollectionModel.StatusEnum.READY && timeWaited < 120000) { + System.out.println("Waiting for collection" + collectionName + " to be ready. Waited " + timeWaited + " milliseconds..."); + Thread.sleep(5000); + timeWaited += 5000; + collection = controlPlaneClient.describeCollection(collectionName); + collectionReady = collection.getStatus(); + } + + if (timeWaited > 120000) { + fail("Collection: " + collectionName + " is not ready after 120 seconds"); + } + + return collection; + } + public static IndexModel isIndexReady(String indexName, PineconeControlPlaneClient controlPlaneClient) throws InterruptedException { final IndexModel[] indexModels = new IndexModel[1]; diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java new file mode 100644 index 00000000..00ea279f --- /dev/null +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java @@ -0,0 +1,143 @@ +package io.pinecone.integration.controlPlane.pod; + +import io.pinecone.PineconeConnection; +import io.pinecone.PineconeControlPlaneClient; +import io.pinecone.exceptions.PineconeException; +import io.pinecone.helpers.RandomStringBuilder; +import io.pinecone.proto.VectorServiceGrpc; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Disabled; +import org.openapitools.client.model.*; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; + +import static io.pinecone.helpers.IndexManager.createNewIndexAndConnect; +import static io.pinecone.helpers.IndexManager.createCollection; +import static io.pinecone.helpers.IndexManager.waitUntilIndexIsReady; +import static io.pinecone.helpers.BuildUpsertRequest.*; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class CollectionErrorTest { + private static final String apiKey = System.getenv("PINECONE_API_KEY"); + private static final String environment = System.getenv("PINECONE_ENVIRONMENT"); + private static final String indexName = RandomStringBuilder.build("collection-error-test", 8); + private static final List upsertIds = Arrays.asList("v1", "v2", "v3"); + private static final int dimension = 3; + private static final String collectionName = RandomStringBuilder.build("reusable-coll", 8); + private static PineconeControlPlaneClient controlPlaneClient; + + @BeforeAll + public static void setUpIndexAndCollection() throws InterruptedException { + controlPlaneClient = new PineconeControlPlaneClient(apiKey); + CreateIndexRequestSpecPod podSpec = new CreateIndexRequestSpecPod().pods(1).podType("p1.x1").replicas(1).environment(environment); + CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); + PineconeConnection dataPlaneConnection = createNewIndexAndConnect(controlPlaneClient, indexName, dimension, IndexMetric.COSINE, spec); + VectorServiceGrpc.VectorServiceBlockingStub blockingStub = dataPlaneConnection.getBlockingStub(); + + // Upsert vectors to index and sleep for freshness + blockingStub.upsert(buildRequiredUpsertRequest(upsertIds, "")); + dataPlaneConnection.close(); + + Thread.sleep(3500); + + // Create collection from index + createCollection(controlPlaneClient, collectionName, indexName, true); + } + + @AfterAll + public static void cleanUp() { + controlPlaneClient.deleteIndex(indexName); + controlPlaneClient.deleteCollection(collectionName); + } + + @Test + public void testCreateCollectionFromInvalidIndex() { + try { + CreateCollectionRequest createCollectionRequest = new CreateCollectionRequest().name(RandomStringBuilder.build("coll1", 8)).source("invalid-index"); + controlPlaneClient.createCollection(createCollectionRequest); + } catch (PineconeException exception) { + assertTrue(exception.getMessage().contains("Resource invalid-index not found")); + } + } + @Test + public void testIndexFromNonExistentCollection() { + try { + CreateIndexRequestSpecPod podSpec = new CreateIndexRequestSpecPod().environment(environment).sourceCollection("non-existent-collection"); + CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); + CreateIndexRequest newCreateIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-nonexistent-coll", 8)).dimension(3).metric(IndexMetric.COSINE).spec(spec); + controlPlaneClient.createIndex(newCreateIndexRequest); + } catch (PineconeException exception) { + assertTrue(exception.getMessage().contains("Resource non-existent-collection not found")); + } + } + + @Test + public void testCreateIndexInMismatchedEnvironment() { + try { + List environments = new LinkedList<>(Arrays.asList( + "eastus-azure", + "eu-west4-gcp", + "northamerica-northeast1-gcp", + "us-central1-gcp", + "us-west4-gcp", + "asia-southeast1-gcp", + "us-east-1-aws", + "asia-northeast1-gcp", + "eu-west1-gcp", + "eu-east1-gcp", + "eu-east4-gcp", + "us-west1-gcp" + )); + CollectionModel collection = controlPlaneClient.describeCollection(collectionName); + environments.remove(collection.getEnvironment()); + String mismatchedEnv = environments.get(new Random().nextInt(environments.size())); + + CreateIndexRequestSpecPod podSpec = new CreateIndexRequestSpecPod().sourceCollection(collection.getName()).environment(mismatchedEnv); + CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); + CreateIndexRequest createIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-coll-", 8)).dimension(dimension).metric(IndexMetric.COSINE).spec(spec); + controlPlaneClient.createIndex(createIndexRequest); + } catch (PineconeException exception) { + assertTrue(exception.getMessage().contains("Source collection must be in the same environment as the index")); + } + } + + @Test + @Disabled("Bug reported in #global-cps") + public void testCreateIndexWithMismatchedDimension() { + try { + CollectionModel collection = controlPlaneClient.describeCollection(collectionName); + CreateIndexRequestSpecPod podSpec = new CreateIndexRequestSpecPod().sourceCollection(collection.getName()).environment(collection.getEnvironment()); + CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); + CreateIndexRequest createIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-coll-", 8)).dimension(dimension + 1).metric(IndexMetric.COSINE).spec(spec); + controlPlaneClient.createIndex(createIndexRequest); + } catch (PineconeException exception) { + assertTrue(exception.getMessage().contains("Index and collection must have the same dimension")); + } + } + + @Test + public void testCreateCollectionFromNotReadyIndex() throws InterruptedException { + String notReadyIndexName = RandomStringBuilder.build("from-coll4", 8); + try { + CreateIndexRequestSpecPod specPod = new CreateIndexRequestSpecPod().pods(1).podType("p1.x1").replicas(1).environment(environment); + CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(specPod); + CreateIndexRequest createIndexRequest = new CreateIndexRequest().name(notReadyIndexName).dimension(dimension).metric(IndexMetric.COSINE).spec(spec); + controlPlaneClient.createIndex(createIndexRequest); + + CreateCollectionRequest createCollectionRequest = new CreateCollectionRequest().name(RandomStringBuilder.build("coll4-", 8)).source(notReadyIndexName); + controlPlaneClient.createCollection(createCollectionRequest); + } catch (PineconeException exception) { + assertTrue(exception.getMessage().contains("Source index is not ready")); + + // Wait for index to initialize and clean up + waitUntilIndexIsReady(controlPlaneClient, notReadyIndexName); + controlPlaneClient.deleteIndex(notReadyIndexName); + } + } +} \ No newline at end of file diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java new file mode 100644 index 00000000..fecfe091 --- /dev/null +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java @@ -0,0 +1,180 @@ +package io.pinecone.integration.controlPlane.pod; + +import io.pinecone.*; +import io.pinecone.helpers.RandomStringBuilder; +import io.pinecone.proto.*; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.openapitools.client.model.*; + +import java.util.Arrays; +import java.util.List; + +import static io.pinecone.helpers.IndexManager.createNewIndexAndConnect; +import static io.pinecone.helpers.IndexManager.waitUntilIndexIsReady; +import static io.pinecone.helpers.IndexManager.createCollection; +import static io.pinecone.helpers.BuildUpsertRequest.*; +import static org.junit.jupiter.api.Assertions.*; + +public class CollectionTest { + + private static PineconeControlPlaneClient controlPlaneClient; + private static final String indexName = RandomStringBuilder.build("collection-test", 8); + private static final IndexMetric indexMetric = IndexMetric.COSINE; + private static final List upsertIds = Arrays.asList("v1", "v2", "v3"); + private static final String namespace = RandomStringBuilder.build("ns", 8); + private static final String apiKey = System.getenv("PINECONE_API_KEY"); + private static final String environment = System.getenv("PINECONE_ENVIRONMENT"); + private static final int dimension = 3; + + @BeforeAll + public static void setUpIndex() throws InterruptedException { + controlPlaneClient = new PineconeControlPlaneClient(apiKey); + CreateIndexRequestSpecPod podSpec = new CreateIndexRequestSpecPod().pods(1).podType("p1.x1").replicas(1).environment(environment); + CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); + PineconeConnection dataPlaneConnection = createNewIndexAndConnect(controlPlaneClient, indexName, dimension, indexMetric, spec); + VectorServiceGrpc.VectorServiceBlockingStub blockingStub = dataPlaneConnection.getBlockingStub(); + + // Upsert vectors to index and sleep for freshness + blockingStub.upsert(buildRequiredUpsertRequest(upsertIds, namespace)); + Thread.sleep(3500); + dataPlaneConnection.close(); + } + + @AfterAll + public static void deleteIndex() throws InterruptedException { + Thread.sleep(5000); + controlPlaneClient.deleteIndex(indexName); + } + + @Test + public void testIndexToCollectionHappyPath() throws InterruptedException { + String collectionName = RandomStringBuilder.build("collection-test", 8); + + // Create collection from index + CollectionModel collection = createCollection(controlPlaneClient, collectionName, indexName, true); + + assertEquals(collection.getName(), collectionName); + assertEquals(collection.getEnvironment(), environment); + assertEquals(collection.getStatus(), CollectionModel.StatusEnum.READY); + + // Verify collection is listed + List collections = controlPlaneClient.listCollections().getCollections(); + boolean collectionFound = false; + if (collections != null && !collections.isEmpty()) { + for (CollectionModel col : collections) { + if (col.getName().equals(collectionName)) { + collectionFound = true; + break; + } + } + } + + if (!collectionFound) { + fail("Collection " + collectionName + " was not found when listing collections"); + } + + // Verify collection can be described + collection = controlPlaneClient.describeCollection(collectionName); + + assertEquals(collection.getStatus(), CollectionModel.StatusEnum.READY); + assertEquals(collection.getDimension(), dimension); + assertEquals(collection.getVectorCount(), 3); + assertNotEquals(collection.getVectorCount(), null); + assertTrue(collection.getSize() > 0); + + // Create index from collection + String newIndexName = RandomStringBuilder.build("index-from-col", 5); + System.out.println("Creating index " + newIndexName + " from collection " + collectionName); + + CreateIndexRequestSpecPod podSpec = new CreateIndexRequestSpecPod().environment(environment).sourceCollection(collectionName); + CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); + CreateIndexRequest newCreateIndexRequest = new CreateIndexRequest().name(newIndexName).dimension(dimension).metric(indexMetric).spec(spec); + controlPlaneClient.createIndex(newCreateIndexRequest); + System.out.println("Index " + newIndexName + " created from collection " + collectionName + ". Waiting until index is ready..."); + waitUntilIndexIsReady(controlPlaneClient, newIndexName); + + IndexModel indexDescription = controlPlaneClient.describeIndex(newIndexName); + assertEquals(indexDescription.getName(), newIndexName); + assertEquals(indexDescription.getSpec().getPod().getSourceCollection(), collectionName); + assertEquals(indexDescription.getStatus().getReady(), true); + Thread.sleep(5000); + + // Set up new index data plane connection + PineconeClient newIndexClient = new PineconeClient(new PineconeClientConfig().withApiKey(apiKey).withEnvironment(environment)); + PineconeConnection newIndexDataPlaneClient = newIndexClient.connect(new PineconeConnectionConfig().withConnectionUrl("https://" + indexDescription.getHost())); + VectorServiceGrpc.VectorServiceBlockingStub newIndexBlockingStub = newIndexDataPlaneClient.getBlockingStub(); + DescribeIndexStatsResponse describeResponse = newIndexBlockingStub.describeIndexStats(DescribeIndexStatsRequest.newBuilder().build()); + + // Verify stats reflect the vectors in the collection + assertEquals(describeResponse.getTotalVectorCount(), 3); + + // Verify the vectors from the collection -> new index can be fetched + FetchResponse fetchedVectors = newIndexBlockingStub.fetch(FetchRequest.newBuilder().addAllIds(upsertIds).setNamespace(namespace).build()); + newIndexDataPlaneClient.close(); + + for (String key : upsertIds) { + assert (fetchedVectors.containsVectors(key)); + } + + // Verify we can delete the collection + controlPlaneClient.deleteCollection(collectionName); + Thread.sleep(2500); + collections = controlPlaneClient.listCollections().getCollections(); + + + if (collections != null) { + boolean isCollectionDeleted = true; + for (CollectionModel col : collections) { + if (col.getName().equals(collectionName)) { + isCollectionDeleted = false; + break; + } + } + + if (!isCollectionDeleted) { + fail("Collection " + collectionName + " was not successfully deleted"); + } + } + + // Clean up + controlPlaneClient.deleteIndex(newIndexName); + } + + @Test + public void testIndexFromDifferentMetricCollection() throws InterruptedException { + String collectionName = RandomStringBuilder.build("collection-test", 8); + + // Create collection from index + CollectionModel collection = createCollection(controlPlaneClient, collectionName, indexName, true); + + assertEquals(collection.getName(), collectionName); + assertEquals(collection.getEnvironment(), environment); + assertEquals(collection.getStatus(), CollectionModel.StatusEnum.READY); + + // Use a different metric than the source index + IndexMetric[] metrics = { IndexMetric.COSINE, IndexMetric.EUCLIDEAN, IndexMetric.DOTPRODUCT }; + IndexMetric targetMetric = IndexMetric.COSINE; + for (IndexMetric metric : metrics) { + if (!metric.equals(indexMetric)) { + targetMetric = metric; + } + } + + String newIndexName = RandomStringBuilder.build("from-coll", 8); + CreateIndexRequestSpecPod podSpec = new CreateIndexRequestSpecPod().environment(environment).sourceCollection(collectionName); + CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); + PineconeConnection dataPlaneConnection = createNewIndexAndConnect(controlPlaneClient, newIndexName, dimension, targetMetric, spec); + + IndexModel newIndex = controlPlaneClient.describeIndex(newIndexName); + assertEquals(newIndex.getName(), newIndexName); + assertEquals(newIndex.getMetric(), targetMetric); + + // Clean up + controlPlaneClient.deleteIndex(newIndexName); + controlPlaneClient.deleteCollection(collectionName); + dataPlaneConnection.close(); + } + +} \ No newline at end of file diff --git a/src/integration/java/io/pinecone/integration/controlPlane/index/pod/ConfigureIndexTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java similarity index 99% rename from src/integration/java/io/pinecone/integration/controlPlane/index/pod/ConfigureIndexTest.java rename to src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java index 4e49cdc5..9e26938c 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/index/pod/ConfigureIndexTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java @@ -1,4 +1,4 @@ -package io.pinecone.integration.controlPlane.index.pod; +package io.pinecone.integration.controlPlane.pod; import io.pinecone.PineconeControlPlaneClient; import io.pinecone.exceptions.PineconeException; diff --git a/src/integration/java/io/pinecone/integration/controlPlane/index/pod/CreateDescribeListAndDeleteIndexTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CreateDescribeListAndDeleteIndexTest.java similarity index 97% rename from src/integration/java/io/pinecone/integration/controlPlane/index/pod/CreateDescribeListAndDeleteIndexTest.java rename to src/integration/java/io/pinecone/integration/controlPlane/pod/CreateDescribeListAndDeleteIndexTest.java index b031e7a6..18333ee6 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/index/pod/CreateDescribeListAndDeleteIndexTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CreateDescribeListAndDeleteIndexTest.java @@ -1,4 +1,4 @@ -package io.pinecone.integration.controlPlane.index.pod; +package io.pinecone.integration.controlPlane.pod; import io.pinecone.PineconeControlPlaneClient; import io.pinecone.helpers.RandomStringBuilder; diff --git a/src/integration/java/io/pinecone/integration/controlPlane/index/serverless/CreateDescribeListAndDeleteIndexTest.java b/src/integration/java/io/pinecone/integration/controlPlane/serverless/CreateDescribeListAndDeleteIndexTest.java similarity index 96% rename from src/integration/java/io/pinecone/integration/controlPlane/index/serverless/CreateDescribeListAndDeleteIndexTest.java rename to src/integration/java/io/pinecone/integration/controlPlane/serverless/CreateDescribeListAndDeleteIndexTest.java index df9a4dba..d39683cf 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/index/serverless/CreateDescribeListAndDeleteIndexTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/serverless/CreateDescribeListAndDeleteIndexTest.java @@ -1,4 +1,4 @@ -package io.pinecone.integration.controlPlane.index.serverless; +package io.pinecone.integration.controlPlane.serverless; import io.pinecone.PineconeControlPlaneClient; import io.pinecone.helpers.RandomStringBuilder; diff --git a/src/main/java/io/pinecone/PineconeControlPlaneClient.java b/src/main/java/io/pinecone/PineconeControlPlaneClient.java index f8c3e09d..1b1b5a51 100644 --- a/src/main/java/io/pinecone/PineconeControlPlaneClient.java +++ b/src/main/java/io/pinecone/PineconeControlPlaneClient.java @@ -2,15 +2,13 @@ import io.pinecone.exceptions.FailedRequestInfo; import io.pinecone.exceptions.HttpErrorMapper; +import io.pinecone.exceptions.PineconeException; import io.pinecone.exceptions.PineconeValidationException; import okhttp3.*; import org.openapitools.client.ApiClient; import org.openapitools.client.ApiException; import org.openapitools.client.api.ManageIndexesApi; -import org.openapitools.client.model.ConfigureIndexRequest; -import org.openapitools.client.model.CreateIndexRequest; -import org.openapitools.client.model.IndexList; -import org.openapitools.client.model.IndexModel; +import org.openapitools.client.model.*; public class PineconeControlPlaneClient { private ManageIndexesApi manageIndexesApi; @@ -29,17 +27,17 @@ public PineconeControlPlaneClient(String apiKey, OkHttpClient okHttpClient) { manageIndexesApi.setApiClient(apiClient); } - public IndexModel createIndex(CreateIndexRequest createIndexRequest) { + public IndexModel createIndex(CreateIndexRequest createIndexRequest) throws PineconeException { IndexModel indexModel = new IndexModel(); try { - manageIndexesApi.createIndex(createIndexRequest); + indexModel = manageIndexesApi.createIndex(createIndexRequest); } catch (ApiException apiException) { handleApiException(apiException); } return indexModel; } - public IndexModel describeIndex(String indexName) { + public IndexModel describeIndex(String indexName) throws PineconeException { IndexModel indexModel = new IndexModel(); try { indexModel = manageIndexesApi.describeIndex(indexName); @@ -49,7 +47,7 @@ public IndexModel describeIndex(String indexName) { return indexModel; } - public void configureIndex(String indexName, ConfigureIndexRequest configureIndexRequest) { + public void configureIndex(String indexName, ConfigureIndexRequest configureIndexRequest) throws PineconeException { try { manageIndexesApi.configureIndex(indexName, configureIndexRequest); } catch (ApiException apiException) { @@ -57,7 +55,7 @@ public void configureIndex(String indexName, ConfigureIndexRequest configureInde } } - public IndexList listIndexes() { + public IndexList listIndexes() throws PineconeException { IndexList indexList = new IndexList(); try { indexList = manageIndexesApi.listIndexes(); @@ -67,7 +65,7 @@ public IndexList listIndexes() { return indexList; } - public void deleteIndex(String indexName) { + public void deleteIndex(String indexName) throws PineconeException { try { manageIndexesApi.deleteIndex(indexName); } catch (ApiException apiException) { @@ -75,6 +73,44 @@ public void deleteIndex(String indexName) { } } + public CollectionModel createCollection(CreateCollectionRequest createCollectionRequest) throws PineconeException { + CollectionModel collection = null; + try { + collection = manageIndexesApi.createCollection(createCollectionRequest); + } catch (ApiException apiException) { + handleApiException(apiException); + } + return collection; + } + + public CollectionModel describeCollection(String collectionName) throws PineconeException { + CollectionModel collection = null; + try { + collection = manageIndexesApi.describeCollection(collectionName); + } catch (ApiException apiException) { + handleApiException(apiException); + } + return collection; + } + + public CollectionList listCollections() throws PineconeException { + CollectionList collections = null; + try { + collections = manageIndexesApi.listCollections(); + } catch (ApiException apiException) { + handleApiException(apiException); + } + return collections; + } + + public void deleteCollection(String collectionName) throws PineconeException { + try { + manageIndexesApi.deleteCollection(collectionName); + } catch (ApiException apiException) { + handleApiException(apiException); + } + } + private void handleApiException(ApiException apiException) { int statusCode = apiException.getCode(); String responseBody = apiException.getResponseBody(); diff --git a/src/main/java/io/pinecone/exceptions/HttpErrorMapper.java b/src/main/java/io/pinecone/exceptions/HttpErrorMapper.java index 4a4ebb73..58c7e2c8 100644 --- a/src/main/java/io/pinecone/exceptions/HttpErrorMapper.java +++ b/src/main/java/io/pinecone/exceptions/HttpErrorMapper.java @@ -2,7 +2,7 @@ public class HttpErrorMapper { - public static void mapHttpStatusError(FailedRequestInfo failedRequestInfo) { + public static void mapHttpStatusError(FailedRequestInfo failedRequestInfo) throws PineconeException { int statusCode = failedRequestInfo.getStatus(); switch (statusCode) { case 400: From 535bf5d4f4af8363869066616b1cd22d0f30ae6a Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Tue, 13 Feb 2024 21:24:58 -0500 Subject: [PATCH 02/22] tweak testCreateCollectionFromNotReadyIndex test --- .../integration/controlPlane/pod/CollectionErrorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java index 00ea279f..1c58a948 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java @@ -133,8 +133,8 @@ public void testCreateCollectionFromNotReadyIndex() throws InterruptedException CreateCollectionRequest createCollectionRequest = new CreateCollectionRequest().name(RandomStringBuilder.build("coll4-", 8)).source(notReadyIndexName); controlPlaneClient.createCollection(createCollectionRequest); } catch (PineconeException exception) { - assertTrue(exception.getMessage().contains("Source index is not ready")); - + assert (exception.getMessage().contains("Source index is not ready")); + } finally { // Wait for index to initialize and clean up waitUntilIndexIsReady(controlPlaneClient, notReadyIndexName); controlPlaneClient.deleteIndex(notReadyIndexName); From a056f5cd6997dbb50541998f4a5131dbf5e3b32d Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Tue, 13 Feb 2024 21:30:29 -0500 Subject: [PATCH 03/22] tweak dimension for indexes in collection tests --- .../integration/controlPlane/pod/CollectionErrorTest.java | 4 ++-- .../pinecone/integration/controlPlane/pod/CollectionTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java index 1c58a948..41e7165b 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java @@ -28,7 +28,7 @@ public class CollectionErrorTest { private static final String environment = System.getenv("PINECONE_ENVIRONMENT"); private static final String indexName = RandomStringBuilder.build("collection-error-test", 8); private static final List upsertIds = Arrays.asList("v1", "v2", "v3"); - private static final int dimension = 3; + private static final int dimension = 4; private static final String collectionName = RandomStringBuilder.build("reusable-coll", 8); private static PineconeControlPlaneClient controlPlaneClient; @@ -70,7 +70,7 @@ public void testIndexFromNonExistentCollection() { try { CreateIndexRequestSpecPod podSpec = new CreateIndexRequestSpecPod().environment(environment).sourceCollection("non-existent-collection"); CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); - CreateIndexRequest newCreateIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-nonexistent-coll", 8)).dimension(3).metric(IndexMetric.COSINE).spec(spec); + CreateIndexRequest newCreateIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-nonexistent-coll", 8)).dimension(dimension).metric(IndexMetric.COSINE).spec(spec); controlPlaneClient.createIndex(newCreateIndexRequest); } catch (PineconeException exception) { assertTrue(exception.getMessage().contains("Resource non-existent-collection not found")); diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java index fecfe091..0577f64f 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java @@ -26,7 +26,7 @@ public class CollectionTest { private static final String namespace = RandomStringBuilder.build("ns", 8); private static final String apiKey = System.getenv("PINECONE_API_KEY"); private static final String environment = System.getenv("PINECONE_ENVIRONMENT"); - private static final int dimension = 3; + private static final int dimension = 4; @BeforeAll public static void setUpIndex() throws InterruptedException { From 7ca2739afba5f9600261e52785aaccf57b175fed Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Tue, 13 Feb 2024 23:47:30 -0500 Subject: [PATCH 04/22] add new vector builder for collections --- .../pinecone/helpers/BuildUpsertRequest.java | 33 ++++++++++++++++--- .../controlPlane/pod/CollectionErrorTest.java | 2 +- .../controlPlane/pod/CollectionTest.java | 2 +- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/integration/java/io/pinecone/helpers/BuildUpsertRequest.java b/src/integration/java/io/pinecone/helpers/BuildUpsertRequest.java index 3fa5acd0..6e1cca36 100644 --- a/src/integration/java/io/pinecone/helpers/BuildUpsertRequest.java +++ b/src/integration/java/io/pinecone/helpers/BuildUpsertRequest.java @@ -7,10 +7,7 @@ import io.pinecone.proto.UpsertRequest; import io.pinecone.proto.Vector; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; +import java.util.*; public class BuildUpsertRequest { private static final float[][] upsertData = {{1.0F, 2.0F, 3.0F}, {4.0F, 5.0F, 6.0F}, {7.0F, 8.0F, 9.0F}}; @@ -44,6 +41,23 @@ public static UpsertRequest buildRequiredUpsertRequest(List upsertIds, S .build(); } + public static UpsertRequest buildRequiredUpsertRequestByDimension(List upsertIds, int dimension, String namespace) { + if (upsertIds.isEmpty()) upsertIds = Arrays.asList("v1", "v2", "v3"); + + List upsertVectors = new ArrayList<>(); + for (String upsertId : upsertIds) { + upsertVectors.add(Vector.newBuilder() + .addAllValues(generateVectorValuesByDimension(dimension)) + .setId(upsertId) + .build()); + } + + return UpsertRequest.newBuilder() + .addAllVectors(upsertVectors) + .setNamespace(namespace) + .build(); + } + public static UpsertRequest buildOptionalUpsertRequest() { return buildOptionalUpsertRequest(new ArrayList<>(), ""); } @@ -108,4 +122,15 @@ public static HashMap> createAndGetMetadataMap() { return metadataMap; } + + public static ArrayList generateVectorValuesByDimension(int dimension) { + ArrayList values = new ArrayList<>(); + Random random = new Random(); + + for (int i = 0; i < dimension; i++) { + values.add(random.nextFloat()); + } + + return values; + } } diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java index 41e7165b..076c0470 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java @@ -41,7 +41,7 @@ public static void setUpIndexAndCollection() throws InterruptedException { VectorServiceGrpc.VectorServiceBlockingStub blockingStub = dataPlaneConnection.getBlockingStub(); // Upsert vectors to index and sleep for freshness - blockingStub.upsert(buildRequiredUpsertRequest(upsertIds, "")); + blockingStub.upsert(buildRequiredUpsertRequestByDimension(upsertIds, dimension, "")); dataPlaneConnection.close(); Thread.sleep(3500); diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java index 0577f64f..654c8504 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java @@ -37,7 +37,7 @@ public static void setUpIndex() throws InterruptedException { VectorServiceGrpc.VectorServiceBlockingStub blockingStub = dataPlaneConnection.getBlockingStub(); // Upsert vectors to index and sleep for freshness - blockingStub.upsert(buildRequiredUpsertRequest(upsertIds, namespace)); + blockingStub.upsert(buildRequiredUpsertRequestByDimension(upsertIds, dimension, namespace)); Thread.sleep(3500); dataPlaneConnection.close(); } From 7c522d9883499bf5a01581c0de1169d8cb819985 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Wed, 14 Feb 2024 00:19:12 -0500 Subject: [PATCH 05/22] remove the call to close from setup in collection tests --- .../integration/controlPlane/pod/CollectionErrorTest.java | 1 - .../io/pinecone/integration/controlPlane/pod/CollectionTest.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java index 076c0470..9dc20404 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java @@ -42,7 +42,6 @@ public static void setUpIndexAndCollection() throws InterruptedException { // Upsert vectors to index and sleep for freshness blockingStub.upsert(buildRequiredUpsertRequestByDimension(upsertIds, dimension, "")); - dataPlaneConnection.close(); Thread.sleep(3500); diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java index 654c8504..58a1e512 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java @@ -39,7 +39,6 @@ public static void setUpIndex() throws InterruptedException { // Upsert vectors to index and sleep for freshness blockingStub.upsert(buildRequiredUpsertRequestByDimension(upsertIds, dimension, namespace)); Thread.sleep(3500); - dataPlaneConnection.close(); } @AfterAll From 0544083e765a49b72566aada8e0a33dbba0dfcb8 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Wed, 14 Feb 2024 01:35:55 -0500 Subject: [PATCH 06/22] adjust ConfigureIndexTest to only create the initial index BeforeAll --- .../integration/controlPlane/pod/CollectionTest.java | 2 +- .../integration/controlPlane/pod/ConfigureIndexTest.java | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java index 58a1e512..a87c3522 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java @@ -92,7 +92,7 @@ public void testIndexToCollectionHappyPath() throws InterruptedException { CreateIndexRequest newCreateIndexRequest = new CreateIndexRequest().name(newIndexName).dimension(dimension).metric(indexMetric).spec(spec); controlPlaneClient.createIndex(newCreateIndexRequest); System.out.println("Index " + newIndexName + " created from collection " + collectionName + ". Waiting until index is ready..."); - waitUntilIndexIsReady(controlPlaneClient, newIndexName); + waitUntilIndexIsReady(controlPlaneClient, newIndexName, 200000); IndexModel indexDescription = controlPlaneClient.describeIndex(newIndexName); assertEquals(indexDescription.getName(), newIndexName); diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java index 9e26938c..58a8921e 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java @@ -20,16 +20,12 @@ public class ConfigureIndexTest { private static PineconeControlPlaneClient controlPlaneClient; - private String indexName; + private static String indexName; private static final Logger logger = LoggerFactory.getLogger(PineconeClientLiveIntegTest.class); @BeforeAll - public static void defineControlPlaneClient() { + public static void setUp() throws InterruptedException, IOException { controlPlaneClient = new PineconeControlPlaneClient(System.getenv("PINECONE_API_KEY")); - } - - @BeforeEach - public void setUp() throws IOException, InterruptedException { indexName = createIndexIfNotExistsControlPlane(controlPlaneClient, 5, IndexModelSpec.SERIALIZED_NAME_POD); } From 18b7164c967de18821d4f1123d59cbc846c84d52 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Wed, 14 Feb 2024 12:16:22 -0500 Subject: [PATCH 07/22] refine cleanUp steps in collection tests to make sure we're deleting things properly, use waitUntilReady properly in createCollection helper --- .../io/pinecone/helpers/IndexManager.java | 24 ++++++----- .../controlPlane/pod/CollectionErrorTest.java | 24 ++++++++--- .../controlPlane/pod/CollectionTest.java | 43 ++++++++++++------- .../controlPlane/pod/ConfigureIndexTest.java | 2 +- 4 files changed, 58 insertions(+), 35 deletions(-) diff --git a/src/integration/java/io/pinecone/helpers/IndexManager.java b/src/integration/java/io/pinecone/helpers/IndexManager.java index 577b2688..fad0e6a0 100644 --- a/src/integration/java/io/pinecone/helpers/IndexManager.java +++ b/src/integration/java/io/pinecone/helpers/IndexManager.java @@ -131,18 +131,20 @@ public static CollectionModel createCollection(PineconeControlPlaneClient contro assertEquals(collection.getStatus(), CollectionModel.StatusEnum.INITIALIZING); // Wait until collection is ready - int timeWaited = 0; - CollectionModel.StatusEnum collectionReady = collection.getStatus(); - while (collectionReady != CollectionModel.StatusEnum.READY && timeWaited < 120000) { - System.out.println("Waiting for collection" + collectionName + " to be ready. Waited " + timeWaited + " milliseconds..."); - Thread.sleep(5000); - timeWaited += 5000; - collection = controlPlaneClient.describeCollection(collectionName); - collectionReady = collection.getStatus(); - } + if (waitUntilReady) { + int timeWaited = 0; + CollectionModel.StatusEnum collectionReady = collection.getStatus(); + while (collectionReady != CollectionModel.StatusEnum.READY && timeWaited < 120000) { + System.out.println("Waiting for collection" + collectionName + " to be ready. Waited " + timeWaited + " milliseconds..."); + Thread.sleep(5000); + timeWaited += 5000; + collection = controlPlaneClient.describeCollection(collectionName); + collectionReady = collection.getStatus(); + } - if (timeWaited > 120000) { - fail("Collection: " + collectionName + " is not ready after 120 seconds"); + if (timeWaited > 120000) { + fail("Collection: " + collectionName + " is not ready after 120 seconds"); + } } return collection; diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java index 9dc20404..d5fa76d1 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java @@ -13,6 +13,7 @@ import org.junit.jupiter.api.Test; import java.util.Arrays; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Random; @@ -27,9 +28,11 @@ public class CollectionErrorTest { private static final String apiKey = System.getenv("PINECONE_API_KEY"); private static final String environment = System.getenv("PINECONE_ENVIRONMENT"); private static final String indexName = RandomStringBuilder.build("collection-error-test", 8); + private static final String collectionName = RandomStringBuilder.build("reusable-coll", 8); + private static ArrayList indexes = new ArrayList<>(); + private static ArrayList collections = new ArrayList<>(); private static final List upsertIds = Arrays.asList("v1", "v2", "v3"); private static final int dimension = 4; - private static final String collectionName = RandomStringBuilder.build("reusable-coll", 8); private static PineconeControlPlaneClient controlPlaneClient; @BeforeAll @@ -39,6 +42,7 @@ public static void setUpIndexAndCollection() throws InterruptedException { CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); PineconeConnection dataPlaneConnection = createNewIndexAndConnect(controlPlaneClient, indexName, dimension, IndexMetric.COSINE, spec); VectorServiceGrpc.VectorServiceBlockingStub blockingStub = dataPlaneConnection.getBlockingStub(); + indexes.add(indexName); // Upsert vectors to index and sleep for freshness blockingStub.upsert(buildRequiredUpsertRequestByDimension(upsertIds, dimension, "")); @@ -47,12 +51,17 @@ public static void setUpIndexAndCollection() throws InterruptedException { // Create collection from index createCollection(controlPlaneClient, collectionName, indexName, true); + collections.add(collectionName); } @AfterAll public static void cleanUp() { - controlPlaneClient.deleteIndex(indexName); - controlPlaneClient.deleteCollection(collectionName); + for (String index : indexes) { + controlPlaneClient.deleteIndex(index); + } + for (String collection : collections) { + controlPlaneClient.deleteCollection(collection); + } } @Test @@ -123,20 +132,21 @@ public void testCreateIndexWithMismatchedDimension() { @Test public void testCreateCollectionFromNotReadyIndex() throws InterruptedException { String notReadyIndexName = RandomStringBuilder.build("from-coll4", 8); + String newCollectionName = RandomStringBuilder.build("coll4-", 8); try { CreateIndexRequestSpecPod specPod = new CreateIndexRequestSpecPod().pods(1).podType("p1.x1").replicas(1).environment(environment); CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(specPod); CreateIndexRequest createIndexRequest = new CreateIndexRequest().name(notReadyIndexName).dimension(dimension).metric(IndexMetric.COSINE).spec(spec); controlPlaneClient.createIndex(createIndexRequest); + indexes.add(notReadyIndexName); - CreateCollectionRequest createCollectionRequest = new CreateCollectionRequest().name(RandomStringBuilder.build("coll4-", 8)).source(notReadyIndexName); - controlPlaneClient.createCollection(createCollectionRequest); + createCollection(controlPlaneClient, newCollectionName, notReadyIndexName, true); + collections.add(newCollectionName); } catch (PineconeException exception) { assert (exception.getMessage().contains("Source index is not ready")); } finally { - // Wait for index to initialize and clean up + // Wait for index to initialize so it can be deleted in @AfterAll waitUntilIndexIsReady(controlPlaneClient, notReadyIndexName); - controlPlaneClient.deleteIndex(notReadyIndexName); } } } \ No newline at end of file diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java index a87c3522..f3634228 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java @@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test; import org.openapitools.client.model.*; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -21,6 +22,8 @@ public class CollectionTest { private static PineconeControlPlaneClient controlPlaneClient; private static final String indexName = RandomStringBuilder.build("collection-test", 8); + private static ArrayList indexes = new ArrayList<>(); + private static ArrayList collections = new ArrayList<>(); private static final IndexMetric indexMetric = IndexMetric.COSINE; private static final List upsertIds = Arrays.asList("v1", "v2", "v3"); private static final String namespace = RandomStringBuilder.build("ns", 8); @@ -29,12 +32,13 @@ public class CollectionTest { private static final int dimension = 4; @BeforeAll - public static void setUpIndex() throws InterruptedException { + public static void setUp() throws InterruptedException { controlPlaneClient = new PineconeControlPlaneClient(apiKey); CreateIndexRequestSpecPod podSpec = new CreateIndexRequestSpecPod().pods(1).podType("p1.x1").replicas(1).environment(environment); CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); PineconeConnection dataPlaneConnection = createNewIndexAndConnect(controlPlaneClient, indexName, dimension, indexMetric, spec); VectorServiceGrpc.VectorServiceBlockingStub blockingStub = dataPlaneConnection.getBlockingStub(); + indexes.add(indexName); // Upsert vectors to index and sleep for freshness blockingStub.upsert(buildRequiredUpsertRequestByDimension(upsertIds, dimension, namespace)); @@ -42,9 +46,16 @@ public static void setUpIndex() throws InterruptedException { } @AfterAll - public static void deleteIndex() throws InterruptedException { - Thread.sleep(5000); - controlPlaneClient.deleteIndex(indexName); + public static void cleanUp() throws InterruptedException { + Thread.sleep(3500); + // Clean up indexes + for (String index : indexes) { + controlPlaneClient.deleteIndex(index); + } + // Clean up collections + for (String collection : collections) { + controlPlaneClient.deleteCollection(collection); + } } @Test @@ -53,16 +64,17 @@ public void testIndexToCollectionHappyPath() throws InterruptedException { // Create collection from index CollectionModel collection = createCollection(controlPlaneClient, collectionName, indexName, true); + collections.add(collectionName); assertEquals(collection.getName(), collectionName); assertEquals(collection.getEnvironment(), environment); assertEquals(collection.getStatus(), CollectionModel.StatusEnum.READY); // Verify collection is listed - List collections = controlPlaneClient.listCollections().getCollections(); + List collectionList = controlPlaneClient.listCollections().getCollections(); boolean collectionFound = false; - if (collections != null && !collections.isEmpty()) { - for (CollectionModel col : collections) { + if (collectionList != null && !collectionList.isEmpty()) { + for (CollectionModel col : collectionList) { if (col.getName().equals(collectionName)) { collectionFound = true; break; @@ -91,6 +103,7 @@ public void testIndexToCollectionHappyPath() throws InterruptedException { CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); CreateIndexRequest newCreateIndexRequest = new CreateIndexRequest().name(newIndexName).dimension(dimension).metric(indexMetric).spec(spec); controlPlaneClient.createIndex(newCreateIndexRequest); + indexes.add(newIndexName); System.out.println("Index " + newIndexName + " created from collection " + collectionName + ". Waiting until index is ready..."); waitUntilIndexIsReady(controlPlaneClient, newIndexName, 200000); @@ -111,7 +124,6 @@ public void testIndexToCollectionHappyPath() throws InterruptedException { // Verify the vectors from the collection -> new index can be fetched FetchResponse fetchedVectors = newIndexBlockingStub.fetch(FetchRequest.newBuilder().addAllIds(upsertIds).setNamespace(namespace).build()); - newIndexDataPlaneClient.close(); for (String key : upsertIds) { assert (fetchedVectors.containsVectors(key)); @@ -119,13 +131,14 @@ public void testIndexToCollectionHappyPath() throws InterruptedException { // Verify we can delete the collection controlPlaneClient.deleteCollection(collectionName); + collections.remove(collectionName); Thread.sleep(2500); - collections = controlPlaneClient.listCollections().getCollections(); + collectionList = controlPlaneClient.listCollections().getCollections(); - if (collections != null) { + if (collectionList != null) { boolean isCollectionDeleted = true; - for (CollectionModel col : collections) { + for (CollectionModel col : collectionList) { if (col.getName().equals(collectionName)) { isCollectionDeleted = false; break; @@ -137,8 +150,7 @@ public void testIndexToCollectionHappyPath() throws InterruptedException { } } - // Clean up - controlPlaneClient.deleteIndex(newIndexName); + newIndexDataPlaneClient.close(); } @Test @@ -147,6 +159,7 @@ public void testIndexFromDifferentMetricCollection() throws InterruptedException // Create collection from index CollectionModel collection = createCollection(controlPlaneClient, collectionName, indexName, true); + collections.add(collectionName); assertEquals(collection.getName(), collectionName); assertEquals(collection.getEnvironment(), environment); @@ -165,14 +178,12 @@ public void testIndexFromDifferentMetricCollection() throws InterruptedException CreateIndexRequestSpecPod podSpec = new CreateIndexRequestSpecPod().environment(environment).sourceCollection(collectionName); CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); PineconeConnection dataPlaneConnection = createNewIndexAndConnect(controlPlaneClient, newIndexName, dimension, targetMetric, spec); + indexes.add(newIndexName); IndexModel newIndex = controlPlaneClient.describeIndex(newIndexName); assertEquals(newIndex.getName(), newIndexName); assertEquals(newIndex.getMetric(), targetMetric); - // Clean up - controlPlaneClient.deleteIndex(newIndexName); - controlPlaneClient.deleteCollection(collectionName); dataPlaneConnection.close(); } diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java index 58a8921e..4c562927 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java @@ -79,7 +79,7 @@ public void scaleUpAndDown() { }); // Scaling down - pod = new ConfigureIndexRequestSpecPod().replicas(3); + pod = new ConfigureIndexRequestSpecPod().replicas(1); spec = new ConfigureIndexRequestSpec().pod(pod); configureIndexRequest = new ConfigureIndexRequest().spec(spec); controlPlaneClient.configureIndex(indexName, configureIndexRequest); From 8dafe1ffd190c9cff3005b72106900344d2768d7 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Wed, 14 Feb 2024 14:03:27 -0500 Subject: [PATCH 08/22] fix logic issue in findIndexWithDimensionAndType --- .../java/io/pinecone/helpers/IndexManager.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/integration/java/io/pinecone/helpers/IndexManager.java b/src/integration/java/io/pinecone/helpers/IndexManager.java index fad0e6a0..fea9e883 100644 --- a/src/integration/java/io/pinecone/helpers/IndexManager.java +++ b/src/integration/java/io/pinecone/helpers/IndexManager.java @@ -48,10 +48,12 @@ private static String findIndexWithDimensionAndType(IndexList indexList, int dim List indexModels = indexList.getIndexes(); while (i < indexModels.size()) { IndexModel indexModel = isIndexReady(indexModels.get(i).getName(), controlPlaneClient); - // ToDo: add pod type support if (indexModel.getDimension() == dimension - && ((indexType.equalsIgnoreCase(IndexModelSpec.SERIALIZED_NAME_POD) && indexModel.getSpec().getPod() != null && indexModel.getSpec().getPod().getReplicas() == 1 && indexModel.getSpec().getPod().getPodType().equalsIgnoreCase("p1.x1")) - || (indexType.equalsIgnoreCase(IndexModelSpec.SERIALIZED_NAME_SERVERLESS)))) { + && (indexType.equalsIgnoreCase(IndexModelSpec.SERIALIZED_NAME_POD) + && indexModel.getSpec().getPod() != null + && indexModel.getSpec().getPod().getReplicas() == 1 + && indexModel.getSpec().getPod().getPodType().equalsIgnoreCase("p1.x1")) + || (indexType.equalsIgnoreCase(IndexModelSpec.SERIALIZED_NAME_SERVERLESS))) { return indexModel.getName(); } i++; From a90eb2a7bf5470c75f51812ef8c68d2e17a673d0 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Wed, 14 Feb 2024 14:33:22 -0500 Subject: [PATCH 09/22] Set max-parallel to 1 for integration tests, remove extra sleep from waitUntilIndexReady --- gradle/wrapper/gradle-wrapper.properties | 2 +- src/integration/java/io/pinecone/helpers/IndexManager.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index da9702f9..e750102e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/integration/java/io/pinecone/helpers/IndexManager.java b/src/integration/java/io/pinecone/helpers/IndexManager.java index fea9e883..98d96bf1 100644 --- a/src/integration/java/io/pinecone/helpers/IndexManager.java +++ b/src/integration/java/io/pinecone/helpers/IndexManager.java @@ -96,8 +96,7 @@ public static IndexModel waitUntilIndexIsReady(PineconeControlPlaneClient contro break; } if (index.getStatus().getReady()) { - Thread.sleep(3000); - System.out.println("Index " + indexName + " is ready after " + waitedTimeMs + 3000 + "ms"); + System.out.println("Index " + indexName + " is ready after " + waitedTimeMs + "ms"); break; } Thread.sleep(intervalMs); From 1bfd814c2b4d3e1e0d7734d0c564b395c28612fd Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Wed, 14 Feb 2024 14:54:54 -0500 Subject: [PATCH 10/22] back out gradle wrapper changes, tweak findIndexByDimensionAndType again, max-parallel again --- .github/workflows/pr.yml | 3 ++- build.gradle | 1 - gradle/wrapper/gradle-wrapper.properties | 2 +- src/integration/java/io/pinecone/helpers/IndexManager.java | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 0533b18d..2e4fa8e9 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -58,6 +58,7 @@ jobs: { java: 8, gradle: 6.8 }, { java: 17, gradle: 7.3.1 } ] + max-parallel: 1 steps: - uses: actions/checkout@v4 @@ -83,5 +84,5 @@ jobs: env: PINECONE_API_KEY: ${{ secrets.PINECONE_API_KEY }} PINECONE_ENVIRONMENT: ${{ secrets.PINECONE_ENVIRONMENT }} - + diff --git a/build.gradle b/build.gradle index aea0cca5..45c0f3bf 100644 --- a/build.gradle +++ b/build.gradle @@ -97,7 +97,6 @@ tasks.named('build') { test { useJUnitPlatform() - testLogging { events = [TestLogEvent.FAILED, TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.STANDARD_OUT] exceptionFormat = TestExceptionFormat.FULL diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e750102e..da9702f9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/integration/java/io/pinecone/helpers/IndexManager.java b/src/integration/java/io/pinecone/helpers/IndexManager.java index 98d96bf1..08dbbfbc 100644 --- a/src/integration/java/io/pinecone/helpers/IndexManager.java +++ b/src/integration/java/io/pinecone/helpers/IndexManager.java @@ -49,11 +49,11 @@ private static String findIndexWithDimensionAndType(IndexList indexList, int dim while (i < indexModels.size()) { IndexModel indexModel = isIndexReady(indexModels.get(i).getName(), controlPlaneClient); if (indexModel.getDimension() == dimension - && (indexType.equalsIgnoreCase(IndexModelSpec.SERIALIZED_NAME_POD) + && ((indexType.equalsIgnoreCase(IndexModelSpec.SERIALIZED_NAME_POD) && indexModel.getSpec().getPod() != null && indexModel.getSpec().getPod().getReplicas() == 1 && indexModel.getSpec().getPod().getPodType().equalsIgnoreCase("p1.x1")) - || (indexType.equalsIgnoreCase(IndexModelSpec.SERIALIZED_NAME_SERVERLESS))) { + || (indexType.equalsIgnoreCase(IndexModelSpec.SERIALIZED_NAME_SERVERLESS)))) { return indexModel.getName(); } i++; From 45b8af274f7f3f7ad099a7fea8e46a166d378cef Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Wed, 14 Feb 2024 15:45:14 -0500 Subject: [PATCH 11/22] make sure we're closing PineconeConnection objects properly in tests where we create one --- .../controlPlane/pod/CollectionErrorTest.java | 6 +++--- .../integration/controlPlane/pod/CollectionTest.java | 2 ++ .../dataplane/PineconeClientLiveIntegTest.java | 10 +++++++++- .../integration/dataplane/UpdateAndQueryTest.java | 10 +++++++++- .../integration/dataplane/UpsertAndDeleteTest.java | 9 ++++++++- .../dataplane/UpsertAndDescribeIndexStatsTest.java | 8 +++++++- 6 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java index d5fa76d1..2612ca24 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java @@ -46,7 +46,7 @@ public static void setUpIndexAndCollection() throws InterruptedException { // Upsert vectors to index and sleep for freshness blockingStub.upsert(buildRequiredUpsertRequestByDimension(upsertIds, dimension, "")); - + dataPlaneConnection.close(); Thread.sleep(3500); // Create collection from index @@ -108,7 +108,7 @@ public void testCreateIndexInMismatchedEnvironment() { CreateIndexRequestSpecPod podSpec = new CreateIndexRequestSpecPod().sourceCollection(collection.getName()).environment(mismatchedEnv); CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); - CreateIndexRequest createIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-coll-", 8)).dimension(dimension).metric(IndexMetric.COSINE).spec(spec); + CreateIndexRequest createIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-coll", 8)).dimension(dimension).metric(IndexMetric.COSINE).spec(spec); controlPlaneClient.createIndex(createIndexRequest); } catch (PineconeException exception) { assertTrue(exception.getMessage().contains("Source collection must be in the same environment as the index")); @@ -122,7 +122,7 @@ public void testCreateIndexWithMismatchedDimension() { CollectionModel collection = controlPlaneClient.describeCollection(collectionName); CreateIndexRequestSpecPod podSpec = new CreateIndexRequestSpecPod().sourceCollection(collection.getName()).environment(collection.getEnvironment()); CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); - CreateIndexRequest createIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-coll-", 8)).dimension(dimension + 1).metric(IndexMetric.COSINE).spec(spec); + CreateIndexRequest createIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-coll", 8)).dimension(dimension + 1).metric(IndexMetric.COSINE).spec(spec); controlPlaneClient.createIndex(createIndexRequest); } catch (PineconeException exception) { assertTrue(exception.getMessage().contains("Index and collection must have the same dimension")); diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java index f3634228..a376be76 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java @@ -42,7 +42,9 @@ public static void setUp() throws InterruptedException { // Upsert vectors to index and sleep for freshness blockingStub.upsert(buildRequiredUpsertRequestByDimension(upsertIds, dimension, namespace)); + dataPlaneConnection.close(); Thread.sleep(3500); + } @AfterAll diff --git a/src/integration/java/io/pinecone/integration/dataplane/PineconeClientLiveIntegTest.java b/src/integration/java/io/pinecone/integration/dataplane/PineconeClientLiveIntegTest.java index e1d2b5be..67d8ec57 100644 --- a/src/integration/java/io/pinecone/integration/dataplane/PineconeClientLiveIntegTest.java +++ b/src/integration/java/io/pinecone/integration/dataplane/PineconeClientLiveIntegTest.java @@ -6,6 +6,7 @@ import io.pinecone.PineconeConnection; import io.pinecone.helpers.RandomStringBuilder; import io.pinecone.proto.*; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -24,14 +25,21 @@ public class PineconeClientLiveIntegTest { private static final Logger logger = LoggerFactory.getLogger(PineconeClientLiveIntegTest.class); + + private static PineconeConnection connection; private static VectorServiceGrpc.VectorServiceBlockingStub blockingStub; @BeforeAll public static void defineConfig() throws IOException, InterruptedException { - PineconeConnection connection = createIndexIfNotExistsDataPlane(3, IndexModelSpec.SERIALIZED_NAME_POD); + connection = createIndexIfNotExistsDataPlane(3, IndexModelSpec.SERIALIZED_NAME_POD); blockingStub = connection.getBlockingStub(); } + @AfterAll + public static void cleanUp() { + connection.close(); + } + @Test public void sanity() throws InterruptedException { String namespace = RandomStringBuilder.build("ns", 8); diff --git a/src/integration/java/io/pinecone/integration/dataplane/UpdateAndQueryTest.java b/src/integration/java/io/pinecone/integration/dataplane/UpdateAndQueryTest.java index fe182f30..c98e33f7 100644 --- a/src/integration/java/io/pinecone/integration/dataplane/UpdateAndQueryTest.java +++ b/src/integration/java/io/pinecone/integration/dataplane/UpdateAndQueryTest.java @@ -6,6 +6,8 @@ import io.pinecone.PineconeConnection; import io.pinecone.helpers.RandomStringBuilder; import io.pinecone.proto.*; +import org.junit.After; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.openapitools.client.model.IndexModelSpec; @@ -21,17 +23,23 @@ import static org.junit.jupiter.api.Assertions.assertEquals; public class UpdateAndQueryTest { + private static PineconeConnection connection; private static VectorServiceGrpc.VectorServiceBlockingStub blockingStub; private static VectorServiceGrpc.VectorServiceFutureStub futureStub; private static final int dimension = 3; @BeforeAll public static void setUp() throws IOException, InterruptedException { - PineconeConnection connection = createIndexIfNotExistsDataPlane(dimension, IndexModelSpec.SERIALIZED_NAME_POD); + connection = createIndexIfNotExistsDataPlane(dimension, IndexModelSpec.SERIALIZED_NAME_POD); blockingStub = connection.getBlockingStub(); futureStub = connection.getFutureStub(); } + @AfterAll + public static void cleanUp() { + connection.close(); + } + @Test public void UpdateRequiredParamsFetchAndQuerySync() throws InterruptedException { // Upsert vectors with required parameters diff --git a/src/integration/java/io/pinecone/integration/dataplane/UpsertAndDeleteTest.java b/src/integration/java/io/pinecone/integration/dataplane/UpsertAndDeleteTest.java index 5fa2629b..c7276325 100644 --- a/src/integration/java/io/pinecone/integration/dataplane/UpsertAndDeleteTest.java +++ b/src/integration/java/io/pinecone/integration/dataplane/UpsertAndDeleteTest.java @@ -5,6 +5,7 @@ import io.pinecone.PineconeConnection; import io.pinecone.helpers.RandomStringBuilder; import io.pinecone.proto.*; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.openapitools.client.model.IndexModelSpec; @@ -20,17 +21,23 @@ import static org.junit.jupiter.api.Assertions.assertThrows; public class UpsertAndDeleteTest { + private static PineconeConnection connection; private static VectorServiceGrpc.VectorServiceBlockingStub blockingStub; private static VectorServiceGrpc.VectorServiceFutureStub futureStub; private static final int dimension = 3; @BeforeAll public static void setUp() throws IOException, InterruptedException { - PineconeConnection connection = createIndexIfNotExistsDataPlane(dimension, IndexModelSpec.SERIALIZED_NAME_POD); + connection = createIndexIfNotExistsDataPlane(dimension, IndexModelSpec.SERIALIZED_NAME_POD); blockingStub = connection.getBlockingStub(); futureStub = connection.getFutureStub(); } + @AfterAll + public static void cleanUp() { + connection.close(); + } + @Test public void UpsertVectorsAndDeleteByIdSyncTest() throws InterruptedException { // Upsert vectors with required parameters diff --git a/src/integration/java/io/pinecone/integration/dataplane/UpsertAndDescribeIndexStatsTest.java b/src/integration/java/io/pinecone/integration/dataplane/UpsertAndDescribeIndexStatsTest.java index 0b065d52..5f639ded 100644 --- a/src/integration/java/io/pinecone/integration/dataplane/UpsertAndDescribeIndexStatsTest.java +++ b/src/integration/java/io/pinecone/integration/dataplane/UpsertAndDescribeIndexStatsTest.java @@ -14,17 +14,23 @@ import java.util.concurrent.ExecutionException; public class UpsertAndDescribeIndexStatsTest { + private static PineconeConnection connection; private static VectorServiceGrpc.VectorServiceBlockingStub blockingStub; private static VectorServiceGrpc.VectorServiceFutureStub futureStub; private static final int dimension = 3; @BeforeAll public static void setUp() throws IOException, InterruptedException { - PineconeConnection connection = createIndexIfNotExistsDataPlane(dimension, IndexModelSpec.SERIALIZED_NAME_POD); + connection = createIndexIfNotExistsDataPlane(dimension, IndexModelSpec.SERIALIZED_NAME_POD); blockingStub = connection.getBlockingStub(); futureStub = connection.getFutureStub(); } + @AfterAll + public static void cleanUp() { + connection.close(); + } + @Test public void UpsertRequiredVectorsAndDescribeIndexStatsSyncTest() throws InterruptedException { // Get vector and namespace counts before upserting vectors with required parameters From 4a2305d7daea74b15f2c1ef9d4167c6628333501 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Wed, 14 Feb 2024 16:28:03 -0500 Subject: [PATCH 12/22] a bit more integration test whack-a-mole with sleeps --- .../java/io/pinecone/helpers/IndexManager.java | 3 +++ .../controlPlane/pod/CollectionErrorTest.java | 4 ++-- .../controlPlane/pod/CollectionTest.java | 15 ++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/integration/java/io/pinecone/helpers/IndexManager.java b/src/integration/java/io/pinecone/helpers/IndexManager.java index 08dbbfbc..31d555cc 100644 --- a/src/integration/java/io/pinecone/helpers/IndexManager.java +++ b/src/integration/java/io/pinecone/helpers/IndexManager.java @@ -115,6 +115,9 @@ public static PineconeConnection createNewIndexAndConnect(PineconeControlPlaneCl // Wait until index is ready waitUntilIndexIsReady(controlPlaneClient, indexName, 200000); + // wait a bit more before we connect... + Thread.sleep(10000); + String host = controlPlaneClient.describeIndex(indexName).getHost(); PineconeClientConfig specificConfig = new PineconeClientConfig().withApiKey(System.getenv("PINECONE_API_KEY")); diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java index 2612ca24..c90cfba8 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java @@ -29,8 +29,8 @@ public class CollectionErrorTest { private static final String environment = System.getenv("PINECONE_ENVIRONMENT"); private static final String indexName = RandomStringBuilder.build("collection-error-test", 8); private static final String collectionName = RandomStringBuilder.build("reusable-coll", 8); - private static ArrayList indexes = new ArrayList<>(); - private static ArrayList collections = new ArrayList<>(); + private static final ArrayList indexes = new ArrayList<>(); + private static final ArrayList collections = new ArrayList<>(); private static final List upsertIds = Arrays.asList("v1", "v2", "v3"); private static final int dimension = 4; private static PineconeControlPlaneClient controlPlaneClient; diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java index a376be76..53e1b73a 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java @@ -22,8 +22,8 @@ public class CollectionTest { private static PineconeControlPlaneClient controlPlaneClient; private static final String indexName = RandomStringBuilder.build("collection-test", 8); - private static ArrayList indexes = new ArrayList<>(); - private static ArrayList collections = new ArrayList<>(); + private static final ArrayList indexes = new ArrayList<>(); + private static final ArrayList collections = new ArrayList<>(); private static final IndexMetric indexMetric = IndexMetric.COSINE; private static final List upsertIds = Arrays.asList("v1", "v2", "v3"); private static final String namespace = RandomStringBuilder.build("ns", 8); @@ -40,16 +40,13 @@ public static void setUp() throws InterruptedException { VectorServiceGrpc.VectorServiceBlockingStub blockingStub = dataPlaneConnection.getBlockingStub(); indexes.add(indexName); - // Upsert vectors to index and sleep for freshness blockingStub.upsert(buildRequiredUpsertRequestByDimension(upsertIds, dimension, namespace)); dataPlaneConnection.close(); - Thread.sleep(3500); } @AfterAll - public static void cleanUp() throws InterruptedException { - Thread.sleep(3500); + public static void cleanUp() { // Clean up indexes for (String index : indexes) { controlPlaneClient.deleteIndex(index); @@ -107,13 +104,14 @@ public void testIndexToCollectionHappyPath() throws InterruptedException { controlPlaneClient.createIndex(newCreateIndexRequest); indexes.add(newIndexName); System.out.println("Index " + newIndexName + " created from collection " + collectionName + ". Waiting until index is ready..."); - waitUntilIndexIsReady(controlPlaneClient, newIndexName, 200000); + waitUntilIndexIsReady(controlPlaneClient, newIndexName, 250000); + // wait a bit more to make sure index is ready... + Thread.sleep(15000); IndexModel indexDescription = controlPlaneClient.describeIndex(newIndexName); assertEquals(indexDescription.getName(), newIndexName); assertEquals(indexDescription.getSpec().getPod().getSourceCollection(), collectionName); assertEquals(indexDescription.getStatus().getReady(), true); - Thread.sleep(5000); // Set up new index data plane connection PineconeClient newIndexClient = new PineconeClient(new PineconeClientConfig().withApiKey(apiKey).withEnvironment(environment)); @@ -134,7 +132,6 @@ public void testIndexToCollectionHappyPath() throws InterruptedException { // Verify we can delete the collection controlPlaneClient.deleteCollection(collectionName); collections.remove(collectionName); - Thread.sleep(2500); collectionList = controlPlaneClient.listCollections().getCollections(); From 817da41e127eff17020155843bcbd712398d5e83 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Wed, 14 Feb 2024 17:06:42 -0500 Subject: [PATCH 13/22] sleep tweaks --- src/integration/java/io/pinecone/helpers/IndexManager.java | 2 +- .../integration/controlPlane/pod/CollectionErrorTest.java | 4 +++- .../integration/controlPlane/pod/CollectionTest.java | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/integration/java/io/pinecone/helpers/IndexManager.java b/src/integration/java/io/pinecone/helpers/IndexManager.java index 31d555cc..38e1c270 100644 --- a/src/integration/java/io/pinecone/helpers/IndexManager.java +++ b/src/integration/java/io/pinecone/helpers/IndexManager.java @@ -116,7 +116,7 @@ public static PineconeConnection createNewIndexAndConnect(PineconeControlPlaneCl // Wait until index is ready waitUntilIndexIsReady(controlPlaneClient, indexName, 200000); // wait a bit more before we connect... - Thread.sleep(10000); + Thread.sleep(15000); String host = controlPlaneClient.describeIndex(indexName).getHost(); diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java index c90cfba8..25f161c8 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java @@ -55,7 +55,9 @@ public static void setUpIndexAndCollection() throws InterruptedException { } @AfterAll - public static void cleanUp() { + public static void cleanUp() throws InterruptedException { + // wait for things to settle before cleanup... + Thread.sleep(3000); for (String index : indexes) { controlPlaneClient.deleteIndex(index); } diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java index 53e1b73a..6b60f875 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java @@ -46,7 +46,9 @@ public static void setUp() throws InterruptedException { } @AfterAll - public static void cleanUp() { + public static void cleanUp() throws InterruptedException { + // wait for things to settle before cleanup... + Thread.sleep(3000); // Clean up indexes for (String index : indexes) { controlPlaneClient.deleteIndex(index); @@ -106,7 +108,7 @@ public void testIndexToCollectionHappyPath() throws InterruptedException { System.out.println("Index " + newIndexName + " created from collection " + collectionName + ". Waiting until index is ready..."); waitUntilIndexIsReady(controlPlaneClient, newIndexName, 250000); // wait a bit more to make sure index is ready... - Thread.sleep(15000); + Thread.sleep(30000); IndexModel indexDescription = controlPlaneClient.describeIndex(newIndexName); assertEquals(indexDescription.getName(), newIndexName); From 20d3e6769a038344d36ce6bae22442ddb2ede9ca Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Wed, 14 Feb 2024 17:44:55 -0500 Subject: [PATCH 14/22] adding loggin to the error tests so we can see what the actual error is on failure --- .../integration/controlPlane/pod/CollectionErrorTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java index 25f161c8..341de480 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java @@ -72,6 +72,7 @@ public void testCreateCollectionFromInvalidIndex() { CreateCollectionRequest createCollectionRequest = new CreateCollectionRequest().name(RandomStringBuilder.build("coll1", 8)).source("invalid-index"); controlPlaneClient.createCollection(createCollectionRequest); } catch (PineconeException exception) { + System.out.println("Exception: " + exception.getMessage()); assertTrue(exception.getMessage().contains("Resource invalid-index not found")); } } @@ -83,6 +84,7 @@ public void testIndexFromNonExistentCollection() { CreateIndexRequest newCreateIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-nonexistent-coll", 8)).dimension(dimension).metric(IndexMetric.COSINE).spec(spec); controlPlaneClient.createIndex(newCreateIndexRequest); } catch (PineconeException exception) { + System.out.println("Exception: " + exception.getMessage()); assertTrue(exception.getMessage().contains("Resource non-existent-collection not found")); } } @@ -113,6 +115,7 @@ public void testCreateIndexInMismatchedEnvironment() { CreateIndexRequest createIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-coll", 8)).dimension(dimension).metric(IndexMetric.COSINE).spec(spec); controlPlaneClient.createIndex(createIndexRequest); } catch (PineconeException exception) { + System.out.println("Exception: " + exception.getMessage()); assertTrue(exception.getMessage().contains("Source collection must be in the same environment as the index")); } } @@ -127,6 +130,7 @@ public void testCreateIndexWithMismatchedDimension() { CreateIndexRequest createIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-coll", 8)).dimension(dimension + 1).metric(IndexMetric.COSINE).spec(spec); controlPlaneClient.createIndex(createIndexRequest); } catch (PineconeException exception) { + System.out.println("Exception: " + exception.getMessage()); assertTrue(exception.getMessage().contains("Index and collection must have the same dimension")); } } @@ -145,6 +149,7 @@ public void testCreateCollectionFromNotReadyIndex() throws InterruptedException createCollection(controlPlaneClient, newCollectionName, notReadyIndexName, true); collections.add(newCollectionName); } catch (PineconeException exception) { + System.out.println("Exception: " + exception.getMessage()); assert (exception.getMessage().contains("Source index is not ready")); } finally { // Wait for index to initialize so it can be deleted in @AfterAll From 71785ffd737e5acb39341dcab75a0c83559fca6b Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Wed, 14 Feb 2024 22:10:12 -0500 Subject: [PATCH 15/22] fix environments in collection error test, sleep adjusts again --- .../integration/controlPlane/pod/CollectionErrorTest.java | 7 ++++--- .../integration/controlPlane/pod/CollectionTest.java | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java index 341de480..788e89b1 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java @@ -57,13 +57,14 @@ public static void setUpIndexAndCollection() throws InterruptedException { @AfterAll public static void cleanUp() throws InterruptedException { // wait for things to settle before cleanup... - Thread.sleep(3000); + Thread.sleep(2500); for (String index : indexes) { controlPlaneClient.deleteIndex(index); } for (String collection : collections) { controlPlaneClient.deleteCollection(collection); } + Thread.sleep(2500); } @Test @@ -102,8 +103,8 @@ public void testCreateIndexInMismatchedEnvironment() { "us-east-1-aws", "asia-northeast1-gcp", "eu-west1-gcp", - "eu-east1-gcp", - "eu-east4-gcp", + "us-east1-gcp", + "us-east4-gcp", "us-west1-gcp" )); CollectionModel collection = controlPlaneClient.describeCollection(collectionName); diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java index 6b60f875..b9033cf2 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java @@ -48,7 +48,7 @@ public static void setUp() throws InterruptedException { @AfterAll public static void cleanUp() throws InterruptedException { // wait for things to settle before cleanup... - Thread.sleep(3000); + Thread.sleep(2500); // Clean up indexes for (String index : indexes) { controlPlaneClient.deleteIndex(index); @@ -57,6 +57,7 @@ public static void cleanUp() throws InterruptedException { for (String collection : collections) { controlPlaneClient.deleteCollection(collection); } + Thread.sleep(2500); } @Test @@ -134,6 +135,8 @@ public void testIndexToCollectionHappyPath() throws InterruptedException { // Verify we can delete the collection controlPlaneClient.deleteCollection(collectionName); collections.remove(collectionName); + Thread.sleep(2500); + collectionList = controlPlaneClient.listCollections().getCollections(); From c3dc78918ced44d4df283c4e26d86784fee64202 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Tue, 20 Feb 2024 15:44:00 -0500 Subject: [PATCH 16/22] review feedback, use logger instead of println, update error handling in assertWithRetry to actuall throw on failure --- .../java/io/pinecone/helpers/AssertRetry.java | 9 +++++++-- .../java/io/pinecone/helpers/IndexManager.java | 9 ++++++--- .../controlPlane/pod/CollectionErrorTest.java | 17 ++++++++++------- .../controlPlane/pod/CollectionTest.java | 8 ++++++-- .../controlPlane/pod/ConfigureIndexTest.java | 4 ++-- .../io/pinecone/PineconeControlPlaneClient.java | 2 +- 6 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/integration/java/io/pinecone/helpers/AssertRetry.java b/src/integration/java/io/pinecone/helpers/AssertRetry.java index 16f4c6cf..7b4a56c6 100644 --- a/src/integration/java/io/pinecone/helpers/AssertRetry.java +++ b/src/integration/java/io/pinecone/helpers/AssertRetry.java @@ -13,16 +13,21 @@ public static void assertWithRetry(AssertionRunnable assertionRunnable) throws I assertWithRetry(assertionRunnable, 2); } - public static void assertWithRetry(AssertionRunnable assertionRunnable, int backOff) throws InterruptedException, PineconeException { + public static void assertWithRetry(AssertionRunnable assertionRunnable, int backOff) throws AssertionError, InterruptedException { int retryCount = 0; int delayCount = delay; boolean success = false; - while (retryCount < maxRetry && !success) { + while (!success) { try { assertionRunnable.run(); success = true; } catch (AssertionError | ExecutionException | IOException e) { + // If we've hit the max number of retries throw and abort + if (retryCount == maxRetry) { + throw new AssertionError(e.getLocalizedMessage()); + } + retryCount++; Thread.sleep(delayCount); delayCount*=backOff; diff --git a/src/integration/java/io/pinecone/helpers/IndexManager.java b/src/integration/java/io/pinecone/helpers/IndexManager.java index 38e1c270..b558388f 100644 --- a/src/integration/java/io/pinecone/helpers/IndexManager.java +++ b/src/integration/java/io/pinecone/helpers/IndexManager.java @@ -3,6 +3,8 @@ import io.pinecone.*; import io.pinecone.exceptions.PineconeException; import org.openapitools.client.model.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.List; @@ -13,6 +15,7 @@ public class IndexManager { private static PineconeClientConfig config; + private static final Logger logger = LoggerFactory.getLogger(IndexManager.class); public static PineconeConnection createIndexIfNotExistsDataPlane(int dimension, String indexType) throws IOException, InterruptedException { String apiKey = System.getenv("PINECONE_API_KEY"); @@ -92,11 +95,11 @@ public static IndexModel waitUntilIndexIsReady(PineconeControlPlaneClient contro while (!index.getStatus().getReady()) { index = controlPlaneClient.describeIndex(indexName); if (waitedTimeMs >= totalMsToWait) { - System.out.println("Index " + indexName + " not ready after " + waitedTimeMs + "ms"); + logger.info("Index " + indexName + " not ready after " + waitedTimeMs + "ms"); break; } if (index.getStatus().getReady()) { - System.out.println("Index " + indexName + " is ready after " + waitedTimeMs + "ms"); + logger.info("Index " + indexName + " is ready after " + waitedTimeMs + "ms"); break; } Thread.sleep(intervalMs); @@ -139,7 +142,7 @@ public static CollectionModel createCollection(PineconeControlPlaneClient contro int timeWaited = 0; CollectionModel.StatusEnum collectionReady = collection.getStatus(); while (collectionReady != CollectionModel.StatusEnum.READY && timeWaited < 120000) { - System.out.println("Waiting for collection" + collectionName + " to be ready. Waited " + timeWaited + " milliseconds..."); + logger.info("Waiting for collection" + collectionName + " to be ready. Waited " + timeWaited + " milliseconds..."); Thread.sleep(5000); timeWaited += 5000; collection = controlPlaneClient.describeCollection(collectionName); diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java index 788e89b1..c7a08b5f 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionErrorTest.java @@ -5,10 +5,12 @@ import io.pinecone.exceptions.PineconeException; import io.pinecone.helpers.RandomStringBuilder; import io.pinecone.proto.VectorServiceGrpc; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Disabled; import org.openapitools.client.model.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -34,6 +36,7 @@ public class CollectionErrorTest { private static final List upsertIds = Arrays.asList("v1", "v2", "v3"); private static final int dimension = 4; private static PineconeControlPlaneClient controlPlaneClient; + private static final Logger logger = LoggerFactory.getLogger(CollectionErrorTest.class); @BeforeAll public static void setUpIndexAndCollection() throws InterruptedException { @@ -73,7 +76,7 @@ public void testCreateCollectionFromInvalidIndex() { CreateCollectionRequest createCollectionRequest = new CreateCollectionRequest().name(RandomStringBuilder.build("coll1", 8)).source("invalid-index"); controlPlaneClient.createCollection(createCollectionRequest); } catch (PineconeException exception) { - System.out.println("Exception: " + exception.getMessage()); + logger.info("Exception: " + exception.getMessage()); assertTrue(exception.getMessage().contains("Resource invalid-index not found")); } } @@ -85,7 +88,7 @@ public void testIndexFromNonExistentCollection() { CreateIndexRequest newCreateIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-nonexistent-coll", 8)).dimension(dimension).metric(IndexMetric.COSINE).spec(spec); controlPlaneClient.createIndex(newCreateIndexRequest); } catch (PineconeException exception) { - System.out.println("Exception: " + exception.getMessage()); + logger.info("Exception: " + exception.getMessage()); assertTrue(exception.getMessage().contains("Resource non-existent-collection not found")); } } @@ -116,7 +119,7 @@ public void testCreateIndexInMismatchedEnvironment() { CreateIndexRequest createIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-coll", 8)).dimension(dimension).metric(IndexMetric.COSINE).spec(spec); controlPlaneClient.createIndex(createIndexRequest); } catch (PineconeException exception) { - System.out.println("Exception: " + exception.getMessage()); + logger.info("Exception: " + exception.getMessage()); assertTrue(exception.getMessage().contains("Source collection must be in the same environment as the index")); } } @@ -131,7 +134,7 @@ public void testCreateIndexWithMismatchedDimension() { CreateIndexRequest createIndexRequest = new CreateIndexRequest().name(RandomStringBuilder.build("from-coll", 8)).dimension(dimension + 1).metric(IndexMetric.COSINE).spec(spec); controlPlaneClient.createIndex(createIndexRequest); } catch (PineconeException exception) { - System.out.println("Exception: " + exception.getMessage()); + logger.info("Exception: " + exception.getMessage()); assertTrue(exception.getMessage().contains("Index and collection must have the same dimension")); } } @@ -150,7 +153,7 @@ public void testCreateCollectionFromNotReadyIndex() throws InterruptedException createCollection(controlPlaneClient, newCollectionName, notReadyIndexName, true); collections.add(newCollectionName); } catch (PineconeException exception) { - System.out.println("Exception: " + exception.getMessage()); + logger.info("Exception: " + exception.getMessage()); assert (exception.getMessage().contains("Source index is not ready")); } finally { // Wait for index to initialize so it can be deleted in @AfterAll diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java index b9033cf2..f18bb920 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java @@ -7,6 +7,8 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.openapitools.client.model.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Arrays; @@ -31,6 +33,8 @@ public class CollectionTest { private static final String environment = System.getenv("PINECONE_ENVIRONMENT"); private static final int dimension = 4; + private static final Logger logger = LoggerFactory.getLogger(CollectionTest.class); + @BeforeAll public static void setUp() throws InterruptedException { controlPlaneClient = new PineconeControlPlaneClient(apiKey); @@ -99,14 +103,14 @@ public void testIndexToCollectionHappyPath() throws InterruptedException { // Create index from collection String newIndexName = RandomStringBuilder.build("index-from-col", 5); - System.out.println("Creating index " + newIndexName + " from collection " + collectionName); + logger.info("Creating index " + newIndexName + " from collection " + collectionName); CreateIndexRequestSpecPod podSpec = new CreateIndexRequestSpecPod().environment(environment).sourceCollection(collectionName); CreateIndexRequestSpec spec = new CreateIndexRequestSpec().pod(podSpec); CreateIndexRequest newCreateIndexRequest = new CreateIndexRequest().name(newIndexName).dimension(dimension).metric(indexMetric).spec(spec); controlPlaneClient.createIndex(newCreateIndexRequest); indexes.add(newIndexName); - System.out.println("Index " + newIndexName + " created from collection " + collectionName + ". Waiting until index is ready..."); + logger.info("Index " + newIndexName + " created from collection " + collectionName + ". Waiting until index is ready..."); waitUntilIndexIsReady(controlPlaneClient, newIndexName, 250000); // wait a bit more to make sure index is ready... Thread.sleep(30000); diff --git a/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java b/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java index 4c562927..148e1a16 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java @@ -21,7 +21,7 @@ public class ConfigureIndexTest { private static PineconeControlPlaneClient controlPlaneClient; private static String indexName; - private static final Logger logger = LoggerFactory.getLogger(PineconeClientLiveIntegTest.class); + private static final Logger logger = LoggerFactory.getLogger(ConfigureIndexTest.class); @BeforeAll public static void setUp() throws InterruptedException, IOException { @@ -91,7 +91,7 @@ public void scaleUpAndDown() { assertEquals(podSpec.getReplicas(), 1); }); } catch (Exception exception) { - throw new PineconeException("Test failed: " + exception.getStackTrace()); + throw new PineconeException("Test failed: " + exception.getLocalizedMessage()); } } diff --git a/src/main/java/io/pinecone/PineconeControlPlaneClient.java b/src/main/java/io/pinecone/PineconeControlPlaneClient.java index 1b1b5a51..9052e561 100644 --- a/src/main/java/io/pinecone/PineconeControlPlaneClient.java +++ b/src/main/java/io/pinecone/PineconeControlPlaneClient.java @@ -111,7 +111,7 @@ public void deleteCollection(String collectionName) throws PineconeException { } } - private void handleApiException(ApiException apiException) { + private void handleApiException(ApiException apiException) throws PineconeException { int statusCode = apiException.getCode(); String responseBody = apiException.getResponseBody(); FailedRequestInfo failedRequestInfo = new FailedRequestInfo(statusCode, responseBody); From 1bcbf95e245aa25020cf70436b3aff2438222b3a Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Tue, 20 Feb 2024 15:49:45 -0500 Subject: [PATCH 17/22] remove testLogging configs from build.gradle --- build.gradle | 60 ---------------------------------------------------- 1 file changed, 60 deletions(-) diff --git a/build.gradle b/build.gradle index 45c0f3bf..b6c75f34 100644 --- a/build.gradle +++ b/build.gradle @@ -96,35 +96,6 @@ tasks.named('build') { test { useJUnitPlatform() - - testLogging { - events = [TestLogEvent.FAILED, TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.STANDARD_OUT] - exceptionFormat = TestExceptionFormat.FULL - showExceptions = true - showCauses = true - showStackTraces = true - - debugOptions { - events = [ - TestLogEvent.STARTED, - TestLogEvent.FAILED, - TestLogEvent.PASSED, - TestLogEvent.SKIPPED, - TestLogEvent.STANDARD_ERROR, - TestLogEvent.STANDARD_OUT - ] - exceptionFormat = TestExceptionFormat.FULL - } - - afterSuite { desc, result -> - if (!desc.parent) { - def output = "Results: ${result.resultType} (${result.testCount}) tests, ${result.successfulTestCount} successful, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped." - def startItem = "| ", endItem = " |" - def repeatLength = startItem.length() + output.length() + endItem.length() - println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength)) - } - } - } } task integrationTest(type: Test) { @@ -132,37 +103,6 @@ task integrationTest(type: Test) { testClassesDirs = sourceSets.integrationTest.output.classesDirs classpath = sourceSets.integrationTest.runtimeClasspath outputs.upToDateWhen { false } - - - testLogging { - events = [TestLogEvent.FAILED, TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.STANDARD_OUT] - exceptionFormat = TestExceptionFormat.FULL - showExceptions = true - showCauses = true - showStackTraces = true - - debugOptions { - events = [ - TestLogEvent.STARTED, - TestLogEvent.FAILED, - TestLogEvent.PASSED, - TestLogEvent.SKIPPED, - TestLogEvent.STANDARD_ERROR, - TestLogEvent.STANDARD_OUT - ] - exceptionFormat = TestExceptionFormat.FULL - - } - - afterSuite { desc, result -> - if (!desc.parent) { - def output = "Results: ${result.resultType} (${result.testCount}) tests, ${result.successfulTestCount} successful, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped." - def startItem = "| ", endItem = " |" - def repeatLength = startItem.length() + output.length() + endItem.length() - println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength)) - } - } - } } // Configure Auto Relocation From bf60c79fd9677d0e6caa10d90df311c03e40fd6b Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Tue, 20 Feb 2024 15:53:19 -0500 Subject: [PATCH 18/22] adjust assertWithRetry error throwing --- .../java/io/pinecone/helpers/AssertRetry.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/integration/java/io/pinecone/helpers/AssertRetry.java b/src/integration/java/io/pinecone/helpers/AssertRetry.java index 7b4a56c6..6d2d4629 100644 --- a/src/integration/java/io/pinecone/helpers/AssertRetry.java +++ b/src/integration/java/io/pinecone/helpers/AssertRetry.java @@ -17,22 +17,23 @@ public static void assertWithRetry(AssertionRunnable assertionRunnable, int back int retryCount = 0; int delayCount = delay; boolean success = false; + String errorMessage = null; - while (!success) { + while (retryCount < maxRetry && !success) { try { assertionRunnable.run(); success = true; } catch (AssertionError | ExecutionException | IOException e) { - // If we've hit the max number of retries throw and abort - if (retryCount == maxRetry) { - throw new AssertionError(e.getLocalizedMessage()); - } - + errorMessage = e.getLocalizedMessage(); retryCount++; Thread.sleep(delayCount); delayCount*=backOff; } } + + if (!success) { + throw new AssertionError(errorMessage); + } } @FunctionalInterface From 80606f3686a9db658d7d6ec70e7e21f595082270 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Tue, 20 Feb 2024 16:17:38 -0500 Subject: [PATCH 19/22] tweak assertWithRetry one more time --- src/integration/java/io/pinecone/helpers/AssertRetry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integration/java/io/pinecone/helpers/AssertRetry.java b/src/integration/java/io/pinecone/helpers/AssertRetry.java index 6d2d4629..c33daa1e 100644 --- a/src/integration/java/io/pinecone/helpers/AssertRetry.java +++ b/src/integration/java/io/pinecone/helpers/AssertRetry.java @@ -26,8 +26,8 @@ public static void assertWithRetry(AssertionRunnable assertionRunnable, int back } catch (AssertionError | ExecutionException | IOException e) { errorMessage = e.getLocalizedMessage(); retryCount++; - Thread.sleep(delayCount); delayCount*=backOff; + Thread.sleep(delayCount); } } From e0a62478d3fb28ed5666ea7b0acf2ee581213709 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Tue, 20 Feb 2024 16:51:56 -0500 Subject: [PATCH 20/22] remove unused imports --- build.gradle | 3 --- 1 file changed, 3 deletions(-) diff --git a/build.gradle b/build.gradle index b6c75f34..dd01b849 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,3 @@ -import org.gradle.api.tasks.testing.logging.TestExceptionFormat; -import org.gradle.api.tasks.testing.logging.TestLogEvent; - plugins { id 'com.github.johnrengelman.shadow' version '6.1.0' id 'java-library' From 41e8f5d057addb679576ec07a432ba348be722d5 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Tue, 20 Feb 2024 17:39:26 -0500 Subject: [PATCH 21/22] up the amount of time isIndexReady waits --- src/integration/java/io/pinecone/helpers/IndexManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integration/java/io/pinecone/helpers/IndexManager.java b/src/integration/java/io/pinecone/helpers/IndexManager.java index b558388f..f363b9be 100644 --- a/src/integration/java/io/pinecone/helpers/IndexManager.java +++ b/src/integration/java/io/pinecone/helpers/IndexManager.java @@ -163,7 +163,7 @@ public static IndexModel isIndexReady(String indexName, PineconeControlPlaneClie assertWithRetry(() -> { indexModels[0] = controlPlaneClient.describeIndex(indexName); assert (indexModels[0].getStatus().getReady()); - }, 1); + }, 3); return indexModels[0]; } From 4b956c38d1fe3423a5d3ee55ffb7b3ce9afee169 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Tue, 20 Feb 2024 19:07:19 -0500 Subject: [PATCH 22/22] bump backoff up a bit more for configure index tests --- src/integration/java/io/pinecone/helpers/IndexManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integration/java/io/pinecone/helpers/IndexManager.java b/src/integration/java/io/pinecone/helpers/IndexManager.java index f363b9be..6d5d3900 100644 --- a/src/integration/java/io/pinecone/helpers/IndexManager.java +++ b/src/integration/java/io/pinecone/helpers/IndexManager.java @@ -163,7 +163,7 @@ public static IndexModel isIndexReady(String indexName, PineconeControlPlaneClie assertWithRetry(() -> { indexModels[0] = controlPlaneClient.describeIndex(indexName); assert (indexModels[0].getStatus().getReady()); - }, 3); + }, 4); return indexModels[0]; }