Monorepo for Tangled
at master 373 lines 9.7 kB view raw
1package models 2 3import ( 4 "strings" 5 "testing" 6 7 "tangled.org/core/api/tangled" 8 "tangled.org/core/workflow" 9) 10 11func sp(s string) *string { return &s } 12 13func TestBuildCloneStep_PushTrigger(t *testing.T) { 14 twf := tangled.Pipeline_Workflow{ 15 Clone: &tangled.Pipeline_CloneOpts{ 16 Depth: 1, 17 Submodules: false, 18 Skip: false, 19 }, 20 } 21 tr := tangled.Pipeline_TriggerMetadata{ 22 Kind: string(workflow.TriggerKindPush), 23 Push: &tangled.Pipeline_PushTriggerData{ 24 NewSha: "abc123", 25 OldSha: "def456", 26 Ref: "refs/heads/main", 27 }, 28 Repo: &tangled.Pipeline_TriggerRepo{ 29 Knot: "example.com", 30 Did: "did:plc:user123", 31 Repo: sp("my-repo"), 32 }, 33 } 34 35 step := BuildCloneStep(twf, tr, false) 36 37 if step.Kind() != StepKindSystem { 38 t.Errorf("Expected StepKindSystem, got %v", step.Kind()) 39 } 40 41 if step.Name() != "Clone repository into workspace" { 42 t.Errorf("Expected 'Clone repository into workspace', got '%s'", step.Name()) 43 } 44 45 commands := step.Commands() 46 if len(commands) != 4 { 47 t.Errorf("Expected 4 commands, got %d", len(commands)) 48 } 49 50 // Verify commands contain expected git operations 51 allCmds := strings.Join(commands, " ") 52 if !strings.Contains(allCmds, "git init") { 53 t.Error("Commands should contain 'git init'") 54 } 55 if !strings.Contains(allCmds, "git remote add origin") { 56 t.Error("Commands should contain 'git remote add origin'") 57 } 58 if !strings.Contains(allCmds, "git fetch") { 59 t.Error("Commands should contain 'git fetch'") 60 } 61 if !strings.Contains(allCmds, "abc123") { 62 t.Error("Commands should contain commit SHA") 63 } 64 if !strings.Contains(allCmds, "git checkout FETCH_HEAD") { 65 t.Error("Commands should contain 'git checkout FETCH_HEAD'") 66 } 67 if !strings.Contains(allCmds, "https://example.com/did:plc:user123/my-repo") { 68 t.Error("Commands should contain expected repo URL") 69 } 70} 71 72func TestBuildCloneStep_PullRequestTrigger(t *testing.T) { 73 twf := tangled.Pipeline_Workflow{ 74 Clone: &tangled.Pipeline_CloneOpts{ 75 Depth: 1, 76 Skip: false, 77 }, 78 } 79 tr := tangled.Pipeline_TriggerMetadata{ 80 Kind: string(workflow.TriggerKindPullRequest), 81 PullRequest: &tangled.Pipeline_PullRequestTriggerData{ 82 SourceSha: "pr-sha-789", 83 SourceBranch: "feature-branch", 84 TargetBranch: "main", 85 Action: "opened", 86 }, 87 Repo: &tangled.Pipeline_TriggerRepo{ 88 Knot: "example.com", 89 Did: "did:plc:user123", 90 Repo: sp("my-repo"), 91 }, 92 } 93 94 step := BuildCloneStep(twf, tr, false) 95 96 allCmds := strings.Join(step.Commands(), " ") 97 if !strings.Contains(allCmds, "pr-sha-789") { 98 t.Error("Commands should contain PR commit SHA") 99 } 100} 101 102func TestBuildCloneStep_ManualTrigger(t *testing.T) { 103 twf := tangled.Pipeline_Workflow{ 104 Clone: &tangled.Pipeline_CloneOpts{ 105 Depth: 1, 106 Skip: false, 107 }, 108 } 109 tr := tangled.Pipeline_TriggerMetadata{ 110 Kind: string(workflow.TriggerKindManual), 111 Manual: &tangled.Pipeline_ManualTriggerData{ 112 Inputs: nil, 113 }, 114 Repo: &tangled.Pipeline_TriggerRepo{ 115 Knot: "example.com", 116 Did: "did:plc:user123", 117 Repo: sp("my-repo"), 118 }, 119 } 120 121 step := BuildCloneStep(twf, tr, false) 122 123 // Manual triggers don't have a SHA yet (TODO), so git fetch won't include a SHA 124 allCmds := strings.Join(step.Commands(), " ") 125 // Should still have basic git commands 126 if !strings.Contains(allCmds, "git init") { 127 t.Error("Commands should contain 'git init'") 128 } 129 if !strings.Contains(allCmds, "git fetch") { 130 t.Error("Commands should contain 'git fetch'") 131 } 132} 133 134func TestBuildCloneStep_SkipFlag(t *testing.T) { 135 twf := tangled.Pipeline_Workflow{ 136 Clone: &tangled.Pipeline_CloneOpts{ 137 Skip: true, 138 }, 139 } 140 tr := tangled.Pipeline_TriggerMetadata{ 141 Kind: string(workflow.TriggerKindPush), 142 Push: &tangled.Pipeline_PushTriggerData{ 143 NewSha: "abc123", 144 }, 145 Repo: &tangled.Pipeline_TriggerRepo{ 146 Knot: "example.com", 147 Did: "did:plc:user123", 148 Repo: sp("my-repo"), 149 }, 150 } 151 152 step := BuildCloneStep(twf, tr, false) 153 154 // Empty step when skip is true 155 if step.Name() != "" { 156 t.Error("Expected empty step name when Skip is true") 157 } 158 if len(step.Commands()) != 0 { 159 t.Errorf("Expected no commands when Skip is true, got %d commands", len(step.Commands())) 160 } 161} 162 163func TestBuildCloneStep_DevMode(t *testing.T) { 164 twf := tangled.Pipeline_Workflow{ 165 Clone: &tangled.Pipeline_CloneOpts{ 166 Depth: 1, 167 Skip: false, 168 }, 169 } 170 tr := tangled.Pipeline_TriggerMetadata{ 171 Kind: string(workflow.TriggerKindPush), 172 Push: &tangled.Pipeline_PushTriggerData{ 173 NewSha: "abc123", 174 }, 175 Repo: &tangled.Pipeline_TriggerRepo{ 176 Knot: "localhost:3000", 177 Did: "did:plc:user123", 178 Repo: sp("my-repo"), 179 }, 180 } 181 182 step := BuildCloneStep(twf, tr, true) 183 184 // In dev mode, should use http:// and replace localhost with host.docker.internal 185 allCmds := strings.Join(step.Commands(), " ") 186 expectedURL := "http://host.docker.internal:3000/did:plc:user123/my-repo" 187 if !strings.Contains(allCmds, expectedURL) { 188 t.Errorf("Expected dev mode URL '%s' in commands", expectedURL) 189 } 190} 191 192func TestBuildCloneStep_DepthAndSubmodules(t *testing.T) { 193 twf := tangled.Pipeline_Workflow{ 194 Clone: &tangled.Pipeline_CloneOpts{ 195 Depth: 10, 196 Submodules: true, 197 Skip: false, 198 }, 199 } 200 tr := tangled.Pipeline_TriggerMetadata{ 201 Kind: string(workflow.TriggerKindPush), 202 Push: &tangled.Pipeline_PushTriggerData{ 203 NewSha: "abc123", 204 }, 205 Repo: &tangled.Pipeline_TriggerRepo{ 206 Knot: "example.com", 207 Did: "did:plc:user123", 208 Repo: sp("my-repo"), 209 }, 210 } 211 212 step := BuildCloneStep(twf, tr, false) 213 214 allCmds := strings.Join(step.Commands(), " ") 215 if !strings.Contains(allCmds, "--depth=10") { 216 t.Error("Commands should contain '--depth=10'") 217 } 218 219 if !strings.Contains(allCmds, "--recurse-submodules=yes") { 220 t.Error("Commands should contain '--recurse-submodules=yes'") 221 } 222} 223 224func TestBuildCloneStep_DefaultDepth(t *testing.T) { 225 twf := tangled.Pipeline_Workflow{ 226 Clone: &tangled.Pipeline_CloneOpts{ 227 Depth: 0, // Default should be 1 228 Skip: false, 229 }, 230 } 231 tr := tangled.Pipeline_TriggerMetadata{ 232 Kind: string(workflow.TriggerKindPush), 233 Push: &tangled.Pipeline_PushTriggerData{ 234 NewSha: "abc123", 235 }, 236 Repo: &tangled.Pipeline_TriggerRepo{ 237 Knot: "example.com", 238 Did: "did:plc:user123", 239 Repo: sp("my-repo"), 240 }, 241 } 242 243 step := BuildCloneStep(twf, tr, false) 244 245 allCmds := strings.Join(step.Commands(), " ") 246 if !strings.Contains(allCmds, "--depth=1") { 247 t.Error("Commands should default to '--depth=1'") 248 } 249} 250 251func TestBuildCloneStep_NilPushData(t *testing.T) { 252 twf := tangled.Pipeline_Workflow{ 253 Clone: &tangled.Pipeline_CloneOpts{ 254 Depth: 1, 255 Skip: false, 256 }, 257 } 258 tr := tangled.Pipeline_TriggerMetadata{ 259 Kind: string(workflow.TriggerKindPush), 260 Push: nil, // Nil push data should create error step 261 Repo: &tangled.Pipeline_TriggerRepo{ 262 Knot: "example.com", 263 Did: "did:plc:user123", 264 Repo: sp("my-repo"), 265 }, 266 } 267 268 step := BuildCloneStep(twf, tr, false) 269 270 // Should return an error step 271 if !strings.Contains(step.Name(), "error") { 272 t.Error("Expected error in step name when push data is nil") 273 } 274 275 allCmds := strings.Join(step.Commands(), " ") 276 if !strings.Contains(allCmds, "Failed to get clone info") { 277 t.Error("Commands should contain error message") 278 } 279 if !strings.Contains(allCmds, "exit 1") { 280 t.Error("Commands should exit with error") 281 } 282} 283 284func TestBuildCloneStep_NilPRData(t *testing.T) { 285 twf := tangled.Pipeline_Workflow{ 286 Clone: &tangled.Pipeline_CloneOpts{ 287 Depth: 1, 288 Skip: false, 289 }, 290 } 291 tr := tangled.Pipeline_TriggerMetadata{ 292 Kind: string(workflow.TriggerKindPullRequest), 293 PullRequest: nil, // Nil PR data should create error step 294 Repo: &tangled.Pipeline_TriggerRepo{ 295 Knot: "example.com", 296 Did: "did:plc:user123", 297 Repo: sp("my-repo"), 298 }, 299 } 300 301 step := BuildCloneStep(twf, tr, false) 302 303 // Should return an error step 304 if !strings.Contains(step.Name(), "error") { 305 t.Error("Expected error in step name when pull request data is nil") 306 } 307 308 allCmds := strings.Join(step.Commands(), " ") 309 if !strings.Contains(allCmds, "Failed to get clone info") { 310 t.Error("Commands should contain error message") 311 } 312} 313 314func TestBuildCloneStep_UnknownTriggerKind(t *testing.T) { 315 twf := tangled.Pipeline_Workflow{ 316 Clone: &tangled.Pipeline_CloneOpts{ 317 Depth: 1, 318 Skip: false, 319 }, 320 } 321 tr := tangled.Pipeline_TriggerMetadata{ 322 Kind: "unknown_trigger", 323 Repo: &tangled.Pipeline_TriggerRepo{ 324 Knot: "example.com", 325 Did: "did:plc:user123", 326 Repo: sp("my-repo"), 327 }, 328 } 329 330 step := BuildCloneStep(twf, tr, false) 331 332 // Should return an error step 333 if !strings.Contains(step.Name(), "error") { 334 t.Error("Expected error in step name for unknown trigger kind") 335 } 336 337 allCmds := strings.Join(step.Commands(), " ") 338 if !strings.Contains(allCmds, "unknown trigger kind") { 339 t.Error("Commands should contain error message about unknown trigger kind") 340 } 341} 342 343func TestBuildCloneStep_NilCloneOpts(t *testing.T) { 344 twf := tangled.Pipeline_Workflow{ 345 Clone: nil, // Nil clone options should use defaults 346 } 347 tr := tangled.Pipeline_TriggerMetadata{ 348 Kind: string(workflow.TriggerKindPush), 349 Push: &tangled.Pipeline_PushTriggerData{ 350 NewSha: "abc123", 351 }, 352 Repo: &tangled.Pipeline_TriggerRepo{ 353 Knot: "example.com", 354 Did: "did:plc:user123", 355 Repo: sp("my-repo"), 356 }, 357 } 358 359 step := BuildCloneStep(twf, tr, false) 360 361 // Should still work with default options 362 if step.Kind() != StepKindSystem { 363 t.Errorf("Expected StepKindSystem, got %v", step.Kind()) 364 } 365 366 allCmds := strings.Join(step.Commands(), " ") 367 if !strings.Contains(allCmds, "--depth=1") { 368 t.Error("Commands should default to '--depth=1' when Clone is nil") 369 } 370 if !strings.Contains(allCmds, "git init") { 371 t.Error("Commands should contain 'git init'") 372 } 373}