diff --git a/CHANGELOG.md b/CHANGELOG.md index 15580a5b..b8c554c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ [comment]: <> (When bumping [pc:VERSION_LATEST_RELEASE] create a new entry below) ### Unreleased version +### 6.2.0 +- Add readUnits, upsertedCount, and matchedRecords to ResponseMetadata +- Add List operation to ResponseMetadataInterceptor + ### 6.1.0 - Add ResponseMetadataListener for dataplane operation observability diff --git a/gradle.properties b/gradle.properties index 9307605d..3deb988b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -pineconeClientVersion = 6.1.0 +pineconeClientVersion = 6.2.0 diff --git a/src/integration/java/io/pinecone/clients/ConnectionsMapTest.java b/src/integration/java/io/pinecone/clients/ConnectionsMapTest.java index 279f554c..1a99e973 100644 --- a/src/integration/java/io/pinecone/clients/ConnectionsMapTest.java +++ b/src/integration/java/io/pinecone/clients/ConnectionsMapTest.java @@ -14,6 +14,8 @@ import static io.pinecone.helpers.TestUtilities.waitUntilIndexIsReady; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; public class ConnectionsMapTest { @@ -78,59 +80,36 @@ public void testMultipleIndexesWithMultipleClients() throws InterruptedException // Create config2 for getting index connection and set the host PineconeConfig config2 = new PineconeConfig(System.getenv("PINECONE_API_KEY")); - config1.setHost(host2); + config2.setHost(host2); // Establish grpc connection for index-1 Index index1_1 = pinecone1.getIndexConnection(indexName1); // Get connections map - ConcurrentHashMap connectionsMap1_1 = pinecone1.getConnectionsMap(); + ConcurrentHashMap connectionsMap = pinecone1.getConnectionsMap(); - // Verify connectionsMap contains only one pair i.e. for index1 and its connection - assertEquals(pinecone1.getConnectionsMap().size(), 1); - // Verify the value for index1 by comparing its value with host1 in the connectionsMap - assertEquals(host1, connectionsMap1_1.get(indexName1).toString()); + // Verify indexName1 is in the map with the correct host + assertEquals(host1, connectionsMap.get(indexName1).toString()); // Establish grpc connection for index-2 Index index1_2 = pinecone1.getIndexConnection(indexName2); - // Get connections map after establishing second connection - ConcurrentHashMap connectionsMap1_2 = pinecone1.getConnectionsMap(); - - // Verify connectionsMap contains two pairs i.e. for index1 and index2 - assertEquals(connectionsMap1_2.size(), 2); - // Verify the values by checking host for both indexName1 and indexName2 - assertEquals(host1, connectionsMap1_2.get(indexName1).toString()); - assertEquals(host2, connectionsMap1_2.get(indexName2).toString()); - - // Establishing connections with index1 and index2 using another pinecone client - pinecone2.getConnection(indexName1, config1); - ConcurrentHashMap connectionsMap2_1 = pinecone1.getConnectionsMap(); - // Verify the new connections map is pointing to the same reference - assert connectionsMap2_1 == connectionsMap1_2; - // Verify the size of connections map is still 2 since the connection for index2 was not closed - assertEquals(2, connectionsMap2_1.size()); - // Verify the connection value for index1 is host1 - assertEquals(host1, connectionsMap2_1.get(indexName1).toString()); - - pinecone2.getConnection(indexName2, config2); - ConcurrentHashMap connectionsMap2_2 = pinecone1.getConnectionsMap(); - // Verify the new connections map is pointing to the same reference - assert connectionsMap2_1 == connectionsMap2_2; - // Verify the size of connections map is still 2 since the connections are not closed - assertEquals(2, connectionsMap2_2.size()); - // Verify the values by checking host for both indexName1 and indexName2 - assertEquals(host1, connectionsMap2_2.get(indexName1).toString()); - assertEquals(host2, connectionsMap2_2.get(indexName2).toString()); + + // Verify both indexes are now in the map with the correct hosts + assertEquals(host1, connectionsMap.get(indexName1).toString()); + assertEquals(host2, connectionsMap.get(indexName2).toString()); + + // Connecting a second client to the same indexes should reuse the existing map entries + assertSame(connectionsMap, pinecone2.getConnectionsMap()); + assertSame(connectionsMap.get(indexName1), pinecone2.getConnection(indexName1, config1)); + assertSame(connectionsMap.get(indexName2), pinecone2.getConnection(indexName2, config2)); // Close the connections index1_1.close(); index1_2.close(); - // Verify the map size is now 0 - assertEquals(connectionsMap1_1.size(), 0); - assertEquals(connectionsMap1_2.size(), 0); - assertEquals(connectionsMap2_1.size(), 0); - assertEquals(connectionsMap2_2.size(), 0); + // Verify the specific entries for this test's indexes were removed + assertFalse(connectionsMap.containsKey(indexName1)); + assertFalse(connectionsMap.containsKey(indexName2)); // Delete the indexes pinecone1.deleteIndex(indexName1); diff --git a/src/integration/java/io/pinecone/helpers/AssertRetry.java b/src/integration/java/io/pinecone/helpers/AssertRetry.java index c33daa1e..d41706c1 100644 --- a/src/integration/java/io/pinecone/helpers/AssertRetry.java +++ b/src/integration/java/io/pinecone/helpers/AssertRetry.java @@ -2,18 +2,15 @@ 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 final int delay = 1500; - public static void assertWithRetry(AssertionRunnable assertionRunnable) throws InterruptedException, PineconeException { + public static void assertWithRetry(AssertionRunnable assertionRunnable) throws Exception { assertWithRetry(assertionRunnable, 2); } - public static void assertWithRetry(AssertionRunnable assertionRunnable, int backOff) throws AssertionError, InterruptedException { + public static void assertWithRetry(AssertionRunnable assertionRunnable, int backOff) throws Exception { int retryCount = 0; int delayCount = delay; boolean success = false; @@ -23,7 +20,10 @@ public static void assertWithRetry(AssertionRunnable assertionRunnable, int back try { assertionRunnable.run(); success = true; - } catch (AssertionError | ExecutionException | IOException e) { + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw e; + } catch (AssertionError | Exception e) { errorMessage = e.getLocalizedMessage(); retryCount++; delayCount*=backOff; @@ -38,6 +38,6 @@ public static void assertWithRetry(AssertionRunnable assertionRunnable, int back @FunctionalInterface public interface AssertionRunnable { - void run() throws AssertionError, ExecutionException, InterruptedException, IOException, PineconeException; + void run() throws Exception; } } diff --git a/src/integration/java/io/pinecone/helpers/TestResourcesManager.java b/src/integration/java/io/pinecone/helpers/TestResourcesManager.java index 15ffe7c3..c609d559 100644 --- a/src/integration/java/io/pinecone/helpers/TestResourcesManager.java +++ b/src/integration/java/io/pinecone/helpers/TestResourcesManager.java @@ -42,7 +42,7 @@ */ public class TestResourcesManager { private static final Logger logger = LoggerFactory.getLogger(TestUtilities.class); - private static TestResourcesManager instance; + private static volatile TestResourcesManager instance; private static final String apiKey = System.getenv("PINECONE_API_KEY"); private final int dimension = System.getenv("DIMENSION") == null ? 4 @@ -66,6 +66,10 @@ public class TestResourcesManager { private String serverlessIndexName; private String collectionName; private CollectionModel collectionModel; + private Index serverlessIndexConnection; + private AsyncIndex serverlessAsyncIndexConnection; + private Index podIndexConnection; + private AsyncIndex podAsyncIndexConnection; private final List vectorIdsForDefaultNamespace = Arrays.asList("def-id1", "def-id2", "def-prefix-id3", "def-prefix-id4"); private final List vectorIdsForCustomNamespace = Arrays.asList("cus-id1", "cus-id2", "cus-prefix-id3", "cus" + "-prefix-id4"); @@ -85,7 +89,7 @@ private TestResourcesManager() { * * @return the {@link TestResourcesManager} instance. */ - public static TestResourcesManager getInstance() { + public static synchronized TestResourcesManager getInstance() { if (instance == null) { instance = new TestResourcesManager(); } @@ -185,8 +189,22 @@ public List getVectorIdsFromCustomNamespace() { * * @return a {@link Index} connection to the serverless index. */ - public Index getOrCreateServerlessIndexConnection() throws InterruptedException { - return getInstance().pineconeClient.getIndexConnection(getOrCreateServerlessIndex()); + /** + * Gets the host for the shared serverless index. Creates the index first if it doesn't exist. + * Used by tests that need to construct their own PineconeConnection (e.g. to attach a custom listener) + * without going through the shared static connection cache. + * + * @return the host URL of the shared serverless index. + */ + public synchronized String getOrCreateServerlessIndexHost() throws InterruptedException { + return pineconeClient.describeIndex(getOrCreateServerlessIndex()).getHost(); + } + + public synchronized Index getOrCreateServerlessIndexConnection() throws InterruptedException { + if (serverlessIndexConnection == null) { + serverlessIndexConnection = pineconeClient.getIndexConnection(getOrCreateServerlessIndex()); + } + return serverlessIndexConnection; } /** @@ -195,8 +213,11 @@ public Index getOrCreateServerlessIndexConnection() throws InterruptedException * * @return a {@link AsyncIndex} connection to the serverless index. */ - public AsyncIndex getOrCreateServerlessAsyncIndexConnection() throws InterruptedException { - return getInstance().pineconeClient.getAsyncIndexConnection(getOrCreateServerlessIndex()); + public synchronized AsyncIndex getOrCreateServerlessAsyncIndexConnection() throws InterruptedException { + if (serverlessAsyncIndexConnection == null) { + serverlessAsyncIndexConnection = pineconeClient.getAsyncIndexConnection(getOrCreateServerlessIndex()); + } + return serverlessAsyncIndexConnection; } /** @@ -205,8 +226,11 @@ public AsyncIndex getOrCreateServerlessAsyncIndexConnection() throws Interrupted * * @return a {@link Index} connection to the pod index. */ - public Index getOrCreatePodIndexConnection() throws InterruptedException { - return getInstance().pineconeClient.getIndexConnection(getOrCreatePodIndex()); + public synchronized Index getOrCreatePodIndexConnection() throws InterruptedException { + if (podIndexConnection == null) { + podIndexConnection = pineconeClient.getIndexConnection(getOrCreatePodIndex()); + } + return podIndexConnection; } /** @@ -215,8 +239,11 @@ public Index getOrCreatePodIndexConnection() throws InterruptedException { * * @return a {@link AsyncIndex} connection to the pod index. */ - public AsyncIndex getOrCreatePodAsyncIndexConnection() throws InterruptedException { - return getInstance().pineconeClient.getAsyncIndexConnection(getOrCreatePodIndex()); + public synchronized AsyncIndex getOrCreatePodAsyncIndexConnection() throws InterruptedException { + if (podAsyncIndexConnection == null) { + podAsyncIndexConnection = pineconeClient.getAsyncIndexConnection(getOrCreatePodIndex()); + } + return podAsyncIndexConnection; } /** @@ -225,7 +252,7 @@ public AsyncIndex getOrCreatePodAsyncIndexConnection() throws InterruptedExcepti * * @return the {@link IndexModel} of the pod index. */ - public IndexModel getOrCreatePodIndexModel() throws InterruptedException { + public synchronized IndexModel getOrCreatePodIndexModel() throws InterruptedException { podIndexModel = pineconeClient.describeIndex(getOrCreatePodIndex()); return podIndexModel; } @@ -236,7 +263,7 @@ public IndexModel getOrCreatePodIndexModel() throws InterruptedException { * * @return the {@link IndexModel} of the serverless index. */ - public IndexModel getOrCreateServerlessIndexModel() throws InterruptedException { + public synchronized IndexModel getOrCreateServerlessIndexModel() throws InterruptedException { serverlessIndexModel = pineconeClient.describeIndex(getOrCreateServerlessIndex()); return serverlessIndexModel; } @@ -247,7 +274,7 @@ public IndexModel getOrCreateServerlessIndexModel() throws InterruptedException * * @return the {@link CollectionModel} of the serverless index. */ - public CollectionModel getOrCreateCollectionModel() throws InterruptedException { + public synchronized CollectionModel getOrCreateCollectionModel() throws InterruptedException { collectionModel = pineconeClient.describeCollection(getOrCreateCollection()); return collectionModel; } @@ -257,6 +284,19 @@ public CollectionModel getOrCreateCollectionModel() throws InterruptedException * after all tests have finished running. */ public void cleanupResources() { + if (serverlessIndexConnection != null) { + serverlessIndexConnection.close(); + } + if (serverlessAsyncIndexConnection != null) { + serverlessAsyncIndexConnection.close(); + } + if (podIndexConnection != null) { + podIndexConnection.close(); + } + if (podAsyncIndexConnection != null) { + podAsyncIndexConnection.close(); + } + if (podIndexName != null) { pineconeClient.deleteIndex(podIndexName); } @@ -280,7 +320,7 @@ public void cleanupResources() { * @throws InterruptedException if the thread is interrupted while waiting for the index to be ready. * @throws PineconeException if the API encounters an error during index creation or if any of the arguments are invalid. */ - public String getOrCreatePodIndex() throws InterruptedException, PineconeException { + public synchronized String getOrCreatePodIndex() throws InterruptedException, PineconeException { if (podIndexName != null) { return podIndexName; } @@ -311,7 +351,7 @@ public String getOrCreatePodIndex() throws InterruptedException, PineconeExcepti * @throws InterruptedException if the thread is interrupted while waiting for the index to be ready. * @throws PineconeException if the API encounters an error during index creation or if any of the arguments are invalid. */ - public String getOrCreateServerlessIndex() throws InterruptedException, PineconeException { + public synchronized String getOrCreateServerlessIndex() throws InterruptedException, PineconeException { if (this.serverlessIndexName != null) { return this.serverlessIndexName; } @@ -344,7 +384,7 @@ public String getOrCreateServerlessIndex() throws InterruptedException, Pinecone * @throws InterruptedException if the thread is interrupted while waiting for the collection to be ready. * @throws PineconeException if the API encounters an error during collection creation. */ - public String getOrCreateCollection() throws InterruptedException, PineconeException { + public synchronized String getOrCreateCollection() throws InterruptedException, PineconeException { if (collectionName != null) { return collectionName; } @@ -359,13 +399,13 @@ public String getOrCreateCollection() throws InterruptedException, PineconeExcep // Wait until collection is ready int timeWaited = 0; String collectionReady = collectionModel.getStatus().toLowerCase(); - while (collectionReady != "ready" && timeWaited < 120000) { + while (!"ready".equals(collectionReady) && timeWaited < 120000) { logger.info("Waiting for collection " + collectionName + " to be ready. Waited " + timeWaited + " " + "milliseconds..."); Thread.sleep(5000); timeWaited += 5000; collectionModel = pineconeClient.describeCollection(collectionName); - collectionReady = collectionModel.getStatus(); + collectionReady = collectionModel.getStatus().toLowerCase(); } if (timeWaited > 120000) { 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 5903862d..b0cbb5f9 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java @@ -41,7 +41,7 @@ public class CollectionTest { private static String namespace; @BeforeAll - public static void setUp() throws InterruptedException { + public static void setUp() throws Exception { indexName = indexManager.getOrCreatePodIndex(); collectionName = indexManager.getOrCreateCollection(); collection = indexManager.getOrCreateCollectionModel(); @@ -49,7 +49,7 @@ public static void setUp() throws InterruptedException { } @AfterAll - public static void cleanUp() throws InterruptedException { + public static void cleanUp() throws Exception { // Clean up indexes for (String index : indexesToCleanUp) { pineconeClient.deleteIndex(index); @@ -57,7 +57,7 @@ public static void cleanUp() throws InterruptedException { } @Test - public void testIndexFromCollectionHappyPath() throws InterruptedException { + public void testIndexFromCollectionHappyPath() throws Exception { // Verify collection is listed List collectionList = pineconeClient.listCollections().getCollections(); boolean collectionFound = false; @@ -115,7 +115,7 @@ public void testIndexFromCollectionHappyPath() throws InterruptedException { } @Test - public void testCreateIndexFromCollectionWithDiffMetric() throws InterruptedException { + public void testCreateIndexFromCollectionWithDiffMetric() throws Exception { // Use a different metric than the source index String[] metrics = { "cosine", @@ -232,7 +232,7 @@ public void testCreateIndexWithMismatchedDimension() { } @Test - public void testCreateCollectionFromNotReadyIndex() throws InterruptedException { + public void testCreateCollectionFromNotReadyIndex() throws Exception { String notReadyIndexName = RandomStringBuilder.build("from-coll", 8); String newCollectionName = RandomStringBuilder.build("coll-", 8); try { 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 dac812f6..1b14e44e 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Isolated; import org.openapitools.db_control.client.model.IndexModel; import org.openapitools.db_control.client.model.PodSpec; import org.slf4j.Logger; @@ -19,6 +20,7 @@ import static io.pinecone.helpers.AssertRetry.assertWithRetry; import static org.junit.jupiter.api.Assertions.*; +@Isolated public class ConfigureIndexTest { private static final Logger logger = LoggerFactory.getLogger(ConfigureIndexTest.class); private static final TestResourcesManager indexManager = TestResourcesManager.getInstance(); @@ -34,16 +36,16 @@ public class ConfigureIndexTest { private static String indexName; @BeforeAll - public static void setUp() throws InterruptedException { + public static void setUp() throws Exception { indexName = indexManager.getOrCreatePodIndex(); } - private static void waitUntilIndexStateIsReady(String indexName) throws InterruptedException { + private static void waitUntilIndexStateIsReady(String indexName) throws Exception { int timeToWaitMs = 100000; int timeWaited = 0; IndexModel index = controlPlaneClient.describeIndex(indexName); - while (index.getStatus().getState() != "ready" && timeWaited <= timeToWaitMs) { + while (!"ready".equalsIgnoreCase(index.getStatus().getState()) && timeWaited <= timeToWaitMs) { Thread.sleep(2000); timeWaited += 2000; logger.info("waited 2000ms for index to upgrade, time waited: " + timeWaited); @@ -55,7 +57,7 @@ private static void waitUntilIndexStateIsReady(String indexName) throws Interrup } @AfterEach - public void afterEach() throws InterruptedException { + public void afterEach() throws Exception { waitUntilIndexStateIsReady(indexName); } @@ -81,7 +83,7 @@ public void configureIndexExceedingQuota() { } @Test - public void scaleUpAndDown() throws InterruptedException { + public void scaleUpAndDown() throws Exception { IndexModel indexModel = controlPlaneClient.describeIndex(indexName); assertNotNull(indexModel.getSpec().getIndexModelPodBased().getPod()); assertEquals(1, indexModel.getSpec().getIndexModelPodBased().getPod().getReplicas()); @@ -106,7 +108,7 @@ public void scaleUpAndDown() throws InterruptedException { } @Test - public void changingBasePodType() throws InterruptedException { + public void changingBasePodType() throws Exception { try { // Verify the starting state IndexModel indexModel = controlPlaneClient.describeIndex(indexName); @@ -123,7 +125,7 @@ public void changingBasePodType() throws InterruptedException { } @Test - public void sizeIncrease() throws InterruptedException { + public void sizeIncrease() throws Exception { // Verify the starting state IndexModel indexModel = controlPlaneClient.describeIndex(indexName); assertNotNull(indexModel.getSpec().getIndexModelPodBased().getPod()); diff --git a/src/integration/java/io/pinecone/integration/controlPlane/serverless/ReadCapacityAndSchemaTest.java b/src/integration/java/io/pinecone/integration/controlPlane/serverless/ReadCapacityAndSchemaTest.java index 24e8c19a..0de8c07a 100644 --- a/src/integration/java/io/pinecone/integration/controlPlane/serverless/ReadCapacityAndSchemaTest.java +++ b/src/integration/java/io/pinecone/integration/controlPlane/serverless/ReadCapacityAndSchemaTest.java @@ -4,10 +4,14 @@ import io.pinecone.helpers.RandomStringBuilder; import okhttp3.OkHttpClient; import org.junit.jupiter.api.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.openapitools.db_control.client.ApiException; import org.openapitools.db_control.client.model.*; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -17,6 +21,7 @@ @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class ReadCapacityAndSchemaTest { + private static final Logger logger = LoggerFactory.getLogger(ReadCapacityAndSchemaTest.class); private static final Pinecone controlPlaneClient = new Pinecone .Builder(System.getenv("PINECONE_API_KEY")) .withSourceTag("pinecone_test") @@ -27,43 +32,49 @@ public class ReadCapacityAndSchemaTest { .build()) .build(); + private static final List createdIndexNames = new ArrayList<>(); + + @AfterAll + static void cleanUp() { + for (String name : createdIndexNames) { + try { + controlPlaneClient.deleteIndex(name); + } catch (Exception e) { + logger.warn("Failed to delete index '{}' during cleanup: {}", name, e.getMessage()); + } + } + } + @Test @Order(1) - public void createServerlessIndexWithOnDemandReadCapacity() throws InterruptedException { - String indexNameOnDemand = RandomStringBuilder.build("ondemand-index", 8); + public void createServerlessIndexWithOnDemandReadCapacity() { + String indexName = RandomStringBuilder.build("ondemand-index", 8); Map tags = new HashMap<>(); tags.put("env", "test"); tags.put("read-capacity", "ondemand"); - // Create index with OnDemand read capacity ReadCapacity readCapacity = new ReadCapacity(new ReadCapacityOnDemandSpec().mode("OnDemand")); IndexModel indexModel = controlPlaneClient.createServerlessIndex( - indexNameOnDemand, "cosine", 1536, "aws", "us-west-2", + indexName, "cosine", 1536, "aws", "us-west-2", "disabled", tags, readCapacity, null); + createdIndexNames.add(indexName); assertNotNull(indexModel); - assertEquals(indexNameOnDemand, indexModel.getName()); + assertEquals(indexName, indexModel.getName()); assertEquals("cosine", indexModel.getMetric()); assertEquals(1536, indexModel.getDimension()); assertEquals("disabled", indexModel.getDeletionProtection()); assertEquals(tags, indexModel.getTags()); - - // Wait for index to be ready and verify read capacity - waitUntilIndexIsReady(controlPlaneClient, indexNameOnDemand); - IndexModel describedIndex = controlPlaneClient.describeIndex(indexNameOnDemand); - assertNotNull(describedIndex.getSpec().getIndexModelServerless()); - // Note: Read capacity response may not be immediately available in describe } @Test @Order(2) - public void createServerlessIndexWithDedicatedReadCapacity() throws InterruptedException { - String indexNameDedicated = RandomStringBuilder.build("dedicated-index", 8); + public void createServerlessIndexWithDedicatedReadCapacity() { + String indexName = RandomStringBuilder.build("dedicated-index", 8); Map tags = new HashMap<>(); tags.put("env", "test"); tags.put("read-capacity", "dedicated"); - // Create index with Dedicated read capacity ScalingConfigManual manual = new ScalingConfigManual().shards(2).replicas(2); ReadCapacityDedicatedConfig dedicated = new ReadCapacityDedicatedConfig() .nodeType("t1") @@ -73,29 +84,26 @@ public void createServerlessIndexWithDedicatedReadCapacity() throws InterruptedE new ReadCapacityDedicatedSpec().mode("Dedicated").dedicated(dedicated)); IndexModel indexModel = controlPlaneClient.createServerlessIndex( - indexNameDedicated, "cosine", 1536, "aws", "us-west-2", + indexName, "cosine", 1536, "aws", "us-west-2", "disabled", tags, readCapacity, null); + createdIndexNames.add(indexName); assertNotNull(indexModel); - assertEquals(indexNameDedicated, indexModel.getName()); + assertEquals(indexName, indexModel.getName()); assertEquals("cosine", indexModel.getMetric()); assertEquals(1536, indexModel.getDimension()); assertEquals("disabled", indexModel.getDeletionProtection()); assertEquals(tags, indexModel.getTags()); - - // Wait for index to be ready - waitUntilIndexIsReady(controlPlaneClient, indexNameDedicated); } @Test @Order(3) - public void createServerlessIndexWithMetadataSchema() throws InterruptedException { - String indexNameWithSchema = RandomStringBuilder.build("schema-index", 8); + public void createServerlessIndexWithMetadataSchema() { + String indexName = RandomStringBuilder.build("schema-index", 8); Map tags = new HashMap<>(); tags.put("env", "test"); tags.put("schema", "configured"); - // Create index with metadata schema Map fields = new HashMap<>(); fields.put("genre", new BackupModelSchemaFieldsValue().filterable(true)); fields.put("year", new BackupModelSchemaFieldsValue().filterable(true)); @@ -103,28 +111,25 @@ public void createServerlessIndexWithMetadataSchema() throws InterruptedExceptio BackupModelSchema schema = new BackupModelSchema().fields(fields); IndexModel indexModel = controlPlaneClient.createServerlessIndex( - indexNameWithSchema, "cosine", 1536, "aws", "us-west-2", + indexName, "cosine", 1536, "aws", "us-west-2", "disabled", tags, null, schema); + createdIndexNames.add(indexName); assertNotNull(indexModel); - assertEquals(indexNameWithSchema, indexModel.getName()); + assertEquals(indexName, indexModel.getName()); assertEquals("cosine", indexModel.getMetric()); assertEquals(1536, indexModel.getDimension()); assertEquals("disabled", indexModel.getDeletionProtection()); assertEquals(tags, indexModel.getTags()); - - // Wait for index to be ready - waitUntilIndexIsReady(controlPlaneClient, indexNameWithSchema); } @Test @Order(4) - public void createServerlessIndexWithBothReadCapacityAndSchema() throws InterruptedException { + public void createServerlessIndexWithBothReadCapacityAndSchema() { String indexName = RandomStringBuilder.build("both-config-index", 8); Map tags = new HashMap<>(); tags.put("env", "test"); - // Create index with both Dedicated read capacity and metadata schema ScalingConfigManual manual = new ScalingConfigManual().shards(1).replicas(1); ReadCapacityDedicatedConfig dedicated = new ReadCapacityDedicatedConfig() .nodeType("t1") @@ -139,29 +144,23 @@ public void createServerlessIndexWithBothReadCapacityAndSchema() throws Interrup BackupModelSchema schema = new BackupModelSchema().fields(fields); IndexModel indexModel = controlPlaneClient.createServerlessIndex( - indexName, "cosine", 1536, "aws", "us-west-2", + indexName, "cosine", 1536, "aws", "us-west-2", "disabled", tags, readCapacity, schema); + createdIndexNames.add(indexName); assertNotNull(indexModel); assertEquals(indexName, indexModel.getName()); assertEquals("cosine", indexModel.getMetric()); assertEquals(1536, indexModel.getDimension()); - - // Wait for index to be ready - waitUntilIndexIsReady(controlPlaneClient, indexName); - - // Clean up - controlPlaneClient.deleteIndex(indexName); } @Test @Order(5) - public void createIndexForModelWithReadCapacityAndSchema() throws InterruptedException, ApiException { - String indexNameForModel = RandomStringBuilder.build("model-index", 8); + public void createIndexForModelWithReadCapacityAndSchema() throws ApiException { + String indexName = RandomStringBuilder.build("model-index", 8); Map tags = new HashMap<>(); tags.put("env", "test"); - // Create index for model with Dedicated read capacity and metadata schema ScalingConfigManual manual = new ScalingConfigManual().shards(1).replicas(1); ReadCapacityDedicatedConfig dedicated = new ReadCapacityDedicatedConfig() .nodeType("t1") @@ -181,52 +180,46 @@ public void createIndexForModelWithReadCapacityAndSchema() throws InterruptedExc embed.fieldMap(fieldMap); IndexModel indexModel = controlPlaneClient.createIndexForModel( - indexNameForModel, "aws", "us-east-1", embed, + indexName, "aws", "us-east-1", embed, "disabled", tags, readCapacity, schema); + createdIndexNames.add(indexName); assertNotNull(indexModel); - assertEquals(indexNameForModel, indexModel.getName()); + assertEquals(indexName, indexModel.getName()); assertEquals("disabled", indexModel.getDeletionProtection()); assertEquals(tags, indexModel.getTags()); - - // Wait for index to be ready - waitUntilIndexIsReady(controlPlaneClient, indexNameForModel); } @Test @Order(6) public void configureReadCapacityOnExistingIndex() throws InterruptedException { - String indexNameToConfigure = RandomStringBuilder.build("configure-index", 8); + String indexName = RandomStringBuilder.build("configure-index", 8); Map tags = new HashMap<>(); tags.put("env", "test"); - // First, create an index without read capacity configuration (defaults to OnDemand) IndexModel indexModel = controlPlaneClient.createServerlessIndex( - indexNameToConfigure, "cosine", 1536, "aws", "us-west-2", + indexName, "cosine", 1536, "aws", "us-west-2", "disabled", tags, null, null); + createdIndexNames.add(indexName); assertNotNull(indexModel); - assertEquals(indexNameToConfigure, indexModel.getName()); + assertEquals(indexName, indexModel.getName()); - // Wait for index to be ready - waitUntilIndexIsReady(controlPlaneClient, indexNameToConfigure); - // Wait for read capacity to be ready before configuring - waitUntilReadCapacityIsReady(controlPlaneClient, indexNameToConfigure); + // Must be ready before configuring read capacity + waitUntilIndexIsReady(controlPlaneClient, indexName); + waitUntilReadCapacityIsReady(controlPlaneClient, indexName); - // Configure to Dedicated read capacity IndexModel configuredIndex = controlPlaneClient.configureServerlessIndex( - indexNameToConfigure, "disabled", tags, null, "Dedicated", "t1", 2, 2); + indexName, "disabled", tags, null, "Dedicated", "t1", 2, 2); assertNotNull(configuredIndex); - assertEquals(indexNameToConfigure, configuredIndex.getName()); + assertEquals(indexName, configuredIndex.getName()); - // Wait a bit for configuration to apply Thread.sleep(10000); - // Verify the configuration by describing the index - IndexModel describedIndex = controlPlaneClient.describeIndex(indexNameToConfigure); + IndexModel describedIndex = controlPlaneClient.describeIndex(indexName); assertNotNull(describedIndex); - assertEquals(indexNameToConfigure, describedIndex.getName()); + assertEquals(indexName, describedIndex.getName()); } // Note: Tests for switching read capacity modes and scaling are omitted due to API rate limits. @@ -236,4 +229,3 @@ public void configureReadCapacityOnExistingIndex() throws InterruptedException { // - Scaling dedicated read capacity (changing shards/replicas) // These operations are still supported by the API, but cannot be tested in CI/CD due to rate limits. } - diff --git a/src/integration/java/io/pinecone/integration/dataPlane/FetchAndUpdateByMetadataTest.java b/src/integration/java/io/pinecone/integration/dataPlane/FetchAndUpdateByMetadataTest.java index 43377195..73acab19 100644 --- a/src/integration/java/io/pinecone/integration/dataPlane/FetchAndUpdateByMetadataTest.java +++ b/src/integration/java/io/pinecone/integration/dataPlane/FetchAndUpdateByMetadataTest.java @@ -9,7 +9,6 @@ import io.pinecone.proto.FetchByMetadataResponse; import io.pinecone.proto.UpdateResponse; import io.pinecone.unsigned_indices_model.VectorWithUnsignedIndices; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -30,7 +29,7 @@ public class FetchAndUpdateByMetadataTest { private static final String namespace = RandomStringBuilder.build("ns", 8); @BeforeAll - public static void setUp() throws InterruptedException { + public static void setUp() throws Exception { int dimension = indexManager.getDimension(); index = indexManager.getOrCreateServerlessIndexConnection(); asyncIndex = indexManager.getOrCreateServerlessAsyncIndexConnection(); @@ -58,14 +57,8 @@ public static void setUp() throws InterruptedException { Thread.sleep(5000); } - @AfterAll - public static void cleanUp() { - index.close(); - asyncIndex.close(); - } - @Test - public void fetchByMetadataSyncTest() throws InterruptedException { + public void fetchByMetadataSyncTest() throws Exception { HashMap> metadataMap = createAndGetMetadataMap(); String filterValue = metadataMap.get(metadataFields[0]).get(0); @@ -86,7 +79,7 @@ public void fetchByMetadataSyncTest() throws InterruptedException { } @Test - public void updateByMetadataSyncTest() throws InterruptedException { + public void updateByMetadataSyncTest() throws Exception { HashMap> metadataMap = createAndGetMetadataMap(); String filterValue = metadataMap.get(metadataFields[0]).get(0); @@ -111,7 +104,7 @@ public void updateByMetadataSyncTest() throws InterruptedException { } @Test - public void fetchByMetadataAsyncTest() throws InterruptedException, ExecutionException { + public void fetchByMetadataAsyncTest() throws Exception { HashMap> metadataMap = createAndGetMetadataMap(); String filterValue = metadataMap.get(metadataFields[1]).get(0); @@ -132,7 +125,7 @@ public void fetchByMetadataAsyncTest() throws InterruptedException, ExecutionExc } @Test - public void updateByMetadataAsyncTest() throws InterruptedException, ExecutionException { + public void updateByMetadataAsyncTest() throws Exception { HashMap> metadataMap = createAndGetMetadataMap(); String filterValue = metadataMap.get(metadataFields[1]).get(0); diff --git a/src/integration/java/io/pinecone/integration/dataPlane/ListEndpointTest.java b/src/integration/java/io/pinecone/integration/dataPlane/ListEndpointTest.java index 33868017..ca9fe7a7 100644 --- a/src/integration/java/io/pinecone/integration/dataPlane/ListEndpointTest.java +++ b/src/integration/java/io/pinecone/integration/dataPlane/ListEndpointTest.java @@ -6,7 +6,6 @@ import io.pinecone.clients.Index; import io.pinecone.helpers.TestResourcesManager; import io.pinecone.proto.ListResponse; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -18,101 +17,91 @@ public class ListEndpointTest { private static AsyncIndex asyncIndexConnection; private static String customNamespace; + // ID prefixes used when seeding the shared index in TestResourcesManager. + // Filtering by these prefixes makes assertions immune to concurrent test writes. + private static final String DEFAULT_NS_PREFIX = "def-"; + private static final String CUSTOM_NS_PREFIX = "cus-"; + private static final String CUSTOM_NS_SUBPREFIX = "cus-prefix-"; + @BeforeAll - public static void setUp() throws InterruptedException { + public static void setUp() throws Exception { indexManager.getOrCreateServerlessIndex(); indexConnection = indexManager.getOrCreateServerlessIndexConnection(); asyncIndexConnection = indexManager.getOrCreateServerlessAsyncIndexConnection(); customNamespace = indexManager.getCustomNamespace(); } - @AfterAll - public static void cleanUp() { - indexConnection.close(); - asyncIndexConnection.close(); - } - @Test - public void testSyncListEndpoint() throws InterruptedException { - // Confirm default vector IDs are returned when no namespace is specified - ListResponse listResponseNoArgs = indexConnection.list(); - assertEquals(listResponseNoArgs.getVectorsList().size(), 4); - assertTrue(listResponseNoArgs.getVectorsList().toString().contains("def-id1")); - assertTrue(listResponseNoArgs.getVectorsList().toString().contains("def-id2")); - assertTrue(listResponseNoArgs.getVectorsList().toString().contains("def-prefix-id3")); - assertTrue(listResponseNoArgs.getVectorsList().toString().contains("def-prefix-id4")); + public void testSyncListEndpoint() throws Exception { + // Use prefix filtering so concurrent writes to these namespaces don't affect counts + ListResponse listDefaultNs = indexConnection.list("", DEFAULT_NS_PREFIX); + assertEquals(4, listDefaultNs.getVectorsList().size()); + assertTrue(listDefaultNs.getVectorsList().toString().contains("def-id1")); + assertTrue(listDefaultNs.getVectorsList().toString().contains("def-id2")); + assertTrue(listDefaultNs.getVectorsList().toString().contains("def-prefix-id3")); + assertTrue(listDefaultNs.getVectorsList().toString().contains("def-prefix-id4")); - // Confirm all vector IDs from custom namespace are returned when pass customNamespace - ListResponse listResponseCustomNamespace = indexConnection.list(customNamespace); - assertEquals(listResponseCustomNamespace.getVectorsList().size(), 4); - assertTrue(listResponseCustomNamespace.getVectorsList().toString().contains("cus-id1")); - assertTrue(listResponseCustomNamespace.getVectorsList().toString().contains("cus-id2")); - assertTrue(listResponseCustomNamespace.getVectorsList().toString().contains("cus-prefix-id3")); - assertTrue(listResponseCustomNamespace.getVectorsList().toString().contains("cus-prefix-id4")); + ListResponse listCustomNs = indexConnection.list(customNamespace, CUSTOM_NS_PREFIX); + assertEquals(4, listCustomNs.getVectorsList().size()); + assertTrue(listCustomNs.getVectorsList().toString().contains("cus-id1")); + assertTrue(listCustomNs.getVectorsList().toString().contains("cus-id2")); + assertTrue(listCustomNs.getVectorsList().toString().contains("cus-prefix-id3")); + assertTrue(listCustomNs.getVectorsList().toString().contains("cus-prefix-id4")); - // Confirm all vector IDs from custom namespace are returned, filtered by given prefix - ListResponse listResponseCustomNamespaceWithPrefix = indexConnection.list(customNamespace, "cus-prefix-"); - assertEquals(listResponseCustomNamespaceWithPrefix.getVectorsList().size(), 2); - assertTrue(listResponseCustomNamespaceWithPrefix.getVectorsList().toString().contains("cus-prefix-id3")); - assertTrue(listResponseCustomNamespaceWithPrefix.getVectorsList().toString().contains("cus-prefix-id4")); + // Sub-prefix filter + ListResponse listCustomNsSubPrefix = indexConnection.list(customNamespace, CUSTOM_NS_SUBPREFIX); + assertEquals(2, listCustomNsSubPrefix.getVectorsList().size()); + assertTrue(listCustomNsSubPrefix.getVectorsList().toString().contains("cus-prefix-id3")); + assertTrue(listCustomNsSubPrefix.getVectorsList().toString().contains("cus-prefix-id4")); - // Confirm all vector IDs from custom namespace are returned when limit is specified - ListResponse listResponseWithLimit = indexConnection.list(customNamespace, 1); - assertEquals(1, listResponseWithLimit.getVectorsList().size()); + // Limit + ListResponse listWithLimit = indexConnection.list(customNamespace, CUSTOM_NS_PREFIX, 1); + assertEquals(1, listWithLimit.getVectorsList().size()); - // Confirm all vector IDs from custom namespace are returned using pagination - ListResponse listResponseWithPaginationNoPrefix1 = indexConnection.list(customNamespace, 2); - assertEquals(listResponseWithPaginationNoPrefix1.getVectorsList().size(), 2); - ListResponse listResponseWithPaginationNoPrefix2 = indexConnection.list( - customNamespace, - 2, - listResponseWithPaginationNoPrefix1.getPagination().getNext() - ); - assertEquals(listResponseWithPaginationNoPrefix2.getVectorsList().size(), 2); + // Pagination over exactly the 4 pre-seeded cus-* vectors + ListResponse page1 = indexConnection.list(customNamespace, CUSTOM_NS_PREFIX, 2); + assertEquals(2, page1.getVectorsList().size()); + ListResponse page2 = indexConnection.list( + customNamespace, CUSTOM_NS_PREFIX, page1.getPagination().getNext(), 2); + assertEquals(2, page2.getVectorsList().size()); } @Test - public void testAsyncListEndpoint() throws InterruptedException { - // Confirm default vector IDs are returned when no namespace is specified - ListenableFuture futureResponseNoArgs = asyncIndexConnection.list(); - ListResponse asyncListResponseNoArgs = Futures.getUnchecked(futureResponseNoArgs); - assertEquals(asyncListResponseNoArgs.getVectorsList().size(), 4); - assertTrue(asyncListResponseNoArgs.getVectorsList().toString().contains("def-id1")); - assertTrue(asyncListResponseNoArgs.getVectorsList().toString().contains("def-id2")); - assertTrue(asyncListResponseNoArgs.getVectorsList().toString().contains("def-prefix-id3")); - assertTrue(asyncListResponseNoArgs.getVectorsList().toString().contains("def-prefix-id4")); + public void testAsyncListEndpoint() throws Exception { + ListResponse asyncListDefaultNs = Futures.getUnchecked( + asyncIndexConnection.list("", DEFAULT_NS_PREFIX)); + assertEquals(4, asyncListDefaultNs.getVectorsList().size()); + assertTrue(asyncListDefaultNs.getVectorsList().toString().contains("def-id1")); + assertTrue(asyncListDefaultNs.getVectorsList().toString().contains("def-id2")); + assertTrue(asyncListDefaultNs.getVectorsList().toString().contains("def-prefix-id3")); + assertTrue(asyncListDefaultNs.getVectorsList().toString().contains("def-prefix-id4")); - // Confirm all vector IDs from custom namespace are returned when pass customNamespace - ListenableFuture futureResponseCustomNamespace = asyncIndexConnection.list(customNamespace); - ListResponse asyncListResponseCustomNamespace = Futures.getUnchecked(futureResponseCustomNamespace); - assertTrue(asyncListResponseCustomNamespace.getVectorsList().toString().contains("cus-id1")); - assertTrue(asyncListResponseCustomNamespace.getVectorsList().toString().contains("cus-id2")); - assertTrue(asyncListResponseCustomNamespace.getVectorsList().toString().contains("cus-prefix-id3")); - assertTrue(asyncListResponseCustomNamespace.getVectorsList().toString().contains("cus-prefix-id4")); + ListResponse asyncListCustomNs = Futures.getUnchecked( + asyncIndexConnection.list(customNamespace, CUSTOM_NS_PREFIX)); + assertEquals(4, asyncListCustomNs.getVectorsList().size()); + assertTrue(asyncListCustomNs.getVectorsList().toString().contains("cus-id1")); + assertTrue(asyncListCustomNs.getVectorsList().toString().contains("cus-id2")); + assertTrue(asyncListCustomNs.getVectorsList().toString().contains("cus-prefix-id3")); + assertTrue(asyncListCustomNs.getVectorsList().toString().contains("cus-prefix-id4")); - // Confirm all vector IDs from custom namespace are returned, filtered by given prefix - ListenableFuture futureResponseCustomNamespaceWithPrefix = - asyncIndexConnection.list(customNamespace, "cus-prefix-"); - ListResponse asyncListResponseCustomNamespaceWithPrefix = Futures.getUnchecked(futureResponseCustomNamespaceWithPrefix); - assertEquals(asyncListResponseCustomNamespaceWithPrefix.getVectorsList().size(), 2); - assertTrue(asyncListResponseCustomNamespaceWithPrefix.getVectorsList().toString().contains("cus-prefix-id3")); - assertTrue(asyncListResponseCustomNamespaceWithPrefix.getVectorsList().toString().contains("cus-prefix-id4")); + // Sub-prefix filter + ListResponse asyncListSubPrefix = Futures.getUnchecked( + asyncIndexConnection.list(customNamespace, CUSTOM_NS_SUBPREFIX)); + assertEquals(2, asyncListSubPrefix.getVectorsList().size()); + assertTrue(asyncListSubPrefix.getVectorsList().toString().contains("cus-prefix-id3")); + assertTrue(asyncListSubPrefix.getVectorsList().toString().contains("cus-prefix-id4")); - // Confirm all vector IDs from custom namespace are returned when limit is specified - ListenableFuture futureResponseWithLimit = asyncIndexConnection.list(customNamespace, 1); - ListResponse asyncListResponseWithLimit = Futures.getUnchecked(futureResponseWithLimit); - assertEquals(1, asyncListResponseWithLimit.getVectorsList().size()); + // Limit + ListResponse asyncListWithLimit = Futures.getUnchecked( + asyncIndexConnection.list(customNamespace, CUSTOM_NS_PREFIX, 1)); + assertEquals(1, asyncListWithLimit.getVectorsList().size()); - // Confirm all vector IDs from custom namespace are returned using pagination - ListenableFuture futureResponseWithPaginationNoPrefix1 = asyncIndexConnection.list(customNamespace, 2); - ListResponse asyncListResponseWithPaginationNoPrefix1 = Futures.getUnchecked(futureResponseWithPaginationNoPrefix1); - assertEquals(asyncListResponseWithPaginationNoPrefix1.getVectorsList().size(), 2); - ListenableFuture futureResponseWithPaginationNoPrefix2 = asyncIndexConnection.list( - customNamespace, - 2, - asyncListResponseWithPaginationNoPrefix1.getPagination().getNext() - ); - ListResponse asyncListResponseWithPaginationNoPrefix2 = Futures.getUnchecked(futureResponseWithPaginationNoPrefix2); - assertEquals(asyncListResponseWithPaginationNoPrefix2.getVectorsList().size(), 2); + // Pagination over exactly the 4 pre-seeded cus-* vectors + ListResponse asyncPage1 = Futures.getUnchecked( + asyncIndexConnection.list(customNamespace, CUSTOM_NS_PREFIX, 2)); + assertEquals(2, asyncPage1.getVectorsList().size()); + ListResponse asyncPage2 = Futures.getUnchecked(asyncIndexConnection.list( + customNamespace, CUSTOM_NS_PREFIX, asyncPage1.getPagination().getNext(), 2)); + assertEquals(2, asyncPage2.getVectorsList().size()); } } diff --git a/src/integration/java/io/pinecone/integration/dataPlane/NamespacesTest.java b/src/integration/java/io/pinecone/integration/dataPlane/NamespacesTest.java index dfd61de8..32e41723 100644 --- a/src/integration/java/io/pinecone/integration/dataPlane/NamespacesTest.java +++ b/src/integration/java/io/pinecone/integration/dataPlane/NamespacesTest.java @@ -6,15 +6,13 @@ import io.pinecone.helpers.TestResourcesManager; import io.pinecone.proto.ListNamespacesResponse; import io.pinecone.proto.NamespaceDescription; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Test; import java.util.concurrent.ExecutionException; +import static io.pinecone.helpers.AssertRetry.assertWithRetry; import static io.pinecone.helpers.BuildUpsertRequest.generateVectorValuesByDimension; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; public class NamespacesTest { private static final TestResourcesManager indexManager = TestResourcesManager.getInstance(); @@ -22,112 +20,103 @@ public class NamespacesTest { private static AsyncIndex asyncIndex; private static final int dimension = indexManager.getDimension(); - @AfterAll - public static void cleanUp() { - index.close(); - asyncIndex.close(); - } - @Test - public void namespacesSyncTest() throws InterruptedException { + public void namespacesSyncTest() throws Exception { + // Use a unique prefix so this test's namespaces can be counted independently + String prefix = "sync-ns-" + RandomStringBuilder.build("", 4) + "-"; String[] namespaces = new String[4]; index = indexManager.getOrCreateServerlessIndexConnection(); - ListNamespacesResponse listNamespacesResponse = index.listNamespaces(); - int namespaceCount = listNamespacesResponse.getNamespacesCount(); - // Create namespace explicitly using createNamespace - namespaces[0] = RandomStringBuilder.build("namespace-", 3); + // Create namespace explicitly + namespaces[0] = prefix + "explicit"; NamespaceDescription createdNamespace = index.createNamespace(namespaces[0]); assertNotNull(createdNamespace); assertEquals(namespaces[0], createdNamespace.getName()); // Create namespaces implicitly by upserting vectors - for (int i=1; i<4; i++) { - namespaces[i] = RandomStringBuilder.build("namespace-", 3); - index.upsert("v"+i, generateVectorValuesByDimension(dimension), namespaces[i]); + for (int i = 1; i < 4; i++) { + namespaces[i] = prefix + i; + index.upsert("v" + i, generateVectorValuesByDimension(dimension), namespaces[i]); } - // wait for vectors to be upserted - Thread.sleep(5000); - listNamespacesResponse = index.listNamespaces(); - assertEquals(listNamespacesResponse.getNamespacesCount(), namespaceCount + 4); + // Wait for all 4 namespaces to appear under this test's unique prefix + assertWithRetry(() -> { + ListNamespacesResponse resp = index.listNamespaces(prefix, null, 100); + assertEquals(4, resp.getNamespacesCount(), + "Expected 4 namespaces with prefix '" + prefix + "'"); + }, 3); index.describeNamespace(namespaces[0]); index.deleteNamespace(namespaces[0]); - // wait for namespace to be deleted - Thread.sleep(3000); - listNamespacesResponse = index.listNamespaces(); - assertEquals(listNamespacesResponse.getNamespacesCount(), namespaceCount + 3); + // Wait for the deleted namespace to disappear + assertWithRetry(() -> { + ListNamespacesResponse resp = index.listNamespaces(prefix, null, 100); + assertEquals(3, resp.getNamespacesCount(), + "Expected 3 namespaces with prefix '" + prefix + "' after deletion"); + }, 3); - // Test prefix filtering and total count - String prefix = "namespace-"; + // Verify all remaining namespaces start with the prefix ListNamespacesResponse prefixResponse = index.listNamespaces(prefix, null, 100); assertNotNull(prefixResponse); assertTrue(prefixResponse.getTotalCount() >= 3, "totalCount should be at least 3"); assertTrue(prefixResponse.getNamespacesCount() >= 3, "Should return at least 3 namespaces with prefix"); - - // Verify all returned namespaces start with the prefix for (int i = 0; i < prefixResponse.getNamespacesCount(); i++) { String namespaceName = prefixResponse.getNamespaces(i).getName(); - assertTrue(namespaceName.startsWith(prefix), - "Namespace " + namespaceName + " should start with prefix " + prefix); + assertTrue(namespaceName.startsWith(prefix), + "Namespace " + namespaceName + " should start with prefix " + prefix); } - - // Verify totalCount is at least the number of namespaces returned assertTrue(prefixResponse.getTotalCount() >= prefixResponse.getNamespacesCount(), - "totalCount should be at least equal to the number of namespaces returned"); + "totalCount should be at least equal to the number of namespaces returned"); } @Test - public void namespacesAsyncTest() throws InterruptedException, ExecutionException { + public void namespacesAsyncTest() throws Exception { + // Use a unique prefix so this test's namespaces can be counted independently + String prefix = "async-ns-" + RandomStringBuilder.build("", 4) + "-"; String[] namespaces = new String[4]; asyncIndex = indexManager.getOrCreateServerlessAsyncIndexConnection(); - ListNamespacesResponse listNamespacesResponse = asyncIndex.listNamespaces().get(); - int namespaceCount = listNamespacesResponse.getNamespacesCount(); - - // Create namespace explicitly using createNamespace - namespaces[0] = RandomStringBuilder.build("namespace-", 3); + // Create namespace explicitly + namespaces[0] = prefix + "explicit"; NamespaceDescription createdNamespace = asyncIndex.createNamespace(namespaces[0]).get(); assertNotNull(createdNamespace); assertEquals(namespaces[0], createdNamespace.getName()); - // Create namespaces implicitly by upserting vectors - for (int i=1; i<4; i++) { - namespaces[i] = RandomStringBuilder.build("namespace-", 3); - asyncIndex.upsert("v"+i, generateVectorValuesByDimension(dimension), namespaces[i]); + // Create namespaces implicitly by upserting vectors; await each to ensure they're registered + for (int i = 1; i < 4; i++) { + namespaces[i] = prefix + i; + asyncIndex.upsert("v" + i, generateVectorValuesByDimension(dimension), namespaces[i]).get(); } - // wait for vectors to be upserted - Thread.sleep(5000); - listNamespacesResponse = asyncIndex.listNamespaces().get(); - assertEquals(listNamespacesResponse.getNamespacesCount(), namespaceCount + 4); + // Wait for all 4 namespaces to appear under this test's unique prefix + assertWithRetry(() -> { + ListNamespacesResponse resp = asyncIndex.listNamespaces(prefix, null, 100).get(); + assertEquals(4, resp.getNamespacesCount(), + "Expected 4 namespaces with prefix '" + prefix + "'"); + }, 3); asyncIndex.describeNamespace(namespaces[0]); asyncIndex.deleteNamespace(namespaces[0]); - // wait for namespace to be deleted - Thread.sleep(3000); - listNamespacesResponse = asyncIndex.listNamespaces().get(); - assertEquals(listNamespacesResponse.getNamespacesCount(), namespaceCount + 3); + // Wait for the deleted namespace to disappear + assertWithRetry(() -> { + ListNamespacesResponse resp = asyncIndex.listNamespaces(prefix, null, 100).get(); + assertEquals(3, resp.getNamespacesCount(), + "Expected 3 namespaces with prefix '" + prefix + "' after deletion"); + }, 3); // Test prefix filtering and total count - String prefix = "namespace-"; ListNamespacesResponse prefixResponse = asyncIndex.listNamespaces(prefix, null, 100).get(); assertNotNull(prefixResponse); assertTrue(prefixResponse.getTotalCount() >= 3, "totalCount should be at least 3"); assertTrue(prefixResponse.getNamespacesCount() >= 3, "Should return at least 3 namespaces with prefix"); - - // Verify all returned namespaces start with the prefix for (int i = 0; i < prefixResponse.getNamespacesCount(); i++) { String namespaceName = prefixResponse.getNamespaces(i).getName(); assertTrue(namespaceName.startsWith(prefix), - "Namespace " + namespaceName + " should start with prefix " + prefix); + "Namespace " + namespaceName + " should start with prefix " + prefix); } - - // Verify totalCount is at least the number of namespaces returned assertTrue(prefixResponse.getTotalCount() >= prefixResponse.getNamespacesCount(), - "totalCount should be at least equal to the number of namespaces returned"); + "totalCount should be at least equal to the number of namespaces returned"); } -} \ No newline at end of file +} diff --git a/src/integration/java/io/pinecone/integration/dataPlane/ResponseMetadataAsyncListenerIntegrationTest.java b/src/integration/java/io/pinecone/integration/dataPlane/ResponseMetadataAsyncListenerIntegrationTest.java index 2d0979ea..f8258596 100644 --- a/src/integration/java/io/pinecone/integration/dataPlane/ResponseMetadataAsyncListenerIntegrationTest.java +++ b/src/integration/java/io/pinecone/integration/dataPlane/ResponseMetadataAsyncListenerIntegrationTest.java @@ -2,7 +2,8 @@ import com.google.common.util.concurrent.ListenableFuture; import io.pinecone.clients.AsyncIndex; -import io.pinecone.clients.Pinecone; +import io.pinecone.configs.PineconeConfig; +import io.pinecone.configs.PineconeConnection; import io.pinecone.configs.ResponseMetadata; import io.pinecone.helpers.RandomStringBuilder; import io.pinecone.helpers.TestResourcesManager; @@ -37,28 +38,31 @@ public class ResponseMetadataAsyncListenerIntegrationTest { private static String indexName; private static AsyncIndex asyncIndex; + private static PineconeConnection connection; private static int dimension; @BeforeAll public static void setUp() throws InterruptedException { dimension = resourceManager.getDimension(); indexName = resourceManager.getOrCreateServerlessIndex(); - - Pinecone pineconeClient = new Pinecone.Builder(System.getenv("PINECONE_API_KEY")) - .withSourceTag("pinecone_test") - .withResponseMetadataListener(metadata -> { - logger.debug("Captured async metadata: {}", metadata); - capturedMetadata.add(metadata); - }) - .build(); - - asyncIndex = pineconeClient.getAsyncIndexConnection(indexName); + String host = resourceManager.getOrCreateServerlessIndexHost(); + + // Build a fresh PineconeConnection directly, bypassing the shared static connectionsMap, + // so this listener-configured connection is guaranteed to be independent of the shared one. + PineconeConfig config = new PineconeConfig(System.getenv("PINECONE_API_KEY"), "pinecone_test"); + config.setHost(host); + config.setResponseMetadataListener(metadata -> { + logger.debug("Captured async metadata: {}", metadata); + capturedMetadata.add(metadata); + }); + connection = new PineconeConnection(config, indexName); + asyncIndex = new AsyncIndex(config, connection, indexName); } @AfterAll public static void cleanUp() { - if (asyncIndex != null) { - asyncIndex.close(); + if (connection != null) { + connection.close(); } } @@ -72,7 +76,6 @@ public void testAsyncUpsertCapturesMetadata() throws ExecutionException, Interru vectorId, values, null, null, null); asyncIndex.upsert(Collections.singletonList(vector), namespace).get(30, TimeUnit.SECONDS); - Thread.sleep(100); ResponseMetadata metadata = findMetadataForOperation("upsert"); assertNotNull(metadata, "Should have captured metadata for async upsert operation"); @@ -95,12 +98,9 @@ public void testAsyncQueryCapturesMetadata() throws ExecutionException, Interrup VectorWithUnsignedIndices vector = buildUpsertVectorWithUnsignedIndices( vectorId, values, null, null, null); asyncIndex.upsert(Collections.singletonList(vector), namespace).get(30, TimeUnit.SECONDS); - - Thread.sleep(1000); capturedMetadata.clear(); asyncIndex.query(5, values, null, null, null, namespace, null, false, false).get(30, TimeUnit.SECONDS); - Thread.sleep(100); ResponseMetadata metadata = findMetadataForOperation("query"); assertNotNull(metadata, "Should have captured metadata for async query operation"); @@ -121,12 +121,9 @@ public void testAsyncFetchCapturesMetadata() throws ExecutionException, Interrup VectorWithUnsignedIndices vector = buildUpsertVectorWithUnsignedIndices( vectorId, values, null, null, null); asyncIndex.upsert(Collections.singletonList(vector), namespace).get(30, TimeUnit.SECONDS); - - Thread.sleep(1000); capturedMetadata.clear(); asyncIndex.fetch(Collections.singletonList(vectorId), namespace).get(30, TimeUnit.SECONDS); - Thread.sleep(100); ResponseMetadata metadata = findMetadataForOperation("fetch"); assertNotNull(metadata, "Should have captured metadata for async fetch operation"); @@ -147,13 +144,10 @@ public void testAsyncUpdateCapturesMetadata() throws ExecutionException, Interru VectorWithUnsignedIndices vector = buildUpsertVectorWithUnsignedIndices( vectorId, values, null, null, null); asyncIndex.upsert(Collections.singletonList(vector), namespace).get(30, TimeUnit.SECONDS); - - Thread.sleep(1000); capturedMetadata.clear(); List updatedValues = generateVectorValuesByDimension(dimension); asyncIndex.update(vectorId, updatedValues, namespace).get(30, TimeUnit.SECONDS); - Thread.sleep(100); ResponseMetadata metadata = findMetadataForOperation("update"); assertNotNull(metadata, "Should have captured metadata for async update operation"); @@ -174,12 +168,9 @@ public void testAsyncDeleteCapturesMetadata() throws ExecutionException, Interru VectorWithUnsignedIndices vector = buildUpsertVectorWithUnsignedIndices( vectorId, values, null, null, null); asyncIndex.upsert(Collections.singletonList(vector), namespace).get(30, TimeUnit.SECONDS); - - Thread.sleep(1000); capturedMetadata.clear(); asyncIndex.deleteByIds(Collections.singletonList(vectorId), namespace).get(30, TimeUnit.SECONDS); - Thread.sleep(100); ResponseMetadata metadata = findMetadataForOperation("delete"); assertNotNull(metadata, "Should have captured metadata for async delete operation"); @@ -213,7 +204,6 @@ public void testAsyncOperationsThreadSafety() throws ExecutionException, Interru future1.get(30, TimeUnit.SECONDS); future2.get(30, TimeUnit.SECONDS); future3.get(30, TimeUnit.SECONDS); - Thread.sleep(100); int upsertCount = 0; for (ResponseMetadata m : capturedMetadata) { diff --git a/src/integration/java/io/pinecone/integration/dataPlane/ResponseMetadataListenerIntegrationTest.java b/src/integration/java/io/pinecone/integration/dataPlane/ResponseMetadataListenerIntegrationTest.java index 2df011ca..a658486e 100644 --- a/src/integration/java/io/pinecone/integration/dataPlane/ResponseMetadataListenerIntegrationTest.java +++ b/src/integration/java/io/pinecone/integration/dataPlane/ResponseMetadataListenerIntegrationTest.java @@ -1,7 +1,8 @@ package io.pinecone.integration.dataPlane; import io.pinecone.clients.Index; -import io.pinecone.clients.Pinecone; +import io.pinecone.configs.PineconeConfig; +import io.pinecone.configs.PineconeConnection; import io.pinecone.configs.ResponseMetadata; import io.pinecone.helpers.RandomStringBuilder; import io.pinecone.helpers.TestResourcesManager; @@ -33,28 +34,31 @@ public class ResponseMetadataListenerIntegrationTest { private static String indexName; private static Index index; + private static PineconeConnection connection; private static int dimension; @BeforeAll public static void setUp() throws InterruptedException { dimension = resourceManager.getDimension(); indexName = resourceManager.getOrCreateServerlessIndex(); - - Pinecone pineconeClient = new Pinecone.Builder(System.getenv("PINECONE_API_KEY")) - .withSourceTag("pinecone_test") - .withResponseMetadataListener(metadata -> { - logger.debug("Captured metadata: {}", metadata); - capturedMetadata.add(metadata); - }) - .build(); - - index = pineconeClient.getIndexConnection(indexName); + String host = resourceManager.getOrCreateServerlessIndexHost(); + + // Build a fresh PineconeConnection directly, bypassing the shared static connectionsMap, + // so this listener-configured connection is guaranteed to be independent of the shared one. + PineconeConfig config = new PineconeConfig(System.getenv("PINECONE_API_KEY"), "pinecone_test"); + config.setHost(host); + config.setResponseMetadataListener(metadata -> { + logger.debug("Captured metadata: {}", metadata); + capturedMetadata.add(metadata); + }); + connection = new PineconeConnection(config, indexName); + index = new Index(config, connection, indexName); } @AfterAll public static void cleanUp() { - if (index != null) { - index.close(); + if (connection != null) { + connection.close(); } } @@ -96,8 +100,6 @@ public void testQueryCapturesMetadata() throws InterruptedException { VectorWithUnsignedIndices vector = buildUpsertVectorWithUnsignedIndices( ids.get(0), values, null, null, null); index.upsert(Collections.singletonList(vector), namespace); - - Thread.sleep(1000); capturedMetadata.clear(); index.query(5, values, null, null, null, namespace, null, false, false); @@ -123,8 +125,6 @@ public void testFetchCapturesMetadata() throws InterruptedException { VectorWithUnsignedIndices vector = buildUpsertVectorWithUnsignedIndices( vectorId, values, null, null, null); index.upsert(Collections.singletonList(vector), namespace); - - Thread.sleep(1000); capturedMetadata.clear(); index.fetch(Collections.singletonList(vectorId), namespace); @@ -150,8 +150,6 @@ public void testUpdateCapturesMetadata() throws InterruptedException { VectorWithUnsignedIndices vector = buildUpsertVectorWithUnsignedIndices( vectorId, values, null, null, null); index.upsert(Collections.singletonList(vector), namespace); - - Thread.sleep(1000); capturedMetadata.clear(); List updatedValues = generateVectorValuesByDimension(dimension); @@ -178,8 +176,6 @@ public void testDeleteCapturesMetadata() throws InterruptedException { VectorWithUnsignedIndices vector = buildUpsertVectorWithUnsignedIndices( vectorId, values, null, null, null); index.upsert(Collections.singletonList(vector), namespace); - - Thread.sleep(1000); capturedMetadata.clear(); index.deleteByIds(Collections.singletonList(vectorId), namespace); @@ -207,8 +203,6 @@ public void testMultipleOperationsCaptureAllMetadata() throws InterruptedExcepti vectorId, values, null, null, null); index.upsert(Collections.singletonList(vector), namespace); - Thread.sleep(500); - index.query(5, values, null, null, null, namespace, null, false, false); index.fetch(Collections.singletonList(vectorId), namespace); diff --git a/src/integration/java/io/pinecone/integration/dataPlane/UpdateFetchAndQueryPodTest.java b/src/integration/java/io/pinecone/integration/dataPlane/UpdateFetchAndQueryPodTest.java index 33252ed8..438b0acf 100644 --- a/src/integration/java/io/pinecone/integration/dataPlane/UpdateFetchAndQueryPodTest.java +++ b/src/integration/java/io/pinecone/integration/dataPlane/UpdateFetchAndQueryPodTest.java @@ -13,7 +13,6 @@ import io.pinecone.unsigned_indices_model.ScoredVectorWithUnsignedIndices; import io.pinecone.unsigned_indices_model.SparseValuesWithUnsignedIndices; import io.pinecone.unsigned_indices_model.VectorWithUnsignedIndices; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -69,14 +68,8 @@ public static void setUp() throws IOException, InterruptedException { index.upsert(vectorsToUpsert, namespace); } - @AfterAll - public static void cleanUp() { - index.close(); - asyncIndex.close(); - } - @Test - public void updateAllParamsFetchAndQuerySyncTest() throws InterruptedException { + public void updateAllParamsFetchAndQuerySyncTest() throws Exception { // Verify the upserted vector count with fetch assertWithRetry(() -> { FetchResponse fetchResponse = index.fetch(upsertIds, namespace); @@ -139,7 +132,7 @@ public void updateAllParamsFetchAndQuerySyncTest() throws InterruptedException { } @Test - public void addIncorrectDimensionalValuesSyncTest() throws InterruptedException { + public void addIncorrectDimensionalValuesSyncTest() throws Exception { // Update required fields only but with incorrect values dimension String idToUpdate = upsertIds.get(0); List updatedValues = Arrays.asList(101F); @@ -172,7 +165,7 @@ public void updateNullSparseIndicesNotNullSparseValuesSyncTest() { } @Test - public void queryWithFiltersSyncTest() throws InterruptedException { + public void queryWithFiltersSyncTest() throws Exception { String fieldToQuery = metadataFields[0]; String valueToQuery = createAndGetMetadataMap().get(fieldToQuery).get(0); @@ -199,7 +192,7 @@ public void queryWithFiltersSyncTest() throws InterruptedException { } @Test - public void updateAllParamsFetchAndQueryFutureTest() throws InterruptedException, ExecutionException { + public void updateAllParamsFetchAndQueryFutureTest() throws Exception { // Verify the upserted vector count with fetch assertWithRetry(() -> { FetchResponse fetchResponse = asyncIndex.fetch(upsertIds, namespace).get(); @@ -263,7 +256,7 @@ public void updateAllParamsFetchAndQueryFutureTest() throws InterruptedException } @Test - public void addIncorrectDimensionalValuesFutureTest() throws InterruptedException { + public void addIncorrectDimensionalValuesFutureTest() throws Exception { // Update required fields only but with incorrect values dimension String idToUpdate = upsertIds.get(0); List updatedValues = Arrays.asList(101F); @@ -278,7 +271,7 @@ public void addIncorrectDimensionalValuesFutureTest() throws InterruptedExceptio } @Test - public void queryWithFiltersFutureTest() throws ExecutionException, InterruptedException { + public void queryWithFiltersFutureTest() throws Exception { String fieldToQuery = metadataFields[0]; String valueToQuery = createAndGetMetadataMap().get(fieldToQuery).get(0); @@ -315,7 +308,7 @@ public void queryWithFiltersFutureTest() throws ExecutionException, InterruptedE } @Test - public void updateNullSparseIndicesNotNullSparseValuesFutureTest() throws InterruptedException, ExecutionException { + public void updateNullSparseIndicesNotNullSparseValuesFutureTest() throws Exception { String id = RandomStringBuilder.build(3); try { diff --git a/src/integration/java/io/pinecone/integration/dataPlane/UpdateFetchAndQueryServerlessTest.java b/src/integration/java/io/pinecone/integration/dataPlane/UpdateFetchAndQueryServerlessTest.java index f08f2936..fedc3758 100644 --- a/src/integration/java/io/pinecone/integration/dataPlane/UpdateFetchAndQueryServerlessTest.java +++ b/src/integration/java/io/pinecone/integration/dataPlane/UpdateFetchAndQueryServerlessTest.java @@ -13,7 +13,6 @@ import io.pinecone.unsigned_indices_model.ScoredVectorWithUnsignedIndices; import io.pinecone.unsigned_indices_model.SparseValuesWithUnsignedIndices; import io.pinecone.unsigned_indices_model.VectorWithUnsignedIndices; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -72,14 +71,8 @@ public static void setUp() throws IOException, InterruptedException { index.upsert(vectorsToUpsert, namespace); } - @AfterAll - public static void cleanUp() { - index.close(); - asyncIndex.close(); - } - @Test - public void updateAllParamsFetchAndQuerySyncTest() throws InterruptedException { + public void updateAllParamsFetchAndQuerySyncTest() throws Exception { // Verify the upserted vector count with fetch assertWithRetry(() -> { FetchResponse fetchResponse = index.fetch(upsertIds, namespace); @@ -146,7 +139,7 @@ public void updateAllParamsFetchAndQuerySyncTest() throws InterruptedException { } @Test - public void addIncorrectDimensionalValuesSyncTest() throws InterruptedException { + public void addIncorrectDimensionalValuesSyncTest() throws Exception { // Update required fields only but with incorrect values dimension String idToUpdate = upsertIds.get(0); List updatedValues = Arrays.asList(101F); // should be of size 4 @@ -180,7 +173,7 @@ public void updateNullSparseIndicesNotNullSparseValuesSyncTest() { } @Test - public void queryWithFiltersSyncTest() throws InterruptedException { + public void queryWithFiltersSyncTest() throws Exception { String fieldToQuery = metadataFields[0]; String valueToQuery = createAndGetMetadataMap().get(fieldToQuery).get(0); @@ -208,7 +201,7 @@ public void queryWithFiltersSyncTest() throws InterruptedException { } @Test - public void updateAllParamsFetchAndQueryFutureTest() throws InterruptedException, ExecutionException { + public void updateAllParamsFetchAndQueryFutureTest() throws Exception { // Verify the upserted vector count with fetch assertWithRetry(() -> { FetchResponse fetchResponse = asyncIndex.fetch(upsertIds, namespace).get(); @@ -275,7 +268,7 @@ public void updateAllParamsFetchAndQueryFutureTest() throws InterruptedException } @Test - public void addIncorrectDimensionalValuesFutureTest() throws InterruptedException { + public void addIncorrectDimensionalValuesFutureTest() throws Exception { // Update required fields only but with incorrect values dimension String idToUpdate = upsertIds.get(0); List updatedValues = Arrays.asList(101F); // should be of size 4 @@ -291,7 +284,7 @@ public void addIncorrectDimensionalValuesFutureTest() throws InterruptedExceptio } @Test - public void queryWithFiltersFutureTest() throws InterruptedException { + public void queryWithFiltersFutureTest() throws Exception { String fieldToQuery = metadataFields[0]; String valueToQuery = createAndGetMetadataMap().get(fieldToQuery).get(0); @@ -319,7 +312,7 @@ public void queryWithFiltersFutureTest() throws InterruptedException { } @Test - public void updateNullSparseIndicesNotNullSparseValuesFutureTest() throws InterruptedException, ExecutionException { + public void updateNullSparseIndicesNotNullSparseValuesFutureTest() throws Exception { String id = RandomStringBuilder.build(3); try { diff --git a/src/integration/java/io/pinecone/integration/dataPlane/UpsertAndQueryPodTest.java b/src/integration/java/io/pinecone/integration/dataPlane/UpsertAndQueryPodTest.java index baac7bb0..6d0e3ec6 100644 --- a/src/integration/java/io/pinecone/integration/dataPlane/UpsertAndQueryPodTest.java +++ b/src/integration/java/io/pinecone/integration/dataPlane/UpsertAndQueryPodTest.java @@ -38,7 +38,7 @@ public static void setUp() throws IOException, InterruptedException { } @Test - public void upsertOptionalVectorsAndQueryIndexSyncTest() throws InterruptedException { + public void upsertOptionalVectorsAndQueryIndexSyncTest() throws Exception { int numOfVectors = 5; int topK = 5; @@ -121,7 +121,7 @@ public void upsertNullSparseIndicesNotNullSparseValuesSyncTest() { } @Test - public void upsertOptionalVectorsAndQueryIndexFutureTest() throws InterruptedException, ExecutionException { + public void upsertOptionalVectorsAndQueryIndexFutureTest() throws Exception { int numOfVectors = 5; int topK = 5; diff --git a/src/integration/java/io/pinecone/integration/dataPlane/UpsertAndQueryServerlessTest.java b/src/integration/java/io/pinecone/integration/dataPlane/UpsertAndQueryServerlessTest.java index 82d8271f..4b4b3055 100644 --- a/src/integration/java/io/pinecone/integration/dataPlane/UpsertAndQueryServerlessTest.java +++ b/src/integration/java/io/pinecone/integration/dataPlane/UpsertAndQueryServerlessTest.java @@ -10,7 +10,6 @@ import io.pinecone.unsigned_indices_model.QueryResponseWithUnsignedIndices; import io.pinecone.unsigned_indices_model.ScoredVectorWithUnsignedIndices; import io.pinecone.unsigned_indices_model.VectorWithUnsignedIndices; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -32,18 +31,12 @@ public class UpsertAndQueryServerlessTest { private static final String namespace = RandomStringBuilder.build("ns", 8); @BeforeAll - public static void setUp() throws InterruptedException { + public static void setUp() throws Exception { dimension = indexManager.getDimension(); index = indexManager.getOrCreateServerlessIndexConnection(); asyncIndex = indexManager.getOrCreateServerlessAsyncIndexConnection(); } - @AfterAll - public static void cleanUp() { - index.close(); - asyncIndex.close(); - } - @Test public void upsertOptionalVectorsAndQueryIndexSyncTest() throws Exception { int numOfVectors = 5; @@ -136,7 +129,7 @@ public void upsertNullSparseIndicesNotNullSparseValuesSyncTest() { } @Test - public void upsertOptionalVectorsAndQueryIndexFutureTest() throws InterruptedException, ExecutionException { + public void upsertOptionalVectorsAndQueryIndexFutureTest() throws Exception { int numOfVectors = 5; int topK = 5; diff --git a/src/integration/java/io/pinecone/integration/dataPlane/UpsertAndSearchRecordsTest.java b/src/integration/java/io/pinecone/integration/dataPlane/UpsertAndSearchRecordsTest.java index 2a82b20a..4a2514d5 100644 --- a/src/integration/java/io/pinecone/integration/dataPlane/UpsertAndSearchRecordsTest.java +++ b/src/integration/java/io/pinecone/integration/dataPlane/UpsertAndSearchRecordsTest.java @@ -13,9 +13,12 @@ import java.util.*; +import static io.pinecone.helpers.AssertRetry.assertWithRetry; +import static io.pinecone.helpers.TestUtilities.waitUntilIndexIsReady; + public class UpsertAndSearchRecordsTest { @Test - public void upsertAndSearchRecordsTest() throws ApiException, org.openapitools.db_control.client.ApiException, InterruptedException { + public void upsertAndSearchRecordsTest() throws Exception { Pinecone pinecone = new Pinecone.Builder(System.getenv("PINECONE_API_KEY")).build(); String indexName = RandomStringBuilder.build("inf", 8); HashMap fieldMap = new HashMap<>(); @@ -23,67 +26,67 @@ public void upsertAndSearchRecordsTest() throws ApiException, org.openapitools.d CreateIndexForModelRequestEmbed embed = new CreateIndexForModelRequestEmbed() .model("multilingual-e5-large") .fieldMap(fieldMap); - pinecone.createIndexForModel(indexName, "aws", "us-west-2", embed, "disabled", new HashMap<>()); - - // Wait for index to be created - Thread.sleep(10000); - - Index index = pinecone.getIndexConnection(indexName); - ArrayList> upsertRecords = new ArrayList<>(); - - HashMap record1 = new HashMap<>(); - record1.put("_id", "rec1"); - record1.put("category", "digestive system"); - record1.put("chunk_text", "Apples are a great source of dietary fiber, which supports digestion and helps maintain a healthy gut."); - - HashMap record2 = new HashMap<>(); - record2.put("_id", "rec2"); - record2.put("category", "cultivation"); - record2.put("chunk_text", "Apples originated in Central Asia and have been cultivated for thousands of years, with over 7,500 varieties available today."); - - HashMap record3 = new HashMap<>(); - record3.put("_id", "rec3"); - record3.put("category", "immune system"); - record3.put("chunk_text", "Rich in vitamin C and other antioxidants, apples contribute to immune health and may reduce the risk of chronic diseases."); - - HashMap record4 = new HashMap<>(); - record4.put("_id", "rec4"); - record4.put("category", "endocrine system"); - record4.put("chunk_text", "The high fiber content in apples can also help regulate blood sugar levels, making them a favorable snack for people with diabetes."); - - upsertRecords.add(record1); - upsertRecords.add(record2); - upsertRecords.add(record3); - upsertRecords.add(record4); - - index.upsertRecords("example-namespace", upsertRecords); - - String namespace = "example-namespace"; - HashMap inputsMap = new HashMap<>(); - inputsMap.put("text", "Disease prevention"); - SearchRecordsRequestQuery query = new SearchRecordsRequestQuery() - .topK(4) - .inputs(inputsMap); - - List fields = new ArrayList<>(); - fields.add("category"); - fields.add("chunk_text"); - - // Wait for vectors to be upserted - Thread.sleep(5000); - - SearchRecordsResponse recordsResponse = index.searchRecordsById(record1.get("_id"), namespace, fields, 1, null, null); - Assertions.assertEquals(1, recordsResponse.getResult().getHits().size()); - Assertions.assertEquals(record1.get("_id"), recordsResponse.getResult().getHits().get(0).getId()); - - SearchRecordsRequestRerank rerank = new SearchRecordsRequestRerank() - .model("bge-reranker-v2-m3") - .topN(2) - .rankFields(Arrays.asList("chunk_text")); - - recordsResponse = index.searchRecordsByText("Disease prevention", namespace, fields, 4, null, rerank); - Assertions.assertEquals(record3.get("_id"), recordsResponse.getResult().getHits().get(0).getId()); - - pinecone.deleteIndex(indexName); + boolean indexCreated = false; + try { + pinecone.createIndexForModel(indexName, "aws", "us-west-2", embed, "disabled", new HashMap<>()); + indexCreated = true; + waitUntilIndexIsReady(pinecone, indexName); + // Additional buffer after ready signal to avoid "no healthy upstream" errors + Thread.sleep(30000); + + Index index = pinecone.getIndexConnection(indexName); + ArrayList> upsertRecords = new ArrayList<>(); + + HashMap record1 = new HashMap<>(); + record1.put("_id", "rec1"); + record1.put("category", "digestive system"); + record1.put("chunk_text", "Apples are a great source of dietary fiber, which supports digestion and helps maintain a healthy gut."); + + HashMap record2 = new HashMap<>(); + record2.put("_id", "rec2"); + record2.put("category", "cultivation"); + record2.put("chunk_text", "Apples originated in Central Asia and have been cultivated for thousands of years, with over 7,500 varieties available today."); + + HashMap record3 = new HashMap<>(); + record3.put("_id", "rec3"); + record3.put("category", "immune system"); + record3.put("chunk_text", "Rich in vitamin C and other antioxidants, apples contribute to immune health and may reduce the risk of chronic diseases."); + + HashMap record4 = new HashMap<>(); + record4.put("_id", "rec4"); + record4.put("category", "endocrine system"); + record4.put("chunk_text", "The high fiber content in apples can also help regulate blood sugar levels, making them a favorable snack for people with diabetes."); + + upsertRecords.add(record1); + upsertRecords.add(record2); + upsertRecords.add(record3); + upsertRecords.add(record4); + + String namespace = "example-namespace"; + index.upsertRecords(namespace, upsertRecords); + + List fields = new ArrayList<>(); + fields.add("category"); + fields.add("chunk_text"); + + // Poll until the upserted record is searchable + assertWithRetry(() -> { + SearchRecordsResponse resp = index.searchRecordsById(record1.get("_id"), namespace, fields, 1, null, null); + Assertions.assertEquals(1, resp.getResult().getHits().size()); + Assertions.assertEquals(record1.get("_id"), resp.getResult().getHits().get(0).getId()); + }, 3); + + SearchRecordsRequestRerank rerank = new SearchRecordsRequestRerank() + .model("bge-reranker-v2-m3") + .topN(2) + .rankFields(Arrays.asList("chunk_text")); + + SearchRecordsResponse recordsResponse = index.searchRecordsByText("Disease prevention", namespace, fields, 4, null, rerank); + Assertions.assertEquals(record3.get("_id"), recordsResponse.getResult().getHits().get(0).getId()); + } finally { + if (indexCreated) { + pinecone.deleteIndex(indexName); + } + } } } diff --git a/src/integration/java/io/pinecone/integration/dataPlane/UpsertDescribeIndexStatsAndDeletePodTest.java b/src/integration/java/io/pinecone/integration/dataPlane/UpsertDescribeIndexStatsAndDeletePodTest.java index 3b4a5567..08df0833 100644 --- a/src/integration/java/io/pinecone/integration/dataPlane/UpsertDescribeIndexStatsAndDeletePodTest.java +++ b/src/integration/java/io/pinecone/integration/dataPlane/UpsertDescribeIndexStatsAndDeletePodTest.java @@ -27,8 +27,6 @@ public class UpsertDescribeIndexStatsAndDeletePodTest { private static AsyncIndex asyncIndex; private static int dimension; private static final Struct nullFilterStruct = null; - private static final String namespace = RandomStringBuilder.build("ns", 8); - private static int namespaceVectorCount = 0; @BeforeAll public static void setUp() throws IOException, InterruptedException { @@ -38,69 +36,58 @@ public static void setUp() throws IOException, InterruptedException { } @Test - public void upsertVectorsAndDeleteByIdSyncTest() throws InterruptedException { - // Upsert vectors with required parameters + public void upsertVectorsAndDeleteByIdSyncTest() throws Exception { + String namespace = RandomStringBuilder.build("ns", 8); int numOfVectors = 3; List upsertIds = getIdsList(numOfVectors); List vectorsToUpsert = new ArrayList<>(numOfVectors); for (String id : upsertIds) { - VectorWithUnsignedIndices vector = - new VectorWithUnsignedIndices(id, generateVectorValuesByDimension(dimension)); - vectorsToUpsert.add(vector); + vectorsToUpsert.add(new VectorWithUnsignedIndices(id, generateVectorValuesByDimension(dimension))); } index.upsert(vectorsToUpsert, namespace); - namespaceVectorCount += numOfVectors; assertWithRetry(() -> { - // call describeIndexStats to get updated vector count - DescribeIndexStatsResponse describeIndexStatsResponse = index.describeIndexStats(); - - // verify the updated vector count - assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), namespaceVectorCount); + DescribeIndexStatsResponse response = index.describeIndexStats(); + NamespaceSummary ns = response.getNamespacesMap().get(namespace); + assertEquals(numOfVectors, ns == null ? 0 : ns.getVectorCount()); }, 3); - // Delete vectors index.delete(upsertIds, false, namespace, nullFilterStruct); - namespaceVectorCount -= numOfVectors; assertWithRetry(() -> { - // Call describeIndexStats to get updated vector count - DescribeIndexStatsResponse describeIndexStatsResponse = index.describeIndexStats(nullFilterStruct); - // Verify the vectors have been deleted - assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), namespaceVectorCount); + DescribeIndexStatsResponse response = index.describeIndexStats(nullFilterStruct); + NamespaceSummary ns = response.getNamespacesMap().get(namespace); + assertEquals(0, ns == null ? 0 : ns.getVectorCount()); }, 3); } @Test - public void upsertVectorsAndDeleteByFilterSyncTest() throws InterruptedException { + public void upsertVectorsAndDeleteByFilterSyncTest() throws Exception { + String namespace = RandomStringBuilder.build("ns", 8); int numOfVectors = 3; List upsertIds = getIdsList(numOfVectors); List vectorsToUpsert = new ArrayList<>(numOfVectors); - // Upsert vectors with required + optional and custom metadata parameters - for (int i=0; i { - // Call describeIndexStats to get updated vector count - DescribeIndexStatsResponse describeIndexStatsResponse = index.describeIndexStats(nullFilterStruct); - // Verify the updated vector count - assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), namespaceVectorCount); + DescribeIndexStatsResponse response = index.describeIndexStats(nullFilterStruct); + NamespaceSummary ns = response.getNamespacesMap().get(namespace); + assertEquals(numOfVectors, ns == null ? 0 : ns.getVectorCount()); }, 3); String fieldToDelete = metadataFields[0]; @@ -114,80 +101,69 @@ public void upsertVectorsAndDeleteByFilterSyncTest() throws InterruptedException .build()) .build(); - // Delete by filtering index.delete(null, false, namespace, filterStruct); - namespaceVectorCount = namespaceVectorCount - 1; + int expectedAfterDelete = numOfVectors - 1; assertWithRetry(() -> { - // Call describeIndexStats to get updated vector count - DescribeIndexStatsResponse describeIndexStatsResponse = index.describeIndexStats(nullFilterStruct); - // Verify the updated vector count - assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), namespaceVectorCount); + DescribeIndexStatsResponse response = index.describeIndexStats(nullFilterStruct); + NamespaceSummary ns = response.getNamespacesMap().get(namespace); + assertEquals(expectedAfterDelete, ns == null ? 0 : ns.getVectorCount()); }, 3); } @Test - public void upsertVectorsAndDeleteByIdFutureTest() throws InterruptedException, ExecutionException { - // Upsert vectors with required parameters + public void upsertVectorsAndDeleteByIdFutureTest() throws Exception { + String namespace = RandomStringBuilder.build("ns", 8); int numOfVectors = 3; List upsertIds = getIdsList(numOfVectors); List vectorsToUpsert = new ArrayList<>(numOfVectors); for (String id : upsertIds) { - VectorWithUnsignedIndices vector = - new VectorWithUnsignedIndices(id, generateVectorValuesByDimension(dimension)); - vectorsToUpsert.add(vector); + vectorsToUpsert.add(new VectorWithUnsignedIndices(id, generateVectorValuesByDimension(dimension))); } + asyncIndex.upsert(vectorsToUpsert, namespace).get(); - namespaceVectorCount += numOfVectors; assertWithRetry(() -> { - // call describeIndexStats to get updated vector count - DescribeIndexStatsResponse describeIndexStatsResponse = asyncIndex.describeIndexStats().get(); - // verify the updated vector count - assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), namespaceVectorCount); + DescribeIndexStatsResponse response = asyncIndex.describeIndexStats().get(); + NamespaceSummary ns = response.getNamespacesMap().get(namespace); + assertEquals(numOfVectors, ns == null ? 0 : ns.getVectorCount()); }, 3); - // Delete vectors asyncIndex.delete(upsertIds, false, namespace, null).get(); - namespaceVectorCount -= numOfVectors; assertWithRetry(() -> { - // Call describeIndexStats to get updated vector count - DescribeIndexStatsResponse describeIndexStatsResponse = asyncIndex.describeIndexStats().get(); - // Verify the updated vector count - assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), namespaceVectorCount); + DescribeIndexStatsResponse response = asyncIndex.describeIndexStats().get(); + NamespaceSummary ns = response.getNamespacesMap().get(namespace); + assertEquals(0, ns == null ? 0 : ns.getVectorCount()); }, 3); } @Test - public void upsertVectorsAndDeleteByFilterFutureTest() throws InterruptedException, ExecutionException { + public void upsertVectorsAndDeleteByFilterFutureTest() throws Exception { + String namespace = RandomStringBuilder.build("ns", 8); int numOfVectors = 3; List upsertIds = getIdsList(numOfVectors); List vectorsToUpsert = new ArrayList<>(numOfVectors); - // Upsert vectors with required + optional and custom metadata parameters - for (int i=0; i { - // Call describeIndexStats to get updated vector count - DescribeIndexStatsResponse describeIndexStatsResponse = asyncIndex.describeIndexStats(nullFilterStruct).get(); - // Verify the updated vector count - assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), namespaceVectorCount); + DescribeIndexStatsResponse response = asyncIndex.describeIndexStats(nullFilterStruct).get(); + NamespaceSummary ns = response.getNamespacesMap().get(namespace); + assertEquals(numOfVectors, ns == null ? 0 : ns.getVectorCount()); }, 3); String fieldToDelete = metadataFields[0]; @@ -201,15 +177,13 @@ public void upsertVectorsAndDeleteByFilterFutureTest() throws InterruptedExcepti .build()) .build(); - // Delete by filtering asyncIndex.delete(new ArrayList<>(), false, namespace, filterStruct).get(); - namespaceVectorCount -= 1; + int expectedAfterDelete = numOfVectors - 1; assertWithRetry(() -> { - // Call describeIndexStats to get updated vector count - DescribeIndexStatsResponse describeIndexStatsResponse = asyncIndex.describeIndexStats(nullFilterStruct).get(); - // Verify the updated vector count - assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), namespaceVectorCount); + DescribeIndexStatsResponse response = asyncIndex.describeIndexStats(nullFilterStruct).get(); + NamespaceSummary ns = response.getNamespacesMap().get(namespace); + assertEquals(expectedAfterDelete, ns == null ? 0 : ns.getVectorCount()); }, 3); } } diff --git a/src/integration/java/io/pinecone/integration/dataPlane/UpsertDescribeIndexStatsAndDeleteServerlessTest.java b/src/integration/java/io/pinecone/integration/dataPlane/UpsertDescribeIndexStatsAndDeleteServerlessTest.java index f055d65e..18f9da42 100644 --- a/src/integration/java/io/pinecone/integration/dataPlane/UpsertDescribeIndexStatsAndDeleteServerlessTest.java +++ b/src/integration/java/io/pinecone/integration/dataPlane/UpsertDescribeIndexStatsAndDeleteServerlessTest.java @@ -6,8 +6,8 @@ import io.pinecone.helpers.RandomStringBuilder; import io.pinecone.helpers.TestResourcesManager; import io.pinecone.proto.DescribeIndexStatsResponse; +import io.pinecone.proto.NamespaceSummary; import io.pinecone.unsigned_indices_model.VectorWithUnsignedIndices; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -25,8 +25,6 @@ public class UpsertDescribeIndexStatsAndDeleteServerlessTest { private static Index index; private static AsyncIndex asyncIndex; private static int dimension; - private static final String namespace = RandomStringBuilder.build("ns", 8); - private static int namespaceVectorCount = 0; @BeforeAll public static void setUp() throws IOException, InterruptedException { @@ -35,83 +33,59 @@ public static void setUp() throws IOException, InterruptedException { asyncIndex = indexManager.getOrCreateServerlessAsyncIndexConnection(); } - @AfterAll - public static void cleanUp() { - index.close(); - asyncIndex.close(); - } - @Test - public void upsertVectorsAndDeleteByIdSyncTest() throws InterruptedException { - // Upsert vectors with required parameters + public void upsertVectorsAndDeleteByIdSyncTest() throws Exception { + String namespace = RandomStringBuilder.build("ns", 8); int numOfVectors = 3; - List upsertIds = getIdsList(numOfVectors); List vectorsToUpsert = new ArrayList<>(numOfVectors); for (String id : upsertIds) { - VectorWithUnsignedIndices vector = - new VectorWithUnsignedIndices(id, generateVectorValuesByDimension(dimension)); - vectorsToUpsert.add(vector); + vectorsToUpsert.add(new VectorWithUnsignedIndices(id, generateVectorValuesByDimension(dimension))); } index.upsert(vectorsToUpsert, namespace); - namespaceVectorCount += numOfVectors; assertWithRetry(() -> { - // call describeIndexStats to get updated vector count - DescribeIndexStatsResponse describeIndexStatsResponse = index.describeIndexStats(); - - // verify the updated vector count - assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), namespaceVectorCount); + DescribeIndexStatsResponse response = index.describeIndexStats(); + NamespaceSummary ns = response.getNamespacesMap().get(namespace); + assertEquals(numOfVectors, ns == null ? 0 : ns.getVectorCount()); }, 3); - // Delete vectors index.deleteByIds(upsertIds, namespace); - namespaceVectorCount -= numOfVectors; assertWithRetry(() -> { - // Call describeIndexStats to get updated vector count - DescribeIndexStatsResponse describeIndexStatsResponse = index.describeIndexStats(); - // Verify the updated vector count - assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), namespaceVectorCount); + DescribeIndexStatsResponse response = index.describeIndexStats(); + NamespaceSummary ns = response.getNamespacesMap().get(namespace); + assertEquals(0, ns == null ? 0 : ns.getVectorCount()); }, 3); } @Test - public void upsertVectorsAndDeleteByIdFutureTest() throws InterruptedException, ExecutionException { - // Upsert vectors with required parameters - Struct emptyFilterStruct = null; + public void upsertVectorsAndDeleteByIdFutureTest() throws Exception { + String namespace = RandomStringBuilder.build("ns", 8); int numOfVectors = 3; List upsertIds = getIdsList(numOfVectors); List vectorsToUpsert = new ArrayList<>(numOfVectors); for (String id : upsertIds) { - VectorWithUnsignedIndices vector = - new VectorWithUnsignedIndices(id, generateVectorValuesByDimension(dimension)); - vectorsToUpsert.add(vector); + vectorsToUpsert.add(new VectorWithUnsignedIndices(id, generateVectorValuesByDimension(dimension))); } asyncIndex.upsert(vectorsToUpsert, namespace).get(); - namespaceVectorCount += numOfVectors; assertWithRetry(() -> { - // call describeIndexStats to get updated vector count - DescribeIndexStatsResponse describeIndexStatsResponse = asyncIndex.describeIndexStats().get(); - - // verify the updated vector count - assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), namespaceVectorCount); + DescribeIndexStatsResponse response = asyncIndex.describeIndexStats().get(); + NamespaceSummary ns = response.getNamespacesMap().get(namespace); + assertEquals(numOfVectors, ns == null ? 0 : ns.getVectorCount()); }, 3); - // Delete vectors asyncIndex.deleteByIds(upsertIds, namespace); - namespaceVectorCount -= numOfVectors; assertWithRetry(() -> { - // Call describeIndexStats to get updated vector count - DescribeIndexStatsResponse describeIndexStatsResponse = asyncIndex.describeIndexStats().get(); - // Verify the updated vector count - assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), namespaceVectorCount); + DescribeIndexStatsResponse response = asyncIndex.describeIndexStats().get(); + NamespaceSummary ns = response.getNamespacesMap().get(namespace); + assertEquals(0, ns == null ? 0 : ns.getVectorCount()); }, 3); } } diff --git a/src/integration/resources/junit-platform.properties b/src/integration/resources/junit-platform.properties new file mode 100644 index 00000000..a708ff05 --- /dev/null +++ b/src/integration/resources/junit-platform.properties @@ -0,0 +1,9 @@ +# Run test classes in parallel, but keep test methods within a class sequential. +# This allows shared indexes (via TestResourcesManager singleton) to be reused +# across classes without per-class re-creation, while still running independent +# test classes concurrently. +junit.jupiter.execution.parallel.enabled=true +junit.jupiter.execution.parallel.mode.default=same_thread +junit.jupiter.execution.parallel.mode.classes.default=concurrent +junit.jupiter.execution.parallel.config.strategy=fixed +junit.jupiter.execution.parallel.config.fixed.parallelism=4 diff --git a/src/main/java/io/pinecone/commons/Constants.java b/src/main/java/io/pinecone/commons/Constants.java index f113d8b9..e147484d 100644 --- a/src/main/java/io/pinecone/commons/Constants.java +++ b/src/main/java/io/pinecone/commons/Constants.java @@ -1,5 +1,5 @@ package io.pinecone.commons; public class Constants { - public static final String pineconeClientVersion = "v6.1.0"; + public static final String pineconeClientVersion = "v6.2.0"; }