From b9fd885bf04ffa1546808747d5859e890c99efa7 Mon Sep 17 00:00:00 2001 From: Ali Behjati Date: Mon, 23 Jan 2023 09:56:31 +0000 Subject: [PATCH 1/8] Update/improve existing tests --- price-service/src/__tests__/rest.test.ts | 76 +++++++++++++++++++++++- price-service/src/__tests__/ws.test.ts | 59 +++++++++--------- 2 files changed, 100 insertions(+), 35 deletions(-) diff --git a/price-service/src/__tests__/rest.test.ts b/price-service/src/__tests__/rest.test.ts index b1ed473711..9272fce442 100644 --- a/price-service/src/__tests__/rest.test.ts +++ b/price-service/src/__tests__/rest.test.ts @@ -1,4 +1,9 @@ -import { HexString, Price, PriceFeed } from "@pythnetwork/pyth-sdk-js"; +import { + HexString, + Price, + PriceFeed, + PriceFeedMetadata, +} from "@pythnetwork/pyth-sdk-js"; import { Express } from "express"; import { StatusCodes } from "http-status-codes"; import request from "supertest"; @@ -40,8 +45,8 @@ function dummyPriceInfoPair( id, { priceFeed: dummyPriceFeed(id), - publishTime: 0, - attestationTime: 0, + publishTime: 1, + attestationTime: 2, seqNum, vaa: Buffer.from(vaa, "hex"), emitterChainId: 0, @@ -92,6 +97,48 @@ describe("Latest Price Feed Endpoint", () => { expect(resp.body).toContainEqual(dummyPriceFeed(ids[1]).toJson()); }); + test("When called with valid ids with leading 0x, returns correct price feed", async () => { + const ids = [expandTo64Len("abcd"), expandTo64Len("3456")]; + const resp = await request(app) + .get("/api/latest_price_feeds") + .query({ + ids: ids.map((id) => "0x" + id), // Add 0x to the queries + }); + expect(resp.status).toBe(StatusCodes.OK); + expect(resp.body.length).toBe(2); + + // Please note that the response id is without 0x + expect(resp.body).toContainEqual(dummyPriceFeed(ids[0]).toJson()); + expect(resp.body).toContainEqual(dummyPriceFeed(ids[1]).toJson()); + }); + + test("When called with valid ids and verbose flag set to true, returns correct price feed with verbose information", async () => { + const ids = [expandTo64Len("abcd"), expandTo64Len("3456")]; + const resp = await request(app) + .get("/api/latest_price_feeds") + .query({ ids, verbose: true }); + expect(resp.status).toBe(StatusCodes.OK); + expect(resp.body.length).toBe(2); + expect(resp.body).toContainEqual({ + ...priceInfoMap.get(ids[0])!.priceFeed.toJson(), + metadata: new PriceFeedMetadata({ + attestationTime: priceInfoMap.get(ids[0])!.attestationTime, + emitterChain: priceInfoMap.get(ids[0])!.emitterChainId, + receiveTime: priceInfoMap.get(ids[0])!.priceServiceReceiveTime, + sequenceNumber: priceInfoMap.get(ids[0])!.seqNum, + }).toJson(), + }); + expect(resp.body).toContainEqual({ + ...priceInfoMap.get(ids[1])!.priceFeed.toJson(), + metadata: new PriceFeedMetadata({ + attestationTime: priceInfoMap.get(ids[1])!.attestationTime, + emitterChain: priceInfoMap.get(ids[1])!.emitterChainId, + receiveTime: priceInfoMap.get(ids[1])!.priceServiceReceiveTime, + sequenceNumber: priceInfoMap.get(ids[1])!.seqNum, + }).toJson(), + }); + }); + test("When called with valid ids and binary flag set to true, returns correct price feed with binary vaa", async () => { const ids = [expandTo64Len("abcd"), expandTo64Len("3456")]; const resp = await request(app) @@ -143,6 +190,29 @@ describe("Latest Vaa Bytes Endpoint", () => { ); }); + test("When called with valid ids with leading 0x, returns vaa bytes as array, merged if necessary", async () => { + const ids = [ + expandTo64Len("abcd"), + expandTo64Len("ef01"), + expandTo64Len("3456"), + ]; + + const resp = await request(app) + .get("/api/latest_vaas") + .query({ + ids: ids.map((id) => "0x" + id), // Add 0x to the queries + }); + + expect(resp.status).toBe(StatusCodes.OK); + expect(resp.body.length).toBe(2); + expect(resp.body).toContain( + Buffer.from("a1b2c3d4", "hex").toString("base64") + ); + expect(resp.body).toContain( + Buffer.from("bad01bad", "hex").toString("base64") + ); + }); + test("When called with some non-existent ids within ids, returns error mentioning non-existent ids", async () => { const ids = [ expandTo64Len("ab01"), diff --git a/price-service/src/__tests__/ws.test.ts b/price-service/src/__tests__/ws.test.ts index aad27090f9..74922e0997 100644 --- a/price-service/src/__tests__/ws.test.ts +++ b/price-service/src/__tests__/ws.test.ts @@ -1,4 +1,9 @@ -import { HexString, Price, PriceFeed } from "@pythnetwork/pyth-sdk-js"; +import { + HexString, + Price, + PriceFeed, + PriceFeedMetadata, +} from "@pythnetwork/pyth-sdk-js"; import { Server } from "http"; import { WebSocket, WebSocketServer } from "ws"; import { sleep } from "../helpers"; @@ -12,39 +17,20 @@ let server: Server; let wss: WebSocketServer; let priceInfos: PriceInfo[]; -let priceMetadata: any; function expandTo64Len(id: string): string { return id.repeat(64).substring(0, 64); } -function dummyPriceMetadata( - attestationTime: number, - emitterChainId: number, - seqNum: number, - priceServiceReceiveTime: number -): any { +function dummyPriceInfo(id: HexString, vaa: HexString): PriceInfo { return { - attestation_time: attestationTime, - emitter_chain: emitterChainId, - sequence_number: seqNum, - price_service_receive_time: priceServiceReceiveTime, - }; -} - -function dummyPriceInfo( - id: HexString, - vaa: HexString, - dummyPriceMetadataValue: any -): PriceInfo { - return { - seqNum: dummyPriceMetadataValue.sequence_number, + seqNum: 1, publishTime: 0, - attestationTime: dummyPriceMetadataValue.attestation_time, - emitterChainId: dummyPriceMetadataValue.emitter_chain, + attestationTime: 2, + emitterChainId: 3, priceFeed: dummyPriceFeed(id), vaa: Buffer.from(vaa, "hex"), - priceServiceReceiveTime: dummyPriceMetadataValue.price_service_receive_time, + priceServiceReceiveTime: 4, }; } @@ -96,12 +82,11 @@ async function createSocketClient(): Promise<[WebSocket, any[]]> { } beforeAll(async () => { - priceMetadata = dummyPriceMetadata(0, 0, 0, 0); priceInfos = [ - dummyPriceInfo(expandTo64Len("abcd"), "a1b2c3d4", priceMetadata), - dummyPriceInfo(expandTo64Len("ef01"), "a1b2c3d4", priceMetadata), - dummyPriceInfo(expandTo64Len("2345"), "bad01bad", priceMetadata), - dummyPriceInfo(expandTo64Len("6789"), "bidbidbid", priceMetadata), + dummyPriceInfo(expandTo64Len("abcd"), "a1b2c3d4"), + dummyPriceInfo(expandTo64Len("ef01"), "a1b2c3d4"), + dummyPriceInfo(expandTo64Len("2345"), "bad01bad"), + dummyPriceInfo(expandTo64Len("6789"), "bidbidbid"), ]; const priceInfo: PriceStore = { @@ -190,7 +175,12 @@ describe("Client receives data", () => { type: "price_update", price_feed: { ...priceInfos[0].priceFeed.toJson(), - metadata: priceMetadata, + metadata: new PriceFeedMetadata({ + attestationTime: 2, + emitterChain: 3, + receiveTime: 4, + sequenceNumber: 1, + }).toJson(), }, }); @@ -202,7 +192,12 @@ describe("Client receives data", () => { type: "price_update", price_feed: { ...priceInfos[1].priceFeed.toJson(), - metadata: priceMetadata, + metadata: new PriceFeedMetadata({ + attestationTime: 2, + emitterChain: 3, + receiveTime: 4, + sequenceNumber: 1, + }).toJson(), }, }); From f62b32186e701c3c0582003052a47128500dd73c Mon Sep 17 00:00:00 2001 From: Ali Behjati Date: Mon, 23 Jan 2023 11:11:00 +0000 Subject: [PATCH 2/8] Add test for VaaCache + a little refactor --- price-service/src/__tests__/listen.test.ts | 128 +++++++++++++++++++++ price-service/src/listen.ts | 37 ++++-- 2 files changed, 153 insertions(+), 12 deletions(-) create mode 100644 price-service/src/__tests__/listen.test.ts diff --git a/price-service/src/__tests__/listen.test.ts b/price-service/src/__tests__/listen.test.ts new file mode 100644 index 0000000000..1863bf6ef3 --- /dev/null +++ b/price-service/src/__tests__/listen.test.ts @@ -0,0 +1,128 @@ +import { DurationInSec } from "../helpers"; +import { VaaConfig, VaaCache } from "../listen"; + +function addDummyValuesToCache( + cache: VaaCache, + key: string, + publistTimeOffset: DurationInSec +) { + cache.set(key, publistTimeOffset + 1, `${key}-1`); + cache.set(key, publistTimeOffset + 4, `${key}-2`); + cache.set(key, publistTimeOffset + 10, `${key}-3`); + cache.set(key, publistTimeOffset + 13, `${key}-4`); +} + +describe("VAA Cache works", () => { + test("Setting and getting works as expected", async () => { + const cache = new VaaCache(); + + expect(cache.get("a", 3)).toBeUndefined(); + + cache.set("a", 1, "a-1"); + + expect(cache.get("a", 3)).toBeUndefined(); + + cache.set("a", 4, "a-2"); + + expect(cache.get("a", 3)).toEqual({ + publishTime: 4, + vaa: "a-2", + }); + + cache.set("a", 10, "a-3"); + + // Adding some elements with other keys to make sure + // they are not stored separately. + cache.set("b", 3, "b-1"); + cache.set("b", 7, "b-2"); + cache.set("b", 9, "b-3"); + + expect(cache.get("a", 3)).toEqual({ + publishTime: 4, + vaa: "a-2", + }); + expect(cache.get("a", 4)).toEqual({ + publishTime: 4, + vaa: "a-2", + }); + expect(cache.get("a", 5)).toEqual({ + publishTime: 10, + vaa: "a-3", + }); + expect(cache.get("a", 10)).toEqual({ + publishTime: 10, + vaa: "a-3", + }); + + expect(cache.get("b", 3)).toEqual({ + publishTime: 3, + vaa: "b-1", + }); + expect(cache.get("b", 4)).toEqual({ + publishTime: 7, + vaa: "b-2", + }); + + // When no item item more recent than asked pubTime is asked it should return undefined + expect(cache.get("a", 11)).toBeUndefined(); + expect(cache.get("b", 10)).toBeUndefined(); + + // When the asked pubTime is less than the first existing pubTime we are not sure that + // this is the first vaa after that time, so we should return undefined. + expect(cache.get("a", 0)).toBeUndefined(); + expect(cache.get("b", 1)).toBeUndefined(); + expect(cache.get("b", 2)).toBeUndefined(); + }); + + test("removeExpiredValues clears the old values", async () => { + jest.useFakeTimers(); + + // TTL of 500 seconds for the cache + const cache = new VaaCache(500); + + cache.set("a", 300, "a-1"); + cache.set("a", 700, "a-2"); + cache.set("a", 900, "a-3"); + + expect(cache.get("a", 300)).toEqual({ + publishTime: 300, + vaa: "a-1", + }); + + expect(cache.get("a", 500)).toEqual({ + publishTime: 700, + vaa: "a-2", + }); + + // Set time to second 1000 + jest.setSystemTime(1000 * 1000); + + cache.removeExpiredValues(); + + expect(cache.get("a", 300)).toBeUndefined(); + expect(cache.get("a", 500)).toBeUndefined(); + }); + + test("the cache clean loop works", async () => { + jest.useFakeTimers(); + + // TTL of 500 seconds for the cache and cleanup of every 100 seconds + const cache = new VaaCache(500, 100); + cache.runRemoveExpiredValuesLoop(); + + cache.set("a", 300, "a-1"); + cache.set("a", 700, "a-2"); + cache.set("a", 900, "a-3"); + + expect(cache.get("a", 900)).toEqual({ + publishTime: 900, + vaa: "a-3", + }); + + // Set time to second 2000. Everything should be evicted from cache now. + jest.setSystemTime(2000 * 1000); + jest.advanceTimersToNextTimer(); + + expect(cache.get("a", 900)).toBeUndefined(); + }); +}); diff --git a/price-service/src/listen.ts b/price-service/src/listen.ts index aca941668f..9a90626311 100644 --- a/price-service/src/listen.ts +++ b/price-service/src/listen.ts @@ -62,14 +62,19 @@ export type VaaConfig = { export class VaaCache { private cache: Map; - private ttl: number; + private ttl: DurationInSec; + private cacheCleanupLoopInterval: DurationInSec; - constructor(ttl: DurationInSec = 300) { + constructor( + ttl: DurationInSec = 300, + cacheCleanupLoopInterval: DurationInSec = 60 + ) { this.cache = new Map(); this.ttl = ttl; + this.cacheCleanupLoopInterval = cacheCleanupLoopInterval; } - set(key: VaaKey, publishTime: number, vaa: string): void { + set(key: VaaKey, publishTime: TimestampInSec, vaa: string): void { if (this.cache.has(key)) { this.cache.get(key)!.push({ publishTime, vaa }); } else { @@ -77,7 +82,7 @@ export class VaaCache { } } - get(key: VaaKey, publishTime: number): VaaConfig | undefined { + get(key: VaaKey, publishTime: TimestampInSec): VaaConfig | undefined { if (!this.cache.has(key)) { return undefined; } else { @@ -86,7 +91,10 @@ export class VaaCache { } } - find(arr: VaaConfig[], publishTime: number): VaaConfig | undefined { + private find( + arr: VaaConfig[], + publishTime: TimestampInSec + ): VaaConfig | undefined { // If the publishTime is less than the first element we are // not sure that this VAA is actually the first VAA after that // time. @@ -123,6 +131,13 @@ export class VaaCache { ); } } + + runRemoveExpiredValuesLoop() { + setInterval( + this.removeExpiredValues.bind(this), + this.cacheCleanupLoopInterval * 1000 + ); + } } export class Listener implements PriceStore { @@ -136,7 +151,6 @@ export class Listener implements PriceStore { private updateCallbacks: ((priceInfo: PriceInfo) => any)[]; private observedVaas: LRUCache; private vaasCache: VaaCache; - private cacheCleanupLoopInterval: DurationInSec; constructor(config: ListenerConfig, promClient?: PromClient) { this.promClient = promClient; @@ -148,8 +162,10 @@ export class Listener implements PriceStore { max: 10000, // At most 10000 items ttl: 60 * 1000, // 60 seconds }); - this.vaasCache = new VaaCache(config.cacheTtl); - this.cacheCleanupLoopInterval = config.cacheCleanupLoopInterval ?? 60; + this.vaasCache = new VaaCache( + config.cacheTtl, + config.cacheCleanupLoopInterval + ); } private loadFilters(filtersRaw?: string) { @@ -188,10 +204,7 @@ export class Listener implements PriceStore { this.spyServiceHost ); - setInterval( - this.vaasCache.removeExpiredValues.bind(this.vaasCache), - this.cacheCleanupLoopInterval * 1000 - ); + this.vaasCache.runRemoveExpiredValuesLoop(); while (true) { let stream: ClientReadableStream | undefined; From 7109f283576a5dafee37bea9e964d2e379a4da73 Mon Sep 17 00:00:00 2001 From: Ali Behjati Date: Mon, 23 Jan 2023 18:23:52 +0000 Subject: [PATCH 3/8] Add tests for get_vaa endpoint --- price-service/src/__tests__/rest.test.ts | 262 ++++++++++++++++++++++- 1 file changed, 253 insertions(+), 9 deletions(-) diff --git a/price-service/src/__tests__/rest.test.ts b/price-service/src/__tests__/rest.test.ts index 9272fce442..b52617f58d 100644 --- a/price-service/src/__tests__/rest.test.ts +++ b/price-service/src/__tests__/rest.test.ts @@ -4,12 +4,13 @@ import { PriceFeed, PriceFeedMetadata, } from "@pythnetwork/pyth-sdk-js"; -import { Express } from "express"; +import express, { Express } from "express"; import { StatusCodes } from "http-status-codes"; import request from "supertest"; -import { PriceInfo, PriceStore, VaaCache } from "../listen"; +import { PriceInfo, PriceStore, VaaCache, VaaConfig } from "../listen"; import { RestAPI } from "../rest"; +let priceInfo: PriceStore; let app: Express; let priceInfoMap: Map; let vaasCache: VaaCache; @@ -62,14 +63,10 @@ beforeAll(async () => { dummyPriceInfoPair(expandTo64Len("3456"), 2, "bad01bad"), dummyPriceInfoPair(expandTo64Len("10101"), 3, "bidbidbid"), ]); + vaasCache = new VaaCache(); - vaasCache.set( - expandTo64Len("abcd"), - 1, - Buffer.from("a1b2c3d4", "hex").toString("base64") - ); - const priceInfo: PriceStore = { + priceInfo = { getLatestPriceInfo: (priceFeedId: string) => { return priceInfoMap.get(priceFeedId); }, @@ -81,7 +78,6 @@ beforeAll(async () => { }; const api = new RestAPI({ port: 8889 }, priceInfo, () => true); - app = await api.createApp(); }); @@ -226,3 +222,251 @@ describe("Latest Vaa Bytes Endpoint", () => { expect(resp.body.message).toContain(ids[2]); }); }); + +describe("Get VAA endpoint and Get VAA CCIP", () => { + test("When called with valid id and timestamp in the cache returns the correct answer", async () => { + const id = expandTo64Len("abcd"); + vaasCache.set(id, 10, "abcd10"); + vaasCache.set(id, 20, "abcd20"); + vaasCache.set(id, 30, "abcd30"); + + const resp = await request(app).get("/api/get_vaa").query({ + id, + publish_time: 16, + }); + expect(resp.status).toBe(StatusCodes.OK); + expect(resp.body).toEqual({ + vaa: "abcd20", + publishTime: 20, + }); + + const pubTime16AsHex64Bit = "0000000000000010"; + const ccip_resp = await request(app) + .get("/api/get_vaa_ccip") + .query({ + data: "0x" + id + pubTime16AsHex64Bit, + }); + const pubTime20AsHex64Bit = "0000000000000014"; + expect(ccip_resp.status).toBe(StatusCodes.OK); + expect(ccip_resp.body).toEqual({ + data: + "0x" + + pubTime20AsHex64Bit + + Buffer.from("abcd20", "base64").toString("hex"), + }); + }); + + test("When called with valid id with leading 0x and timestamp in the cache returns the correct answer", async () => { + const id = expandTo64Len("abcd"); + vaasCache.set(id, 10, "abcd10"); + vaasCache.set(id, 20, "abcd20"); + vaasCache.set(id, 30, "abcd30"); + + const resp = await request(app) + .get("/api/get_vaa") + .query({ + id: "0x" + id, + publish_time: 16, + }); + expect(resp.status).toBe(StatusCodes.OK); + expect(resp.body).toEqual({ + vaa: "abcd20", + publishTime: 20, + }); + }); + + test("When called with invalid id returns price id found", async () => { + // dead does not exist in the ids + const id = expandTo64Len("dead"); + + const resp = await request(app).get("/api/get_vaa").query({ + id, + publish_time: 16, + }); + expect(resp.status).toBe(StatusCodes.BAD_REQUEST); + expect(resp.body.message).toContain(id); + + const pubTime16AsHex64Bit = "0000000000000010"; + const ccip_resp = await request(app) + .get("/api/get_vaa_ccip") + .query({ + data: "0x" + id + pubTime16AsHex64Bit, + }); + expect(ccip_resp.status).toBe(StatusCodes.BAD_REQUEST); + expect(ccip_resp.body.message).toContain(id); + }); + + test("When called with valid id and timestamp not in the cache without db returns vaa not found", async () => { + const id = expandTo64Len("abcd"); + vaasCache.set(id, 10, "abcd10"); + vaasCache.set(id, 20, "abcd20"); + vaasCache.set(id, 30, "abcd30"); + + const resp = await request(app) + .get("/api/get_vaa") + .query({ + id: "0x" + id, + publish_time: 5, + }); + expect(resp.status).toBe(StatusCodes.NOT_FOUND); + + const pubTime5AsHex64Bit = "0000000000000005"; + const ccip_resp = await request(app) + .get("/api/get_vaa_ccip") + .query({ + data: "0x" + id + pubTime5AsHex64Bit, + }); + // On CCIP we expect bad gateway so the client want to retry other ccip endpoints. + expect(ccip_resp.status).toBe(StatusCodes.BAD_GATEWAY); + }); + + test("When called with valid id and timestamp not in the cache with db returns ok", async () => { + const dbBackend = express(); + dbBackend.get("/vaa", (req, res) => { + const id = req.query.id; + const pubTime = Number(req.query.publishTime); + const cluster = req.query.cluster; + + res.json([ + { + vaa: `${cluster}${id}${pubTime}`, + publishTime: new Date(pubTime * 1000).toISOString(), + }, + ]); + }); + const dbApp = dbBackend.listen({ port: 37777 }); + + const apiWithDb = new RestAPI( + { + port: 8889, + dbApiCluster: "pythnet", + dbApiEndpoint: "http://localhost:37777", + }, + priceInfo, + () => true + ); + const appWithDb = await apiWithDb.createApp(); + + const id = expandTo64Len("abcd"); + vaasCache.set(id, 10, "abcd10"); + vaasCache.set(id, 20, "abcd20"); + vaasCache.set(id, 30, "abcd30"); + + const resp = await request(appWithDb) + .get("/api/get_vaa") + .query({ + id: "0x" + id, + publish_time: 5, + }); + expect(resp.status).toBe(StatusCodes.OK); + expect(resp.body).toEqual({ + vaa: `pythnet${id}5`, + publishTime: 5, + }); + + const pubTime5AsHex64Bit = "0000000000000005"; + const ccip_resp = await request(appWithDb) + .get("/api/get_vaa_ccip") + .query({ + data: "0x" + id + pubTime5AsHex64Bit, + }); + expect(ccip_resp.status).toBe(StatusCodes.OK); + expect(ccip_resp.body).toEqual({ + data: + "0x" + + pubTime5AsHex64Bit + + Buffer.from(`pythnet${id}5`, "base64").toString("hex"), + }); + + dbApp.close(); + }); + + test( + "When called with valid id and timestamp not in the cache" + + "and not in the db returns vaa not found", + async () => { + const dbBackend = express(); + dbBackend.get("/vaa", (_req, res) => { + // Return an empty array when vaa is not there, this is the same + // behaviour as our api. + res.json([]); + }); + + const dbApp = dbBackend.listen({ port: 37777 }); + + const apiWithDb = new RestAPI( + { + port: 8889, + dbApiCluster: "pythnet", + dbApiEndpoint: "http://localhost:37777", + }, + priceInfo, + () => true + ); + const appWithDb = await apiWithDb.createApp(); + + const id = expandTo64Len("abcd"); + vaasCache.set(id, 10, "abcd10"); + vaasCache.set(id, 20, "abcd20"); + vaasCache.set(id, 30, "abcd30"); + + const resp = await request(appWithDb) + .get("/api/get_vaa") + .query({ + id: "0x" + id, + publish_time: 5, + }); + expect(resp.status).toBe(StatusCodes.NOT_FOUND); + + const pubTime5AsHex64Bit = "0000000000000005"; + const ccip_resp = await request(appWithDb) + .get("/api/get_vaa_ccip") + .query({ + data: "0x" + id + pubTime5AsHex64Bit, + }); + + // On CCIP we expect bad gateway so the client want to retry other ccip endpoints. + expect(ccip_resp.status).toBe(StatusCodes.BAD_GATEWAY); + + dbApp.close(); + } + ); + + test( + "When called with valid id and timestamp not in the cache" + + "and db is not available returns internal server error", + async () => { + const apiWithDb = new RestAPI( + { + port: 8889, + dbApiCluster: "pythnet", + dbApiEndpoint: "http://localhost:37777", + }, + priceInfo, + () => true + ); + const appWithDb = await apiWithDb.createApp(); + + const id = expandTo64Len("abcd"); + vaasCache.set(id, 10, "abcd10"); + vaasCache.set(id, 20, "abcd20"); + vaasCache.set(id, 30, "abcd30"); + + const resp = await request(appWithDb) + .get("/api/get_vaa") + .query({ + id: "0x" + id, + publish_time: 5, + }); + expect(resp.status).toBe(StatusCodes.INTERNAL_SERVER_ERROR); + + const pubTime5AsHex64Bit = "0000000000000005"; + const ccip_resp = await request(appWithDb) + .get("/api/get_vaa_ccip") + .query({ + data: "0x" + id + pubTime5AsHex64Bit, + }); + expect(ccip_resp.status).toBe(StatusCodes.INTERNAL_SERVER_ERROR); + } + ); +}); From fd7bb19443f401df7340ee2c668a82c1fd73e49d Mon Sep 17 00:00:00 2001 From: Ali Behjati Date: Mon, 23 Jan 2023 18:25:09 +0000 Subject: [PATCH 4/8] Fix linting issues --- price-service/src/__tests__/rest.test.ts | 34 ++++++++++++------------ tilt-devnet/k8s/pyth-price-service.yaml | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/price-service/src/__tests__/rest.test.ts b/price-service/src/__tests__/rest.test.ts index b52617f58d..709ecfa882 100644 --- a/price-service/src/__tests__/rest.test.ts +++ b/price-service/src/__tests__/rest.test.ts @@ -241,14 +241,14 @@ describe("Get VAA endpoint and Get VAA CCIP", () => { }); const pubTime16AsHex64Bit = "0000000000000010"; - const ccip_resp = await request(app) + const ccipResp = await request(app) .get("/api/get_vaa_ccip") .query({ data: "0x" + id + pubTime16AsHex64Bit, }); const pubTime20AsHex64Bit = "0000000000000014"; - expect(ccip_resp.status).toBe(StatusCodes.OK); - expect(ccip_resp.body).toEqual({ + expect(ccipResp.status).toBe(StatusCodes.OK); + expect(ccipResp.body).toEqual({ data: "0x" + pubTime20AsHex64Bit + @@ -287,13 +287,13 @@ describe("Get VAA endpoint and Get VAA CCIP", () => { expect(resp.body.message).toContain(id); const pubTime16AsHex64Bit = "0000000000000010"; - const ccip_resp = await request(app) + const ccipResp = await request(app) .get("/api/get_vaa_ccip") .query({ data: "0x" + id + pubTime16AsHex64Bit, }); - expect(ccip_resp.status).toBe(StatusCodes.BAD_REQUEST); - expect(ccip_resp.body.message).toContain(id); + expect(ccipResp.status).toBe(StatusCodes.BAD_REQUEST); + expect(ccipResp.body.message).toContain(id); }); test("When called with valid id and timestamp not in the cache without db returns vaa not found", async () => { @@ -311,25 +311,25 @@ describe("Get VAA endpoint and Get VAA CCIP", () => { expect(resp.status).toBe(StatusCodes.NOT_FOUND); const pubTime5AsHex64Bit = "0000000000000005"; - const ccip_resp = await request(app) + const ccipResp = await request(app) .get("/api/get_vaa_ccip") .query({ data: "0x" + id + pubTime5AsHex64Bit, }); // On CCIP we expect bad gateway so the client want to retry other ccip endpoints. - expect(ccip_resp.status).toBe(StatusCodes.BAD_GATEWAY); + expect(ccipResp.status).toBe(StatusCodes.BAD_GATEWAY); }); test("When called with valid id and timestamp not in the cache with db returns ok", async () => { const dbBackend = express(); dbBackend.get("/vaa", (req, res) => { - const id = req.query.id; + const priceId = req.query.id; const pubTime = Number(req.query.publishTime); const cluster = req.query.cluster; res.json([ { - vaa: `${cluster}${id}${pubTime}`, + vaa: `${cluster}${priceId}${pubTime}`, publishTime: new Date(pubTime * 1000).toISOString(), }, ]); @@ -365,13 +365,13 @@ describe("Get VAA endpoint and Get VAA CCIP", () => { }); const pubTime5AsHex64Bit = "0000000000000005"; - const ccip_resp = await request(appWithDb) + const ccipResp = await request(appWithDb) .get("/api/get_vaa_ccip") .query({ data: "0x" + id + pubTime5AsHex64Bit, }); - expect(ccip_resp.status).toBe(StatusCodes.OK); - expect(ccip_resp.body).toEqual({ + expect(ccipResp.status).toBe(StatusCodes.OK); + expect(ccipResp.body).toEqual({ data: "0x" + pubTime5AsHex64Bit + @@ -419,14 +419,14 @@ describe("Get VAA endpoint and Get VAA CCIP", () => { expect(resp.status).toBe(StatusCodes.NOT_FOUND); const pubTime5AsHex64Bit = "0000000000000005"; - const ccip_resp = await request(appWithDb) + const ccipResp = await request(appWithDb) .get("/api/get_vaa_ccip") .query({ data: "0x" + id + pubTime5AsHex64Bit, }); // On CCIP we expect bad gateway so the client want to retry other ccip endpoints. - expect(ccip_resp.status).toBe(StatusCodes.BAD_GATEWAY); + expect(ccipResp.status).toBe(StatusCodes.BAD_GATEWAY); dbApp.close(); } @@ -461,12 +461,12 @@ describe("Get VAA endpoint and Get VAA CCIP", () => { expect(resp.status).toBe(StatusCodes.INTERNAL_SERVER_ERROR); const pubTime5AsHex64Bit = "0000000000000005"; - const ccip_resp = await request(appWithDb) + const ccipResp = await request(appWithDb) .get("/api/get_vaa_ccip") .query({ data: "0x" + id + pubTime5AsHex64Bit, }); - expect(ccip_resp.status).toBe(StatusCodes.INTERNAL_SERVER_ERROR); + expect(ccipResp.status).toBe(StatusCodes.INTERNAL_SERVER_ERROR); } ); }); diff --git a/tilt-devnet/k8s/pyth-price-service.yaml b/tilt-devnet/k8s/pyth-price-service.yaml index 35cfdcac21..0224373216 100644 --- a/tilt-devnet/k8s/pyth-price-service.yaml +++ b/tilt-devnet/k8s/pyth-price-service.yaml @@ -26,7 +26,7 @@ spec: matchLabels: app: pyth-price-service serviceName: pyth-price-service - replicas: 2 + replicas: 1 template: metadata: labels: From 026643eaf4ce7bbeef6235ba7fc65adc560435cc Mon Sep 17 00:00:00 2001 From: Ali Behjati Date: Mon, 23 Jan 2023 18:30:27 +0000 Subject: [PATCH 5/8] Add tests to tilt --- tilt-devnet/k8s/pyth-price-service.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tilt-devnet/k8s/pyth-price-service.yaml b/tilt-devnet/k8s/pyth-price-service.yaml index 0224373216..87ce1238b7 100644 --- a/tilt-devnet/k8s/pyth-price-service.yaml +++ b/tilt-devnet/k8s/pyth-price-service.yaml @@ -76,3 +76,12 @@ spec: value: "60" - name: CACHE_TTL_SECONDS value: "300" + - name: tests + image: pyth-price-service + command: + - "npm run test && nc -lkp 2000 0.0.0.0" + readinessProbe: + periodSeconds: 1 + failureThreshold: 300 + tcpSocket: + port: 2000 From 7be634323dc5602ff4b27cee1e96259d2c40052c Mon Sep 17 00:00:00 2001 From: Ali Behjati Date: Mon, 23 Jan 2023 18:38:52 +0000 Subject: [PATCH 6/8] Fix tilt --- tilt-devnet/k8s/pyth-price-service.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tilt-devnet/k8s/pyth-price-service.yaml b/tilt-devnet/k8s/pyth-price-service.yaml index 87ce1238b7..8b93e9403e 100644 --- a/tilt-devnet/k8s/pyth-price-service.yaml +++ b/tilt-devnet/k8s/pyth-price-service.yaml @@ -79,6 +79,8 @@ spec: - name: tests image: pyth-price-service command: + - /bin/sh + - -c - "npm run test && nc -lkp 2000 0.0.0.0" readinessProbe: periodSeconds: 1 From 65b384d72b45c961708df87e1794fcef1c77f206 Mon Sep 17 00:00:00 2001 From: Ali Behjati Date: Mon, 23 Jan 2023 19:18:57 +0000 Subject: [PATCH 7/8] Fix tilt --- tilt-devnet/k8s/pyth-price-service.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tilt-devnet/k8s/pyth-price-service.yaml b/tilt-devnet/k8s/pyth-price-service.yaml index 8b93e9403e..d8db577080 100644 --- a/tilt-devnet/k8s/pyth-price-service.yaml +++ b/tilt-devnet/k8s/pyth-price-service.yaml @@ -81,9 +81,9 @@ spec: command: - /bin/sh - -c - - "npm run test && nc -lkp 2000 0.0.0.0" + - "npm run test && nc -lkp 2358 0.0.0.0" readinessProbe: - periodSeconds: 1 + periodSeconds: 5 failureThreshold: 300 tcpSocket: - port: 2000 + port: 2358 From f66db50cd65e524138075524ab481022272fa2be Mon Sep 17 00:00:00 2001 From: Ali Behjati Date: Tue, 24 Jan 2023 09:19:23 +0000 Subject: [PATCH 8/8] Remove unused method --- price-service/src/__tests__/listen.test.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/price-service/src/__tests__/listen.test.ts b/price-service/src/__tests__/listen.test.ts index 1863bf6ef3..e747caaf48 100644 --- a/price-service/src/__tests__/listen.test.ts +++ b/price-service/src/__tests__/listen.test.ts @@ -1,17 +1,5 @@ -import { DurationInSec } from "../helpers"; import { VaaConfig, VaaCache } from "../listen"; -function addDummyValuesToCache( - cache: VaaCache, - key: string, - publistTimeOffset: DurationInSec -) { - cache.set(key, publistTimeOffset + 1, `${key}-1`); - cache.set(key, publistTimeOffset + 4, `${key}-2`); - cache.set(key, publistTimeOffset + 10, `${key}-3`); - cache.set(key, publistTimeOffset + 13, `${key}-4`); -} - describe("VAA Cache works", () => { test("Setting and getting works as expected", async () => { const cache = new VaaCache();