core/plan/plan_test.go
core/plan/plan_test.goBrowse 1970 files
2,292 tokens
7,233 bytes
Token encoding: o200k_base
Snapshot 21a254f
← Back to SKILL.md
1package plan2 3import (4 "encoding/json"5 "testing"6 7 "github.com/google/go-cmp/cmp"8 "github.com/stretchr/testify/require"9)10 11func TestSerialization(t *testing.T) {12 jsonPlan := `{13 "steps": [14 {15 "name": "install",16 "commands": [17 {"cmd": "apt-get update"},18 {"cmd": "apt-get install -y curl"}19 ],20 "startingImage": "ubuntu:22.04"21 },22 {23 "name": "deps",24 "dependsOn": ["install"],25 "commands": [26 {"path": "/root/.npm", "name": ".npmrc"},27 {"cmd": "npm ci"},28 {"cmd": "npm run build"}29 ],30 "useSecrets": true,31 "outputs": [32 "dist",33 "node_modules/.cache"34 ],35 "assets": {36 "npmrc": "registry=https://registry.npmjs.org/\n//registry.npmjs.org/:_authToken=${NPM_TOKEN}\nalways-auth=true"37 }38 },39 {40 "name": "build",41 "dependsOn": ["deps"],42 "commands": [43 {"src": ".", "dest": "."},44 {"cmd": "npm run test"},45 {"path": "/usr/local/bin"},46 {"name": "NODE_ENV", "value": "production"}47 ],48 "useSecrets": false49 }50 ],51 "start": {52 "baseImage": "node:18-slim",53 "cmd": "npm start",54 "paths": ["/usr/local/bin", "/app/node_modules/.bin"]55 },56 "caches": {57 "npm": {58 "directory": "/root/.npm",59 "type": "shared"60 },61 "build-cache": {62 "directory": "node_modules/.cache",63 "type": "locked"64 }65 },66 "secrets": ["NPM_TOKEN", "GITHUB_TOKEN"]67 }`68 69 var plan1 BuildPlan70 err := json.Unmarshal([]byte(jsonPlan), &plan1)71 require.NoError(t, err)72 73 serialized, err := json.MarshalIndent(&plan1, "", " ")74 require.NoError(t, err)75 76 var plan2 BuildPlan77 err = json.Unmarshal(serialized, &plan2)78 require.NoError(t, err)79 80 if diff := cmp.Diff(plan1, plan2); diff != "" {81 t.Errorf("plans mismatch (-want +got):\n%s", diff)82 }83}84 85func TestNormalize(t *testing.T) {86 tests := []struct {87 name string88 plan *BuildPlan89 expectedPlan *BuildPlan90 }{91 {92 name: "empty plan",93 plan: &BuildPlan{94 Steps: []Step{},95 Deploy: Deploy{},96 },97 expectedPlan: &BuildPlan{98 Steps: []Step{},99 Deploy: Deploy{},100 },101 },102 {103 name: "removes empty inputs",104 plan: &BuildPlan{105 Steps: []Step{106 {107 Name: "step1",108 Inputs: []Layer{109 {},110 NewStepLayer("step2"),111 },112 },113 },114 Deploy: Deploy{115 Inputs: []Layer{116 {},117 NewImageLayer("ubuntu:22.04"),118 },119 },120 },121 expectedPlan: &BuildPlan{122 Steps: []Step{123 {124 Name: "step1",125 Inputs: []Layer{126 NewStepLayer("step2"),127 },128 },129 },130 Deploy: Deploy{131 Inputs: []Layer{132 NewImageLayer("ubuntu:22.04"),133 },134 },135 },136 },137 {138 name: "removes unreferenced steps",139 plan: &BuildPlan{140 Steps: []Step{141 {142 Name: "step1",143 Inputs: []Layer{},144 },145 {146 Name: "step2",147 Inputs: []Layer{},148 },149 {150 Name: "step3",151 Inputs: []Layer{152 NewStepLayer("step2"),153 },154 },155 {156 Name: "step4",157 Inputs: []Layer{},158 },159 },160 Deploy: Deploy{161 Base: NewStepLayer("step4"),162 Inputs: []Layer{163 NewStepLayer("step3"),164 },165 },166 },167 expectedPlan: &BuildPlan{168 Steps: []Step{169 {170 Name: "step3",171 Inputs: []Layer{172 NewStepLayer("step2"),173 },174 },175 {176 Name: "step2",177 Inputs: []Layer{},178 },179 {180 Name: "step4",181 Inputs: []Layer{},182 },183 },184 Deploy: Deploy{185 Base: NewStepLayer("step4"),186 Inputs: []Layer{187 NewStepLayer("step3"),188 },189 },190 },191 },192 {193 name: "keeps only transitively referenced steps",194 plan: &BuildPlan{195 Steps: []Step{196 {197 Name: "step1",198 Inputs: []Layer{},199 },200 {201 Name: "step2",202 Inputs: []Layer{203 NewStepLayer("step1"),204 },205 },206 {207 Name: "step3",208 Inputs: []Layer{209 NewStepLayer("step2"),210 },211 },212 {213 Name: "step4",214 Inputs: []Layer{215 NewStepLayer("step3"),216 },217 },218 {219 Name: "step5",220 Inputs: []Layer{},221 },222 },223 Deploy: Deploy{224 Base: NewStepLayer("step3"),225 Inputs: []Layer{226 NewStepLayer("step5"),227 },228 },229 },230 expectedPlan: &BuildPlan{231 Steps: []Step{232 {233 Name: "step1",234 Inputs: []Layer{},235 },236 {237 Name: "step2",238 Inputs: []Layer{239 NewStepLayer("step1"),240 },241 },242 {243 Name: "step3",244 Inputs: []Layer{245 NewStepLayer("step2"),246 },247 },248 {249 Name: "step5",250 Inputs: []Layer{},251 },252 },253 Deploy: Deploy{254 Base: NewStepLayer("step3"),255 Inputs: []Layer{256 NewStepLayer("step5"),257 },258 },259 },260 },261 {262 name: "handles circular dependencies",263 plan: &BuildPlan{264 Steps: []Step{265 {266 Name: "step1",267 Inputs: []Layer{268 NewStepLayer("step2"),269 },270 },271 {272 Name: "step2",273 Inputs: []Layer{274 NewStepLayer("step3"),275 },276 },277 {278 Name: "step3",279 Inputs: []Layer{280 NewStepLayer("step1"),281 },282 },283 {284 Name: "step4",285 Inputs: []Layer{286 NewStepLayer("step1"),287 },288 },289 },290 Deploy: Deploy{291 Base: NewStepLayer("step4"),292 },293 },294 expectedPlan: &BuildPlan{295 Steps: []Step{296 {297 Name: "step4",298 Inputs: []Layer{299 NewStepLayer("step1"),300 },301 },302 {303 Name: "step1",304 Inputs: []Layer{305 NewStepLayer("step2"),306 },307 },308 {309 Name: "step2",310 Inputs: []Layer{311 NewStepLayer("step3"),312 },313 },314 {315 Name: "step3",316 Inputs: []Layer{317 NewStepLayer("step1"),318 },319 },320 },321 Deploy: Deploy{322 Base: NewStepLayer("step4"),323 },324 },325 },326 {327 name: "handles self-referential step",328 plan: &BuildPlan{329 Steps: []Step{330 {331 Name: "step1",332 Inputs: []Layer{333 NewStepLayer("step1"), // References itself334 },335 },336 },337 Deploy: Deploy{338 Base: NewStepLayer("step1"),339 },340 },341 expectedPlan: &BuildPlan{342 Steps: []Step{343 {344 Name: "step1",345 Inputs: []Layer{346 NewStepLayer("step1"),347 },348 },349 },350 Deploy: Deploy{351 Base: NewStepLayer("step1"),352 },353 },354 },355 }356 357 for _, tc := range tests {358 t.Run(tc.name, func(t *testing.T) {359 tc.plan.Normalize()360 361 // Compare Steps length362 require.Equal(t, len(tc.expectedPlan.Steps), len(tc.plan.Steps), "Steps length mismatch")363 364 // Create map of expected steps by name for easier comparison365 expectedSteps := make(map[string]Step)366 for _, step := range tc.expectedPlan.Steps {367 expectedSteps[step.Name] = step368 }369 370 // Verify each step is as expected371 for _, step := range tc.plan.Steps {372 expectedStep, exists := expectedSteps[step.Name]373 require.True(t, exists, "Unexpected step: %s", step.Name)374 require.Equal(t, expectedStep.Inputs, step.Inputs, "Inputs mismatch for step %s", step.Name)375 }376 377 // Compare Deploy inputs and base378 require.Equal(t, tc.expectedPlan.Deploy.Inputs, tc.plan.Deploy.Inputs, "Deploy inputs mismatch")379 require.Equal(t, tc.expectedPlan.Deploy.Base, tc.plan.Deploy.Base, "Deploy base mismatch")380 })381 }382}383