From a064d39f530d1048dc70cc65a30ff907b429f7b9 Mon Sep 17 00:00:00 2001 From: Brit Myers Date: Sun, 19 Oct 2025 01:20:58 -0400 Subject: [PATCH 1/2] chore(sdf-api-test): Refactor tests to not rely on SchemaVariantCategories With the removal of SchemaVariantCategories, these tests need to be updated to not rely on them. We were previously using this MV to determine whether various Schemas used in tests were installed or not, as SDF still requires the caller to pass in this information. The following updates were made: - Add support for fetching the deployment index and deployment MVs - Create a test helper that creates the correct component payload, based on whether the schema in question is installed or not - Update all tests to use the new helper - Update 8-check_mjolnir, which was directly relying on SchemaVariantCategories to determine that a variant was installed when the component was created for it. Replace this with checking for the LuminorkDefaultVariant - Update 2-create_and_apply_across_change_sets to hardcode the `SchemaId` for the `TestResourceActions` Schema, which is a special asset we use only for that test that exists in the module index --- bin/si-sdf-api-test/sdf_api_client.ts | 101 ++- bin/si-sdf-api-test/test_helpers.ts | 145 ++-- bin/si-sdf-api-test/tests/0-add_action.ts | 26 +- .../1-create_and_apply_across_change_sets.ts | 43 +- .../tests/2-create_and_upgrade_component.ts | 54 +- ...te_two_components_connect_and_propagate.ts | 21 +- .../tests/5-emulate_paul_stack.ts | 104 +-- .../tests/7-emulate_authoring.ts | 707 +++++++++--------- bin/si-sdf-api-test/tests/8-check_mjolnir.ts | 222 +++--- 9 files changed, 807 insertions(+), 616 deletions(-) diff --git a/bin/si-sdf-api-test/sdf_api_client.ts b/bin/si-sdf-api-test/sdf_api_client.ts index de02fe176e..11f78f848b 100644 --- a/bin/si-sdf-api-test/sdf_api_client.ts +++ b/bin/si-sdf-api-test/sdf_api_client.ts @@ -156,6 +156,21 @@ export const ROUTES = { `/v2/workspaces/${vars.workspaceId}/change-sets/${vars.changeSetId}/index/multi_mjolnir`, method: "POST", }, + deployment_mjolnir: { + path: (vars: ROUTE_VARS) => + `/v2/workspaces/${vars.workspaceId}/mjolnir?kind=${vars.referenceKind}&id=${vars.materializedViewId}`, + method: "POST", + }, + deployment_multi_mjolnir: { + path: (vars: ROUTE_VARS) => + `/v2/workspaces/${vars.workspaceId}/multi_mjolnir`, + method: "POST", + }, + deployment_index: { + path: (vars: ROUTE_VARS) => + `/v2/workspaces/${vars.workspaceId}/deployment_index`, + method: "GET", + }, // Websockets ----------------------------------------- workspace_updates_ws: { @@ -329,7 +344,7 @@ export class SdfApiClient { await retryUntil( async () => { - const dvuRoots = await this.mjolnir( + const dvuRoots = await this.changeSetMjolnir( changeSetId, "DependentValueComponentList", this.workspaceId, @@ -377,7 +392,7 @@ export class SdfApiClient { } // Helper functions for interacting with MVs - public async mjolnir( + public async changeSetMjolnir( changeSetId: string, kind: string, id: string, @@ -414,7 +429,7 @@ export class SdfApiClient { return null; } - public async multiMjolnir( + public async changeSetMultiMjolnir( changeSetId: string, mvs: { kind: string; id: string }[], ) { @@ -451,6 +466,86 @@ export class SdfApiClient { } } + public async deploymentMultiMjolnir(mvs: { kind: string; id: string }[]) { + const response = await this.call( + { + route: "deployment_multi_mjolnir", + body: { requests: mvs }, + }, + true, + ); + + if (response?.status === 200) { + try { + const json = await response.json(); + if (json.failed && json.failed.length > 0) { + console.warn( + "Some MVs were not found during multi mjolnir:", + json.failed, + ); + } + return json.successful.map((v: any) => v.frontEndObject.data); + } catch (err) { + console.error("Error trying to parse response body as JSON", err); + throw new Error(`Error trying to parse response body as JSON: ${err}`); + } + } else { + // Fail on non-200 errors + console.error( + `Error ${response.status}: Unable to fetch multiple Deployment MVs:`, + await response.text(), + ); + throw new Error(`Error ${response.status}: ${await response.text()}`); + } + } + + public async fetchDeploymentIndex(): Promise { + const response = await this.call( + { + route: "deployment_index", + }, + true, + ); + if (response?.status === 200) { + const json = await response.json(); + return json; + } else { + console.warn(`Deployment index missing! This is bad!`); + throw new Error(`Deployment index missing! This is bad!`); + } + } + + public async deploymentMjolnir( + kind: string, + id: string, + ): Promise { + const response = await this.call( + { + route: "deployment_mjolnir", + routeVars: { materializedViewId: id, referenceKind: kind }, + }, + true, + ); + if (response?.status === 200) { + try { + const json = await response.json(); + return json.data; + } catch (err) { + console.error("Error trying to parse response body as JSON", err); + } + } else { + console.warn( + `Deployment Materialized view for ${kind} with ID ${id} not found`, + ); + throw new Error( + "Deployment Materialized view not found for kind: " + + kind + + ", id: " + + id, + ); + } + } + public async fetchChangeSetIndex( changeSetId: string, timeout_ms: number = 150000, diff --git a/bin/si-sdf-api-test/test_helpers.ts b/bin/si-sdf-api-test/test_helpers.ts index f2db55368c..a1afab7dc3 100644 --- a/bin/si-sdf-api-test/test_helpers.ts +++ b/bin/si-sdf-api-test/test_helpers.ts @@ -254,40 +254,6 @@ export async function createComponent( return newComponentId; } -export function createComponentPayload( - schemaVariantCategoriesMV: any, - schemaName: string, -) { - const installedVariant = schemaVariantCategoriesMV.installed?.find( - (sv: any) => sv.schemaName === schemaName, - ); - if (installedVariant) { - return { - schemaVariantId: installedVariant.schemaVariantId, - x: "0", - y: "0", - height: "0", - width: "0", - parentId: null, - schemaType: "installed", - }; - } else { - const uninstalledVariant = schemaVariantCategoriesMV.uninstalled?.find( - (sv: any) => sv.schemaName === schemaName, - ); - assert(uninstalledVariant, `Expected to find ${schemaName} schema variant`); - return { - schemaId: uninstalledVariant.schemaId, - schemaType: "uninstalled", - x: "0", - y: "0", - height: "0", - width: "0", - parentId: null, - }; - } -} - // Func Helpers ------------------------------------------------------------ export async function getFuncRun( @@ -419,7 +385,7 @@ export async function abandon_all_change_sets(sdf: SdfApiClient) { } export async function getActions(sdf: SdfApiClient, changeSetId: string) { - const actions = await sdf.mjolnir( + const actions = await sdf.changeSetMjolnir( changeSetId, "ActionViewList", sdf.workspaceId, @@ -428,52 +394,85 @@ export async function getActions(sdf: SdfApiClient, changeSetId: string) { return actions; } -export async function getVariants(sdf: SdfApiClient, changeSetId: string) { - const schemas = await sdf.mjolnir( - changeSetId, - "SchemaVariantCategories", - sdf.workspaceId, +// Used to generate the correct payload for sdf +// If not given a Schema Id, assume it's a builtin, and find +// the Id by the name by looking at the CachedSchemas Deployment MV +// If given a schema Id, just try to find an installed one +export async function createComponentPayload( + sdf: SdfApiClient, + changeSetId: string, + schemaName: string, + schemaId?: string, +) { + const deploymentIndex = await sdf.fetchDeploymentIndex(); + // console.log(deploymentIndex); + + const cachedSchemasMV = deploymentIndex.frontEndObject.data.mvList.find( + (mv: any) => mv.kind === "CachedSchemas", ); - assert(schemas, "Expected to get schemas MV"); - - const installedList: { kind: string; id: string }[] = - schemas.categories.flatMap((c: any) => - c.schemaVariants - .filter((v: any) => v.type === "installed") - .map((v: any) => { - return { - kind: "SchemaVariant", - id: v.id, - }; - }), + const cachedSchemasMVId = cachedSchemasMV.id; + let actualSchemaId = undefined; + if (!schemaId) { + // Get the builtin version, so we can get the Schema Id as we only have the name + const builtins = await sdf.deploymentMjolnir( + "CachedSchemas", + cachedSchemasMVId, + ); + + assert(builtins, "Expected to get schemas MV"); + let foundSchema = builtins.schemas.find( + (schema: { id: string; name: string }) => schema.name === schemaName, ); - let installed = []; - if (installedList.length > 0) { - let installedResp = await sdf.multiMjolnir(changeSetId, installedList); - assert(installedResp, "Expected to get installed variants data"); - installed = installedResp; + assert(foundSchema, `Expected to find id for Schema Name ${schemaName}`); + actualSchemaId = foundSchema.id; + assert(actualSchemaId, `Expected to find id for Schema Name ${schemaName}`); + } else { + actualSchemaId = schemaId; } - const uninstalled = schemas.categories.flatMap((c: any) => - c.schemaVariants - .filter((v: any) => v.type === "uninstalled") - .map((v: any) => { - const uninstalledMeta = schemas.uninstalled?.[v.id]; - assert( - uninstalledMeta, - `Expected uninstalled metadata for schemaId ${v.id}`, - ); - return uninstalledMeta; - }), - ); - return { installed, uninstalled }; + assert(actualSchemaId, "we have a valid schema Id!"); + try { + // First is it installed? + const maybeInstalled = await sdf.changeSetMjolnir( + changeSetId, + "LuminorkDefaultVariant", + actualSchemaId, + ); + // if so, return it + return { + schemaVariantId: maybeInstalled.variantId, + x: "0", + y: "0", + height: "0", + width: "0", + parentId: null, + schemaType: "installed", + }; + } catch (e) { + console.log( + `LuminorkDefaultVariant not found for ${schemaName}, assuming it's uninstalled`, + ); + return { + schemaId: actualSchemaId, + schemaType: "uninstalled", + x: "0", + y: "0", + height: "0", + width: "0", + parentId: null, + }; + } } export async function getViews(sdf: SdfApiClient, changeSetId: string) { - const viewsList = await sdf.mjolnir(changeSetId, "ViewList", sdf.workspaceId); + const viewsList = await sdf.changeSetMjolnir( + changeSetId, + "ViewList", + sdf.workspaceId, + ); assert(viewsList, "Expected to get views MV"); let viewsToFetch = viewsList.views; - let views = await sdf.multiMjolnir(changeSetId, viewsToFetch); + let views = await sdf.changeSetMultiMjolnir(changeSetId, viewsToFetch); assert(views, "Expected to get views data"); return views; } @@ -493,7 +492,7 @@ export async function eventualMVAssert( } await retryUntil( async () => { - const mv = await sdf.mjolnir(changeSetId, kind, id); + const mv = await sdf.changeSetMjolnir(changeSetId, kind, id); if (mv) { try { if (assertFn(mv)) { diff --git a/bin/si-sdf-api-test/tests/0-add_action.ts b/bin/si-sdf-api-test/tests/0-add_action.ts index a8e2e8135c..bae82b65e1 100644 --- a/bin/si-sdf-api-test/tests/0-add_action.ts +++ b/bin/si-sdf-api-test/tests/0-add_action.ts @@ -1,6 +1,13 @@ import assert from "node:assert"; import { SdfApiClient } from "../sdf_api_client.ts"; -import { createComponent, createComponentPayload, eventualMVAssert, getActions, getVariants, getViews, runWithTemporaryChangeset } from "../test_helpers.ts"; +import { + createComponent, + createComponentPayload, + eventualMVAssert, + getActions, + getViews, + runWithTemporaryChangeset, +} from "../test_helpers.ts"; export default async function add_action(sdfApiClient: SdfApiClient) { return runWithTemporaryChangeset(sdfApiClient, add_action_inner); @@ -14,12 +21,14 @@ export async function add_action_inner( // Store the original length of actions to verify later assert(Array.isArray(data.actions), "Expected actions to be an array"); - const actionOriginalLength = data.actions.length; // Get all Schema Variants - let schemaVariants = await getVariants(sdfApiClient, changeSetId); - let createComponentBody = createComponentPayload(schemaVariants, "AWS::EC2::Instance"); + let createComponentBody = await createComponentPayload( + sdfApiClient, + changeSetId, + "AWS::EC2::Instance", + ); // Get the views and find the default one const views = await getViews(sdfApiClient, changeSetId); @@ -40,8 +49,13 @@ export async function add_action_inner( changeSetId, "ActionViewList", sdfApiClient.workspaceId, - (mv) => { return mv.actions.some((action: any) => action.componentId === newComponentId) && mv.actions.length === actionOriginalLength + 1; }, + (mv) => { + return ( + mv.actions.some( + (action: any) => action.componentId === newComponentId, + ) && mv.actions.length === actionOriginalLength + 1 + ); + }, "No action with the expected componentId found", ); - } diff --git a/bin/si-sdf-api-test/tests/1-create_and_apply_across_change_sets.ts b/bin/si-sdf-api-test/tests/1-create_and_apply_across_change_sets.ts index 03f715e83a..c4cae8eb1c 100644 --- a/bin/si-sdf-api-test/tests/1-create_and_apply_across_change_sets.ts +++ b/bin/si-sdf-api-test/tests/1-create_and_apply_across_change_sets.ts @@ -5,7 +5,6 @@ import { createComponent, createComponentPayload, eventualMVAssert, - getVariants, getViews, installModule, } from "../test_helpers.ts"; @@ -15,7 +14,8 @@ export default async function create_and_and_apply_across_change_sets( ) { return await create_and_and_apply_across_change_sets_inner(sdfApiClient); } -const TEST_RESOURCE_ACTION_MODULE_ID = "01JMJB1QW3M8D7MNN8NGBR739J"; +const TEST_RESOURCE_ACTION_MODULE_ID = "01JMJB1QW3M8D7MNN8NGBR739J"; // From module index +const TEST_RESOURCE_SCHEMA_ID = "01J85S2MXMFPJVW6FP3N9K4WSE"; // From module index - static id async function create_and_and_apply_across_change_sets_inner( sdf: SdfApiClient, ) { @@ -35,15 +35,15 @@ async function create_and_and_apply_across_change_sets_inner( const defaultView = views.find((v: any) => v.isDefault); assert(defaultView, "Expected to find a default view"); - let schemaVariants = await getVariants(sdf, changeSetId); - + let createComponentMaybeUninstalled = await createComponentPayload( + sdf, + changeSetId, + "TestResourceActions", + TEST_RESOURCE_SCHEMA_ID, + ); // first let's make sure our test asset is installed // this is really just so we can run this against any workspace - if ( - !schemaVariants.installed.some( - (v: any) => v.schemaName === "TestResourceActions", - ) - ) { + if (createComponentMaybeUninstalled.schemaType === "uninstalled") { const installResult = await installModule( sdf, changeSetId, @@ -54,7 +54,6 @@ async function create_and_and_apply_across_change_sets_inner( installResult[0]?.schemaVariantId, "Expected to get a schemaVariantId after installing TestResourceActions module", ); - const installedVariantId = installResult[0].schemaVariantId; console.log( "Installing TestResourceActions schema variant...", installResult, @@ -62,32 +61,24 @@ async function create_and_and_apply_across_change_sets_inner( await eventualMVAssert( sdf, changeSetId, - "SchemaVariantCategories", - sdf.workspaceId, + "LuminorkDefaultVariant", + TEST_RESOURCE_SCHEMA_ID, (mv) => { - const installedList: string[] = mv.categories.flatMap((c: any) => - c.schemaVariants - .filter((v: any) => v.type === "installed") - .map((v: any) => { - return v.id; - }), - ); - console.log("Installed Schema Variants:", installedList); - console.log("Expected Schema Variant ID:", installedVariantId); - return installedList.some((v: any) => v === installedVariantId); + return mv?.id === TEST_RESOURCE_SCHEMA_ID; }, "Expected TestResourceActions schema variant to be installed", ); - schemaVariants = await getVariants(sdf, changeSetId); } // Create a component with the TestResourceActions schema variant console.log( "Creating a component with the TestResourceActions schema variant...", ); - let createComponentBody = createComponentPayload( - schemaVariants, + let createComponentBody = await createComponentPayload( + sdf, + changeSetId, "TestResourceActions", + TEST_RESOURCE_SCHEMA_ID, ); const newComponentId = await createComponent( sdf, @@ -159,7 +150,7 @@ async function cleanupHead(sdf: SdfApiClient): Promise { const changeSetId = await createChangeSet(sdf); const workspaceId = sdf.workspaceId; - const components = await sdf.mjolnir( + const components = await sdf.changeSetMjolnir( changeSetId, "ComponentList", workspaceId, diff --git a/bin/si-sdf-api-test/tests/2-create_and_upgrade_component.ts b/bin/si-sdf-api-test/tests/2-create_and_upgrade_component.ts index efcadaac45..792bd2e5b7 100644 --- a/bin/si-sdf-api-test/tests/2-create_and_upgrade_component.ts +++ b/bin/si-sdf-api-test/tests/2-create_and_upgrade_component.ts @@ -1,6 +1,12 @@ import assert from "node:assert"; import { SdfApiClient } from "../sdf_api_client.ts"; -import { createComponent, createComponentPayload, eventualMVAssert, getVariants, getViews, runWithTemporaryChangeset } from "../test_helpers.ts"; +import { + createComponent, + createComponentPayload, + eventualMVAssert, + getViews, + runWithTemporaryChangeset, +} from "../test_helpers.ts"; export default async function create_and_upgrade_component( sdfApiClient: SdfApiClient, @@ -20,9 +26,11 @@ async function create_and_upgrade_component_inner( sdfApiClient: SdfApiClient, changeSetId: string, ) { - // Get all Schema Variants - let schemaVariants = await getVariants(sdfApiClient, changeSetId); - let createComponentBody = createComponentPayload(schemaVariants, "Region"); + let createComponentBody = await createComponentPayload( + sdfApiClient, + changeSetId, + "Region", + ); // Get the views and find the default one const views = await getViews(sdfApiClient, changeSetId); @@ -37,20 +45,37 @@ async function create_and_upgrade_component_inner( createComponentBody, ); assert(newComponentId, "Expected to get a component id after creation"); - const region = await sdfApiClient.mjolnir(changeSetId, "Component", newComponentId); + const region = await sdfApiClient.changeSetMjolnir( + changeSetId, + "Component", + newComponentId, + ); assert(region, "Expected to get a region after creation"); const originalSchemaVariantId = region.schemaVariantId.id; - assert(originalSchemaVariantId, "Expected to get a schema variant id after creation"); + assert( + originalSchemaVariantId, + "Expected to get a schema variant id after creation", + ); const schemaId = region.schemaId; assert(schemaId, "Expected to get a schema id after creation"); // ensure this schema is the default variant and there is no editing variant - const schemaMembers = await sdfApiClient.mjolnir(changeSetId, "SchemaMembers", schemaId); + const schemaMembers = await sdfApiClient.changeSetMjolnir( + changeSetId, + "SchemaMembers", + schemaId, + ); assert(schemaMembers, "Expected to get a schema after creation"); - assert(schemaMembers.defaultVariantId === originalSchemaVariantId, "Expected default variant to match original schema variant id"); - assert(schemaMembers.editingVariantId === null, "Expected no editing variant for the schema"); + assert( + schemaMembers.defaultVariantId === originalSchemaVariantId, + "Expected default variant to match original schema variant id", + ); + assert( + schemaMembers.editingVariantId === null, + "Expected no editing variant for the schema", + ); - // unlock the region schema variant + // unlock the region schema variant const newSchemaVariant = await sdfApiClient.call({ route: "create_unlocked_copy", routeVars: { @@ -59,7 +84,10 @@ async function create_and_upgrade_component_inner( schemaVariantId: originalSchemaVariantId, }, }); - assert(newSchemaVariant, "Expected to get a new schema variant after unlocking"); + assert( + newSchemaVariant, + "Expected to get a new schema variant after unlocking", + ); console.log("Created new schema variant:", newSchemaVariant); // see that the component has an upgrade available @@ -68,7 +96,9 @@ async function create_and_upgrade_component_inner( changeSetId, "SchemaMembers", schemaId, - (mv) => mv.defaultVariantId === originalSchemaVariantId && mv.editingVariantId !== null, + (mv) => + mv.defaultVariantId === originalSchemaVariantId && + mv.editingVariantId !== null, "Component MV should have upgradeAvailable set to true", ); // upgrade the component diff --git a/bin/si-sdf-api-test/tests/4-create_two_components_connect_and_propagate.ts b/bin/si-sdf-api-test/tests/4-create_two_components_connect_and_propagate.ts index 4b52d49a18..7b062c1522 100644 --- a/bin/si-sdf-api-test/tests/4-create_two_components_connect_and_propagate.ts +++ b/bin/si-sdf-api-test/tests/4-create_two_components_connect_and_propagate.ts @@ -4,9 +4,7 @@ import { createComponent, createComponentPayload, eventualMVAssert, - getVariants, getViews, - retryWithBackoff, runWithTemporaryChangeset, } from "../test_helpers.ts"; @@ -31,25 +29,26 @@ async function create_two_components_connect_and_propagate_inner( sdf: SdfApiClient, changeSetId: string, ) { - // Get the schema variants (uninstalled and installed) - let schemaVariants = await getVariants(sdf, changeSetId); - // Get the views and find the default one const views = await getViews(sdf, changeSetId); const defaultView = views.find((v: any) => v.isDefault); assert(defaultView, "Expected to find a default view"); // Create three components, an EC2 Instance, a Region, and a Credential - let createEC2ComponentBody = createComponentPayload( - schemaVariants, + let createEC2ComponentBody = await createComponentPayload( + sdf, + changeSetId, "AWS::EC2::Instance", ); - let createRegionComponentBody = createComponentPayload( - schemaVariants, + + let createRegionComponentBody = await createComponentPayload( + sdf, + changeSetId, "Region", ); - let createCredentialComponentBody = createComponentPayload( - schemaVariants, + let createCredentialComponentBody = await createComponentPayload( + sdf, + changeSetId, "AWS Credential", ); const newEC2ComponentId = await createComponent( diff --git a/bin/si-sdf-api-test/tests/5-emulate_paul_stack.ts b/bin/si-sdf-api-test/tests/5-emulate_paul_stack.ts index 49a2aec11e..4baa6b6894 100644 --- a/bin/si-sdf-api-test/tests/5-emulate_paul_stack.ts +++ b/bin/si-sdf-api-test/tests/5-emulate_paul_stack.ts @@ -5,10 +5,9 @@ import { runWithTemporaryChangeset, sleepBetween, createComponent, - getVariants, - createComponentPayload, getViews, eventualMVAssert, + createComponentPayload, } from "../test_helpers.ts"; export default async function emulate_paul_stack(sdfApiClient: SdfApiClient) { @@ -20,9 +19,11 @@ async function emulate_paul_stack_inner( sdf: SdfApiClient, changeSetId: string, ) { - // Get the schema variants (uninstalled and installed) - let schemaVariants = await getVariants(sdf, changeSetId); - let createRegionBody = createComponentPayload(schemaVariants, "Region"); + let createRegionBody = await createComponentPayload( + sdf, + changeSetId, + "Region", + ); // Get the views and find the default one const views = await getViews(sdf, changeSetId); @@ -49,10 +50,12 @@ async function emulate_paul_stack_inner( }, }); - - // CREATE VPC - let createVPCBody = createComponentPayload(schemaVariants, "AWS::EC2::VPC"); + let createVPCBody = await createComponentPayload( + sdf, + changeSetId, + "AWS::EC2::VPC", + ); const vpcComponentId = await createComponent( sdf, changeSetId, @@ -70,10 +73,10 @@ async function emulate_paul_stack_inner( }, body: { "/domain/extra/Region": { - "$source": { - "component": regionComponentId, - "path": "/domain/region", - } + $source: { + component: regionComponentId, + path: "/domain/region", + }, }, }, }); @@ -84,14 +87,14 @@ async function emulate_paul_stack_inner( changeSetId, "AttributeTree", vpcComponentId, - (mv) => Object.values(mv.attributeValues).some( - (av: any) => av.path === "/domain/extra/Region" && - av.externalSources.length === 1, - ), + (mv) => + Object.values(mv.attributeValues).some( + (av: any) => + av.path === "/domain/extra/Region" && av.externalSources.length === 1, + ), "Expected VPC to be subscribed to Region", ); - // CONFIGURE VPC const updateVpcResponse = await sdf.call({ route: "attributes", @@ -113,17 +116,20 @@ async function emulate_paul_stack_inner( changeSetId, "AttributeTree", vpcComponentId, - (mv) => Object.values(mv.attributeValues).some( - (av: any) => av.path === "/domain/CidrBlock" && - av.value === "10.0.0.0/16" - ), - "Expected VPC to have CidrBlock set to 10.0.0.0/16" + (mv) => + Object.values(mv.attributeValues).some( + (av: any) => + av.path === "/domain/CidrBlock" && av.value === "10.0.0.0/16", + ), + "Expected VPC to have CidrBlock set to 10.0.0.0/16", ); - // Public Subnet Components - const createSubnetBody = createComponentPayload(schemaVariants, "AWS::EC2::Subnet"); - + const createSubnetBody = await createComponentPayload( + sdf, + changeSetId, + "AWS::EC2::Subnet", + ); for (const { index, data } of [ { CidrBlock: "10.0.128.0/20", AvailabilityZone: "us-east-1a" }, @@ -147,15 +153,15 @@ async function emulate_paul_stack_inner( }, body: { "/domain/extra/Region": { - "$source": { - "component": regionComponentId, - "path": "/domain/region", + $source: { + component: regionComponentId, + path: "/domain/region", }, }, "/domain/VpcId": { - "$source": { - "component": vpcComponentId, - "path": "/resource_value/VpcId", + $source: { + component: vpcComponentId, + path: "/resource_value/VpcId", }, }, }, @@ -166,11 +172,13 @@ async function emulate_paul_stack_inner( changeSetId, "AttributeTree", subnetComponentId, - (mv) => Object.values(mv.attributeValues).some( - (av: any) => av.path === "/domain/extra/Region" && - av.externalSources.length === 1 && - av.externalSources[0].path === "/domain/region", - ), + (mv) => + Object.values(mv.attributeValues).some( + (av: any) => + av.path === "/domain/extra/Region" && + av.externalSources.length === 1 && + av.externalSources[0].path === "/domain/region", + ), "Expected Subnet to be subscribed to Region", ); @@ -210,7 +218,11 @@ async function emulate_paul_stack_inner( }); await sdf.waitForDVURoots(changeSetId, 500, 30000); // verify that the region value propagated to the vpc and subnets - const componentsToCheck = await sdf.mjolnir(changeSetId, "ComponentList", sdf.workspaceId); + const componentsToCheck = await sdf.changeSetMjolnir( + changeSetId, + "ComponentList", + sdf.workspaceId, + ); const componentIds = componentsToCheck.components.map((c) => c.id); for (const id of componentIds) { await eventualMVAssert( @@ -218,17 +230,15 @@ async function emulate_paul_stack_inner( changeSetId, "AttributeTree", id, - (mv) => Object.values(mv.attributeValues).some( - (av: any) => av.path === "/domain/extra/Region" && - av.value === "us-east-1", - ) || Object.values(mv.attributeValues).some( - (av: any) => av.path === "/domain/region" && - av.value === "us-east-1", - ), + (mv) => + Object.values(mv.attributeValues).some( + (av: any) => + av.path === "/domain/extra/Region" && av.value === "us-east-1", + ) || + Object.values(mv.attributeValues).some( + (av: any) => av.path === "/domain/region" && av.value === "us-east-1", + ), `Expected component ${id} to have region set to us-east-1`, ); } } - - - diff --git a/bin/si-sdf-api-test/tests/7-emulate_authoring.ts b/bin/si-sdf-api-test/tests/7-emulate_authoring.ts index c1dbf08ca5..dc3f384da7 100644 --- a/bin/si-sdf-api-test/tests/7-emulate_authoring.ts +++ b/bin/si-sdf-api-test/tests/7-emulate_authoring.ts @@ -2,217 +2,255 @@ import assert from "node:assert"; import { SdfApiClient } from "../sdf_api_client.ts"; import { - runWithTemporaryChangeset, - sleepBetween, - createAsset, - updateAssetCode, - nilId, - createQualification, - eventualMVAssert, - getViews, + runWithTemporaryChangeset, + sleepBetween, + createAsset, + updateAssetCode, + nilId, + createQualification, + eventualMVAssert, + getViews, } from "../test_helpers.ts"; export default async function emulate_authoring(sdfApiClient: SdfApiClient) { - await sleepBetween(0, 750); - return runWithTemporaryChangeset(sdfApiClient, emulate_authoring_inner); + await sleepBetween(0, 750); + return runWithTemporaryChangeset(sdfApiClient, emulate_authoring_inner); } -async function emulate_authoring_inner(sdf: SdfApiClient, - changeSetId: string, -) { - - // Get the views and find the default one - const views = await getViews(sdf, changeSetId); - const defaultView = views.find((v: any) => v.isDefault); - assert(defaultView, "Expected to find a default view"); - - // Create new asset - let schemaVariantId = await createAsset(sdf, changeSetId, "doubler"); - - // wait for and verify schema variant MV - await eventualMVAssert( - sdf, - changeSetId, - "SchemaVariant", - schemaVariantId, - (mv) => mv.id === schemaVariantId, - "SchemaVariant MV should exist and have matching id" - ); - - // Update Code and Regenerate - schemaVariantId = await updateAssetCode(sdf, changeSetId, schemaVariantId, doublerAssetCode); - - await eventualMVAssert( - sdf, - changeSetId, - "SchemaVariant", - schemaVariantId, - (mv) => { - const props = Object.values(mv.propTree?.props) || []; - return mv.id === schemaVariantId && - props.some((p: any) => p.path === "root/domain/input") && - props.some((p: any) => p.path === "root/domain/doubled"); - }, - "SchemaVariant MV should exist and have added input/doubled props" - ); - let doublerVariant = await sdf.mjolnir(changeSetId, "SchemaVariant", schemaVariantId); - assert(doublerVariant?.propTree?.props, "Expected props list"); - - let doublerProps = Object.values(doublerVariant.propTree.props); - - assert(Array.isArray(doublerProps), "Expected props to be an array"); - // Add an attribute function - const outputProp = doublerProps.find((p: any) => p.path === "root/domain/doubled"); - assert(outputProp, "Expected to find doubled prop"); - let inputProp: any = doublerProps.find((p: any) => p.path === "root/domain/input"); - assert(inputProp, "Expected to find input prop"); - const args = [ - { - name: "input", - kind: "string", - propId: inputProp.id, - inputSocketId: null, - }, - ]; - - const doubleFuncId = await createAttributeFunction(sdf, changeSetId, "double", doublerVariant.id, doubleFuncCode, outputProp.id, args); - let createComponentBody = { - "schemaVariantId": schemaVariantId, - "x": "0", - "y": "0", - "height": "0", - "width": "0", - "parentId": null, - "schemaType": "installed" - - }; - - // create a component for the doubler - const createComponentResp = await sdf.call({ - route: "create_component_v2", - routeVars: { - workspaceId: sdf.workspaceId, - changeSetId, - viewId: defaultView.id, - }, - body: createComponentBody, - }); - const doublerComponentId = createComponentResp?.componentId; - assert(doublerComponentId, "Expected to get a component id after creation"); - await eventualMVAssert( - sdf, - changeSetId, - "Component", - doublerComponentId, - (mv) => mv.id === doublerComponentId && mv.qualificationTotals.succeeded === 0, - "Component MV should exist" - ); - - // update input prop to be a number - const updateRegionResponse = await sdf.call({ - route: "attributes", - routeVars: { - workspaceId: sdf.workspaceId, - changeSetId, - componentId: doublerComponentId, - }, - body: { - "/domain/input": "2", - }, - }); - - await eventualMVAssert( - sdf, - changeSetId, - "AttributeTree", - doublerComponentId, - (mv) => Object.values(mv.attributeValues).some( - (av: any) => av.path === "/domain/input" && - av.value === "2", - ), - "Expected value to be set for domain/input", - ); - - - // now add a qualification and check that the component gets it - const qualification = await createQualification( - sdf, - changeSetId, "doublerQualification", - schemaVariantId, - doublerQualificationCode - ); - - - // it is failing - await eventualMVAssert( - sdf, - changeSetId, - "Component", - doublerComponentId, - (mv) => mv.qualificationTotals.failed === 1, - "Component should have a failed qualification now", - ); - - - await eventualMVAssert( - sdf, - changeSetId, - "AttributeTree", - doublerComponentId, - (mv) => Object.values(mv.attributeValues).some( - (av: any) => av.path === "/domain/doubled" && - av.value === "4", - ), - "Expected doubled attribute value to be 4", - ); - - // Now let's add a prop, regenerate, add an attribute func, and make sure it all works - schemaVariantId = await updateAssetCode(sdf, changeSetId, schemaVariantId, doublerAssetCodeAddedTripled); - await eventualMVAssert( - sdf, - changeSetId, - "SchemaVariant", - schemaVariantId, - (mv) => Object.values(mv.propTree.props).some((p: any) => p.path === "root/domain/tripled"), - "SchemaVariant should have new tripled prop" - ); - - doublerVariant = await sdf.mjolnir(changeSetId, "SchemaVariant", schemaVariantId); - doublerProps = Object.values(doublerVariant.propTree.props); - assert(Array.isArray(doublerProps), "Expected props to be an array"); - - // Add an attribute function - const tripleProp = doublerProps.find((p: any) => p.path === "root/domain/tripled"); - assert(tripleProp, "Expected to find output prop"); - inputProp = doublerProps.find((p: any) => p.path === "root/domain/input"); - assert(inputProp, "Expected to find input prop"); - const triplerArgs = [ - { - name: "input", - kind: "string", - propId: inputProp.id, - inputSocketId: null, - }, - ]; - - const tripleFuncId = await createAttributeFunction(sdf, changeSetId, "triple", schemaVariantId, tripleFuncCode, tripleProp.id, triplerArgs); - - // now ensure the component has the new prop too and it's value has been updated - await eventualMVAssert( - sdf, - changeSetId, - "AttributeTree", - doublerComponentId, - (mv) => Object.values(mv.attributeValues).some( - (av: any) => av.path === "/domain/tripled" && - av.value === "6", - ), - "Expected tripled attribute value to be 6", - ); - +async function emulate_authoring_inner(sdf: SdfApiClient, changeSetId: string) { + // Get the views and find the default one + const views = await getViews(sdf, changeSetId); + const defaultView = views.find((v: any) => v.isDefault); + assert(defaultView, "Expected to find a default view"); + + // Create new asset + let schemaVariantId = await createAsset(sdf, changeSetId, "doubler"); + + // wait for and verify schema variant MV + await eventualMVAssert( + sdf, + changeSetId, + "SchemaVariant", + schemaVariantId, + (mv) => mv.id === schemaVariantId, + "SchemaVariant MV should exist and have matching id", + ); + + // Update Code and Regenerate + schemaVariantId = await updateAssetCode( + sdf, + changeSetId, + schemaVariantId, + doublerAssetCode, + ); + + await eventualMVAssert( + sdf, + changeSetId, + "SchemaVariant", + schemaVariantId, + (mv) => { + const props = Object.values(mv.propTree?.props) || []; + return ( + mv.id === schemaVariantId && + props.some((p: any) => p.path === "root/domain/input") && + props.some((p: any) => p.path === "root/domain/doubled") + ); + }, + "SchemaVariant MV should exist and have added input/doubled props", + ); + let doublerVariant = await sdf.changeSetMjolnir( + changeSetId, + "SchemaVariant", + schemaVariantId, + ); + assert(doublerVariant?.propTree?.props, "Expected props list"); + + let doublerProps = Object.values(doublerVariant.propTree.props); + + assert(Array.isArray(doublerProps), "Expected props to be an array"); + // Add an attribute function + const outputProp = doublerProps.find( + (p: any) => p.path === "root/domain/doubled", + ); + assert(outputProp, "Expected to find doubled prop"); + let inputProp: any = doublerProps.find( + (p: any) => p.path === "root/domain/input", + ); + assert(inputProp, "Expected to find input prop"); + const args = [ + { + name: "input", + kind: "string", + propId: inputProp.id, + inputSocketId: null, + }, + ]; + + const doubleFuncId = await createAttributeFunction( + sdf, + changeSetId, + "double", + doublerVariant.id, + doubleFuncCode, + outputProp.id, + args, + ); + let createComponentBody = { + schemaVariantId: schemaVariantId, + x: "0", + y: "0", + height: "0", + width: "0", + parentId: null, + schemaType: "installed", + }; + + // create a component for the doubler + const createComponentResp = await sdf.call({ + route: "create_component_v2", + routeVars: { + workspaceId: sdf.workspaceId, + changeSetId, + viewId: defaultView.id, + }, + body: createComponentBody, + }); + const doublerComponentId = createComponentResp?.componentId; + assert(doublerComponentId, "Expected to get a component id after creation"); + await eventualMVAssert( + sdf, + changeSetId, + "Component", + doublerComponentId, + (mv) => + mv.id === doublerComponentId && mv.qualificationTotals.succeeded === 0, + "Component MV should exist", + ); + + // update input prop to be a number + const updateRegionResponse = await sdf.call({ + route: "attributes", + routeVars: { + workspaceId: sdf.workspaceId, + changeSetId, + componentId: doublerComponentId, + }, + body: { + "/domain/input": "2", + }, + }); + + await eventualMVAssert( + sdf, + changeSetId, + "AttributeTree", + doublerComponentId, + (mv) => + Object.values(mv.attributeValues).some( + (av: any) => av.path === "/domain/input" && av.value === "2", + ), + "Expected value to be set for domain/input", + ); + + // now add a qualification and check that the component gets it + const qualification = await createQualification( + sdf, + changeSetId, + "doublerQualification", + schemaVariantId, + doublerQualificationCode, + ); + + // it is failing + await eventualMVAssert( + sdf, + changeSetId, + "Component", + doublerComponentId, + (mv) => mv.qualificationTotals.failed === 1, + "Component should have a failed qualification now", + ); + + await eventualMVAssert( + sdf, + changeSetId, + "AttributeTree", + doublerComponentId, + (mv) => + Object.values(mv.attributeValues).some( + (av: any) => av.path === "/domain/doubled" && av.value === "4", + ), + "Expected doubled attribute value to be 4", + ); + + // Now let's add a prop, regenerate, add an attribute func, and make sure it all works + schemaVariantId = await updateAssetCode( + sdf, + changeSetId, + schemaVariantId, + doublerAssetCodeAddedTripled, + ); + await eventualMVAssert( + sdf, + changeSetId, + "SchemaVariant", + schemaVariantId, + (mv) => + Object.values(mv.propTree.props).some( + (p: any) => p.path === "root/domain/tripled", + ), + "SchemaVariant should have new tripled prop", + ); + + doublerVariant = await sdf.changeSetMjolnir( + changeSetId, + "SchemaVariant", + schemaVariantId, + ); + doublerProps = Object.values(doublerVariant.propTree.props); + assert(Array.isArray(doublerProps), "Expected props to be an array"); + + // Add an attribute function + const tripleProp = doublerProps.find( + (p: any) => p.path === "root/domain/tripled", + ); + assert(tripleProp, "Expected to find output prop"); + inputProp = doublerProps.find((p: any) => p.path === "root/domain/input"); + assert(inputProp, "Expected to find input prop"); + const triplerArgs = [ + { + name: "input", + kind: "string", + propId: inputProp.id, + inputSocketId: null, + }, + ]; + + const tripleFuncId = await createAttributeFunction( + sdf, + changeSetId, + "triple", + schemaVariantId, + tripleFuncCode, + tripleProp.id, + triplerArgs, + ); + + // now ensure the component has the new prop too and it's value has been updated + await eventualMVAssert( + sdf, + changeSetId, + "AttributeTree", + doublerComponentId, + (mv) => + Object.values(mv.attributeValues).some( + (av: any) => av.path === "/domain/tripled" && av.value === "6", + ), + "Expected tripled attribute value to be 6", + ); } - const doubleFuncCode = `async function main(input: Input): Promise < Output > { const number = parseInt(input?.input); if (!number) { @@ -304,140 +342,143 @@ const doublerQualificationCode = `async function main(component: Input): Promise // REQUEST HELPERS WITH VALIDATIONS -async function createAttributeFunction(sdf: SdfApiClient, changeSetId: string, name: string, schemaVariantId: string, code: string, outputLocationId: string, funcArguments: any[]) { - const createFuncPayload = { - name, - displayName: name, - description: "", - binding: { - funcId: nilId, - schemaVariantId: schemaVariantId, - bindingKind: "attribute", - argumentBindings: [], - propId: outputLocationId, - }, - kind: "Attribute", - requestUlid: changeSetId, +async function createAttributeFunction( + sdf: SdfApiClient, + changeSetId: string, + name: string, + schemaVariantId: string, + code: string, + outputLocationId: string, + funcArguments: any[], +) { + const createFuncPayload = { + name, + displayName: name, + description: "", + binding: { + funcId: nilId, + schemaVariantId: schemaVariantId, + bindingKind: "attribute", + argumentBindings: [], + propId: outputLocationId, + }, + kind: "Attribute", + requestUlid: changeSetId, + }; + + const createFuncResp = await sdf.call({ + route: "create_func", + routeVars: { + workspaceId: sdf.workspaceId, + changeSetId, + }, + body: createFuncPayload, + }); + + // now list funcs and let's make sure we see it + const funcs = await sdf.call({ + route: "func_list", + routeVars: { + workspaceId: sdf.workspaceId, + changeSetId, + }, + }); + + const createdFunc = funcs.find((f) => f.name === name); + assert(createdFunc, "Expected to find newly created func"); + const funcId = createdFunc.funcId; + const codePayload = { + code, + requestUlid: changeSetId, + }; + + // save the code + const updateCodeResp = await sdf.call({ + route: "update_func_code", + routeVars: { + workspaceId: sdf.workspaceId, + changeSetId, + funcId, + }, + body: codePayload, + }); + + // create func arguments + let numArgs = 0; + for (const funcArg of funcArguments) { + // create the argument + let argPayload = { + created_at: new Date(), + updated_at: new Date(), + name: funcArg.name, + id: nilId, + kind: funcArg.kind, + requestUlid: changeSetId, }; - - const createFuncResp = await sdf.call({ - route: "create_func", - routeVars: { - workspaceId: sdf.workspaceId, - changeSetId, - }, - body: createFuncPayload, + const createArgResp = await sdf.call({ + route: "create_func_arg", + routeVars: { + workspaceId: sdf.workspaceId, + changeSetId, + funcId, + }, + body: argPayload, }); - - // now list funcs and let's make sure we see it - const funcs = await sdf.call({ - route: "func_list", - routeVars: { - workspaceId: sdf.workspaceId, - changeSetId, + const args = createArgResp.arguments; + assert(Array.isArray(createArgResp?.arguments), "Expected arguments list"); + numArgs++; + assert( + createArgResp?.arguments.length === numArgs, + `Expected ${numArgs} but found ${createArgResp?.arguments.length}`, + ); + const createdArg = args.find((arg) => arg.name === funcArg.name); + const attributePrototypeArgumentId = createdArg.id; + const attributePrototypeId = + createArgResp?.bindings[0].attributePrototypeId; + // now update the argument bindings + + const bindingPayload = { + funcId, + bindings: [ + { + bindingKind: "attribute", + attributePrototypeId: attributePrototypeId, + funcId, + propId: outputLocationId, + componentId: null, + outputSocketId: null, + schemaVariantId, + argumentBindings: [ + { + funcArgumentId: createdArg.id, + propId: funcArg.propId, + attributePrototypeArgumentId: attributePrototypeArgumentId, + inputSocketId: funcArg.inputSocketId, + }, + ], }, - }); - - const createdFunc = funcs.find((f) => f.name === name); - assert(createdFunc, "Expected to find newly created func"); - const funcId = createdFunc.funcId; - const codePayload = { - code, - requestUlid: changeSetId, + ], }; - - // save the code - const updateCodeResp = await sdf.call({ - route: "update_func_code", - routeVars: { - workspaceId: sdf.workspaceId, - changeSetId, - funcId, - }, - body: codePayload, + const updateBindingResp = await sdf.call({ + route: "create_func_binding", + routeVars: { + workspaceId: sdf.workspaceId, + changeSetId, + funcId, + }, + body: bindingPayload, }); - // create func arguments - let numArgs = 0; - for (const funcArg of funcArguments) { - // create the argument - let argPayload = { - created_at: new Date(), - updated_at: new Date(), - name: funcArg.name, - id: nilId, - kind: funcArg.kind, - requestUlid: changeSetId, - }; - const createArgResp = await sdf.call({ - route: "create_func_arg", - routeVars: { - workspaceId: sdf.workspaceId, - changeSetId, - funcId, - }, - body: argPayload, - }); - const args = createArgResp.arguments; - assert( - Array.isArray(createArgResp?.arguments), - "Expected arguments list", - ); - numArgs++; - assert(createArgResp?.arguments.length === numArgs, `Expected ${numArgs} but found ${createArgResp?.arguments.length}`); - const createdArg = args.find((arg) => arg.name === funcArg.name); - const attributePrototypeArgumentId = createdArg.id; - const attributePrototypeId = createArgResp?.bindings[0].attributePrototypeId; - // now update the argument bindings - - const bindingPayload = { - funcId, - bindings: [ - { - bindingKind: "attribute", - attributePrototypeId: attributePrototypeId, - funcId, - propId: outputLocationId, - componentId: null, - outputSocketId: null, - schemaVariantId, - argumentBindings: [ - { - funcArgumentId: createdArg.id, - propId: funcArg.propId, - attributePrototypeArgumentId: attributePrototypeArgumentId, - inputSocketId: funcArg.inputSocketId, - } - ] - } - ] - } - const updateBindingResp = await sdf.call({ - route: "create_func_binding", - routeVars: { - workspaceId: sdf.workspaceId, - changeSetId, - funcId, - }, - body: bindingPayload, - }); - - assert( - Array.isArray(updateBindingResp), - "Expected bindings list", - ); - assert( - Array.isArray(updateBindingResp[0].argumentBindings), - "Expected argument bindings list", - ); - assert( - updateBindingResp[0].argumentBindings.length === numArgs, - "Expected argument bindings list", - ); - } - - return funcId; + assert(Array.isArray(updateBindingResp), "Expected bindings list"); + assert( + Array.isArray(updateBindingResp[0].argumentBindings), + "Expected argument bindings list", + ); + assert( + updateBindingResp[0].argumentBindings.length === numArgs, + "Expected argument bindings list", + ); + } + return funcId; } - - diff --git a/bin/si-sdf-api-test/tests/8-check_mjolnir.ts b/bin/si-sdf-api-test/tests/8-check_mjolnir.ts index 4c9adabed3..33c2485e20 100644 --- a/bin/si-sdf-api-test/tests/8-check_mjolnir.ts +++ b/bin/si-sdf-api-test/tests/8-check_mjolnir.ts @@ -1,6 +1,11 @@ import assert from "node:assert"; import { SdfApiClient } from "../sdf_api_client.ts"; -import { eventualMVAssert, getVariants, runWithTemporaryChangeset, createComponentPayload, getViews } from "../test_helpers.ts"; +import { + eventualMVAssert, + runWithTemporaryChangeset, + getViews, + createComponentPayload, +} from "../test_helpers.ts"; // ========================== // Tunables for testing here! @@ -8,116 +13,123 @@ const SCHEMA_NAME = "AWS::EC2::KeyPair"; // the schema name to be used for the t // ========================== export default async function check_mjolnir( - sdfApiClient: SdfApiClient, - changeSetId: string, + sdfApiClient: SdfApiClient, + changeSetId: string, ) { - if (changeSetId) { - return await check_mjolnir_inner(sdfApiClient, changeSetId); - } else { - return runWithTemporaryChangeset(sdfApiClient, check_mjolnir_inner); - } + if (changeSetId) { + return await check_mjolnir_inner(sdfApiClient, changeSetId); + } else { + return runWithTemporaryChangeset(sdfApiClient, check_mjolnir_inner); + } } -async function check_mjolnir_inner( - sdf: SdfApiClient, - changeSetId: string, -) { - - // Get the schema variants (uninstalled and installed) - let schemaVariants = await getVariants(sdf, changeSetId); - let createComponentBody = createComponentPayload(schemaVariants, SCHEMA_NAME); - - // Get the views and find the default one - const views = await getViews(sdf, changeSetId); - const defaultView = views.find((v: any) => v.isDefault); - assert(defaultView, "Expected to find a default view"); +async function check_mjolnir_inner(sdf: SdfApiClient, changeSetId: string) { + // Get the schema variants (uninstalled and installed) + let createComponentBody = await createComponentPayload( + sdf, + changeSetId, + SCHEMA_NAME, + ); - // Create a Component - const createComponentResp = await sdf.call({ - route: "create_component_v2", - routeVars: { - workspaceId: sdf.workspaceId, - changeSetId, - viewId: defaultView.id, - }, - body: createComponentBody, - }); - const { newComponentId, newComponentName } = { newComponentId: createComponentResp?.componentId, newComponentName: createComponentResp?.materializedView?.name }; - assert(newComponentId, "Expected to get a component id after creation"); + // Get the views and find the default one + const views = await getViews(sdf, changeSetId); + const defaultView = views.find((v: any) => v.isDefault); + assert(defaultView, "Expected to find a default view"); - // Wait for and verify component MV - await eventualMVAssert( - sdf, - changeSetId, - "Component", - newComponentId, - (mv) => mv.name === newComponentName, - "Component MV should exist and have matching name" - ); - const componentMV = await sdf.mjolnir(changeSetId, "Component", newComponentId); - assert(componentMV, "Expected to get a component schema variant id after creation"); - const schemaVariantId = componentMV.schemaVariantId.id; - // Delete the Component - const deleteComponentPayload = { - componentIds: [newComponentId], - forceErase: false, - }; - await sdf.call({ - route: "delete_components_v2", - routeVars: { - workspaceId: sdf.workspaceId, - changeSetId, - }, - body: deleteComponentPayload, - }); + // Create a Component + const createComponentResp = await sdf.call({ + route: "create_component_v2", + routeVars: { + workspaceId: sdf.workspaceId, + changeSetId, + viewId: defaultView.id, + }, + body: createComponentBody, + }); + const { newComponentId, newComponentName } = { + newComponentId: createComponentResp?.componentId, + newComponentName: createComponentResp?.materializedView?.name, + }; + assert(newComponentId, "Expected to get a component id after creation"); - // Verify component deletion - await eventualMVAssert( - sdf, - changeSetId, - "ComponentList", - sdf.workspaceId, - (mv) => mv.components.length === 0, - "Should have no components after deletion" - ); + // Wait for and verify component MV + await eventualMVAssert( + sdf, + changeSetId, + "Component", + newComponentId, + (mv) => mv.name === newComponentName, + "Component MV should exist and have matching name", + ); + const componentMV = await sdf.changeSetMjolnir( + changeSetId, + "Component", + newComponentId, + ); + assert( + componentMV, + "Expected to get a component schema variant id after creation", + ); + const schemaVariantId = componentMV.schemaVariantId.id; + // Delete the Component + const deleteComponentPayload = { + componentIds: [newComponentId], + forceErase: false, + }; + await sdf.call({ + route: "delete_components_v2", + routeVars: { + workspaceId: sdf.workspaceId, + changeSetId, + }, + body: deleteComponentPayload, + }); - // await an installed schema variant now - await eventualMVAssert( - sdf, - changeSetId, - "SchemaVariantCategories", - sdf.workspaceId, - (mv) => mv.categories.some((c: any) => c.schemaVariants.some((v: any) => { - if(v.type === "installed"){ - console.log("Found installed schema variant:", v.id, "Expected:", schemaVariantId); - } - return v.type === "installed" && v.id === schemaVariantId; - })), - "Schema variant should be installed", - ); - // create another one - schemaVariants = await getVariants(sdf, changeSetId); - createComponentBody = createComponentPayload(schemaVariants, SCHEMA_NAME); - const createComponent2Resp = await sdf.call({ - route: "create_component_v2", - routeVars: { - workspaceId: sdf.workspaceId, - changeSetId, - viewId: defaultView.id, - }, - body: createComponentBody, - }); - const { newComponentId2, newComponentName2 } = { newComponentId2: createComponent2Resp?.componentId, newComponentName2: createComponent2Resp?.materializedView?.name }; - assert(newComponentId2, "Expected to get a component id after creation"); - await eventualMVAssert( - sdf, - changeSetId, - "Component", - newComponentId2, - (mv) => mv.name === newComponentName2, - "Component MV should exist and have matching name" - ); + // Verify component deletion + await eventualMVAssert( + sdf, + changeSetId, + "ComponentList", + sdf.workspaceId, + (mv) => mv.components.length === 0, + "Should have no components after deletion", + ); + // await an installed schema variant now + await eventualMVAssert( + sdf, + changeSetId, + "LuminorkSchemaVariant", + schemaVariantId, + (mv) => mv.id === schemaVariantId, + "Schema variant should be installed", + ); + // create another one + createComponentBody = await createComponentPayload( + sdf, + changeSetId, + SCHEMA_NAME, + ); + const createComponent2Resp = await sdf.call({ + route: "create_component_v2", + routeVars: { + workspaceId: sdf.workspaceId, + changeSetId, + viewId: defaultView.id, + }, + body: createComponentBody, + }); + const { newComponentId2, newComponentName2 } = { + newComponentId2: createComponent2Resp?.componentId, + newComponentName2: createComponent2Resp?.materializedView?.name, + }; + assert(newComponentId2, "Expected to get a component id after creation"); + await eventualMVAssert( + sdf, + changeSetId, + "Component", + newComponentId2, + (mv) => mv.name === newComponentName2, + "Component MV should exist and have matching name", + ); } - - From 6375aead0200dca393ee8626448235322bf0209f Mon Sep 17 00:00:00 2001 From: Brit Myers Date: Sun, 19 Oct 2025 01:14:07 -0400 Subject: [PATCH 2/2] chore(sdf): Re-enqueue the deployment Mv build on migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We had disabled enqueuing the Edda task that would build the Deployment MVs, when the builtins are cached during migration as the task was taking 4ish hours. Now that this task completes rather quickly, let’s do this on migration again. This mostly improves the local dev experience so we don’t have to manually enqueue it to see the builtins available for component creation on startup. --- lib/dal/src/cached_module.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/dal/src/cached_module.rs b/lib/dal/src/cached_module.rs index afd5208b69..7c862e60ea 100644 --- a/lib/dal/src/cached_module.rs +++ b/lib/dal/src/cached_module.rs @@ -310,7 +310,7 @@ impl CachedModule { ctx: &DalContext, modules: &HashMap, module_index_client: ModuleIndexClient, - _edda_client: EddaClient, + edda_client: EddaClient, ) -> CachedModuleResult> { let hashes = modules.keys().map(ToOwned::to_owned).collect_vec(); let uncached_hashes = CachedModule::find_missing_entries(ctx, hashes).await?; @@ -355,11 +355,7 @@ impl CachedModule { } // Ask edda to rebuild the deployment MVs, which include the cached modules - // - // Until the performance issues in building the deployment-level MVs are fixed, - // this is only going to be deployed through the manual module sync process. - // - // edda_client.rebuild_for_deployment().await?; + edda_client.rebuild_for_deployment().await?; Ok(new_modules) }