From 7057fa8b65e5b99394fa7e7bfaceb9058b057f5d Mon Sep 17 00:00:00 2001 From: Yaroslav Grishajev Date: Thu, 9 May 2024 10:05:16 +0200 Subject: [PATCH] test(sdl): cover denom validation also improve basic yml templating with default values refs akash-network/cloudmos#133 --- src/config/network.ts | 2 + src/sdl/SDL/SDL.spec.ts | 73 ++++++++++++------- src/sdl/SDL/SDL.ts | 4 +- ...rld-basic-with-creds.yml => sdl-basic.yml} | 2 +- test/yml.ts | 27 +++++++ 5 files changed, 78 insertions(+), 30 deletions(-) rename test/fixtures/{sdl-hello-world-basic-with-creds.yml => sdl-basic.yml} (94%) diff --git a/src/config/network.ts b/src/config/network.ts index da6dbb5..4d6a51e 100644 --- a/src/config/network.ts +++ b/src/config/network.ts @@ -9,3 +9,5 @@ export const USDC_IBC_DENOMS: Record = { [SANDBOX_ID]: "ibc/12C6A0C374171B595A0A9E18B83FA09D295FB1F2D8C6DAA3AC28683471752D84", [TESTNET_ID]: "" }; + +export const AKT_DENOM = "uakt"; diff --git a/src/sdl/SDL/SDL.spec.ts b/src/sdl/SDL/SDL.spec.ts index fa744d4..bae9275 100644 --- a/src/sdl/SDL/SDL.spec.ts +++ b/src/sdl/SDL/SDL.spec.ts @@ -1,15 +1,42 @@ import { faker } from "@faker-js/faker"; -import template from "lodash/template"; -import omit from "lodash/omit"; -import { readYml, toYmlFragment } from "../../../test/yml"; +import { readBasicSdl } from "../../../test/yml"; import { SdlValidationError } from "../../error"; import { SDL } from "./SDL"; import { v2ServiceImageCredentials } from "../types"; - -const createYML = template(readYml("sdl-hello-world-basic-with-creds")); +import { omit } from "lodash"; +import { AKT_DENOM, SANDBOX_ID, USDC_IBC_DENOMS } from "../../config/network"; describe("SDL", () => { + describe("profiles placement pricing denomination", () => { + it.each([AKT_DENOM, USDC_IBC_DENOMS[SANDBOX_ID]])('should resolve a group with a valid "%s" denomination', denom => { + const yml = readBasicSdl({ denom }); + const sdl = SDL.fromString(yml, "beta3", "sandbox"); + + expect(sdl.groups()).toMatchObject([ + { + resources: [ + { + price: { + denom: denom, + amount: "1000" + } + } + ] + } + ]); + }); + + it("should throw an error when denomination is invalid", () => { + const denom = "usdt"; + const yml = readBasicSdl({ denom }); + + expect(() => SDL.fromString(yml, "beta3", "sandbox")).toThrow( + new SdlValidationError(`Invalid denom: "${denom}". Only uakt and ${USDC_IBC_DENOMS[SANDBOX_ID]} are supported.`) + ); + }); + }); + describe("service image credentials", () => { it("should resolve a service with valid credentials", () => { const credentials = { @@ -17,19 +44,21 @@ describe("SDL", () => { username: faker.internet.userName(), password: faker.internet.password() }; - const yml = createYML({ - credentials: toYmlFragment({ credentials }, { nestingLevel: 2 }) - }); - const sdl = SDL.fromString(yml, "beta3", "sandbox"); + const sdl = SDL.fromString(readBasicSdl({ credentials }), "beta3", "sandbox"); - expect(sdl.manifest()).toMatchObject([{ services: [{ credentials }] }]); + expect(sdl.manifest()).toMatchObject([ + { + services: [ + { + credentials + } + ] + } + ]); }); it("should resolve a service without credentials", () => { - const yml = createYML({ - credentials: "" - }); - const sdl = SDL.fromString(yml, "beta3", "sandbox"); + const sdl = SDL.fromString(readBasicSdl(), "beta3", "sandbox"); const group = sdl.manifest()[0]; if (!("services" in group)) { @@ -52,34 +81,24 @@ describe("SDL", () => { }); it.each(fields)('should throw an error when credentials are missing "%s"', field => { - const yml = createYML({ - credentials: toYmlFragment({ credentials: omit(credentials, field) }, { nestingLevel: 2 }) - }); - expect(() => { - SDL.fromString(yml, "beta3", "sandbox"); + SDL.fromString(readBasicSdl({ credentials: omit(credentials, field) }), "beta3", "sandbox"); }).toThrowError(new SdlValidationError(`service "web" credentials missing "${field}"`)); }); it.each(fields)('should throw an error when credentials "%s" is empty', field => { credentials[field] = ""; - const yml = createYML({ - credentials: toYmlFragment({ credentials: omit(credentials, field) }, { nestingLevel: 2 }) - }); expect(() => { - SDL.fromString(yml, "beta3", "sandbox"); + SDL.fromString(readBasicSdl({ credentials }), "beta3", "sandbox"); }).toThrowError(new SdlValidationError(`service "web" credentials missing "${field}"`)); }); it.each(fields)('should throw an error when credentials "%s" contains spaces only', field => { credentials[field] = " "; - const yml = createYML({ - credentials: toYmlFragment({ credentials: omit(credentials, field) }, { nestingLevel: 2 }) - }); expect(() => { - SDL.fromString(yml, "beta3", "sandbox"); + SDL.fromString(readBasicSdl({ credentials }), "beta3", "sandbox"); }).toThrowError(new SdlValidationError(`service "web" credentials missing "${field}"`)); }); }); diff --git a/src/sdl/SDL/SDL.ts b/src/sdl/SDL/SDL.ts index ad080df..c707752 100644 --- a/src/sdl/SDL/SDL.ts +++ b/src/sdl/SDL/SDL.ts @@ -34,7 +34,7 @@ import { import { convertCpuResourceString, convertResourceString } from "./../sizes"; import { default as stableStringify } from "json-stable-stringify"; import crypto from "node:crypto"; -import { MAINNET_ID, USDC_IBC_DENOMS } from "../../config/network"; +import { AKT_DENOM, MAINNET_ID, USDC_IBC_DENOMS } from "../../config/network"; import { NetworkId } from "../../types/network"; import { SdlValidationError } from "../../error"; @@ -180,7 +180,7 @@ export class SDL { const denoms = this.groups() .flatMap(g => g.resources) .map(resource => resource.price.denom); - const invalidDenom = denoms.find(denom => denom !== "uakt" && denom !== usdcDenom); + const invalidDenom = denoms.find(denom => denom !== AKT_DENOM && denom !== usdcDenom); SdlValidationError.assert(!invalidDenom, `Invalid denom: "${invalidDenom}". Only uakt and ${usdcDenom} are supported.`); } diff --git a/test/fixtures/sdl-hello-world-basic-with-creds.yml b/test/fixtures/sdl-basic.yml similarity index 94% rename from test/fixtures/sdl-hello-world-basic-with-creds.yml rename to test/fixtures/sdl-basic.yml index 58fcfaf..2282629 100644 --- a/test/fixtures/sdl-hello-world-basic-with-creds.yml +++ b/test/fixtures/sdl-basic.yml @@ -25,7 +25,7 @@ profiles: dcloud: pricing: web: - denom: uakt + denom: ${denom} amount: 1000 deployment: diff --git a/test/yml.ts b/test/yml.ts index 65f9f48..bb836a4 100644 --- a/test/yml.ts +++ b/test/yml.ts @@ -1,6 +1,12 @@ import fs from "fs"; import path from "path"; import { dump } from "js-yaml"; +import { faker } from "@faker-js/faker"; +import template from "lodash/template"; +import memoize from "lodash/memoize"; +import { AKT_DENOM } from "../src/config/network"; +import { SANDBOX_ID, USDC_IBC_DENOMS } from "../src/config/network"; +import { pick } from "lodash"; export const readYml = (name: string): string => { return fs.readFileSync(path.resolve(__dirname, `./fixtures/${name}.yml`), "utf-8"); @@ -23,3 +29,24 @@ export const toYmlFragment = (object: YmlInputObject, options?: { nestingLevel: .map(line => indentation + line) .join("\n"); }; + +interface BasicSdlTemplateVariables { + denom?: string; + credentials?: { + host?: string; + username?: string; + password?: string; + }; +} + +const readBasicSdlTemplate = memoize(() => template(readYml("sdl-basic"))); + +export const readBasicSdl = (variables: BasicSdlTemplateVariables = {}): string => { + const createYML = readBasicSdlTemplate(); + const ymlVars: Record = { + denom: variables.denom || faker.helpers.arrayElement([AKT_DENOM, USDC_IBC_DENOMS[SANDBOX_ID]]), + credentials: variables.credentials ? toYmlFragment(pick(variables, "credentials"), { nestingLevel: 2 }) : "" + }; + + return createYML(ymlVars); +};