-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update integration test setup (#109)
## Problem I want Typescript to work properly within my integration tests without having to manage a separate tsconfig file. ## Solution Getting this working was a bit of an adventure. As usual, when I thought I was 80% done I was only actually about 20% done. First I did these things: - Move integration tests underneath the `src/` directory, which is the `rootDir` in our `tsconfig.json` file. - Update test commands in package.json so that `npm run test:unit` does not include integration tests. - Add a new test, `src/integration/data/deleteMany.test.ts`, using a randomly generated namespace to store test-specific state in the index from other test runs. In testing these data plane operations, it seems fine to recycle the same index and save the time it would take to spin up a fresh one for every test. That was enough to get tests passing locally with `npm run test:integration`. Then I tried running them in CI and everything was mysteriously failing. After some investigation, I realized there was no `fetch` present in the node environment where things run on Github Actions. I'm still somewhat baffled how this was working on my local machine, in the node repl and in the sample apps, but not in this node CI env. To address this: - I explicitly import `cross-fetch` and pass that fetch implementation to the openapi client. Node doesn't natively have a `fetch` command. `cross-fetch` ([npm](https://www.npmjs.com/package/cross-fetch)) is a polyfill proxy that attempts to activate the correct fetch polyfill for the current environment. - Updated tests for the projectIdSingleton, which is the only thing I've written in this client that used fetch directly. All other unit tests are mocking things at the openapi object layer so had no direct dependency on fetch. Also: - Cleanup and remove vestiges of the old integration test suite, which hasn't been running for quite a while. ## Type of Change - [x] New feature (non-breaking change which adds functionality) - [x] Infrastructure change (CI configs, etc) ## Test Plan CI should be green.
- Loading branch information
Showing
14 changed files
with
206 additions
and
421 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { Pinecone, Index } from '../../index'; | ||
import { | ||
randomString, | ||
createIndexIfDoesNotExist, | ||
generateRecords, | ||
} from '../test-helpers'; | ||
|
||
describe('deleteMany', () => { | ||
const INDEX_NAME = 'ts-integration'; | ||
let pinecone: Pinecone, index: Index, ns: Index, namespace: string; | ||
|
||
beforeAll(async () => { | ||
pinecone = new Pinecone(); | ||
|
||
await createIndexIfDoesNotExist(pinecone, INDEX_NAME); | ||
|
||
namespace = randomString(16); | ||
index = pinecone.index(INDEX_NAME); | ||
ns = index.namespace(namespace); | ||
}); | ||
|
||
afterAll(async () => { | ||
await pinecone.listIndexes(); | ||
await ns.deleteAll(); | ||
}); | ||
|
||
test('verify deleteMany with ids', async () => { | ||
const recordsToUpsert = generateRecords(5, 3); | ||
expect(recordsToUpsert).toHaveLength(3); | ||
expect(recordsToUpsert[0].id).toEqual('0'); | ||
expect(recordsToUpsert[1].id).toEqual('1'); | ||
expect(recordsToUpsert[2].id).toEqual('2'); | ||
|
||
await ns.upsert(recordsToUpsert); | ||
|
||
// Check records got upserted | ||
let stats = await ns.describeIndexStats(); | ||
if (stats.namespaces) { | ||
expect(stats.namespaces[namespace].recordCount).toEqual(3); | ||
} else { | ||
fail('Expected namespaces to be defined'); | ||
} | ||
|
||
// Look more closely at one of the records to make sure values set | ||
const fetchResult = await ns.fetch(['0']); | ||
const records = fetchResult.records; | ||
if (records) { | ||
expect(records['0'].id).toEqual('0'); | ||
expect(records['0'].values.length).toEqual(5); | ||
} else { | ||
fail( | ||
'Did not find expected records. Fetch result was ' + | ||
JSON.stringify(fetchResult) | ||
); | ||
} | ||
|
||
// Try deleting 2 of 3 vectors | ||
await ns.deleteMany(['0', '2']); | ||
stats = await ns.describeIndexStats(); | ||
if (stats.namespaces) { | ||
expect(stats.namespaces[namespace].recordCount).toEqual(1); | ||
} else { | ||
fail( | ||
'Expected namespaces to be defined (second call). Stats were ' + | ||
JSON.stringify(stats) | ||
); | ||
} | ||
|
||
// Check that record id='1' still exists | ||
const fetchResult2 = await ns.fetch(['1']); | ||
const records2 = fetchResult2.records; | ||
if (records2) { | ||
expect(records2['1']).not.toBeUndefined(); | ||
} else { | ||
fail( | ||
'Expected record 2 to be defined. Fetch result was ' + | ||
JSON.stringify(fetchResult2) | ||
); | ||
} | ||
|
||
// deleting non-existent indexes should not throw | ||
await ns.deleteMany(['0', '1', '2', '3']); | ||
|
||
// Verify all are now removed | ||
stats = await ns.describeIndexStats(); | ||
if (stats.namespaces) { | ||
expect(stats.namespaces[namespace]).toBeUndefined(); | ||
} else { | ||
// no-op. This should actually happen unless there | ||
// are leftover namespaces from previous runs that | ||
// failed or stopped without proper cleanup. | ||
} | ||
}); | ||
}); |
2 changes: 1 addition & 1 deletion
2
tests/integration/initialization.test.ts → src/integration/initialization.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { Pinecone } from '../index'; | ||
import type { PineconeRecord, RecordSparseValues } from '../index'; | ||
|
||
export const randomString = (length) => { | ||
const characters = | ||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | ||
let result = ''; | ||
|
||
for (let i = 0; i < length; i++) { | ||
const randomIndex = Math.floor(Math.random() * characters.length); | ||
result += characters.charAt(randomIndex); | ||
} | ||
|
||
return result; | ||
}; | ||
|
||
export const createIndexIfDoesNotExist = async ( | ||
pinecone: Pinecone, | ||
indexName: string | ||
) => { | ||
const indexList = await pinecone.listIndexes(); | ||
let found = false; | ||
indexList.forEach((i) => { | ||
if (i.name === indexName) { | ||
found = true; | ||
} | ||
}); | ||
if (!found) { | ||
await pinecone.createIndex({ | ||
name: indexName, | ||
dimension: 5, | ||
waitUntilReady: true, | ||
}); | ||
} | ||
}; | ||
|
||
export const generateRecords = ( | ||
dimension: number, | ||
quantity: number, | ||
withSparseValues?: boolean | ||
): PineconeRecord[] => { | ||
const vectors: PineconeRecord[] = []; | ||
for (let i = 0; i < quantity; i++) { | ||
const values: number[] = []; | ||
for (let j = 0; j < dimension; j++) { | ||
values.push(Math.random()); | ||
} | ||
let vector: PineconeRecord = { | ||
id: i.toString(), | ||
values, | ||
}; | ||
if (withSparseValues) { | ||
vector = { | ||
...vector, | ||
sparseValues: generateSparseValues(dimension), | ||
}; | ||
} | ||
|
||
vectors.push(vector); | ||
} | ||
return vectors; | ||
}; | ||
|
||
export const generateSparseValues = (dimension: number): RecordSparseValues => { | ||
const values: number[] = []; | ||
const indices: number[] = []; | ||
for (let j = 0; j < dimension; j++) { | ||
values.push(Math.random()); | ||
indices.push(j); | ||
} | ||
const sparseValues: RecordSparseValues = { indices, values }; | ||
return sparseValues; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.