Skip to content

Commit

Permalink
Overhaul error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
jhamon committed Oct 6, 2023
1 parent b0eb619 commit 808366c
Show file tree
Hide file tree
Showing 54 changed files with 680 additions and 1,156 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"format": "prettier --write .",
"lint": "eslint src/ --ext .ts",
"repl": "npm run build && node utils/replInit.ts",
"test:integration:node": "jest src/integration/ -c jest.config.integration-node.js",
"test:integration:edge": "jest src/integration/ -c jest.config.integration-edge.js",
"test:integration:node": "TEST_ENV=node jest src/integration/ -c jest.config.integration-node.js --runInBand --bail",
"test:integration:edge": "TEST_ENV=edge jest src/integration/ -c jest.config.integration-edge.js --runInBand --bail",
"test:unit": "jest src/"
},
"engines": {
Expand Down
93 changes: 0 additions & 93 deletions src/control/__tests__/configureIndex.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import { configureIndex } from '../configureIndex';
import {
PineconeBadRequestError,
PineconeInternalServerError,
PineconeNotFoundError,
} from '../../errors';
import { IndexOperationsApi } from '../../pinecone-generated-ts-fetch';
import type { ConfigureIndexRequest } from '../../pinecone-generated-ts-fetch';

Expand All @@ -13,9 +8,6 @@ describe('configureIndex', () => {
jest.fn();
const IOA = { configureIndex: fakeConfigure } as IndexOperationsApi;

jest.mock('../../pinecone-generated-ts-fetch', () => ({
IndexOperationsApi: IOA,
}));
const returned = await configureIndex(IOA)('index-name', { replicas: 10 });

expect(returned).toBe(void 0);
Expand All @@ -24,89 +16,4 @@ describe('configureIndex', () => {
patchRequest: { replicas: 10 },
});
});

describe('http error mapping', () => {
test('when 500 occurs', async () => {
const fakeConfigure: (req: ConfigureIndexRequest) => Promise<string> =
jest.fn().mockImplementation(() =>
Promise.reject({
response: {
status: 500,
text: () => 'backend error message',
},
})
);
const IOA = {
configureIndex: fakeConfigure,
} as IndexOperationsApi;

jest.mock('../../pinecone-generated-ts-fetch', () => ({
IndexOperationsApi: IOA,
}));

const toThrow = async () => {
await configureIndex(IOA)('index-name', { replicas: 10 });
};

await expect(toThrow).rejects.toThrow(PineconeInternalServerError);
});

test('when 400 occurs, displays server message', async () => {
const fakeConfigure: (req: ConfigureIndexRequest) => Promise<string> =
jest.fn().mockImplementation(() =>
Promise.reject({
response: {
status: 400,
text: () => 'backend error message',
},
})
);
const IOA = {
configureIndex: fakeConfigure,
} as IndexOperationsApi;

jest.mock('../../pinecone-generated-ts-fetch', () => ({
IndexOperationsApi: IOA,
}));

const toThrow = async () => {
await configureIndex(IOA)('index-name', { replicas: 10 });
};

await expect(toThrow).rejects.toThrow(PineconeBadRequestError);
await expect(toThrow).rejects.toThrow('backend error message');
});

test('when 404 occurs, show available indexes', async () => {
const fakeConfigure: (req: ConfigureIndexRequest) => Promise<string> =
jest.fn().mockImplementation(() =>
Promise.reject({
response: {
status: 404,
text: () => 'not found',
},
})
);
const fakeListIndexes: () => Promise<string[]> = jest
.fn()
.mockImplementation(() => Promise.resolve(['foo', 'bar']));
const IOA = {
configureIndex: fakeConfigure,
listIndexes: fakeListIndexes,
} as IndexOperationsApi;

jest.mock('../../pinecone-generated-ts-fetch', () => ({
IndexOperationsApi: IOA,
}));

const toThrow = async () => {
await configureIndex(IOA)('index-name', { replicas: 10 });
};

await expect(toThrow).rejects.toThrow(PineconeNotFoundError);
await expect(toThrow).rejects.toThrow(
"Index 'index-name' does not exist. Valid index names: ['foo', 'bar']"
);
});
});
});
71 changes: 1 addition & 70 deletions src/control/__tests__/createCollection.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { createCollection } from '../createCollection';
import {
PineconeArgumentError,
PineconeBadRequestError,
PineconeInternalServerError,
PineconeNotFoundError,
} from '../../errors';
import { PineconeArgumentError } from '../../errors';
import { IndexOperationsApi } from '../../pinecone-generated-ts-fetch';
import type { CreateCollectionOperationRequest as CCOR } from '../../pinecone-generated-ts-fetch';

Expand Down Expand Up @@ -149,68 +144,4 @@ describe('createCollection', () => {
},
});
});

