Initial import of zappier-edge from zapier monorepo
This commit is contained in:
commit
2e035b1e80
128 changed files with 20545 additions and 0 deletions
86
tests/meter.test.ts
Normal file
86
tests/meter.test.ts
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import express from 'express';
|
||||
import request from 'supertest';
|
||||
import { apiKeyAuth, Customer, InMemoryCustomerRepo } from '../src/auth';
|
||||
import { meter } from '../src/meter';
|
||||
import { DEFAULT_PRICING } from '../src/pricing';
|
||||
import { InMemoryUsageRepo } from '../src/usage';
|
||||
|
||||
const FREE_ADA: Customer = { id: 'cust_1', name: 'Ada', tierId: 'free', apiKey: 'key-ada' };
|
||||
|
||||
function buildApp(seed: Customer[] = [FREE_ADA]) {
|
||||
const customers = new InMemoryCustomerRepo(seed);
|
||||
const usage = new InMemoryUsageRepo();
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use(apiKeyAuth(customers));
|
||||
app.post('/transform', meter('transform', usage, DEFAULT_PRICING), (req, res) =>
|
||||
res.json({ quote: res.locals.quote }),
|
||||
);
|
||||
app.post('/storage', meter('storage', usage, DEFAULT_PRICING), (req, res) =>
|
||||
res.json({ quote: res.locals.quote }),
|
||||
);
|
||||
app.post('/experimental', meter('experimental', usage, DEFAULT_PRICING), (req, res) =>
|
||||
res.json({ quote: res.locals.quote }),
|
||||
);
|
||||
return { app, usage };
|
||||
}
|
||||
|
||||
describe('meter middleware', () => {
|
||||
it('quotes a fixed endpoint at the multiplied tier price and records usage', async () => {
|
||||
const { app, usage } = buildApp();
|
||||
const res = await request(app)
|
||||
.post('/transform')
|
||||
.set('x-api-key', 'key-ada')
|
||||
.send({ text: 'hi' });
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.quote.totalCents).toBe(4); // free tier, multiplier 1
|
||||
const entries = usage.listFor('cust_1');
|
||||
expect(entries).toHaveLength(1);
|
||||
expect(entries[0].endpointId).toBe('transform');
|
||||
expect(entries[0].cents).toBe(4);
|
||||
});
|
||||
|
||||
it('charges per KB of metadata on variable endpoints', async () => {
|
||||
const { app } = buildApp();
|
||||
const res = await request(app)
|
||||
.post('/storage')
|
||||
.set('x-api-key', 'key-ada')
|
||||
.send({ metadata: { note: 'x'.repeat(2048) } });
|
||||
// JSON of metadata is 2059 bytes -> 3 KB -> list 10 + 3 * 1 = 13
|
||||
expect(res.body.quote.totalCents).toBe(13);
|
||||
});
|
||||
|
||||
it('applies a per-customer multiplier override', async () => {
|
||||
const { app } = buildApp([
|
||||
{ id: 'cust_vip', name: 'Vip', tierId: 'free', apiKey: 'key-vip', multiplierOverride: 0.5 },
|
||||
]);
|
||||
const res = await request(app)
|
||||
.post('/transform')
|
||||
.set('x-api-key', 'key-vip')
|
||||
.send({ text: 'hi' });
|
||||
expect(res.body.quote.totalCents).toBe(2); // list 4 x override 0.5
|
||||
});
|
||||
|
||||
it('returns 401 when no customer is attached', async () => {
|
||||
const usage = new InMemoryUsageRepo();
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.post('/transform', meter('transform', usage, DEFAULT_PRICING), (req, res) =>
|
||||
res.json({}),
|
||||
);
|
||||
const res = await request(app).post('/transform').send({ text: 'hi' });
|
||||
expect(res.status).toBe(401);
|
||||
expect(usage.listFor('cust_1')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('returns 403 for an endpoint with no price rule on the caller tier', async () => {
|
||||
const { app, usage } = buildApp();
|
||||
const res = await request(app)
|
||||
.post('/experimental')
|
||||
.set('x-api-key', 'key-ada')
|
||||
.send({});
|
||||
expect(res.status).toBe(403);
|
||||
expect(res.body.error).toMatch(/No price rule/);
|
||||
expect(usage.listFor('cust_1')).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue