Skip to main content
Glama
setup-platform-resources.ts21.9 kB
import { afterAll, beforeAll, expect, setDefaultTimeout } from "bun:test"; import { copyFile, mkdir } from "node:fs/promises"; import { join } from "node:path"; import { loadEnv } from "@settlemint/sdk-utils/environment"; import { exists } from "@settlemint/sdk-utils/filesystem"; import type { DotEnv } from "@settlemint/sdk-utils/validation"; import { AAT_NAME, APPLICATION_NAME, BLOCKSCOUT_NAME, CLUSTER_PROVIDER, CLUSTER_REGION, GRAPH_NAME, HASURA_NAME, HD_PRIVATE_KEY_NAME, IPFS_NAME, LOAD_BALANCER_NAME, MINIO_NAME, NETWORK_NAME, NODE_NAME, NODE_NAME_2_WITH_PK, NODE_NAME_3_WITHOUT_PK, PORTAL_NAME, PRIVATE_KEY_NODE_2_NAME, PRIVATE_KEY_SMART_CONTRACTS_NAMES, RELAYER_PRIVATE_KEY_NAME, WORKSPACE_NAME, } from "../constants/test-resources"; import { isLocalEnv } from "../utils/is-local-env"; import { type CommandResult, runCommand } from "../utils/run-command"; import { blockchainNodeAlreadyCreated, defaultResourceAlreadyCreated, findBlockchainNodeByName, findLoadBalancerByName, findPrivateKeyByName, privateKeyAlreadyCreated, setupSettleMintClient, } from "../utils/test-resources"; // Needed so it loads the correct environment variables process.env.NODE_ENV = "development"; const COMMAND_TEST_SCOPE = __filename; const DISABLE_CONCURRENT_DEPLOYMENT = process.env.DISABLE_CONCURRENT_DEPLOYMENT === "true"; // Required for the beforeAll hook to not to timeout setDefaultTimeout(1000 * 60 * 60); // 1 hour async function cleanup(force = false) { if (process.env.DISABLE_WORKSPACE_DELETE && !force) { console.log("Skipping delete of workspace and application"); return; } try { const { output: deleteApplicationOutput } = await runCommand(COMMAND_TEST_SCOPE, [ "platform", "delete", "application", "--accept-defaults", "--force", "default", ]).result; expect(deleteApplicationOutput).toInclude(`Application ${APPLICATION_NAME} deleted successfully`); const { output: deleteWorkspaceOutput } = await runCommand(COMMAND_TEST_SCOPE, [ "platform", "delete", "workspace", "--accept-defaults", "--force", "default", ]).result; expect(deleteWorkspaceOutput).toInclude(`Workspace ${WORKSPACE_NAME} deleted successfully`); await logout(); } catch (err) { const error = err as Error; console.error(`Cleaning up resources failed: ${error.message}`, error); } } beforeAll(async () => { try { await login(); await createWorkspaceAndApplication(); await createApplicationAccessToken(); await createBlockchainNetworkMinioAndIpfs(); await createBlockchainNodes(); await createLoadBalancer(); await createPrivateKeySmartcontractSetPortalAndBlockscout(); await createGraphMiddlewareAndActivatedPrivateKey(); await prepareTestApp(); } catch (err) { console.error("Failed to create resources", err); await cleanup(); process.exit(1); } }); afterAll(cleanup); async function addWorkspaceCredits() { // Add some credits so the workspace will not be auto paused const env: Partial<DotEnv> = await loadEnv(false, false); expect(env.SETTLEMINT_WORKSPACE).toBeString(); const settlemint = await setupSettleMintClient(); if (!isLocalEnv()) { const workspace = await settlemint.workspace.read(env.SETTLEMINT_WORKSPACE!); await settlemint.workspace.addCredits(workspace.id, 5_000); } } async function createWorkspaceAndApplication() { const hasWorkspace = await defaultResourceAlreadyCreated(["SETTLEMINT_WORKSPACE"]); if (!hasWorkspace) { const { output: workspaceOutput } = await runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "workspace", `${WORKSPACE_NAME}`, "--company-name", "Test Company", "--tax-id-type", "eu_vat", "--tax-id-value", "BE0123456789", "--address-line-1", "123 Test St", "--city", "Test City", "--postal-code", "12345", "--country", "BE", "--accept-defaults", "--default", ]).result; expect(workspaceOutput).toInclude(`Workspace ${WORKSPACE_NAME} created successfully`); await addWorkspaceCredits(); } const hasApplication = await defaultResourceAlreadyCreated(["SETTLEMINT_APPLICATION"]); if (!hasApplication) { const { output: applicationOutput } = await runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "application", `${APPLICATION_NAME}`, "--accept-defaults", "--default", ]).result; expect(applicationOutput).toInclude(`Application ${APPLICATION_NAME} created successfully`); } } async function createBlockchainNetworkMinioAndIpfs() { const hasBlockchainNetwork = await defaultResourceAlreadyCreated(["SETTLEMINT_BLOCKCHAIN_NETWORK"]); const hasBlockchainNode = await defaultResourceAlreadyCreated(["SETTLEMINT_BLOCKCHAIN_NODE"]); const hasHasuraIntegration = await defaultResourceAlreadyCreated(["SETTLEMINT_HASURA"]); const hasMinioStorage = await defaultResourceAlreadyCreated(["SETTLEMINT_MINIO"]); const hasIpfsStorage = await defaultResourceAlreadyCreated(["SETTLEMINT_IPFS"]); const results = await deployResources([ () => hasBlockchainNetwork && hasBlockchainNode ? Promise.resolve(undefined) : runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "blockchain-network", "besu", NETWORK_NAME, "--provider", CLUSTER_PROVIDER, "--region", CLUSTER_REGION, "--node-name", NODE_NAME, "--includePredeployedContracts", "--accept-defaults", "--default", "--wait", "--restart-if-timeout", "--restart-on-error", ]).result, () => hasHasuraIntegration ? Promise.resolve(undefined) : runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "integration-tool", "hasura", "--provider", CLUSTER_PROVIDER, "--region", CLUSTER_REGION, "--accept-defaults", "--default", "--wait", "--restart-if-timeout", "--restart-on-error", HASURA_NAME, ]).result, () => hasMinioStorage ? Promise.resolve(undefined) : runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "storage", "minio", "--provider", CLUSTER_PROVIDER, "--region", CLUSTER_REGION, "--accept-defaults", "--default", "--wait", "--restart-if-timeout", "--restart-on-error", MINIO_NAME, ]).result, () => hasIpfsStorage ? Promise.resolve(undefined) : runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "storage", "ipfs", "--provider", CLUSTER_PROVIDER, "--region", CLUSTER_REGION, "--accept-defaults", "--default", "--wait", "--restart-if-timeout", "--restart-on-error", IPFS_NAME, ]).result, ]); const [networkResult, hasuraResult, minioResult, ipfsResult] = results; expect([networkResult?.status, hasuraResult?.status, minioResult?.status, ipfsResult?.status]).toEqual([ "fulfilled", "fulfilled", "fulfilled", "fulfilled", ]); if (networkResult?.status === "fulfilled" && networkResult.value) { expect(networkResult.value.output).toInclude(`Blockchain network ${NETWORK_NAME} created successfully`); expect(networkResult.value.output).toInclude("Blockchain node is deployed"); } if (hasuraResult?.status === "fulfilled" && hasuraResult.value) { expect(hasuraResult.value.output).toInclude(`Integration tool ${HASURA_NAME} created successfully`); expect(hasuraResult.value.output).toInclude("Integration tool is deployed"); } if (minioResult?.status === "fulfilled" && minioResult.value) { expect(minioResult.value.output).toInclude(`Storage ${MINIO_NAME} created successfully`); expect(minioResult.value.output).toInclude("Storage is deployed"); } if (ipfsResult?.status === "fulfilled" && ipfsResult.value) { expect(ipfsResult.value.output).toInclude(`Storage ${IPFS_NAME} created successfully`); expect(ipfsResult.value.output).toInclude("Storage is deployed"); } const privateKeyResults = await deployResources( PRIVATE_KEY_SMART_CONTRACTS_NAMES.map((privateKeyName) => { return async () => { const hasPrivateKey = await privateKeyAlreadyCreated(privateKeyName); if (!hasPrivateKey) { const env: Partial<DotEnv> = await loadEnv(false, false); const { output: privateKeyHsmCreateCommandOutput } = await runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "private-key", "accessible-ecdsa-p256", "--blockchain-node", env.SETTLEMINT_BLOCKCHAIN_NODE!, "--accept-defaults", "--default", "--wait", "--restart-if-timeout", "--restart-on-error", privateKeyName, ]).result; expect(privateKeyHsmCreateCommandOutput).toInclude(`Private key ${privateKeyName} created successfully`); expect(privateKeyHsmCreateCommandOutput).toInclude("Private key is deployed"); } return Promise.resolve(undefined); }; }), ); expect(privateKeyResults.every((result) => result?.status === "fulfilled")).toBe(true); const hasRelayerPrivateKey = await privateKeyAlreadyCreated(RELAYER_PRIVATE_KEY_NAME); if (!hasRelayerPrivateKey) { const env: Partial<DotEnv> = await loadEnv(false, false); const { output: privateKeyRelayerCommandOutput } = await runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "private-key", "accessible-ecdsa-p256", "--blockchain-node", env.SETTLEMINT_BLOCKCHAIN_NODE!, "--accept-defaults", "--default", "--wait", "--restart-if-timeout", "--restart-on-error", RELAYER_PRIVATE_KEY_NAME, ]).result; expect(privateKeyRelayerCommandOutput).toInclude(`Private key ${RELAYER_PRIVATE_KEY_NAME} created successfully`); expect(privateKeyRelayerCommandOutput).toInclude("Private key is deployed"); } } async function createBlockchainNodes() { const hasBlockchainNodeWithPk = await blockchainNodeAlreadyCreated(NODE_NAME_2_WITH_PK); const hasBlockchainNodeWithoutPk = await blockchainNodeAlreadyCreated(NODE_NAME_3_WITHOUT_PK); const results = await deployResources([ () => hasBlockchainNodeWithPk ? Promise.resolve(undefined) : runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "blockchain-node", "besu", "--node-type", "NON_VALIDATOR", "--provider", CLUSTER_PROVIDER, "--region", CLUSTER_REGION, "--accept-defaults", "--wait", "--restart-if-timeout", "--restart-on-error", NODE_NAME_2_WITH_PK, ]).result, () => hasBlockchainNodeWithoutPk ? Promise.resolve(undefined) : runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "blockchain-node", "besu", "--node-type", "NON_VALIDATOR", "--provider", CLUSTER_PROVIDER, "--region", CLUSTER_REGION, "--accept-defaults", "--wait", "--restart-if-timeout", "--restart-on-error", NODE_NAME_3_WITHOUT_PK, ]).result, ]); const [nodeWithPkResult, nodeWithoutPkResult] = results; expect([nodeWithPkResult?.status, nodeWithoutPkResult?.status]).toEqual(["fulfilled", "fulfilled"]); if (nodeWithPkResult?.status === "fulfilled" && nodeWithPkResult.value) { expect(nodeWithPkResult.value.output).toInclude(`Blockchain node ${NODE_NAME_2_WITH_PK} created successfully`); expect(nodeWithPkResult.value.output).toInclude("Blockchain node is deployed"); } if (nodeWithoutPkResult?.status === "fulfilled" && nodeWithoutPkResult.value) { expect(nodeWithoutPkResult.value.output).toInclude( `Blockchain node ${NODE_NAME_3_WITHOUT_PK} created successfully`, ); expect(nodeWithoutPkResult.value.output).toInclude("Blockchain node is deployed"); } } async function createPrivateKeySmartcontractSetPortalAndBlockscout() { const hasPrivateKey = await defaultResourceAlreadyCreated(["SETTLEMINT_HD_PRIVATE_KEY"]); const hasPortalMiddleware = await defaultResourceAlreadyCreated(["SETTLEMINT_PORTAL"]); const hasBlockscoutInsights = await defaultResourceAlreadyCreated(["SETTLEMINT_BLOCKSCOUT"]); const relayerPrivateKey = await findPrivateKeyByName(RELAYER_PRIVATE_KEY_NAME); const env: Partial<DotEnv> = await loadEnv(false, false); const results = await deployResources([ () => hasPrivateKey ? Promise.resolve(undefined) : runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "private-key", "hd-ecdsa-p256", "--blockchain-node", env.SETTLEMINT_BLOCKCHAIN_NODE!, "--trusted-forwarder-address", "0x5e771e1417100000000000000000000000000099", "--trusted-forwarder-name", "AssetTokenizationForwarder", "--relayer-key-unique-name", relayerPrivateKey!.uniqueName, "--accept-defaults", "--default", "--wait", "--restart-if-timeout", "--restart-on-error", HD_PRIVATE_KEY_NAME, ]).result, () => hasPortalMiddleware ? Promise.resolve(undefined) : runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "middleware", "smart-contract-portal", PORTAL_NAME, "--provider", CLUSTER_PROVIDER, "--region", CLUSTER_REGION, "--accept-defaults", "--default", "--wait", "--restart-if-timeout", "--restart-on-error", "--include-predeployed-abis", "asset-tokenization", ]).result, () => hasBlockscoutInsights ? Promise.resolve(undefined) : runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "insights", "blockscout", "--provider", CLUSTER_PROVIDER, "--region", CLUSTER_REGION, "--accept-defaults", "--default", "--wait", "--restart-if-timeout", "--restart-on-error", BLOCKSCOUT_NAME, ]).result, ]); const [privateKeyResult, portalResult, blockscoutResult] = results; expect([privateKeyResult?.status, portalResult?.status, blockscoutResult?.status]).toEqual([ "fulfilled", "fulfilled", "fulfilled", ]); if (privateKeyResult?.status === "fulfilled" && privateKeyResult.value) { expect(privateKeyResult.value.output).toInclude(`Private key ${HD_PRIVATE_KEY_NAME} created successfully`); expect(privateKeyResult.value.output).toInclude("Private key is deployed"); } if (portalResult?.status === "fulfilled" && portalResult.value) { expect(portalResult.value.output).toInclude(`Middleware ${PORTAL_NAME} created successfully`); expect(portalResult.value.output).toInclude("Middleware is deployed"); } if (blockscoutResult?.status === "fulfilled" && blockscoutResult.value) { expect(blockscoutResult.value.output).toInclude(`Insights ${BLOCKSCOUT_NAME} created successfully`); expect(blockscoutResult.value.output).toInclude("Insights is deployed"); } } async function createGraphMiddlewareAndActivatedPrivateKey() { const hasGraphMiddleware = await defaultResourceAlreadyCreated(["SETTLEMINT_THEGRAPH"]); const hasPrivateKey2 = await privateKeyAlreadyCreated(PRIVATE_KEY_NODE_2_NAME); const blockchainNodeWithPk = await findBlockchainNodeByName(NODE_NAME_2_WITH_PK); const loadBalancer = await findLoadBalancerByName(LOAD_BALANCER_NAME); const results = await deployResources([ () => hasGraphMiddleware ? Promise.resolve(undefined) : runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "middleware", "graph", "--load-balancer", loadBalancer!.uniqueName, "--provider", CLUSTER_PROVIDER, "--region", CLUSTER_REGION, "--accept-defaults", "--default", "--wait", "--restart-if-timeout", "--restart-on-error", GRAPH_NAME, ]).result, () => hasPrivateKey2 ? Promise.resolve(undefined) : runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "private-key", "hsm-ecdsa-p256", "--blockchain-node", blockchainNodeWithPk!.uniqueName, "--accept-defaults", "--wait", "--restart-if-timeout", "--restart-on-error", PRIVATE_KEY_NODE_2_NAME, ]).result, ]); const [graphMiddlewareResult, privateKey2Result] = results; expect([graphMiddlewareResult?.status, privateKey2Result?.status]).toEqual(["fulfilled", "fulfilled"]); if (graphMiddlewareResult?.status === "fulfilled" && graphMiddlewareResult.value) { expect(graphMiddlewareResult.value.output).toInclude(`Middleware ${GRAPH_NAME} created successfully`); expect(graphMiddlewareResult.value.output).toInclude("Middleware is deployed"); } if (privateKey2Result?.status === "fulfilled" && privateKey2Result.value) { expect(privateKey2Result.value.output).toInclude(`Private key ${PRIVATE_KEY_NODE_2_NAME} created successfully`); expect(privateKey2Result.value.output).toInclude("Private key is deployed"); } } async function createLoadBalancer() { const hasLoadBalancer = await defaultResourceAlreadyCreated(["SETTLEMINT_BLOCKCHAIN_NODE_OR_LOAD_BALANCER"]); if (!hasLoadBalancer) { const blockchainNodeWithPk = await findBlockchainNodeByName(NODE_NAME_2_WITH_PK); const blockchainNodeWithoutPk = await findBlockchainNodeByName(NODE_NAME_3_WITHOUT_PK); const { output: loadBalancerCreateCommandOutput } = await runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "load-balancer", "evm", "--blockchain-nodes", blockchainNodeWithPk!.uniqueName, blockchainNodeWithoutPk!.uniqueName, "--provider", CLUSTER_PROVIDER, "--region", CLUSTER_REGION, "--accept-defaults", "--default", "--wait", "--restart-if-timeout", "--restart-on-error", LOAD_BALANCER_NAME, ]).result; expect(loadBalancerCreateCommandOutput).toInclude(`Load balancer ${LOAD_BALANCER_NAME} created successfully`); expect(loadBalancerCreateCommandOutput).toInclude("Load balancer is deployed"); } } async function login() { const { output: loginOutput } = await runCommand( COMMAND_TEST_SCOPE, ["login", "--token-stdin", "--accept-defaults"], { stdin: process.env.SETTLEMINT_ACCESS_TOKEN_E2E_TESTS, }, ).result; expect(loginOutput).toInclude("Successfully logged in to SettleMint!"); } async function logout() { const { output: logoutOutput } = await runCommand(COMMAND_TEST_SCOPE, ["logout", "--all"]).result; expect(logoutOutput).toInclude("Successfully logged out from all instances"); } async function createApplicationAccessToken() { const hasAat = await defaultResourceAlreadyCreated(["SETTLEMINT_ACCESS_TOKEN"]); if (hasAat) { return; } const { output: graphOutput } = await runCommand(COMMAND_TEST_SCOPE, [ "platform", "create", "aat", "--validity-period", "NONE", "--accept-defaults", "--default", AAT_NAME, ]).result; expect(graphOutput).toInclude(`Application access token ${AAT_NAME} created successfully`); } async function deployResources(commands: (() => Promise<CommandResult | undefined>)[]) { if (DISABLE_CONCURRENT_DEPLOYMENT) { console.log("Disabling concurrent deployment, running commands sequentially"); const results: PromiseSettledResult<undefined | CommandResult>[] = []; for (const command of commands) { try { const result = await command(); results.push({ status: "fulfilled", value: result, }); } catch (err) { results.push({ status: "rejected", reason: err, }); } } return results; } return await Promise.allSettled(commands.map((command) => command())); } export async function prepareTestApp() { const cwd = process.cwd(); try { const testAppDir = join(__dirname, "../test-app"); await mkdir(testAppDir, { recursive: true }); console.log("Copying .env in", testAppDir); if (await exists(join(__dirname, "../../.env"))) { await copyFile(join(__dirname, "../../.env"), join(testAppDir, ".env")); } if (await exists(join(__dirname, "../../.env.local"))) { await copyFile(join(__dirname, "../../.env.local"), join(testAppDir, ".env.local")); } console.log("Running codegen in", testAppDir); await runCommand(COMMAND_TEST_SCOPE, ["codegen"], { cwd: testAppDir, }).result; } finally { process.chdir(cwd); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/settlemint/sdk'

If you have feedback or need assistance with the MCP directory API, please join our Discord server