describe('http error mapping', () => {
test('when 500 occurs', async () => {
const IOA = setOpenAPIResponse(() =>
Promise.reject({
response: {
status: 500,
text: () => 'backend error message',
},
})
);

const toThrow = async () => {
await createCollection(IOA)({
name: 'collection-name',
source: 'index-name',
});
};

await expect(toThrow).rejects.toThrow(PineconeInternalServerError);
});

test('when 400 occurs, displays server message', async () => {
const IOA = setOpenAPIResponse(() =>
Promise.reject({
response: {
status: 400,
text: () => 'backend error message',
},
})
);
const toThrow = async () => {
await createCollection(IOA)({
name: 'collection-name',
source: 'index-name',
});
};

await expect(toThrow).rejects.toThrow(PineconeBadRequestError);
await expect(toThrow).rejects.toThrow('backend error message');
});

test('when 404 occurs, show available indexes', async () => {
const IOA = setOpenAPIResponse(() =>
Promise.reject({
response: {
status: 404,
text: () => 'not found',
},
})
);
const toThrow = async () => {
await createCollection(IOA)({
name: 'collection-name',
source: 'index-name',
});
};

await expect(toThrow).rejects.toThrow(PineconeNotFoundError);
await expect(toThrow).rejects.toThrow(
"Index 'index-name' does not exist. Valid index names: ['foo', 'bar']"
);
});
});
});
56 changes: 1 addition & 55 deletions src/control/__tests__/createIndex.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import { createIndex } from '../createIndex';
import {
PineconeBadRequestError,
PineconeConflictError,
PineconeInternalServerError,
} from '../../errors';
import { IndexOperationsApi } from '../../pinecone-generated-ts-fetch';
import type {
CreateIndexRequest,
Expand All @@ -23,7 +18,7 @@ const setupCreateIndexResponse = (
.mockImplementation(() =>
isCreateIndexSuccess
? Promise.resolve(createIndexResponse)
: Promise.reject({ response: createIndexResponse })
: Promise.reject(createIndexResponse)
);

// unfold describeIndexResponse
Expand Down Expand Up @@ -134,53 +129,4 @@ describe('createIndex', () => {
});
});
});

describe('http error mapping', () => {
test('when 500 occurs', async () => {
const IOA = setupCreateIndexResponse(
{ status: 500, text: () => 'backend error message' },
undefined,
false
);

const toThrow = async () => {
const createIndexFn = createIndex(IOA);
await createIndexFn({ name: 'index-name', dimension: 10 });
};

await expect(toThrow).rejects.toThrow(PineconeInternalServerError);
});

test('when 400 occurs, displays server message', async () => {
const serverError = 'there has been a server error!';
const IOA = setupCreateIndexResponse(
{ status: 400, text: () => serverError },
undefined,
false
);

const toThrow = async () => {
const createIndexFn = createIndex(IOA);
await createIndexFn({ name: 'index-name', dimension: 10 });
};

await expect(toThrow).rejects.toThrow(PineconeBadRequestError);
await expect(toThrow).rejects.toThrow(serverError);
});

test('when 409 occurs', async () => {
const IOA = setupCreateIndexResponse(
{ status: 409, text: () => 'conflict error message' },
undefined,
false
);

const toThrow = async () => {
const createIndexFn = createIndex(IOA);
await createIndexFn({ name: 'index-name', dimension: 10 });
};

await expect(toThrow).rejects.toThrow(PineconeConflictError);
});
});
});
73 changes: 1 addition & 72 deletions src/control/__tests__/deleteCollection.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { deleteCollection } from '../deleteCollection';
import {
PineconeArgumentError,
PineconeInternalServerError,
PineconeNotFoundError,
} from '../../errors';
import { PineconeArgumentError } from '../../errors';
import { IndexOperationsApi } from '../../pinecone-generated-ts-fetch';
import type { DeleteCollectionRequest as DCR } from '../../pinecone-generated-ts-fetch';

Expand Down Expand Up @@ -59,71 +55,4 @@ describe('deleteCollection', () => {
);
});
});

describe('uses http error mapper', () => {
test('it should map errors with the http error mapper (500)', async () => {
const IOA = setupMocks(() =>
Promise.reject({ response: { status: 500, text: async () => '' } })
);

// @ts-ignore
const expectToThrow = async () =>
await deleteCollection(IOA)('collection-name');

expect(expectToThrow).rejects.toThrowError(PineconeInternalServerError);
});
});

describe('custom error mapping', () => {
test('not found (404), fetches and shows available collection names', async () => {
const IOA = setupMocks(
() =>
Promise.reject({ response: { status: 404, text: async () => '' } }),
() => Promise.resolve(['foo', 'bar'])
);

// @ts-ignore
const expectToThrow = async () =>
await deleteCollection(IOA)('collection-name');

expect(expectToThrow).rejects.toThrowError(PineconeNotFoundError);
expect(expectToThrow).rejects.toThrowError(
`Collection 'collection-name' does not exist. Valid collection names: ['foo', 'bar']`
);
});

test('not found (404), fetches and shows available collection names (empty list)', async () => {
const IOA = setupMocks(
() =>
Promise.reject({ response: { status: 404, text: async () => '' } }),
() => Promise.resolve([])
);

// @ts-ignore
const expectToThrow = async () =>
await deleteCollection(IOA)('collection-name');

expect(expectToThrow).rejects.toThrowError(PineconeNotFoundError);
expect(expectToThrow).rejects.toThrowError(
`Collection 'collection-name' does not exist. Valid collection names: []`
);
});

test('not found (404), error while fetching collection list', async () => {
const IOA = setupMocks(
() =>
Promise.reject({ response: { status: 404, text: async () => '' } }),
() => Promise.reject('error')
);

// @ts-ignore
const expectToThrow = async () =>
await deleteCollection(IOA)('collection-name');

expect(expectToThrow).rejects.toThrowError(PineconeNotFoundError);
expect(expectToThrow).rejects.toThrowError(
`Collection 'collection-name' does not exist.`
);
});
});
});
Loading

0 comments on commit 808366c

Please sign in to comment.