@chainlink/external-adapter-framework 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter.js +60 -0
- package/dist/background-executor.js +45 -0
- package/dist/cache/factory.js +57 -0
- package/dist/cache/index.js +163 -0
- package/dist/cache/local.js +83 -0
- package/dist/cache/metrics.js +114 -0
- package/dist/cache/redis.js +100 -0
- package/dist/config/index.js +364 -0
- package/dist/config/provider-limits.js +75 -0
- package/dist/examples/coingecko/batch-warming.js +52 -0
- package/dist/examples/coingecko/index.js +10 -0
- package/dist/examples/coingecko/rest.js +50 -0
- package/dist/examples/ncfx/config/index.js +15 -0
- package/dist/examples/ncfx/index.js +10 -0
- package/dist/examples/ncfx/websocket.js +72 -0
- package/dist/index.js +89 -0
- package/dist/metrics/constants.js +25 -0
- package/dist/metrics/index.js +76 -0
- package/dist/metrics/util.js +9 -0
- package/dist/rate-limiting/factory.js +33 -0
- package/dist/rate-limiting/index.js +36 -0
- package/dist/rate-limiting/metrics.js +32 -0
- package/dist/rate-limiting/nop-limiter.js +15 -0
- package/dist/rate-limiting/simple-counting.js +61 -0
- package/dist/src/adapter.js +112 -0
- package/dist/src/background-executor.js +45 -0
- package/dist/src/cache/factory.js +57 -0
- package/dist/src/cache/index.js +165 -0
- package/dist/src/cache/local.js +83 -0
- package/dist/src/cache/metrics.js +114 -0
- package/dist/src/cache/redis.js +100 -0
- package/dist/src/config/index.js +366 -0
- package/dist/src/config/provider-limits.js +75 -0
- package/dist/src/examples/bank-frick/accounts.js +191 -0
- package/dist/src/examples/bank-frick/config/index.js +45 -0
- package/dist/src/examples/bank-frick/index.js +14 -0
- package/dist/src/examples/bank-frick/util.js +39 -0
- package/dist/src/examples/coingecko/batch-warming.js +52 -0
- package/dist/src/examples/coingecko/index.js +10 -0
- package/dist/src/examples/coingecko/rest.js +50 -0
- package/dist/src/examples/ncfx/config/index.js +15 -0
- package/dist/src/examples/ncfx/index.js +10 -0
- package/dist/src/examples/ncfx/websocket.js +72 -0
- package/dist/src/index.js +89 -0
- package/dist/src/metrics/constants.js +25 -0
- package/dist/src/metrics/index.js +76 -0
- package/dist/src/metrics/util.js +9 -0
- package/dist/src/rate-limiting/background/fixed-frequency.js +37 -0
- package/dist/src/rate-limiting/index.js +63 -0
- package/dist/src/rate-limiting/metrics.js +32 -0
- package/dist/src/rate-limiting/request/simple-counting.js +62 -0
- package/dist/src/test.js +6 -0
- package/dist/src/transports/batch-warming.js +55 -0
- package/dist/src/transports/index.js +85 -0
- package/dist/src/transports/metrics.js +119 -0
- package/dist/src/transports/rest.js +93 -0
- package/dist/src/transports/util.js +85 -0
- package/dist/src/transports/websocket.js +175 -0
- package/dist/src/util/expiring-sorted-set.js +47 -0
- package/dist/src/util/index.js +35 -0
- package/dist/src/util/logger.js +62 -0
- package/dist/src/util/request.js +2 -0
- package/dist/src/validation/error.js +41 -0
- package/dist/src/validation/index.js +84 -0
- package/dist/src/validation/input-params.js +30 -0
- package/dist/src/validation/override-functions.js +40 -0
- package/dist/src/validation/preset-tokens.json +23 -0
- package/dist/src/validation/validator.js +303 -0
- package/dist/test.js +6 -0
- package/dist/transports/batch-warming.js +57 -0
- package/dist/transports/index.js +76 -0
- package/dist/transports/metrics.js +133 -0
- package/dist/transports/rest.js +91 -0
- package/dist/transports/util.js +85 -0
- package/dist/transports/websocket.js +171 -0
- package/dist/util/expiring-sorted-set.js +47 -0
- package/dist/util/index.js +35 -0
- package/dist/util/logger.js +62 -0
- package/dist/util/request.js +2 -0
- package/dist/validation/error.js +41 -0
- package/dist/validation/index.js +82 -0
- package/dist/validation/input-params.js +30 -0
- package/dist/validation/overrideFunctions.js +42 -0
- package/dist/validation/presetTokens.json +23 -0
- package/dist/validation/validator.js +303 -0
- package/package.json +6 -2
- package/.c8rc.json +0 -3
- package/.eslintignore +0 -9
- package/.eslintrc.js +0 -96
- package/.github/README.MD +0 -17
- package/.github/actions/setup/action.yaml +0 -13
- package/.github/workflows/main.yaml +0 -39
- package/.github/workflows/publish.yaml +0 -17
- package/.prettierignore +0 -13
- package/.yarnrc +0 -0
- package/docker-compose.yaml +0 -35
- package/src/adapter.ts +0 -236
- package/src/background-executor.ts +0 -53
- package/src/cache/factory.ts +0 -28
- package/src/cache/index.ts +0 -236
- package/src/cache/local.ts +0 -73
- package/src/cache/metrics.ts +0 -112
- package/src/cache/redis.ts +0 -93
- package/src/config/index.ts +0 -501
- package/src/config/provider-limits.ts +0 -130
- package/src/examples/coingecko/batch-warming.ts +0 -79
- package/src/examples/coingecko/index.ts +0 -9
- package/src/examples/coingecko/rest.ts +0 -77
- package/src/examples/ncfx/config/index.ts +0 -12
- package/src/examples/ncfx/index.ts +0 -9
- package/src/examples/ncfx/websocket.ts +0 -100
- package/src/index.ts +0 -106
- package/src/metrics/constants.ts +0 -23
- package/src/metrics/index.ts +0 -116
- package/src/metrics/util.ts +0 -11
- package/src/rate-limiting/background/fixed-frequency.ts +0 -47
- package/src/rate-limiting/index.ts +0 -100
- package/src/rate-limiting/metrics.ts +0 -18
- package/src/rate-limiting/request/simple-counting.ts +0 -76
- package/src/test.ts +0 -5
- package/src/transports/batch-warming.ts +0 -121
- package/src/transports/index.ts +0 -173
- package/src/transports/metrics.ts +0 -95
- package/src/transports/rest.ts +0 -161
- package/src/transports/util.ts +0 -63
- package/src/transports/websocket.ts +0 -238
- package/src/util/expiring-sorted-set.ts +0 -52
- package/src/util/index.ts +0 -20
- package/src/util/logger.ts +0 -69
- package/src/util/request.ts +0 -115
- package/src/validation/error.ts +0 -116
- package/src/validation/index.ts +0 -101
- package/src/validation/input-params.ts +0 -45
- package/src/validation/override-functions.ts +0 -44
- package/src/validation/preset-tokens.json +0 -23
- package/src/validation/validator.ts +0 -384
- package/test/adapter.test.ts +0 -27
- package/test/background-executor.test.ts +0 -109
- package/test/cache/cache-key.test.ts +0 -96
- package/test/cache/helper.ts +0 -101
- package/test/cache/local.test.ts +0 -54
- package/test/cache/redis.test.ts +0 -89
- package/test/correlation.test.ts +0 -114
- package/test/index.test.ts +0 -37
- package/test/metrics/feed-id.test.ts +0 -33
- package/test/metrics/helper.ts +0 -14
- package/test/metrics/labels.test.ts +0 -36
- package/test/metrics/metrics.test.ts +0 -267
- package/test/metrics/redis-metrics.test.ts +0 -113
- package/test/metrics/warmer-metrics.test.ts +0 -192
- package/test/metrics/ws-metrics.test.ts +0 -225
- package/test/rate-limit-config.test.ts +0 -243
- package/test/transports/batch.test.ts +0 -465
- package/test/transports/rest.test.ts +0 -242
- package/test/transports/websocket.test.ts +0 -183
- package/test/tsconfig.json +0 -5
- package/test/util.ts +0 -76
- package/test/validation.test.ts +0 -169
- package/test.sh +0 -20
- package/tsconfig.json +0 -24
- package/typedoc.json +0 -6
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
import FakeTimers from '@sinonjs/fake-timers'
|
|
2
|
-
import untypedTest, { TestFn } from 'ava'
|
|
3
|
-
import axios, { AxiosError } from 'axios'
|
|
4
|
-
import { Server, WebSocket } from 'mock-socket'
|
|
5
|
-
import { AddressInfo } from 'net'
|
|
6
|
-
import { expose } from '../../src'
|
|
7
|
-
import { Adapter, AdapterEndpoint } from '../../src/adapter'
|
|
8
|
-
import { DEFAULT_SHARED_MS_BETWEEN_REQUESTS } from '../../src/rate-limiting'
|
|
9
|
-
import { DEFAULT_WS_TTL, WebSocketClassProvider, WebSocketTransport } from '../../src/transports'
|
|
10
|
-
import { ProviderResult } from '../../src/util'
|
|
11
|
-
import { InputParameters } from '../../src/validation'
|
|
12
|
-
import { MockCache } from '../util'
|
|
13
|
-
import { parsePromMetrics } from './helper'
|
|
14
|
-
|
|
15
|
-
export const test = untypedTest as TestFn<{
|
|
16
|
-
serverAddress: string
|
|
17
|
-
cache: MockCache
|
|
18
|
-
adapterEndpoint: AdapterEndpoint
|
|
19
|
-
server: Server
|
|
20
|
-
}>
|
|
21
|
-
|
|
22
|
-
interface AdapterRequestParams {
|
|
23
|
-
base: string
|
|
24
|
-
quote: string
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const inputParameters: InputParameters = {
|
|
28
|
-
base: {
|
|
29
|
-
type: 'string',
|
|
30
|
-
required: true,
|
|
31
|
-
},
|
|
32
|
-
quote: {
|
|
33
|
-
type: 'string',
|
|
34
|
-
required: true,
|
|
35
|
-
},
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
interface ProviderMessage {
|
|
39
|
-
pair: string
|
|
40
|
-
value: number
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const URL = 'wss://test-ws.com/asd'
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Sets the mocked websocket instance in the provided provider class.
|
|
47
|
-
* We need this here, because the tests will connect using their instance of WebSocketClassProvider;
|
|
48
|
-
* fetching from this library to the \@chainlink/ea-bootstrap package would access _another_ instance
|
|
49
|
-
* of the same constructor. Although it should be a singleton, dependencies are different so that
|
|
50
|
-
* means that the static classes themselves are also different.
|
|
51
|
-
*
|
|
52
|
-
* @param provider - singleton WebSocketClassProvider
|
|
53
|
-
*/
|
|
54
|
-
export const mockWebSocketProvider = (provider: typeof WebSocketClassProvider): void => {
|
|
55
|
-
// Extend mock WebSocket class to bypass protocol headers error
|
|
56
|
-
class MockWebSocket extends WebSocket {
|
|
57
|
-
constructor(url: string, protocol: string | string[] | Record<string, string> | undefined) {
|
|
58
|
-
super(url, protocol instanceof Object ? undefined : protocol)
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Need to disable typing, the mock-socket impl does not implement the ws interface fully
|
|
63
|
-
provider.set(MockWebSocket as any) // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export const websocketTransport = new WebSocketTransport({
|
|
67
|
-
url: URL,
|
|
68
|
-
handlers: {
|
|
69
|
-
async open() {
|
|
70
|
-
return
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
message(message: ProviderMessage): ProviderResult<AdapterRequestParams>[] {
|
|
74
|
-
const [base, quote] = message.pair.split('/')
|
|
75
|
-
return [
|
|
76
|
-
{
|
|
77
|
-
params: { base, quote },
|
|
78
|
-
value: message.value,
|
|
79
|
-
},
|
|
80
|
-
]
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
builders: {
|
|
84
|
-
subscribeMessage: (params: AdapterRequestParams) => ({
|
|
85
|
-
request: 'subscribe',
|
|
86
|
-
pair: `${params.base}/${params.quote}`,
|
|
87
|
-
}),
|
|
88
|
-
unsubscribeMessage: (params: AdapterRequestParams) => ({
|
|
89
|
-
request: 'unsubscribe',
|
|
90
|
-
pair: `${params.base}/${params.quote}`,
|
|
91
|
-
}),
|
|
92
|
-
},
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
const base = 'ETH'
|
|
96
|
-
const quote = 'USD'
|
|
97
|
-
const price = 1234
|
|
98
|
-
|
|
99
|
-
export const webSocketEndpoint: AdapterEndpoint = {
|
|
100
|
-
name: 'test',
|
|
101
|
-
transport: websocketTransport,
|
|
102
|
-
inputParameters,
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const CACHE_MAX_AGE = 1000
|
|
106
|
-
|
|
107
|
-
const adapter: Adapter = {
|
|
108
|
-
name: 'test',
|
|
109
|
-
defaultEndpoint: 'test',
|
|
110
|
-
endpoints: [webSocketEndpoint],
|
|
111
|
-
envDefaultOverrides: {
|
|
112
|
-
CACHE_MAX_AGE,
|
|
113
|
-
},
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const clock = FakeTimers.install()
|
|
117
|
-
|
|
118
|
-
test.before(async (t) => {
|
|
119
|
-
process.env['METRICS_ENABLED'] = 'true'
|
|
120
|
-
process.env['METRICS_PORT'] = '9093'
|
|
121
|
-
// Disable retries to make the testing flow easier
|
|
122
|
-
process.env['CACHE_POLLING_MAX_RETRIES'] = '0'
|
|
123
|
-
|
|
124
|
-
// Mock WS
|
|
125
|
-
mockWebSocketProvider(WebSocketClassProvider)
|
|
126
|
-
const mockWsServer = new Server(URL, { mock: false })
|
|
127
|
-
mockWsServer.on('connection', (socket) => {
|
|
128
|
-
let counter = 0
|
|
129
|
-
const parseMessage = () => {
|
|
130
|
-
if (counter++ === 0) {
|
|
131
|
-
socket.send(
|
|
132
|
-
JSON.stringify({
|
|
133
|
-
pair: `${base}/${quote}`,
|
|
134
|
-
value: price,
|
|
135
|
-
}),
|
|
136
|
-
)
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
socket.on('message', parseMessage)
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
// Create mocked cache so we can listen when values are set
|
|
143
|
-
// This is a more reliable method than expecting precise clock timings
|
|
144
|
-
const mockCache = new MockCache()
|
|
145
|
-
|
|
146
|
-
// Start up adapter
|
|
147
|
-
const server = await expose(adapter, {
|
|
148
|
-
cache: mockCache,
|
|
149
|
-
})
|
|
150
|
-
t.context.serverAddress = `http://localhost:${(server?.address() as AddressInfo)?.port}`
|
|
151
|
-
t.context.cache = mockCache
|
|
152
|
-
t.context.server = mockWsServer
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
test.after(async () => {
|
|
156
|
-
clock.uninstall()
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
test.serial('Test WS connection, subscription, and message metrics', async (t) => {
|
|
160
|
-
const makeRequest = () =>
|
|
161
|
-
axios.post(t.context.serverAddress, {
|
|
162
|
-
data: {
|
|
163
|
-
base,
|
|
164
|
-
quote,
|
|
165
|
-
},
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
// Expect the first response to time out
|
|
169
|
-
// The polling behavior is tested in the cache tests, so this is easier here.
|
|
170
|
-
// Start the request:
|
|
171
|
-
const errorPromise: Promise<AxiosError | undefined> = t.throwsAsync(makeRequest)
|
|
172
|
-
// Advance enough time for the initial request async flow
|
|
173
|
-
clock.tickAsync(10)
|
|
174
|
-
// Wait for the failed cache get -> instant 504
|
|
175
|
-
const error = await errorPromise
|
|
176
|
-
t.is(error?.response?.status, 504)
|
|
177
|
-
|
|
178
|
-
// Advance clock so that the batch warmer executes once again and wait for the cache to be set
|
|
179
|
-
const cacheValueSetPromise = t.context.cache.waitForNextSet()
|
|
180
|
-
await clock.tickAsync(DEFAULT_SHARED_MS_BETWEEN_REQUESTS + 10)
|
|
181
|
-
await cacheValueSetPromise
|
|
182
|
-
|
|
183
|
-
// Second request should find the response in the cache
|
|
184
|
-
let response = await makeRequest()
|
|
185
|
-
|
|
186
|
-
t.is(response.status, 200)
|
|
187
|
-
|
|
188
|
-
// Check connection, subscription active, subscription total, and message total metrics when subscribed to feed
|
|
189
|
-
const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
|
|
190
|
-
response = await axios.get(metricsAddress)
|
|
191
|
-
let metricsMap = parsePromMetrics(response.data)
|
|
192
|
-
let expectedLabel = '{app_name="test",app_version="undefined"}'
|
|
193
|
-
t.is(metricsMap.get(`ws_connection_active${expectedLabel}`), 1)
|
|
194
|
-
expectedLabel =
|
|
195
|
-
'{feed_id="|base:eth|quote:usd",subscription_key="test-|base:eth|quote:usd",app_name="test",app_version="undefined"}'
|
|
196
|
-
t.is(metricsMap.get(`ws_subscription_active${expectedLabel}`), 1)
|
|
197
|
-
t.is(metricsMap.get(`ws_subscription_total${expectedLabel}`), 1)
|
|
198
|
-
t.is(metricsMap.get(`ws_message_total${expectedLabel}`), 1)
|
|
199
|
-
|
|
200
|
-
// Wait until the cache expires, and the subscription is out
|
|
201
|
-
await clock.tickAsync(Math.ceil(CACHE_MAX_AGE / DEFAULT_WS_TTL) * DEFAULT_WS_TTL + 1)
|
|
202
|
-
|
|
203
|
-
// Now that the cache is out and the subscription no longer there, this should time out
|
|
204
|
-
const error2: AxiosError | undefined = await t.throwsAsync(makeRequest)
|
|
205
|
-
t.is(error2?.response?.status, 504)
|
|
206
|
-
|
|
207
|
-
// Check connection, subscription active, subscription total, and message total metrics when unsubscribed from feed
|
|
208
|
-
response = await axios.get(metricsAddress)
|
|
209
|
-
metricsMap = parsePromMetrics(response.data)
|
|
210
|
-
expectedLabel = '{app_name="test",app_version="undefined"}'
|
|
211
|
-
t.is(metricsMap.get(`ws_connection_active${expectedLabel}`), 1)
|
|
212
|
-
expectedLabel =
|
|
213
|
-
'{feed_id="|base:eth|quote:usd",subscription_key="test-|base:eth|quote:usd",app_name="test",app_version="undefined"}'
|
|
214
|
-
t.is(metricsMap.get(`ws_subscription_active${expectedLabel}`), 0)
|
|
215
|
-
t.is(metricsMap.get(`ws_subscription_total${expectedLabel}`), 1)
|
|
216
|
-
t.is(metricsMap.get(`ws_message_total${expectedLabel}`), 2)
|
|
217
|
-
|
|
218
|
-
t.context.server.close()
|
|
219
|
-
|
|
220
|
-
// Check connection metric after connection closed
|
|
221
|
-
response = await axios.get(metricsAddress)
|
|
222
|
-
metricsMap = parsePromMetrics(response.data)
|
|
223
|
-
expectedLabel = '{app_name="test",app_version="undefined"}'
|
|
224
|
-
t.is(metricsMap.get(`ws_connection_active${expectedLabel}`), 0)
|
|
225
|
-
})
|
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
import test from 'ava'
|
|
2
|
-
import { expose } from '../src'
|
|
3
|
-
import { Adapter } from '../src/adapter'
|
|
4
|
-
import { SimpleCountingRateLimiter } from '../src/rate-limiting'
|
|
5
|
-
import { AdapterDependencies } from '../src/transports'
|
|
6
|
-
import { NopTransport } from './util'
|
|
7
|
-
|
|
8
|
-
test('empty tiers in rate limiting fails on startup', async (t) => {
|
|
9
|
-
const adapter: Adapter = {
|
|
10
|
-
name: 'test',
|
|
11
|
-
endpoints: [
|
|
12
|
-
{
|
|
13
|
-
name: 'test',
|
|
14
|
-
inputParameters: {},
|
|
15
|
-
transport: new NopTransport(),
|
|
16
|
-
},
|
|
17
|
-
],
|
|
18
|
-
rateLimiting: {
|
|
19
|
-
tiers: {},
|
|
20
|
-
},
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
await t.throwsAsync(async () => expose(adapter), {
|
|
24
|
-
message: 'The tiers object is defined, but has no entries',
|
|
25
|
-
})
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test('selected tier is not a valid option', async (t) => {
|
|
29
|
-
const adapter: Adapter = {
|
|
30
|
-
name: 'test',
|
|
31
|
-
endpoints: [
|
|
32
|
-
{
|
|
33
|
-
name: 'test',
|
|
34
|
-
inputParameters: {},
|
|
35
|
-
transport: new NopTransport(),
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
rateLimiting: {
|
|
39
|
-
tiers: {
|
|
40
|
-
free: {
|
|
41
|
-
rateLimit1s: 123,
|
|
42
|
-
},
|
|
43
|
-
pro: {
|
|
44
|
-
rateLimit1s: 1234,
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
envDefaultOverrides: {
|
|
49
|
-
RATE_LIMIT_API_TIER: 'asdasdasd',
|
|
50
|
-
},
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
await t.throwsAsync(async () => expose(adapter), {
|
|
54
|
-
message: 'The selected rate limit tier "asdasdasd" is not valid (can be one of "free", "pro")',
|
|
55
|
-
})
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('throws error if explicit allocation leaves no room for implicitly allocated endpoints', async (t) => {
|
|
59
|
-
const adapter: Adapter = {
|
|
60
|
-
name: 'test',
|
|
61
|
-
endpoints: [
|
|
62
|
-
{
|
|
63
|
-
name: 'test',
|
|
64
|
-
inputParameters: {},
|
|
65
|
-
transport: new NopTransport(),
|
|
66
|
-
rateLimiting: {
|
|
67
|
-
allocationPercentage: 100,
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
name: 'test2',
|
|
72
|
-
inputParameters: {},
|
|
73
|
-
transport: new NopTransport(),
|
|
74
|
-
},
|
|
75
|
-
],
|
|
76
|
-
rateLimiting: {
|
|
77
|
-
tiers: {
|
|
78
|
-
free: {
|
|
79
|
-
rateLimit1s: 123,
|
|
80
|
-
},
|
|
81
|
-
pro: {
|
|
82
|
-
rateLimit1s: 1234,
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
envDefaultOverrides: {
|
|
87
|
-
RATE_LIMIT_API_TIER: 'asdasdasd',
|
|
88
|
-
},
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
await t.throwsAsync(async () => expose(adapter), {
|
|
92
|
-
message: 'The explicit allocation is at 100% but there are endpoints with implicit allocation',
|
|
93
|
-
})
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
test('throws error if explicit allocation exceeds 100%', async (t) => {
|
|
97
|
-
const adapter: Adapter = {
|
|
98
|
-
name: 'test',
|
|
99
|
-
endpoints: [
|
|
100
|
-
{
|
|
101
|
-
name: 'test',
|
|
102
|
-
inputParameters: {},
|
|
103
|
-
transport: new NopTransport(),
|
|
104
|
-
rateLimiting: {
|
|
105
|
-
allocationPercentage: 80,
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
name: 'test2',
|
|
110
|
-
inputParameters: {},
|
|
111
|
-
transport: new NopTransport(),
|
|
112
|
-
rateLimiting: {
|
|
113
|
-
allocationPercentage: 30,
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
],
|
|
117
|
-
rateLimiting: {
|
|
118
|
-
tiers: {
|
|
119
|
-
free: {
|
|
120
|
-
rateLimit1s: 123,
|
|
121
|
-
},
|
|
122
|
-
pro: {
|
|
123
|
-
rateLimit1s: 1234,
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
envDefaultOverrides: {
|
|
128
|
-
RATE_LIMIT_API_TIER: 'asdasdasd',
|
|
129
|
-
},
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
await t.throwsAsync(async () => expose(adapter), {
|
|
133
|
-
message: 'The total allocation set for all endpoints summed cannot exceed 100%',
|
|
134
|
-
})
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
test('uses most restrictive tier if none is specified in settings', async (t) => {
|
|
138
|
-
const adapter: Adapter = {
|
|
139
|
-
name: 'test',
|
|
140
|
-
endpoints: [
|
|
141
|
-
{
|
|
142
|
-
name: 'test',
|
|
143
|
-
inputParameters: {},
|
|
144
|
-
transport: new (class extends NopTransport {
|
|
145
|
-
override async initialize(dependencies: AdapterDependencies): Promise<void> {
|
|
146
|
-
t.true(dependencies.requestRateLimiter instanceof SimpleCountingRateLimiter)
|
|
147
|
-
t.is(
|
|
148
|
-
(dependencies.requestRateLimiter as unknown as Record<string, number>)[
|
|
149
|
-
'perSecondLimit'
|
|
150
|
-
],
|
|
151
|
-
123,
|
|
152
|
-
)
|
|
153
|
-
}
|
|
154
|
-
})(),
|
|
155
|
-
},
|
|
156
|
-
],
|
|
157
|
-
rateLimiting: {
|
|
158
|
-
tiers: {
|
|
159
|
-
asd: {
|
|
160
|
-
rateLimit1s: 5234,
|
|
161
|
-
rateLimit1m: 3000 * 60,
|
|
162
|
-
},
|
|
163
|
-
free: {
|
|
164
|
-
rateLimit1s: 123,
|
|
165
|
-
rateLimit1h: 1000 * 60,
|
|
166
|
-
},
|
|
167
|
-
pro: {
|
|
168
|
-
rateLimit1m: 1234 * 60,
|
|
169
|
-
},
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
await expose(adapter)
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
test('uses unlimited tier if none is specified in settings', async (t) => {
|
|
178
|
-
const adapter: Adapter = {
|
|
179
|
-
name: 'test',
|
|
180
|
-
endpoints: [
|
|
181
|
-
{
|
|
182
|
-
name: 'test',
|
|
183
|
-
inputParameters: {},
|
|
184
|
-
transport: new (class extends NopTransport {
|
|
185
|
-
override async initialize(dependencies: AdapterDependencies): Promise<void> {
|
|
186
|
-
t.true(dependencies.requestRateLimiter instanceof SimpleCountingRateLimiter)
|
|
187
|
-
t.is(
|
|
188
|
-
(dependencies.requestRateLimiter as unknown as Record<string, number>)[
|
|
189
|
-
'perSecondLimit'
|
|
190
|
-
],
|
|
191
|
-
Infinity,
|
|
192
|
-
)
|
|
193
|
-
}
|
|
194
|
-
})(),
|
|
195
|
-
},
|
|
196
|
-
],
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
await expose(adapter)
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
test('uses specified tier if present in settings', async (t) => {
|
|
203
|
-
const adapter: Adapter = {
|
|
204
|
-
name: 'test',
|
|
205
|
-
endpoints: [
|
|
206
|
-
{
|
|
207
|
-
name: 'test',
|
|
208
|
-
inputParameters: {},
|
|
209
|
-
transport: new (class extends NopTransport {
|
|
210
|
-
override async initialize(dependencies: AdapterDependencies): Promise<void> {
|
|
211
|
-
t.true(dependencies.requestRateLimiter instanceof SimpleCountingRateLimiter)
|
|
212
|
-
t.is(
|
|
213
|
-
(dependencies.requestRateLimiter as unknown as Record<string, number>)[
|
|
214
|
-
'perSecondLimit'
|
|
215
|
-
],
|
|
216
|
-
1234,
|
|
217
|
-
)
|
|
218
|
-
}
|
|
219
|
-
})(),
|
|
220
|
-
},
|
|
221
|
-
],
|
|
222
|
-
rateLimiting: {
|
|
223
|
-
tiers: {
|
|
224
|
-
asd: {
|
|
225
|
-
rateLimit1s: 5234,
|
|
226
|
-
rateLimit1m: 3000 * 60,
|
|
227
|
-
},
|
|
228
|
-
free: {
|
|
229
|
-
rateLimit1s: 123,
|
|
230
|
-
rateLimit1h: 1000 * 60,
|
|
231
|
-
},
|
|
232
|
-
pro: {
|
|
233
|
-
rateLimit1s: 1234,
|
|
234
|
-
},
|
|
235
|
-
},
|
|
236
|
-
},
|
|
237
|
-
envDefaultOverrides: {
|
|
238
|
-
RATE_LIMIT_API_TIER: 'pro',
|
|
239
|
-
},
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
await expose(adapter)
|
|
243
|
-
})
|