github.com/fastly/cli@v1.7.2-0.20240304164155-9d0f1d77c3bf/pkg/commands/domain/domain_test.go (about) 1 package domain_test 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 "strings" 9 "testing" 10 11 "github.com/fastly/go-fastly/v9/fastly" 12 13 "github.com/fastly/cli/pkg/app" 14 "github.com/fastly/cli/pkg/global" 15 "github.com/fastly/cli/pkg/mock" 16 "github.com/fastly/cli/pkg/testutil" 17 ) 18 19 func TestDomainCreate(t *testing.T) { 20 args := testutil.Args 21 scenarios := []testutil.TestScenario{ 22 { 23 Args: args("domain create --version 1"), 24 WantError: "error reading service: no service ID found", 25 }, 26 { 27 Args: args("domain create --service-id 123 --version 1 --name www.test.com --autoclone"), 28 API: mock.API{ 29 ListVersionsFn: testutil.ListVersions, 30 CloneVersionFn: testutil.CloneVersionResult(4), 31 CreateDomainFn: createDomainOK, 32 }, 33 WantOutput: "Created domain www.test.com (service 123 version 4)", 34 }, 35 { 36 Args: args("domain create --service-id 123 --version 1 --name www.test.com --autoclone"), 37 API: mock.API{ 38 ListVersionsFn: testutil.ListVersions, 39 CloneVersionFn: testutil.CloneVersionResult(4), 40 CreateDomainFn: createDomainError, 41 }, 42 WantError: errTest.Error(), 43 }, 44 } 45 for testcaseIdx := range scenarios { 46 testcase := &scenarios[testcaseIdx] 47 t.Run(testcase.Name, func(t *testing.T) { 48 var stdout bytes.Buffer 49 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 50 opts := testutil.MockGlobalData(testcase.Args, &stdout) 51 opts.APIClientFactory = mock.APIClient(testcase.API) 52 return opts, nil 53 } 54 err := app.Run(testcase.Args, nil) 55 testutil.AssertErrorContains(t, err, testcase.WantError) 56 testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) 57 }) 58 } 59 } 60 61 func TestDomainList(t *testing.T) { 62 args := testutil.Args 63 scenarios := []testutil.TestScenario{ 64 { 65 Args: args("domain list --service-id 123 --version 1"), 66 API: mock.API{ 67 ListVersionsFn: testutil.ListVersions, 68 ListDomainsFn: listDomainsOK, 69 }, 70 WantOutput: listDomainsShortOutput, 71 }, 72 { 73 Args: args("domain list --service-id 123 --version 1 --verbose"), 74 API: mock.API{ 75 ListVersionsFn: testutil.ListVersions, 76 ListDomainsFn: listDomainsOK, 77 }, 78 WantOutput: listDomainsVerboseOutput, 79 }, 80 { 81 Args: args("domain list --service-id 123 --version 1 -v"), 82 API: mock.API{ 83 ListVersionsFn: testutil.ListVersions, 84 ListDomainsFn: listDomainsOK, 85 }, 86 WantOutput: listDomainsVerboseOutput, 87 }, 88 { 89 Args: args("domain --verbose list --service-id 123 --version 1"), 90 API: mock.API{ 91 ListVersionsFn: testutil.ListVersions, 92 ListDomainsFn: listDomainsOK, 93 }, 94 WantOutput: listDomainsVerboseOutput, 95 }, 96 { 97 Args: args("-v domain list --service-id 123 --version 1"), 98 API: mock.API{ 99 ListVersionsFn: testutil.ListVersions, 100 ListDomainsFn: listDomainsOK, 101 }, 102 WantOutput: listDomainsVerboseOutput, 103 }, 104 { 105 Args: args("domain list --service-id 123 --version 1"), 106 API: mock.API{ 107 ListVersionsFn: testutil.ListVersions, 108 ListDomainsFn: listDomainsError, 109 }, 110 WantError: errTest.Error(), 111 }, 112 } 113 for testcaseIdx := range scenarios { 114 testcase := &scenarios[testcaseIdx] 115 t.Run(testcase.Name, func(t *testing.T) { 116 var stdout bytes.Buffer 117 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 118 opts := testutil.MockGlobalData(testcase.Args, &stdout) 119 opts.APIClientFactory = mock.APIClient(testcase.API) 120 return opts, nil 121 } 122 err := app.Run(testcase.Args, nil) 123 testutil.AssertErrorContains(t, err, testcase.WantError) 124 testutil.AssertString(t, testcase.WantOutput, stdout.String()) 125 }) 126 } 127 } 128 129 func TestDomainDescribe(t *testing.T) { 130 args := testutil.Args 131 scenarios := []testutil.TestScenario{ 132 { 133 Args: args("domain describe --service-id 123 --version 1"), 134 WantError: "error parsing arguments: required flag --name not provided", 135 }, 136 { 137 Args: args("domain describe --service-id 123 --version 1 --name www.test.com"), 138 API: mock.API{ 139 ListVersionsFn: testutil.ListVersions, 140 GetDomainFn: getDomainError, 141 }, 142 WantError: errTest.Error(), 143 }, 144 { 145 Args: args("domain describe --service-id 123 --version 1 --name www.test.com"), 146 API: mock.API{ 147 ListVersionsFn: testutil.ListVersions, 148 GetDomainFn: getDomainOK, 149 }, 150 WantOutput: describeDomainOutput, 151 }, 152 } 153 for testcaseIdx := range scenarios { 154 testcase := &scenarios[testcaseIdx] 155 t.Run(testcase.Name, func(t *testing.T) { 156 var stdout bytes.Buffer 157 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 158 opts := testutil.MockGlobalData(testcase.Args, &stdout) 159 opts.APIClientFactory = mock.APIClient(testcase.API) 160 return opts, nil 161 } 162 err := app.Run(testcase.Args, nil) 163 testutil.AssertErrorContains(t, err, testcase.WantError) 164 testutil.AssertString(t, testcase.WantOutput, stdout.String()) 165 }) 166 } 167 } 168 169 func TestDomainUpdate(t *testing.T) { 170 args := testutil.Args 171 scenarios := []testutil.TestScenario{ 172 { 173 Args: args("domain update --service-id 123 --version 1 --new-name www.test.com --comment "), 174 WantError: "error parsing arguments: required flag --name not provided", 175 }, 176 { 177 Args: args("domain update --service-id 123 --version 1 --name www.test.com --autoclone"), 178 API: mock.API{ 179 ListVersionsFn: testutil.ListVersions, 180 CloneVersionFn: testutil.CloneVersionResult(4), 181 UpdateDomainFn: updateDomainOK, 182 }, 183 WantError: "error parsing arguments: must provide either --new-name or --comment to update domain", 184 }, 185 { 186 Args: args("domain update --service-id 123 --version 1 --name www.test.com --new-name www.example.com --autoclone"), 187 API: mock.API{ 188 ListVersionsFn: testutil.ListVersions, 189 CloneVersionFn: testutil.CloneVersionResult(4), 190 UpdateDomainFn: updateDomainError, 191 }, 192 WantError: errTest.Error(), 193 }, 194 { 195 Args: args("domain update --service-id 123 --version 1 --name www.test.com --new-name www.example.com --autoclone"), 196 API: mock.API{ 197 ListVersionsFn: testutil.ListVersions, 198 CloneVersionFn: testutil.CloneVersionResult(4), 199 UpdateDomainFn: updateDomainOK, 200 }, 201 WantOutput: "Updated domain www.example.com (service 123 version 4)", 202 }, 203 } 204 for testcaseIdx := range scenarios { 205 testcase := &scenarios[testcaseIdx] 206 t.Run(testcase.Name, func(t *testing.T) { 207 var stdout bytes.Buffer 208 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 209 opts := testutil.MockGlobalData(testcase.Args, &stdout) 210 opts.APIClientFactory = mock.APIClient(testcase.API) 211 return opts, nil 212 } 213 err := app.Run(testcase.Args, nil) 214 testutil.AssertErrorContains(t, err, testcase.WantError) 215 testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) 216 }) 217 } 218 } 219 220 func TestDomainDelete(t *testing.T) { 221 args := testutil.Args 222 scenarios := []testutil.TestScenario{ 223 { 224 Args: args("domain delete --service-id 123 --version 1"), 225 WantError: "error parsing arguments: required flag --name not provided", 226 }, 227 { 228 Args: args("domain delete --service-id 123 --version 1 --name www.test.com --autoclone"), 229 API: mock.API{ 230 ListVersionsFn: testutil.ListVersions, 231 CloneVersionFn: testutil.CloneVersionResult(4), 232 DeleteDomainFn: deleteDomainError, 233 }, 234 WantError: errTest.Error(), 235 }, 236 { 237 Args: args("domain delete --service-id 123 --version 1 --name www.test.com --autoclone"), 238 API: mock.API{ 239 ListVersionsFn: testutil.ListVersions, 240 CloneVersionFn: testutil.CloneVersionResult(4), 241 DeleteDomainFn: deleteDomainOK, 242 }, 243 WantOutput: "Deleted domain www.test.com (service 123 version 4)", 244 }, 245 } 246 for testcaseIdx := range scenarios { 247 testcase := &scenarios[testcaseIdx] 248 t.Run(testcase.Name, func(t *testing.T) { 249 var stdout bytes.Buffer 250 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 251 opts := testutil.MockGlobalData(testcase.Args, &stdout) 252 opts.APIClientFactory = mock.APIClient(testcase.API) 253 return opts, nil 254 } 255 err := app.Run(testcase.Args, nil) 256 testutil.AssertErrorContains(t, err, testcase.WantError) 257 testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) 258 }) 259 } 260 } 261 262 func TestDomainValidate(t *testing.T) { 263 args := testutil.Args 264 scenarios := []testutil.TestScenario{ 265 { 266 Name: "validate missing --version flag", 267 Args: args("domain validate"), 268 WantError: "error parsing arguments: required flag --version not provided", 269 }, 270 { 271 Name: "validate missing --service-id flag", 272 Args: args("domain validate --version 3"), 273 WantError: "error reading service: no service ID found", 274 }, 275 { 276 Name: "validate missing --name flag", 277 API: mock.API{ 278 ListVersionsFn: testutil.ListVersions, 279 }, 280 Args: args("domain validate --service-id 123 --version 3"), 281 WantError: "error parsing arguments: must provide --name flag", 282 }, 283 { 284 Name: "validate ValidateDomain API error", 285 API: mock.API{ 286 ListVersionsFn: testutil.ListVersions, 287 ValidateDomainFn: func(i *fastly.ValidateDomainInput) (*fastly.DomainValidationResult, error) { 288 return nil, testutil.Err 289 }, 290 }, 291 Args: args("domain validate --name foo.example.com --service-id 123 --version 3"), 292 WantError: testutil.Err.Error(), 293 }, 294 { 295 Name: "validate ValidateAllDomains API error", 296 API: mock.API{ 297 ListVersionsFn: testutil.ListVersions, 298 ValidateAllDomainsFn: func(i *fastly.ValidateAllDomainsInput) ([]*fastly.DomainValidationResult, error) { 299 return nil, testutil.Err 300 }, 301 }, 302 Args: args("domain validate --all --service-id 123 --version 3"), 303 WantError: testutil.Err.Error(), 304 }, 305 { 306 Name: "validate ValidateDomain API success", 307 API: mock.API{ 308 ListVersionsFn: testutil.ListVersions, 309 ValidateDomainFn: validateDomain, 310 }, 311 Args: args("domain validate --name foo.example.com --service-id 123 --version 3"), 312 WantOutput: validateAPISuccess(3), 313 }, 314 { 315 Name: "validate ValidateAllDomains API success", 316 API: mock.API{ 317 ListVersionsFn: testutil.ListVersions, 318 ValidateAllDomainsFn: validateAllDomains, 319 }, 320 Args: args("domain validate --all --service-id 123 --version 3"), 321 WantOutput: validateAllAPISuccess(), 322 }, 323 { 324 Name: "validate missing --autoclone flag is OK", 325 API: mock.API{ 326 ListVersionsFn: testutil.ListVersions, 327 ValidateDomainFn: validateDomain, 328 }, 329 Args: args("domain validate --name foo.example.com --service-id 123 --version 1"), 330 WantOutput: validateAPISuccess(1), 331 }, 332 } 333 334 for testcaseIdx := range scenarios { 335 testcase := &scenarios[testcaseIdx] 336 t.Run(testcase.Name, func(t *testing.T) { 337 var stdout bytes.Buffer 338 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 339 opts := testutil.MockGlobalData(testcase.Args, &stdout) 340 opts.APIClientFactory = mock.APIClient(testcase.API) 341 return opts, nil 342 } 343 err := app.Run(testcase.Args, nil) 344 testutil.AssertErrorContains(t, err, testcase.WantError) 345 testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) 346 }) 347 } 348 } 349 350 var errTest = errors.New("fixture error") 351 352 func createDomainOK(i *fastly.CreateDomainInput) (*fastly.Domain, error) { 353 return &fastly.Domain{ 354 ServiceID: fastly.ToPointer(i.ServiceID), 355 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 356 Name: i.Name, 357 }, nil 358 } 359 360 func createDomainError(_ *fastly.CreateDomainInput) (*fastly.Domain, error) { 361 return nil, errTest 362 } 363 364 func listDomainsOK(i *fastly.ListDomainsInput) ([]*fastly.Domain, error) { 365 return []*fastly.Domain{ 366 { 367 ServiceID: fastly.ToPointer(i.ServiceID), 368 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 369 Name: fastly.ToPointer("www.test.com"), 370 Comment: fastly.ToPointer("test"), 371 }, 372 { 373 ServiceID: fastly.ToPointer(i.ServiceID), 374 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 375 Name: fastly.ToPointer("www.example.com"), 376 Comment: fastly.ToPointer("example"), 377 }, 378 }, nil 379 } 380 381 func listDomainsError(_ *fastly.ListDomainsInput) ([]*fastly.Domain, error) { 382 return nil, errTest 383 } 384 385 var listDomainsShortOutput = strings.TrimSpace(` 386 SERVICE VERSION NAME COMMENT 387 123 1 www.test.com test 388 123 1 www.example.com example 389 `) + "\n" 390 391 var listDomainsVerboseOutput = strings.TrimSpace(` 392 Fastly API endpoint: https://api.fastly.com 393 Fastly API token provided via config file (profile: user) 394 395 Service ID (via --service-id): 123 396 397 Version: 1 398 Domain 1/2 399 Name: www.test.com 400 Comment: test 401 Domain 2/2 402 Name: www.example.com 403 Comment: example 404 `) + "\n\n" 405 406 func getDomainOK(i *fastly.GetDomainInput) (*fastly.Domain, error) { 407 return &fastly.Domain{ 408 ServiceID: fastly.ToPointer(i.ServiceID), 409 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 410 Name: fastly.ToPointer(i.Name), 411 Comment: fastly.ToPointer("test"), 412 }, nil 413 } 414 415 func getDomainError(_ *fastly.GetDomainInput) (*fastly.Domain, error) { 416 return nil, errTest 417 } 418 419 var describeDomainOutput = "\n" + strings.TrimSpace(` 420 Service ID: 123 421 Version: 1 422 Name: www.test.com 423 Comment: test 424 `) + "\n" 425 426 func updateDomainOK(i *fastly.UpdateDomainInput) (*fastly.Domain, error) { 427 return &fastly.Domain{ 428 ServiceID: fastly.ToPointer(i.ServiceID), 429 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 430 Name: i.NewName, 431 }, nil 432 } 433 434 func updateDomainError(_ *fastly.UpdateDomainInput) (*fastly.Domain, error) { 435 return nil, errTest 436 } 437 438 func deleteDomainOK(_ *fastly.DeleteDomainInput) error { 439 return nil 440 } 441 442 func deleteDomainError(_ *fastly.DeleteDomainInput) error { 443 return errTest 444 } 445 446 func validateDomain(i *fastly.ValidateDomainInput) (*fastly.DomainValidationResult, error) { 447 return &fastly.DomainValidationResult{ 448 Metadata: &fastly.DomainMetadata{ 449 ServiceID: fastly.ToPointer(i.ServiceID), 450 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 451 Name: fastly.ToPointer(i.Name), 452 }, 453 CName: fastly.ToPointer("foo"), 454 Valid: fastly.ToPointer(true), 455 }, nil 456 } 457 458 func validateAllDomains(i *fastly.ValidateAllDomainsInput) (results []*fastly.DomainValidationResult, err error) { 459 return []*fastly.DomainValidationResult{ 460 { 461 Metadata: &fastly.DomainMetadata{ 462 ServiceID: fastly.ToPointer(i.ServiceID), 463 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 464 Name: fastly.ToPointer("foo.example.com"), 465 }, 466 CName: fastly.ToPointer("foo"), 467 Valid: fastly.ToPointer(true), 468 }, 469 { 470 Metadata: &fastly.DomainMetadata{ 471 ServiceID: fastly.ToPointer(i.ServiceID), 472 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 473 Name: fastly.ToPointer("bar.example.com"), 474 }, 475 CName: fastly.ToPointer("bar"), 476 Valid: fastly.ToPointer(true), 477 }, 478 }, nil 479 } 480 481 func validateAPISuccess(version int) string { 482 return fmt.Sprintf(` 483 Service ID: 123 484 Service Version: %d 485 486 Name: foo.example.com 487 Valid: true 488 CNAME: foo`, version) 489 } 490 491 func validateAllAPISuccess() string { 492 return ` 493 Service ID: 123 494 Service Version: 3 495 496 Name: foo.example.com 497 Valid: true 498 CNAME: foo 499 500 Name: bar.example.com 501 Valid: true 502 CNAME: bar` 503 }