From 19ec74707b18791f8ba7d186b922d973edd7f051 Mon Sep 17 00:00:00 2001 From: Sas Swart Date: Tue, 15 Apr 2025 10:55:29 +0000 Subject: [PATCH 1/6] fix: add some more thorough testing for preset workspace creation --- coderd/workspaces_test.go | 278 +++++++++++++++++++++++++++++++++----- 1 file changed, 244 insertions(+), 34 deletions(-) diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 136e259d541f9..c7e75466f8aa6 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -426,47 +426,257 @@ func TestWorkspace(t *testing.T) { t.Run("TemplateVersionPreset", func(t *testing.T) { t.Parallel() - client, _, api := coderdtest.NewWithAPI(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - user := coderdtest.CreateFirstUser(t, client) - authz := coderdtest.AssertRBAC(t, api, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Response{{ - Type: &proto.Response_Plan{ - Plan: &proto.PlanComplete{ - Presets: []*proto.Preset{{ - Name: "test", - }}, + + testCases := []struct { + name string + presets []*proto.Preset + expectedCount int + selectedPresetIndex int // Index of the preset to use, or -1 if no preset should be used + }{ + { + name: "No Presets", + presets: []*proto.Preset{}, + expectedCount: 0, + selectedPresetIndex: -1, + }, + { + name: "Single Preset - No Parameters", + presets: []*proto.Preset{{ + Name: "test", + Parameters: []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + {Name: "param2", Value: "value2"}, + }, + }}, + expectedCount: 1, + selectedPresetIndex: 0, + }, + { + name: "Single Preset - With Parameters", + presets: []*proto.Preset{{ + Name: "test", + Parameters: []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + {Name: "param2", Value: "value2"}, }, + }}, + expectedCount: 1, + selectedPresetIndex: 0, + }, + { + name: "Multiple Presets - No Parameters", + presets: []*proto.Preset{ + {Name: "test1"}, + {Name: "test2"}, + {Name: "test3"}, }, - }}, - ProvisionApply: echo.ApplyComplete, - }) - coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + expectedCount: 3, + selectedPresetIndex: 0, + }, + { + name: "Multiple Presets - First Has Parameters", + presets: []*proto.Preset{ + { + Name: "test1", + Parameters: []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + {Name: "param2", Value: "value2"}, + }, + }, + {Name: "test2"}, + {Name: "test3"}, + }, + expectedCount: 3, + selectedPresetIndex: 0, + }, + { + name: "Multiple Presets - Middle Has Parameters", + presets: []*proto.Preset{ + {Name: "test1"}, + { + Name: "test2", + Parameters: []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + {Name: "param2", Value: "value2"}, + }, + }, + {Name: "test3"}, + }, + expectedCount: 3, + selectedPresetIndex: 1, + }, + { + name: "Multiple Presets - Last Has Parameters", + presets: []*proto.Preset{ + {Name: "test1"}, + {Name: "test2"}, + { + Name: "test3", + Parameters: []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + {Name: "param2", Value: "value2"}, + }, + }, + }, + expectedCount: 3, + selectedPresetIndex: 2, + }, + { + name: "Multiple Presets - All Have Parameters", + presets: []*proto.Preset{ + { + Name: "test1", + Parameters: []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + }, + }, + { + Name: "test2", + Parameters: []*proto.PresetParameter{ + {Name: "param2", Value: "value2"}, + }, + }, + { + Name: "test3", + Parameters: []*proto.PresetParameter{ + {Name: "param3", Value: "value3"}, + }, + }, + }, + expectedCount: 3, + selectedPresetIndex: 1, + }, + { + name: "Multiple Presets - With Parameters But Not Used", + presets: []*proto.Preset{ + { + Name: "test1", + Parameters: []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + }, + }, + { + Name: "test2", + Parameters: []*proto.PresetParameter{ + {Name: "param2", Value: "value2"}, + }, + }, + }, + expectedCount: 2, + selectedPresetIndex: -1, + }, + } - ctx := testutil.Context(t, testutil.WaitLong) + for _, tc := range testCases { + tc := tc // Capture range variable + t.Run(tc.name, func(t *testing.T) { + t.Parallel() - presets, err := client.TemplateVersionPresets(ctx, version.ID) - require.NoError(t, err) - require.Equal(t, 1, len(presets)) - require.Equal(t, "test", presets[0].Name) + client, _, api := coderdtest.NewWithAPI(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user := coderdtest.CreateFirstUser(t, client) + authz := coderdtest.AssertRBAC(t, api, client) - workspace := coderdtest.CreateWorkspace(t, client, template.ID, func(request *codersdk.CreateWorkspaceRequest) { - request.TemplateVersionPresetID = presets[0].ID - }) + // Create a plan response with the specified presets + planResponse := &proto.Response{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ + Presets: tc.presets, + }, + }, + } - authz.Reset() // Reset all previous checks done in setup. - ws, err := client.Workspace(ctx, workspace.ID) - authz.AssertChecked(t, policy.ActionRead, ws) - require.NoError(t, err) - require.Equal(t, user.UserID, ws.LatestBuild.InitiatorID) - require.Equal(t, codersdk.BuildReasonInitiator, ws.LatestBuild.Reason) - require.Equal(t, presets[0].ID, *ws.LatestBuild.TemplateVersionPresetID) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ + Parse: echo.ParseComplete, + ProvisionPlan: []*proto.Response{planResponse}, + ProvisionApply: echo.ApplyComplete, + }) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - org, err := client.Organization(ctx, ws.OrganizationID) - require.NoError(t, err) - require.Equal(t, ws.OrganizationName, org.Name) + ctx := testutil.Context(t, testutil.WaitLong) + + // Check presets + presets, err := client.TemplateVersionPresets(ctx, version.ID) + require.NoError(t, err) + require.Equal(t, tc.expectedCount, len(presets)) + + if tc.expectedCount > 0 { + // Verify preset names and parameters + for i, preset := range presets { + require.Equal(t, tc.presets[i].Name, preset.Name) + + // Check if the preset should have parameters + if tc.presets[i].Parameters != nil { + // Verify that the preset has the expected parameters + for _, param := range tc.presets[i].Parameters { + found := false + for _, presetParam := range preset.Parameters { + if param.Name == presetParam.Name { + require.Equal(t, param.Value, presetParam.Value, + "Parameter %s should have value %s", param.Name, param.Value) + found = true + break + } + } + require.True(t, found, "Parameter %s should be present in preset", param.Name) + } + } + } + } + + // Create workspace with or without preset + var workspace codersdk.Workspace + if tc.selectedPresetIndex >= 0 && tc.expectedCount > 0 { + // Use the selected preset + selectedIndex := tc.selectedPresetIndex + if selectedIndex >= len(presets) { + selectedIndex = 0 // Fallback to first preset if index is out of bounds + } + + workspace = coderdtest.CreateWorkspace(t, client, template.ID, func(request *codersdk.CreateWorkspaceRequest) { + request.TemplateVersionPresetID = presets[selectedIndex].ID + }) + } else { + workspace = coderdtest.CreateWorkspace(t, client, template.ID) + } + + // Verify workspace details + authz.Reset() // Reset all previous checks done in setup. + ws, err := client.Workspace(ctx, workspace.ID) + authz.AssertChecked(t, policy.ActionRead, ws) + require.NoError(t, err) + require.Equal(t, user.UserID, ws.LatestBuild.InitiatorID) + require.Equal(t, codersdk.BuildReasonInitiator, ws.LatestBuild.Reason) + + // Check preset ID if expected + if tc.selectedPresetIndex >= 0 && tc.expectedCount > 0 { + require.NotNil(t, ws.LatestBuild.TemplateVersionPresetID) + + // Use the selected preset index + selectedIndex := tc.selectedPresetIndex + if selectedIndex >= len(presets) { + selectedIndex = 0 // Fallback to first preset if index is out of bounds + } + + require.Equal(t, presets[selectedIndex].ID, *ws.LatestBuild.TemplateVersionPresetID) + + // If the selected preset has parameters, verify they were applied + if tc.presets[selectedIndex].Parameters != nil { + // This would require additional verification based on how parameters + // are stored in the workspace. For now, we'll just log that we checked. + t.Logf("Selected preset %s has parameters that should be applied to the workspace", + tc.presets[selectedIndex].Name) + } + } else { + require.Nil(t, ws.LatestBuild.TemplateVersionPresetID) + } + + // Verify organization + org, err := client.Organization(ctx, ws.OrganizationID) + require.NoError(t, err) + require.Equal(t, ws.OrganizationName, org.Name) + }) + } }) } From 2fad945e31383e665ba71ba48bf3af3f45f08ee0 Mon Sep 17 00:00:00 2001 From: Sas Swart Date: Tue, 15 Apr 2025 13:57:06 +0000 Subject: [PATCH 2/6] fix: set preset parameters in the API instead of relying on the frontend --- coderd/workspaces_test.go | 268 ++++++++++++++++++++++++++++------ coderd/wsbuilder/wsbuilder.go | 42 ++++-- 2 files changed, 256 insertions(+), 54 deletions(-) diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index c7e75466f8aa6..cbc2503feed74 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -428,19 +428,39 @@ func TestWorkspace(t *testing.T) { t.Parallel() testCases := []struct { - name string - presets []*proto.Preset - expectedCount int - selectedPresetIndex int // Index of the preset to use, or -1 if no preset should be used + name string + presets []*proto.Preset + templateVersionParameters []*proto.RichParameter + selectedPresetIndex int // -1 if no preset should be used }{ { - name: "No Presets", - presets: []*proto.Preset{}, - expectedCount: 0, - selectedPresetIndex: -1, + name: "No Presets", + presets: []*proto.Preset{}, + templateVersionParameters: []*proto.RichParameter{}, + selectedPresetIndex: -1, }, { name: "Single Preset - No Parameters", + presets: []*proto.Preset{{ + Name: "test", + }}, + templateVersionParameters: []*proto.RichParameter{}, + selectedPresetIndex: 0, + }, + { + name: "Single Preset - With Parameters But No Template Parameters", + presets: []*proto.Preset{{ + Name: "test", + Parameters: []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + {Name: "param2", Value: "value2"}, + }, + }}, + templateVersionParameters: []*proto.RichParameter{}, + selectedPresetIndex: 0, + }, + { + name: "Single Preset - With Matching Parameters", presets: []*proto.Preset{{ Name: "test", Parameters: []*proto.PresetParameter{ @@ -448,19 +468,26 @@ func TestWorkspace(t *testing.T) { {Name: "param2", Value: "value2"}, }, }}, - expectedCount: 1, + templateVersionParameters: []*proto.RichParameter{ + {Name: "param1", Type: "string", Required: true}, + {Name: "param2", Type: "string", Required: true}, + }, selectedPresetIndex: 0, }, { - name: "Single Preset - With Parameters", + name: "Single Preset - With Partial Matching Parameters", presets: []*proto.Preset{{ Name: "test", Parameters: []*proto.PresetParameter{ {Name: "param1", Value: "value1"}, {Name: "param2", Value: "value2"}, + {Name: "param3", Value: "value3"}, // This parameter doesn't exist in template }, }}, - expectedCount: 1, + templateVersionParameters: []*proto.RichParameter{ + {Name: "param1", Type: "string", Required: false}, + {Name: "param2", Type: "string", Required: false}, + }, selectedPresetIndex: 0, }, { @@ -470,8 +497,8 @@ func TestWorkspace(t *testing.T) { {Name: "test2"}, {Name: "test3"}, }, - expectedCount: 3, - selectedPresetIndex: 0, + templateVersionParameters: []*proto.RichParameter{}, + selectedPresetIndex: 0, }, { name: "Multiple Presets - First Has Parameters", @@ -486,7 +513,26 @@ func TestWorkspace(t *testing.T) { {Name: "test2"}, {Name: "test3"}, }, - expectedCount: 3, + templateVersionParameters: []*proto.RichParameter{}, + selectedPresetIndex: 0, + }, + { + name: "Multiple Presets - First Has Matching Parameters", + presets: []*proto.Preset{ + { + Name: "test1", + Parameters: []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + {Name: "param2", Value: "value2"}, + }, + }, + {Name: "test2"}, + {Name: "test3"}, + }, + templateVersionParameters: []*proto.RichParameter{ + {Name: "param1", Type: "string", Required: true}, + {Name: "param2", Type: "string", Required: true}, + }, selectedPresetIndex: 0, }, { @@ -502,7 +548,26 @@ func TestWorkspace(t *testing.T) { }, {Name: "test3"}, }, - expectedCount: 3, + templateVersionParameters: []*proto.RichParameter{}, + selectedPresetIndex: 1, + }, + { + name: "Multiple Presets - Middle Has Matching Parameters", + presets: []*proto.Preset{ + {Name: "test1"}, + { + Name: "test2", + Parameters: []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + {Name: "param2", Value: "value2"}, + }, + }, + {Name: "test3"}, + }, + templateVersionParameters: []*proto.RichParameter{ + {Name: "param1", Type: "string", Required: true}, + {Name: "param2", Type: "string", Required: true}, + }, selectedPresetIndex: 1, }, { @@ -518,7 +583,26 @@ func TestWorkspace(t *testing.T) { }, }, }, - expectedCount: 3, + templateVersionParameters: []*proto.RichParameter{}, + selectedPresetIndex: 2, + }, + { + name: "Multiple Presets - Last Has Matching Parameters", + presets: []*proto.Preset{ + {Name: "test1"}, + {Name: "test2"}, + { + Name: "test3", + Parameters: []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + {Name: "param2", Value: "value2"}, + }, + }, + }, + templateVersionParameters: []*proto.RichParameter{ + {Name: "param1", Type: "string", Required: true}, + {Name: "param2", Type: "string", Required: true}, + }, selectedPresetIndex: 2, }, { @@ -543,7 +627,36 @@ func TestWorkspace(t *testing.T) { }, }, }, - expectedCount: 3, + templateVersionParameters: []*proto.RichParameter{}, + selectedPresetIndex: 1, + }, + { + name: "Multiple Presets - All Have Matching Parameters", + presets: []*proto.Preset{ + { + Name: "test1", + Parameters: []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + }, + }, + { + Name: "test2", + Parameters: []*proto.PresetParameter{ + {Name: "param2", Value: "value2"}, + }, + }, + { + Name: "test3", + Parameters: []*proto.PresetParameter{ + {Name: "param3", Value: "value3"}, + }, + }, + }, + templateVersionParameters: []*proto.RichParameter{ + {Name: "param1", Type: "string", Required: false}, + {Name: "param2", Type: "string", Required: true}, + {Name: "param3", Type: "string", Required: false}, + }, selectedPresetIndex: 1, }, { @@ -562,7 +675,29 @@ func TestWorkspace(t *testing.T) { }, }, }, - expectedCount: 2, + templateVersionParameters: []*proto.RichParameter{}, + selectedPresetIndex: -1, + }, + { + name: "Multiple Presets - With Matching Parameters But Not Used", + presets: []*proto.Preset{ + { + Name: "test1", + Parameters: []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + }, + }, + { + Name: "test2", + Parameters: []*proto.PresetParameter{ + {Name: "param2", Value: "value2"}, + }, + }, + }, + templateVersionParameters: []*proto.RichParameter{ + {Name: "param1", Type: "string", Required: false}, + {Name: "param2", Type: "string", Required: false}, + }, selectedPresetIndex: -1, }, } @@ -576,11 +711,12 @@ func TestWorkspace(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) authz := coderdtest.AssertRBAC(t, api, client) - // Create a plan response with the specified presets + // Create a plan response with the specified presets and parameters planResponse := &proto.Response{ Type: &proto.Response_Plan{ Plan: &proto.PlanComplete{ - Presets: tc.presets, + Presets: tc.presets, + Parameters: tc.templateVersionParameters, }, }, } @@ -598,9 +734,9 @@ func TestWorkspace(t *testing.T) { // Check presets presets, err := client.TemplateVersionPresets(ctx, version.ID) require.NoError(t, err) - require.Equal(t, tc.expectedCount, len(presets)) + require.Equal(t, len(tc.presets), len(presets)) - if tc.expectedCount > 0 { + if len(tc.presets) > 0 { // Verify preset names and parameters for i, preset := range presets { require.Equal(t, tc.presets[i].Name, preset.Name) @@ -626,15 +762,10 @@ func TestWorkspace(t *testing.T) { // Create workspace with or without preset var workspace codersdk.Workspace - if tc.selectedPresetIndex >= 0 && tc.expectedCount > 0 { + if tc.selectedPresetIndex >= 0 { // Use the selected preset - selectedIndex := tc.selectedPresetIndex - if selectedIndex >= len(presets) { - selectedIndex = 0 // Fallback to first preset if index is out of bounds - } - workspace = coderdtest.CreateWorkspace(t, client, template.ID, func(request *codersdk.CreateWorkspaceRequest) { - request.TemplateVersionPresetID = presets[selectedIndex].ID + request.TemplateVersionPresetID = presets[tc.selectedPresetIndex].ID }) } else { workspace = coderdtest.CreateWorkspace(t, client, template.ID) @@ -649,23 +780,76 @@ func TestWorkspace(t *testing.T) { require.Equal(t, codersdk.BuildReasonInitiator, ws.LatestBuild.Reason) // Check preset ID if expected - if tc.selectedPresetIndex >= 0 && tc.expectedCount > 0 { + if tc.selectedPresetIndex >= 0 { require.NotNil(t, ws.LatestBuild.TemplateVersionPresetID) + require.Equal(t, presets[tc.selectedPresetIndex].ID, *ws.LatestBuild.TemplateVersionPresetID) + + // If the selected preset has parameters and there are template version parameters, + // verify that only matching parameters were applied + if tc.presets[tc.selectedPresetIndex].Parameters != nil && len(tc.templateVersionParameters) > 0 { + builds, err := client.WorkspaceBuilds(ctx, codersdk.WorkspaceBuildsRequest{ + WorkspaceID: ws.ID, + }) + require.NoError(t, err) + require.Equal(t, 1, len(builds)) + parameters, err := client.WorkspaceBuildParameters(ctx, builds[0].ID) + require.NoError(t, err) + parametersSetByPreset := 0 + for _, param := range parameters { + for _, presetParam := range tc.presets[tc.selectedPresetIndex].Parameters { + if param.Name == presetParam.Name && param.Value == presetParam.Value { + parametersSetByPreset++ + break + } + } + } - // Use the selected preset index - selectedIndex := tc.selectedPresetIndex - if selectedIndex >= len(presets) { - selectedIndex = 0 // Fallback to first preset if index is out of bounds - } + // Track which template parameters were set by the preset + expectedParamCount := 0 + for _, presetParam := range tc.presets[tc.selectedPresetIndex].Parameters { + for _, templateParam := range tc.templateVersionParameters { + if presetParam.Name == templateParam.Name { + expectedParamCount++ + break + } + } + } - require.Equal(t, presets[selectedIndex].ID, *ws.LatestBuild.TemplateVersionPresetID) + // Verify that only the expected number of parameters were set + require.Equal(t, expectedParamCount, parametersSetByPreset, + "Expected %d parameters to be set, but found %d", expectedParamCount, parametersSetByPreset) + + // Verify each parameter that should have been set + for _, presetParam := range tc.presets[tc.selectedPresetIndex].Parameters { + // Check if this parameter exists in the template version + paramExists := false + for _, templateParam := range tc.templateVersionParameters { + if presetParam.Name == templateParam.Name { + paramExists = true + break + } + } - // If the selected preset has parameters, verify they were applied - if tc.presets[selectedIndex].Parameters != nil { - // This would require additional verification based on how parameters - // are stored in the workspace. For now, we'll just log that we checked. - t.Logf("Selected preset %s has parameters that should be applied to the workspace", - tc.presets[selectedIndex].Name) + if paramExists { + // This parameter should have been set + paramFound := false + for _, appliedParam := range parameters { + if appliedParam.Name == presetParam.Name { + require.Equal(t, presetParam.Value, appliedParam.Value, + "Parameter %s should have value %s", presetParam.Name, presetParam.Value) + paramFound = true + break + } + } + require.True(t, paramFound, "Parameter %s should be applied to the workspace", presetParam.Name) + } else { + // This parameter should NOT have been set + for _, appliedParam := range parameters { + require.NotEqual(t, presetParam.Name, appliedParam.Name, + "Parameter %s should not be applied to the workspace", presetParam.Name) + } + } + } } } else { require.Nil(t, ws.LatestBuild.TemplateVersionPresetID) diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go index 469c8fbcfdd6d..fa7c00861202d 100644 --- a/coderd/wsbuilder/wsbuilder.go +++ b/coderd/wsbuilder/wsbuilder.go @@ -61,18 +61,19 @@ type Builder struct { store database.Store // cache of objects, so we only fetch once - template *database.Template - templateVersion *database.TemplateVersion - templateVersionJob *database.ProvisionerJob - templateVersionParameters *[]database.TemplateVersionParameter - templateVersionVariables *[]database.TemplateVersionVariable - templateVersionWorkspaceTags *[]database.TemplateVersionWorkspaceTag - lastBuild *database.WorkspaceBuild - lastBuildErr *error - lastBuildParameters *[]database.WorkspaceBuildParameter - lastBuildJob *database.ProvisionerJob - parameterNames *[]string - parameterValues *[]string + template *database.Template + templateVersion *database.TemplateVersion + templateVersionJob *database.ProvisionerJob + templateVersionParameters *[]database.TemplateVersionParameter + templateVersionVariables *[]database.TemplateVersionVariable + templateVersionWorkspaceTags *[]database.TemplateVersionWorkspaceTag + lastBuild *database.WorkspaceBuild + lastBuildErr *error + lastBuildParameters *[]database.WorkspaceBuildParameter + lastBuildJob *database.ProvisionerJob + parameterNames *[]string + parameterValues *[]string + templateVersionPresetParameterValues []database.TemplateVersionPresetParameter prebuild bool @@ -565,6 +566,14 @@ func (b *Builder) getParameters() (names, values []string, err error) { if err != nil { return nil, nil, BuildError{http.StatusInternalServerError, "failed to fetch last build parameters", err} } + if b.templateVersionPresetID != uuid.Nil { + // Fetch and cache these, since we'll need them to override requested values if a preset was chosen + presetParameters, err := b.store.GetPresetParametersByPresetID(b.ctx, b.templateVersionPresetID) + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "failed to get preset parameters", err} + } + b.templateVersionPresetParameterValues = presetParameters + } err = b.verifyNoLegacyParameters() if err != nil { return nil, nil, BuildError{http.StatusBadRequest, "Unable to build workspace with unsupported parameters", err} @@ -597,6 +606,15 @@ func (b *Builder) getParameters() (names, values []string, err error) { } func (b *Builder) findNewBuildParameterValue(name string) *codersdk.WorkspaceBuildParameter { + for _, v := range b.templateVersionPresetParameterValues { + if v.Name == name { + return &codersdk.WorkspaceBuildParameter{ + Name: v.Name, + Value: v.Value, + } + } + } + for _, v := range b.richParameterValues { if v.Name == name { return &v From 86d93c5a4ea61505c08a1d7eae6a828f103e07fd Mon Sep 17 00:00:00 2001 From: Sas Swart Date: Tue, 15 Apr 2025 14:25:26 +0000 Subject: [PATCH 3/6] update expectations in TestWorkspaceBuildWithPreset --- coderd/wsbuilder/wsbuilder_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/coderd/wsbuilder/wsbuilder_test.go b/coderd/wsbuilder/wsbuilder_test.go index bd6e64a60414a..901d8ffe80273 100644 --- a/coderd/wsbuilder/wsbuilder_test.go +++ b/coderd/wsbuilder/wsbuilder_test.go @@ -789,6 +789,7 @@ func TestWorkspaceBuildWithPreset(t *testing.T) { // Inputs withTemplate, withActiveVersion(nil), + withTemplateVersionPreset(presetID), withLastBuildNotFound, withTemplateVersionVariables(activeVersionID, nil), withParameterSchemas(activeJobID, nil), @@ -960,6 +961,12 @@ func withInactiveVersion(params []database.TemplateVersionParameter) func(mTx *d } } +func withTemplateVersionPreset(presetID uuid.UUID) func(mTx *dbmock.MockStore) { + return func(mTx *dbmock.MockStore) { + mTx.EXPECT().GetPresetParametersByPresetID(gomock.Any(), presetID).Return(nil, nil) + } +} + func withLastBuildFound(mTx *dbmock.MockStore) { mTx.EXPECT().GetLatestWorkspaceBuildByWorkspaceID(gomock.Any(), workspaceID). Times(1). From 24cb22577c7094167c1ccde0e7921df05dd7af1c Mon Sep 17 00:00:00 2001 From: Sas Swart Date: Wed, 16 Apr 2025 10:38:01 +0000 Subject: [PATCH 4/6] simplify tests --- coderd/util/slice/slice.go | 13 ++ coderd/workspaces_test.go | 461 +++++++++++++++---------------------- 2 files changed, 197 insertions(+), 277 deletions(-) diff --git a/coderd/util/slice/slice.go b/coderd/util/slice/slice.go index 508827dfaae81..b4ee79291d73f 100644 --- a/coderd/util/slice/slice.go +++ b/coderd/util/slice/slice.go @@ -66,6 +66,19 @@ func Contains[T comparable](haystack []T, needle T) bool { }) } +func CountMatchingPairs[A, B any](a []A, b []B, match func(A, B) bool) int { + count := 0 + for _, a := range a { + for _, b := range b { + if match(a, b) { + count++ + break + } + } + } + return count +} + // Find returns the first element that satisfies the condition. func Find[T any](haystack []T, cond func(T) bool) (T, bool) { for _, hay := range haystack { diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index cbc2503feed74..8f7ec4ec7ff14 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -36,6 +36,7 @@ import ( "github.com/coder/coder/v2/coderd/schedule" "github.com/coder/coder/v2/coderd/schedule/cron" "github.com/coder/coder/v2/coderd/util/ptr" + "github.com/coder/coder/v2/coderd/util/slice" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/cryptorand" "github.com/coder/coder/v2/provisioner/echo" @@ -427,278 +428,226 @@ func TestWorkspace(t *testing.T) { t.Run("TemplateVersionPreset", func(t *testing.T) { t.Parallel() + // Test Utility variables + templateVersionParameters := []*proto.RichParameter{ + {Name: "param1", Type: "string", Required: false}, + {Name: "param2", Type: "string", Required: false}, + {Name: "param3", Type: "string", Required: false}, + } + presetParameters := []*proto.PresetParameter{ + {Name: "param1", Value: "value1"}, + {Name: "param2", Value: "value2"}, + {Name: "param3", Value: "value3"}, + } + emptyPreset := &proto.Preset{ + Name: "Empty Preset", + } + presetWithParameters := &proto.Preset{ + Name: "Preset With Parameters", + Parameters: presetParameters, + } + testCases := []struct { name string presets []*proto.Preset templateVersionParameters []*proto.RichParameter - selectedPresetIndex int // -1 if no preset should be used + selectedPresetIndex *int }{ { - name: "No Presets", + name: "No Presets - No Template Parameters", presets: []*proto.Preset{}, - templateVersionParameters: []*proto.RichParameter{}, - selectedPresetIndex: -1, + templateVersionParameters: templateVersionParameters, }, { - name: "Single Preset - No Parameters", - presets: []*proto.Preset{{ - Name: "test", - }}, - templateVersionParameters: []*proto.RichParameter{}, - selectedPresetIndex: 0, + name: "No Presets - With Template Parameters", + presets: []*proto.Preset{}, + templateVersionParameters: templateVersionParameters, }, { - name: "Single Preset - With Parameters But No Template Parameters", - presets: []*proto.Preset{{ - Name: "test", - Parameters: []*proto.PresetParameter{ - {Name: "param1", Value: "value1"}, - {Name: "param2", Value: "value2"}, - }, - }}, - templateVersionParameters: []*proto.RichParameter{}, - selectedPresetIndex: 0, + name: "Single Preset - No Preset Parameters But With Template Parameters", + presets: []*proto.Preset{emptyPreset}, + templateVersionParameters: templateVersionParameters, + selectedPresetIndex: ptr.Ref(0), }, { - name: "Single Preset - With Matching Parameters", - presets: []*proto.Preset{{ - Name: "test", - Parameters: []*proto.PresetParameter{ - {Name: "param1", Value: "value1"}, - {Name: "param2", Value: "value2"}, - }, - }}, - templateVersionParameters: []*proto.RichParameter{ - {Name: "param1", Type: "string", Required: true}, - {Name: "param2", Type: "string", Required: true}, - }, - selectedPresetIndex: 0, + name: "Single Preset - No Preset Parameters And No Template Parameters", + presets: []*proto.Preset{emptyPreset}, + selectedPresetIndex: ptr.Ref(0), + }, + { + name: "Single Preset - With Preset Parameters But No Template Parameters", + presets: []*proto.Preset{presetWithParameters}, + selectedPresetIndex: ptr.Ref(0), + }, + { + name: "Single Preset - With Matching Parameters", + presets: []*proto.Preset{presetWithParameters}, + templateVersionParameters: templateVersionParameters, + selectedPresetIndex: ptr.Ref(0), }, { name: "Single Preset - With Partial Matching Parameters", presets: []*proto.Preset{{ - Name: "test", - Parameters: []*proto.PresetParameter{ - {Name: "param1", Value: "value1"}, - {Name: "param2", Value: "value2"}, - {Name: "param3", Value: "value3"}, // This parameter doesn't exist in template - }, + Name: "test", + Parameters: presetParameters, }}, - templateVersionParameters: []*proto.RichParameter{ - {Name: "param1", Type: "string", Required: false}, - {Name: "param2", Type: "string", Required: false}, - }, - selectedPresetIndex: 0, + templateVersionParameters: templateVersionParameters[:2], + selectedPresetIndex: ptr.Ref(0), }, { name: "Multiple Presets - No Parameters", presets: []*proto.Preset{ - {Name: "test1"}, - {Name: "test2"}, - {Name: "test3"}, + {Name: "preset1"}, + {Name: "preset2"}, + {Name: "preset3"}, }, - templateVersionParameters: []*proto.RichParameter{}, - selectedPresetIndex: 0, + selectedPresetIndex: ptr.Ref(0), }, { name: "Multiple Presets - First Has Parameters", presets: []*proto.Preset{ { - Name: "test1", - Parameters: []*proto.PresetParameter{ - {Name: "param1", Value: "value1"}, - {Name: "param2", Value: "value2"}, - }, + Name: "preset1", + Parameters: presetParameters, }, - {Name: "test2"}, - {Name: "test3"}, + {Name: "preset2"}, + {Name: "preset3"}, }, - templateVersionParameters: []*proto.RichParameter{}, - selectedPresetIndex: 0, + selectedPresetIndex: ptr.Ref(0), }, { name: "Multiple Presets - First Has Matching Parameters", presets: []*proto.Preset{ - { - Name: "test1", - Parameters: []*proto.PresetParameter{ - {Name: "param1", Value: "value1"}, - {Name: "param2", Value: "value2"}, - }, - }, - {Name: "test2"}, - {Name: "test3"}, - }, - templateVersionParameters: []*proto.RichParameter{ - {Name: "param1", Type: "string", Required: true}, - {Name: "param2", Type: "string", Required: true}, + presetWithParameters, + {Name: "preset2"}, + {Name: "preset3"}, }, - selectedPresetIndex: 0, + templateVersionParameters: templateVersionParameters, + selectedPresetIndex: ptr.Ref(0), }, { name: "Multiple Presets - Middle Has Parameters", presets: []*proto.Preset{ - {Name: "test1"}, - { - Name: "test2", - Parameters: []*proto.PresetParameter{ - {Name: "param1", Value: "value1"}, - {Name: "param2", Value: "value2"}, - }, - }, - {Name: "test3"}, + {Name: "preset1"}, + presetWithParameters, + {Name: "preset3"}, }, - templateVersionParameters: []*proto.RichParameter{}, - selectedPresetIndex: 1, + selectedPresetIndex: ptr.Ref(1), }, { name: "Multiple Presets - Middle Has Matching Parameters", presets: []*proto.Preset{ - {Name: "test1"}, - { - Name: "test2", - Parameters: []*proto.PresetParameter{ - {Name: "param1", Value: "value1"}, - {Name: "param2", Value: "value2"}, - }, - }, - {Name: "test3"}, - }, - templateVersionParameters: []*proto.RichParameter{ - {Name: "param1", Type: "string", Required: true}, - {Name: "param2", Type: "string", Required: true}, + {Name: "preset1"}, + presetWithParameters, + {Name: "preset3"}, }, - selectedPresetIndex: 1, + templateVersionParameters: templateVersionParameters, + selectedPresetIndex: ptr.Ref(1), }, { name: "Multiple Presets - Last Has Parameters", presets: []*proto.Preset{ - {Name: "test1"}, - {Name: "test2"}, - { - Name: "test3", - Parameters: []*proto.PresetParameter{ - {Name: "param1", Value: "value1"}, - {Name: "param2", Value: "value2"}, - }, - }, + {Name: "preset1"}, + {Name: "preset2"}, + presetWithParameters, }, - templateVersionParameters: []*proto.RichParameter{}, - selectedPresetIndex: 2, + selectedPresetIndex: ptr.Ref(2), }, { name: "Multiple Presets - Last Has Matching Parameters", presets: []*proto.Preset{ - {Name: "test1"}, - {Name: "test2"}, - { - Name: "test3", - Parameters: []*proto.PresetParameter{ - {Name: "param1", Value: "value1"}, - {Name: "param2", Value: "value2"}, - }, - }, - }, - templateVersionParameters: []*proto.RichParameter{ - {Name: "param1", Type: "string", Required: true}, - {Name: "param2", Type: "string", Required: true}, + {Name: "preset1"}, + {Name: "preset2"}, + presetWithParameters, }, - selectedPresetIndex: 2, + templateVersionParameters: templateVersionParameters, + selectedPresetIndex: ptr.Ref(2), }, { name: "Multiple Presets - All Have Parameters", presets: []*proto.Preset{ { - Name: "test1", - Parameters: []*proto.PresetParameter{ - {Name: "param1", Value: "value1"}, - }, + Name: "preset1", + Parameters: presetParameters[:1], }, { - Name: "test2", - Parameters: []*proto.PresetParameter{ - {Name: "param2", Value: "value2"}, - }, + Name: "preset2", + Parameters: presetParameters[1:2], }, { - Name: "test3", - Parameters: []*proto.PresetParameter{ - {Name: "param3", Value: "value3"}, - }, + Name: "preset3", + Parameters: presetParameters[2:3], }, }, - templateVersionParameters: []*proto.RichParameter{}, - selectedPresetIndex: 1, + selectedPresetIndex: ptr.Ref(1), }, { - name: "Multiple Presets - All Have Matching Parameters", + name: "Multiple Presets - All Have Partially Matching Parameters", presets: []*proto.Preset{ { - Name: "test1", - Parameters: []*proto.PresetParameter{ - {Name: "param1", Value: "value1"}, - }, + Name: "preset1", + Parameters: presetParameters[:1], + }, + { + Name: "preset2", + Parameters: presetParameters[1:2], }, { - Name: "test2", + Name: "preset3", + Parameters: presetParameters[2:3], + }, + }, + templateVersionParameters: templateVersionParameters, + selectedPresetIndex: ptr.Ref(1), + }, + { + name: "Multiple presets - With Overlapping Matching Parameters", + presets: []*proto.Preset{ + { + Name: "preset1", Parameters: []*proto.PresetParameter{ - {Name: "param2", Value: "value2"}, + {Name: "param1", Value: "expectedValue1"}, + {Name: "param2", Value: "expectedValue2"}, }, }, { - Name: "test3", + Name: "preset2", Parameters: []*proto.PresetParameter{ - {Name: "param3", Value: "value3"}, + {Name: "param1", Value: "incorrectValue1"}, + {Name: "param2", Value: "incorrectValue2"}, }, }, }, - templateVersionParameters: []*proto.RichParameter{ - {Name: "param1", Type: "string", Required: false}, - {Name: "param2", Type: "string", Required: true}, - {Name: "param3", Type: "string", Required: false}, - }, - selectedPresetIndex: 1, + templateVersionParameters: templateVersionParameters, + selectedPresetIndex: ptr.Ref(0), }, { name: "Multiple Presets - With Parameters But Not Used", presets: []*proto.Preset{ { - Name: "test1", - Parameters: []*proto.PresetParameter{ - {Name: "param1", Value: "value1"}, - }, + Name: "preset1", + Parameters: presetParameters[:1], }, { - Name: "test2", - Parameters: []*proto.PresetParameter{ - {Name: "param2", Value: "value2"}, - }, + Name: "preset2", + Parameters: presetParameters[1:2], }, }, - templateVersionParameters: []*proto.RichParameter{}, - selectedPresetIndex: -1, + templateVersionParameters: templateVersionParameters, }, { name: "Multiple Presets - With Matching Parameters But Not Used", presets: []*proto.Preset{ { - Name: "test1", - Parameters: []*proto.PresetParameter{ - {Name: "param1", Value: "value1"}, - }, + Name: "preset1", + Parameters: presetParameters[:1], }, { - Name: "test2", - Parameters: []*proto.PresetParameter{ - {Name: "param2", Value: "value2"}, - }, + Name: "preset2", + Parameters: presetParameters[1:2], }, }, - templateVersionParameters: []*proto.RichParameter{ - {Name: "param1", Type: "string", Required: false}, - {Name: "param2", Type: "string", Required: false}, - }, - selectedPresetIndex: -1, + templateVersionParameters: templateVersionParameters[0:2], }, } @@ -731,41 +680,32 @@ func TestWorkspace(t *testing.T) { ctx := testutil.Context(t, testutil.WaitLong) - // Check presets - presets, err := client.TemplateVersionPresets(ctx, version.ID) + // Check createdPresets + createdPresets, err := client.TemplateVersionPresets(ctx, version.ID) require.NoError(t, err) - require.Equal(t, len(tc.presets), len(presets)) - - if len(tc.presets) > 0 { - // Verify preset names and parameters - for i, preset := range presets { - require.Equal(t, tc.presets[i].Name, preset.Name) - - // Check if the preset should have parameters - if tc.presets[i].Parameters != nil { - // Verify that the preset has the expected parameters - for _, param := range tc.presets[i].Parameters { - found := false - for _, presetParam := range preset.Parameters { - if param.Name == presetParam.Name { - require.Equal(t, param.Value, presetParam.Value, - "Parameter %s should have value %s", param.Name, param.Value) - found = true - break - } - } - require.True(t, found, "Parameter %s should be present in preset", param.Name) - } - } + require.Equal(t, len(tc.presets), len(createdPresets)) + + for _, createdPreset := range createdPresets { + presetIndex := slices.IndexFunc(tc.presets, func(expectedPreset *proto.Preset) bool { + return expectedPreset.Name == createdPreset.Name + }) + require.NotEqual(t, -1, presetIndex, "Preset %s should be present", createdPreset.Name) + + // Verify that the preset has the expected parameters + for _, expectedPresetParam := range tc.presets[presetIndex].Parameters { + paramFoundAtIndex := slices.IndexFunc(createdPreset.Parameters, func(createdPresetParam codersdk.PresetParameter) bool { + return expectedPresetParam.Name == createdPresetParam.Name && expectedPresetParam.Value == createdPresetParam.Value + }) + require.NotEqual(t, -1, paramFoundAtIndex, "Parameter %s should be present in preset", expectedPresetParam.Name) } } // Create workspace with or without preset var workspace codersdk.Workspace - if tc.selectedPresetIndex >= 0 { + if tc.selectedPresetIndex != nil { // Use the selected preset workspace = coderdtest.CreateWorkspace(t, client, template.ID, func(request *codersdk.CreateWorkspaceRequest) { - request.TemplateVersionPresetID = presets[tc.selectedPresetIndex].ID + request.TemplateVersionPresetID = createdPresets[*tc.selectedPresetIndex].ID }) } else { workspace = coderdtest.CreateWorkspace(t, client, template.ID) @@ -779,86 +719,53 @@ func TestWorkspace(t *testing.T) { require.Equal(t, user.UserID, ws.LatestBuild.InitiatorID) require.Equal(t, codersdk.BuildReasonInitiator, ws.LatestBuild.Reason) - // Check preset ID if expected - if tc.selectedPresetIndex >= 0 { - require.NotNil(t, ws.LatestBuild.TemplateVersionPresetID) - require.Equal(t, presets[tc.selectedPresetIndex].ID, *ws.LatestBuild.TemplateVersionPresetID) + // Check that the preset ID is set if expected + require.Equal(t, tc.selectedPresetIndex == nil, ws.LatestBuild.TemplateVersionPresetID == nil) - // If the selected preset has parameters and there are template version parameters, - // verify that only matching parameters were applied - if tc.presets[tc.selectedPresetIndex].Parameters != nil && len(tc.templateVersionParameters) > 0 { - builds, err := client.WorkspaceBuilds(ctx, codersdk.WorkspaceBuildsRequest{ - WorkspaceID: ws.ID, - }) - require.NoError(t, err) - require.Equal(t, 1, len(builds)) - parameters, err := client.WorkspaceBuildParameters(ctx, builds[0].ID) - require.NoError(t, err) - parametersSetByPreset := 0 - for _, param := range parameters { - for _, presetParam := range tc.presets[tc.selectedPresetIndex].Parameters { - if param.Name == presetParam.Name && param.Value == presetParam.Value { - parametersSetByPreset++ - break - } - } - } - - // Track which template parameters were set by the preset - expectedParamCount := 0 - for _, presetParam := range tc.presets[tc.selectedPresetIndex].Parameters { - for _, templateParam := range tc.templateVersionParameters { - if presetParam.Name == templateParam.Name { - expectedParamCount++ - break - } - } - } - - // Verify that only the expected number of parameters were set - require.Equal(t, expectedParamCount, parametersSetByPreset, - "Expected %d parameters to be set, but found %d", expectedParamCount, parametersSetByPreset) - - // Verify each parameter that should have been set - for _, presetParam := range tc.presets[tc.selectedPresetIndex].Parameters { - // Check if this parameter exists in the template version - paramExists := false - for _, templateParam := range tc.templateVersionParameters { - if presetParam.Name == templateParam.Name { - paramExists = true - break - } - } - - if paramExists { - // This parameter should have been set - paramFound := false - for _, appliedParam := range parameters { - if appliedParam.Name == presetParam.Name { - require.Equal(t, presetParam.Value, appliedParam.Value, - "Parameter %s should have value %s", presetParam.Name, presetParam.Value) - paramFound = true - break - } - } - require.True(t, paramFound, "Parameter %s should be applied to the workspace", presetParam.Name) - } else { - // This parameter should NOT have been set - for _, appliedParam := range parameters { - require.NotEqual(t, presetParam.Name, appliedParam.Name, - "Parameter %s should not be applied to the workspace", presetParam.Name) - } - } - } - } - } else { - require.Nil(t, ws.LatestBuild.TemplateVersionPresetID) + if tc.selectedPresetIndex == nil { + // No preset selected, so no further checks are needed + // Pre-preset tests cover this case sufficiently. + return } - // Verify organization - org, err := client.Organization(ctx, ws.OrganizationID) + // If we get here, we expect a preset to be selected. + // So we need to assert that selecting the preset had all the correct consequences. + require.Equal(t, createdPresets[*tc.selectedPresetIndex].ID, *ws.LatestBuild.TemplateVersionPresetID) + + selectedPresetParameters := tc.presets[*tc.selectedPresetIndex].Parameters + + // Get parameters that were applied to the latest workspace build + builds, err := client.WorkspaceBuilds(ctx, codersdk.WorkspaceBuildsRequest{ + WorkspaceID: ws.ID, + }) require.NoError(t, err) - require.Equal(t, ws.OrganizationName, org.Name) + require.Equal(t, 1, len(builds)) + gotWorkspaceBuildParameters, err := client.WorkspaceBuildParameters(ctx, builds[0].ID) + require.NoError(t, err) + + // Count how many parameters were set by the preset + parametersSetByPreset := slice.CountMatchingPairs( + gotWorkspaceBuildParameters, + selectedPresetParameters, + func(gotParameter codersdk.WorkspaceBuildParameter, presetParameter *proto.PresetParameter) bool { + namesMatch := gotParameter.Name == presetParameter.Name + valuesMatch := gotParameter.Value == presetParameter.Value + return namesMatch && valuesMatch + }, + ) + + // Count how many parameters should have been set by the preset + expectedParamCount := slice.CountMatchingPairs( + selectedPresetParameters, + tc.templateVersionParameters, + func(presetParam *proto.PresetParameter, templateParam *proto.RichParameter) bool { + return presetParam.Name == templateParam.Name + }, + ) + + // Verify that only the expected number of parameters were set by the preset + require.Equal(t, expectedParamCount, parametersSetByPreset, + "Expected %d parameters to be set, but found %d", expectedParamCount, parametersSetByPreset) }) } }) From 9bdb8ce6229cc51e4206262596a4dbec098d9044 Mon Sep 17 00:00:00 2001 From: Sas Swart Date: Wed, 16 Apr 2025 12:40:10 +0000 Subject: [PATCH 5/6] remove typo in presets test case --- coderd/workspaces_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 8f7ec4ec7ff14..3101346f5b43a 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -454,9 +454,8 @@ func TestWorkspace(t *testing.T) { selectedPresetIndex *int }{ { - name: "No Presets - No Template Parameters", - presets: []*proto.Preset{}, - templateVersionParameters: templateVersionParameters, + name: "No Presets - No Template Parameters", + presets: []*proto.Preset{}, }, { name: "No Presets - With Template Parameters", From a66c533684c6b4e4a5db56211e19a07c4008c081 Mon Sep 17 00:00:00 2001 From: Sas Swart Date: Wed, 16 Apr 2025 12:40:40 +0000 Subject: [PATCH 6/6] add the option to specify preset parameters in wsbuilder_test --- coderd/wsbuilder/wsbuilder_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/coderd/wsbuilder/wsbuilder_test.go b/coderd/wsbuilder/wsbuilder_test.go index 901d8ffe80273..00b7b5f0ae08b 100644 --- a/coderd/wsbuilder/wsbuilder_test.go +++ b/coderd/wsbuilder/wsbuilder_test.go @@ -789,7 +789,10 @@ func TestWorkspaceBuildWithPreset(t *testing.T) { // Inputs withTemplate, withActiveVersion(nil), - withTemplateVersionPreset(presetID), + // building workspaces using presets with different combinations of parameters + // is tested at the API layer, in TestWorkspace. Here, it is sufficient to + // test that the preset is used when provided. + withTemplateVersionPresetParameters(presetID, nil), withLastBuildNotFound, withTemplateVersionVariables(activeVersionID, nil), withParameterSchemas(activeJobID, nil), @@ -961,9 +964,9 @@ func withInactiveVersion(params []database.TemplateVersionParameter) func(mTx *d } } -func withTemplateVersionPreset(presetID uuid.UUID) func(mTx *dbmock.MockStore) { +func withTemplateVersionPresetParameters(presetID uuid.UUID, params []database.TemplateVersionPresetParameter) func(mTx *dbmock.MockStore) { return func(mTx *dbmock.MockStore) { - mTx.EXPECT().GetPresetParametersByPresetID(gomock.Any(), presetID).Return(nil, nil) + mTx.EXPECT().GetPresetParametersByPresetID(gomock.Any(), presetID).Return(params, nil) } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy