Skip to content

Commit

Permalink
Merge pull request #13 from seamapi/test-retry
Browse files Browse the repository at this point in the history
  • Loading branch information
razor-x authored Oct 6, 2023
2 parents b7f0e80 + bae8de6 commit 10cb4b3
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 7 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
"axios-retry": "^3.8.0"
},
"devDependencies": {
"@seamapi/fake-seam-connect": "^1.21.0",
"@seamapi/fake-seam-connect": "^1.22.0",
"@seamapi/types": "^1.24.0",
"@types/eslint": "^8.44.2",
"@types/node": "^18.11.18",
Expand Down
13 changes: 11 additions & 2 deletions test/fixtures/seam/connect/api.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { createFake, type Seed } from '@seamapi/fake-seam-connect'
import {
createFake,
type Database,
type Seed,
} from '@seamapi/fake-seam-connect'
import type { ExecutionContext } from 'ava'
import fetch from 'node-fetch' // TODO: Remove node-fetch when Node v16 support is dropped.

export const getTestServer = async (
t: ExecutionContext,
): Promise<{ endpoint: string; seed: Seed }> => {
): Promise<{
endpoint: string
seed: Seed
db: Database
}> => {
const fake = await createFake()
const seed = await fake.seed()

Expand All @@ -21,5 +29,6 @@ export const getTestServer = async (
return {
endpoint,
seed,
db: fake.database,
}
}
80 changes: 80 additions & 0 deletions test/seam/connect/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ import { getTestServer } from 'fixtures/seam/connect/api.js'

import { SeamHttp } from '@seamapi/http/connect'

import type {
DevicesGetResponse,
DevicesListBody,
DevicesListResponse,
} from 'lib/seam/connect/routes/devices.js'

test('SeamHttp: fromClient returns instance that uses client', async (t) => {
const { seed, endpoint } = await getTestServer(t)
const seam = SeamHttp.fromClient(
Expand All @@ -26,3 +32,77 @@ test('SeamHttp: constructor returns instance that uses client', async (t) => {
t.is(device.workspace_id, seed.seed_workspace_1)
t.is(device.device_id, seed.august_device_1)
})

test('SeamHttp: can use client to make requests', async (t) => {
const { seed, endpoint } = await getTestServer(t)
const seam = new SeamHttp({
client: SeamHttp.fromApiKey(seed.seam_apikey1_token, { endpoint }).client,
})
const {
data: { device },
status,
} = await seam.client.get<DevicesGetResponse>('/devices/get', {
params: { device_id: seed.august_device_1 },
})
t.is(status, 200)
t.is(device.workspace_id, seed.seed_workspace_1)
t.is(device.device_id, seed.august_device_1)
})

test('SeamHttp: client serializes array params', async (t) => {
const { seed, endpoint } = await getTestServer(t)
const seam = new SeamHttp({
client: SeamHttp.fromApiKey(seed.seam_apikey1_token, { endpoint }).client,
})
const params: DevicesListBody = {
device_ids: [seed.august_device_1],
}
const {
data: { devices },
status,
} = await seam.client.get<DevicesListResponse>('/devices/list', {
params,
})
t.is(status, 200)
t.is(devices.length, 1)
const [device] = devices
t.is(device?.workspace_id, seed.seed_workspace_1)
t.is(device?.device_id, seed.august_device_1)
})

test('SeamHttp: merges axiosOptions when creating client', async (t) => {
const { seed, endpoint } = await getTestServer(t)
const seam = SeamHttp.fromApiKey(seed.seam_apikey1_token, {
endpoint,
axiosOptions: {
transformResponse: [
(data) =>
JSON.parse(
data.replaceAll(seed.august_device_1, 'transformed-device-id'),
),
],
},
})
const device = await seam.devices.get({
device_id: seed.august_device_1,
})
t.is(device.workspace_id, seed.seed_workspace_1)
t.is(device.device_id, 'transformed-device-id')
})

test('SeamHttp: merges axios headers when creating client', async (t) => {
const { seed, endpoint } = await getTestServer(t)
const seam = SeamHttp.fromApiKey('seam_invalidapikey_token', {
endpoint,
axiosOptions: {
headers: {
Authorization: `Bearer ${seed.seam_apikey1_token}`,
},
},
})
const device = await seam.devices.get({
device_id: seed.august_device_1,
})
t.is(device.workspace_id, seed.seed_workspace_1)
t.is(device.device_id, seed.august_device_1)
})
41 changes: 41 additions & 0 deletions test/seam/connect/retry.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import test from 'ava'
import { AxiosError } from 'axios'
import { getTestServer } from 'fixtures/seam/connect/api.js'

import { SeamHttp } from '@seamapi/http/connect'

test('SeamHttp: retries 503 status errors twice by default ', async (t) => {
const { seed, endpoint, db } = await getTestServer(t)
const expectedRetryCount = 2

db.simulateWorkspaceOutage(seed.seed_workspace_1, {
routes: ['/devices/get'],
})

t.plan(expectedRetryCount + 2)

const seam = SeamHttp.fromApiKey(seed.seam_apikey1_token, {
endpoint,
axiosRetryOptions: {
onRetry: (retryCount) => {
t.true(retryCount <= expectedRetryCount)
},
},
})

const err = await t.throwsAsync(
async () =>
// UPSTREAM: This test should use seam.devices.get({ device_id: '...' }).
// Only idempotent methods, e.g., GET not POST, are retried by default.
// The SDK should use GET over POST once that method is supported upstream.
// https://github.com/seamapi/nextlove/issues/117
await seam.client.get('/devices/get', {
params: {
device_id: seed.august_device_1,
},
}),
{ instanceOf: AxiosError },
)

t.is(err?.response?.status, 503)
})

0 comments on commit 10cb4b3

Please sign in to comment.