github.com/fastly/cli@v1.7.2-0.20240304164155-9d0f1d77c3bf/pkg/commands/service/service_test.go (about) 1 package service_test 2 3 import ( 4 "bytes" 5 "errors" 6 "io" 7 "net/http" 8 "os" 9 "path/filepath" 10 "regexp" 11 "strings" 12 "testing" 13 14 "github.com/fastly/go-fastly/v9/fastly" 15 16 "github.com/fastly/cli/pkg/app" 17 "github.com/fastly/cli/pkg/global" 18 "github.com/fastly/cli/pkg/manifest" 19 "github.com/fastly/cli/pkg/mock" 20 "github.com/fastly/cli/pkg/testutil" 21 ) 22 23 func TestServiceCreate(t *testing.T) { 24 args := testutil.Args 25 scenarios := []struct { 26 args []string 27 api mock.API 28 wantError string 29 wantOutput string 30 }{ 31 { 32 args: args("service create --name Foo"), 33 api: mock.API{CreateServiceFn: createServiceOK}, 34 wantOutput: "Created service 12345", 35 }, 36 { 37 args: args("service create -n=Foo"), 38 api: mock.API{CreateServiceFn: createServiceOK}, 39 wantOutput: "Created service 12345", 40 }, 41 { 42 args: args("service create --name Foo --type wasm"), 43 api: mock.API{CreateServiceFn: createServiceOK}, 44 wantOutput: "Created service 12345", 45 }, 46 { 47 args: args("service create --name Foo --type wasm --comment Hello"), 48 api: mock.API{CreateServiceFn: createServiceOK}, 49 wantOutput: "Created service 12345", 50 }, 51 { 52 args: args("service create -n Foo --comment Hello"), 53 api: mock.API{CreateServiceFn: createServiceOK}, 54 wantOutput: "Created service 12345", 55 }, 56 { 57 args: args("service create -n Foo"), 58 api: mock.API{CreateServiceFn: createServiceError}, 59 wantError: errTest.Error(), 60 }, 61 } 62 for testcaseIdx := range scenarios { 63 testcase := &scenarios[testcaseIdx] 64 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 65 var stdout bytes.Buffer 66 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 67 opts := testutil.MockGlobalData(testcase.args, &stdout) 68 opts.APIClientFactory = mock.APIClient(testcase.api) 69 return opts, nil 70 } 71 err := app.Run(testcase.args, nil) 72 testutil.AssertErrorContains(t, err, testcase.wantError) 73 testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) 74 }) 75 } 76 } 77 78 func TestServiceList(t *testing.T) { 79 args := testutil.Args 80 scenarios := []struct { 81 args []string 82 api mock.API 83 wantError string 84 wantOutput string 85 }{ 86 { 87 api: mock.API{ 88 GetServicesFn: func(i *fastly.GetServicesInput) *fastly.ListPaginator[fastly.Service] { 89 return fastly.NewPaginator[fastly.Service](mock.HTTPClient{ 90 Errors: []error{ 91 testutil.Err, 92 }, 93 Responses: []*http.Response{nil}, 94 }, fastly.ListOpts{}, "/example") 95 }, 96 }, 97 args: args("service list"), 98 wantError: testutil.Err.Error(), 99 }, 100 { 101 api: mock.API{ 102 GetServicesFn: func(i *fastly.GetServicesInput) *fastly.ListPaginator[fastly.Service] { 103 return fastly.NewPaginator[fastly.Service](mock.HTTPClient{ 104 Errors: []error{nil}, 105 Responses: []*http.Response{ 106 { 107 Body: io.NopCloser(strings.NewReader(`[ 108 { 109 "name": "Foo", 110 "id": "123", 111 "type": "wasm", 112 "version": 2, 113 "updated_at": "2021-06-15T23:00:00Z" 114 }, 115 { 116 "name": "Bar", 117 "id": "456", 118 "type": "wasm", 119 "version": 1, 120 "updated_at": "2021-06-15T23:00:00Z" 121 }, 122 { 123 "name": "Baz", 124 "id": "789", 125 "type": "vcl", 126 "version": 1 127 } 128 ]`)), 129 }, 130 }, 131 }, fastly.ListOpts{}, "/example") 132 }, 133 }, 134 args: args("service list --per-page 1"), 135 wantOutput: listServicesShortOutput, 136 }, 137 { 138 api: mock.API{ 139 GetServicesFn: func(i *fastly.GetServicesInput) *fastly.ListPaginator[fastly.Service] { 140 return fastly.NewPaginator[fastly.Service](mock.HTTPClient{ 141 Errors: []error{nil}, 142 Responses: []*http.Response{ 143 { 144 Body: io.NopCloser(strings.NewReader(`[ 145 { 146 "name": "Foo", 147 "id": "123", 148 "type": "wasm", 149 "version": 2, 150 "updated_at": "2021-06-15T23:00:00Z", 151 "customer_id": "mycustomerid", 152 "versions": [ 153 { 154 "number": 1, 155 "comment": "a", 156 "service_id": "b", 157 "active": false, 158 "locked": false, 159 "deployed": false, 160 "staging": false, 161 "testing": false, 162 "created_at": "2021-06-15T23:00:00Z", 163 "deleted_at": "2021-06-15T23:00:00Z", 164 "updated_at": "2021-06-15T23:00:00Z" 165 }, 166 { 167 "number": 2, 168 "comment": "c", 169 "service_id": "d", 170 "active": true, 171 "locked": false, 172 "deployed": true, 173 "staging": false, 174 "testing": false, 175 "created_at": "2021-06-15T23:00:00Z", 176 "updated_at": "2021-06-15T23:00:00Z" 177 } 178 ] 179 }, 180 { 181 "name": "Bar", 182 "id": "456", 183 "type": "wasm", 184 "version": 1, 185 "updated_at": "2021-06-15T23:00:00Z", 186 "customer_id": "mycustomerid" 187 }, 188 { 189 "name": "Baz", 190 "id": "789", 191 "type": "vcl", 192 "version": 1, 193 "customer_id": "mycustomerid" 194 } 195 ]`)), 196 }, 197 }, 198 }, fastly.ListOpts{}, "/example") 199 }, 200 }, 201 args: args("service list --verbose"), 202 wantOutput: listServicesVerboseOutput, 203 }, 204 } 205 for testcaseIdx := range scenarios { 206 testcase := &scenarios[testcaseIdx] 207 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 208 var stdout bytes.Buffer 209 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 210 opts := testutil.MockGlobalData(testcase.args, &stdout) 211 opts.APIClientFactory = mock.APIClient(testcase.api) 212 return opts, nil 213 } 214 err := app.Run(testcase.args, nil) 215 testutil.AssertErrorContains(t, err, testcase.wantError) 216 testutil.AssertString(t, testcase.wantOutput, stdout.String()) 217 }) 218 } 219 } 220 221 func TestServiceDescribe(t *testing.T) { 222 args := testutil.Args 223 scenarios := []struct { 224 args []string 225 api mock.API 226 wantError string 227 wantOutput string 228 }{ 229 { 230 args: args("service describe"), 231 api: mock.API{GetServiceDetailsFn: describeServiceOK}, 232 wantError: "error reading service: no service ID found", 233 }, 234 { 235 args: args("service describe --service-id 123"), 236 api: mock.API{GetServiceDetailsFn: describeServiceOK}, 237 wantOutput: describeServiceShortOutput, 238 }, 239 { 240 args: args("service describe --service-id 123 --verbose"), 241 api: mock.API{GetServiceDetailsFn: describeServiceOK}, 242 wantOutput: describeServiceVerboseOutput, 243 }, 244 { 245 args: args("service describe --service-id 123 -v"), 246 api: mock.API{GetServiceDetailsFn: describeServiceOK}, 247 wantOutput: describeServiceVerboseOutput, 248 }, 249 { 250 args: args("service --verbose describe --service-id 123"), 251 api: mock.API{GetServiceDetailsFn: describeServiceOK}, 252 wantOutput: describeServiceVerboseOutput, 253 }, 254 { 255 args: args("-v service describe --service-id 123"), 256 api: mock.API{GetServiceDetailsFn: describeServiceOK}, 257 wantOutput: describeServiceVerboseOutput, 258 }, 259 { 260 args: args("service describe --service-id 123"), 261 api: mock.API{GetServiceDetailsFn: describeServiceError}, 262 wantError: errTest.Error(), 263 }, 264 } 265 for testcaseIdx := range scenarios { 266 testcase := &scenarios[testcaseIdx] 267 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 268 var stdout bytes.Buffer 269 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 270 opts := testutil.MockGlobalData(testcase.args, &stdout) 271 opts.APIClientFactory = mock.APIClient(testcase.api) 272 return opts, nil 273 } 274 err := app.Run(testcase.args, nil) 275 testutil.AssertErrorContains(t, err, testcase.wantError) 276 testutil.AssertString(t, testcase.wantOutput, stdout.String()) 277 }) 278 } 279 } 280 281 func TestServiceSearch(t *testing.T) { 282 args := testutil.Args 283 scenarios := []struct { 284 args []string 285 api mock.API 286 wantError string 287 wantOutput string 288 }{ 289 { 290 args: args("service search"), 291 wantError: "error parsing arguments: required flag --name not provided", 292 }, 293 { 294 args: args("service search --name Foo"), 295 api: mock.API{SearchServiceFn: searchServiceOK}, 296 wantOutput: searchServiceShortOutput, 297 }, 298 { 299 args: args("service search --name Foo -v"), 300 api: mock.API{SearchServiceFn: searchServiceOK}, 301 wantOutput: searchServiceVerboseOutput, 302 }, 303 { 304 args: args("service search --name"), 305 api: mock.API{SearchServiceFn: searchServiceOK}, 306 wantError: "error parsing arguments: expected argument for flag '--name'", 307 }, 308 } 309 for testcaseIdx := range scenarios { 310 testcase := &scenarios[testcaseIdx] 311 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 312 var stdout bytes.Buffer 313 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 314 opts := testutil.MockGlobalData(testcase.args, &stdout) 315 opts.APIClientFactory = mock.APIClient(testcase.api) 316 return opts, nil 317 } 318 err := app.Run(testcase.args, nil) 319 testutil.AssertErrorContains(t, err, testcase.wantError) 320 testutil.AssertString(t, testcase.wantOutput, stdout.String()) 321 }) 322 } 323 } 324 325 func TestServiceUpdate(t *testing.T) { 326 args := testutil.Args 327 scenarios := []struct { 328 args []string 329 api mock.API 330 wantError string 331 wantOutput string 332 }{ 333 { 334 args: args("service update"), 335 api: mock.API{ 336 GetServiceFn: getServiceOK, 337 UpdateServiceFn: updateServiceOK, 338 }, 339 wantError: "error reading service: no service ID found", 340 }, 341 { 342 args: args("service update --service-id 12345"), 343 api: mock.API{UpdateServiceFn: updateServiceOK}, 344 wantError: "error parsing arguments: must provide either --name or --comment to update service", 345 }, 346 { 347 args: args("service update --service-id 12345 --name Foo"), 348 api: mock.API{UpdateServiceFn: updateServiceOK}, 349 wantOutput: "Updated service 12345", 350 }, 351 { 352 args: args("service update --service-id 12345 -n=Foo"), 353 api: mock.API{UpdateServiceFn: updateServiceOK}, 354 wantOutput: "Updated service 12345", 355 }, 356 { 357 args: args("service update --service-id 12345 --name Foo"), 358 api: mock.API{UpdateServiceFn: updateServiceOK}, 359 wantOutput: "Updated service 12345", 360 }, 361 { 362 args: args("service update --service-id 12345 --name Foo --comment Hello"), 363 api: mock.API{UpdateServiceFn: updateServiceOK}, 364 wantOutput: "Updated service 12345", 365 }, 366 { 367 args: args("service update --service-id 12345 -n Foo --comment Hello"), 368 api: mock.API{UpdateServiceFn: updateServiceOK}, 369 wantOutput: "Updated service 12345", 370 }, 371 { 372 args: args("service update --service-id 12345 -n Foo"), 373 api: mock.API{UpdateServiceFn: updateServiceError}, 374 wantError: errTest.Error(), 375 }, 376 } 377 for testcaseIdx := range scenarios { 378 testcase := &scenarios[testcaseIdx] 379 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 380 var stdout bytes.Buffer 381 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 382 opts := testutil.MockGlobalData(testcase.args, &stdout) 383 opts.APIClientFactory = mock.APIClient(testcase.api) 384 return opts, nil 385 } 386 err := app.Run(testcase.args, nil) 387 testutil.AssertErrorContains(t, err, testcase.wantError) 388 testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) 389 }) 390 } 391 } 392 393 func TestServiceDelete(t *testing.T) { 394 args := testutil.Args 395 nonEmptyServiceID := regexp.MustCompile(`service_id = "[^"]+"`) 396 397 scenarios := []struct { 398 args []string 399 api mock.API 400 manifest string 401 wantError string 402 wantOutput string 403 expectEmptyServiceID bool 404 }{ 405 { 406 args: args("service delete"), 407 api: mock.API{DeleteServiceFn: deleteServiceOK}, 408 manifest: "fastly-no-serviceid.toml", 409 wantError: "error reading service: no service ID found", 410 }, 411 { 412 args: args("service delete"), 413 api: mock.API{DeleteServiceFn: deleteServiceOK}, 414 manifest: "fastly-valid.toml", 415 wantOutput: "Deleted service ID 123", 416 expectEmptyServiceID: true, 417 }, 418 { 419 args: args("service delete --service-id 001"), 420 api: mock.API{DeleteServiceFn: deleteServiceOK}, 421 wantOutput: "Deleted service ID 001", 422 }, 423 { 424 args: args("service delete --service-id 001"), 425 api: mock.API{DeleteServiceFn: deleteServiceOK}, 426 manifest: "fastly-valid.toml", 427 wantOutput: "Deleted service ID 001", 428 expectEmptyServiceID: false, 429 }, 430 { 431 args: args("service delete --service-id 001"), 432 api: mock.API{DeleteServiceFn: deleteServiceError}, 433 manifest: "fastly-valid.toml", 434 wantError: errTest.Error(), 435 }, 436 } 437 for testcaseIdx := range scenarios { 438 testcase := &scenarios[testcaseIdx] 439 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 440 // We're going to chdir to an temp environment, 441 // so save the PWD to return to, afterwards. 442 pwd, err := os.Getwd() 443 if err != nil { 444 t.Fatal(err) 445 } 446 447 // Create test environment 448 opts := testutil.EnvOpts{T: t} 449 if testcase.manifest != "" { 450 b, err := os.ReadFile(filepath.Join("testdata", testcase.manifest)) 451 if err != nil { 452 t.Fatal(err) 453 } 454 opts.Write = []testutil.FileIO{ 455 {Src: string(b), Dst: manifest.Filename}, 456 } 457 } 458 rootdir := testutil.NewEnv(opts) 459 defer os.RemoveAll(rootdir) 460 461 // Before running the test, chdir into the temp environment. 462 // When we're done, chdir back to our original location. 463 // This is so we can reliably assert file structure. 464 if err := os.Chdir(rootdir); err != nil { 465 t.Fatal(err) 466 } 467 defer func() { 468 _ = os.Chdir(pwd) 469 }() 470 471 var stdout bytes.Buffer 472 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 473 runOpts := testutil.MockGlobalData(testcase.args, &stdout) 474 runOpts.APIClientFactory = mock.APIClient(testcase.api) 475 return runOpts, nil 476 } 477 runErr := app.Run(testcase.args, nil) 478 testutil.AssertErrorContains(t, runErr, testcase.wantError) 479 testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) 480 481 if testcase.manifest != "" { 482 m := filepath.Join(rootdir, manifest.Filename) 483 b, err := os.ReadFile(m) 484 if err != nil { 485 t.Fatal(err) 486 } 487 488 if testcase.expectEmptyServiceID { 489 testutil.AssertStringContains(t, string(b), `service_id = ""`) 490 } else if !nonEmptyServiceID.Match(b) && runErr == nil { 491 // The runErr check is to prevent the first test case from causing an 492 // accidental failure. As the fastly.toml doesn't have a service_id 493 // set, while marshalling back and forth it'll get converted to an 494 // empty string in the manifest file which will accidentally trigger 495 // the following test error otherwise if we don't check for the nil 496 // error value. Because that first test case expects an error to be 497 // raised we know that we can safely check for `runErr == nil` here. 498 t.Fatal("expected service_id to contain a value") 499 } 500 } 501 }) 502 } 503 } 504 505 var errTest = errors.New("fixture error") 506 507 func createServiceOK(i *fastly.CreateServiceInput) (*fastly.Service, error) { 508 return &fastly.Service{ 509 ServiceID: fastly.ToPointer("12345"), 510 Name: i.Name, 511 }, nil 512 } 513 514 func createServiceError(*fastly.CreateServiceInput) (*fastly.Service, error) { 515 return nil, errTest 516 } 517 518 var listServicesShortOutput = strings.TrimSpace(` 519 NAME ID TYPE ACTIVE VERSION LAST EDITED (UTC) 520 Foo 123 wasm 2 2021-06-15 23:00 521 Bar 456 wasm 1 2021-06-15 23:00 522 Baz 789 vcl 1 n/a 523 `) + "\n" 524 525 var listServicesVerboseOutput = strings.TrimSpace(` 526 Fastly API endpoint: https://api.fastly.com 527 Fastly API token provided via config file (profile: user) 528 529 Service 1/3 530 ID: 123 531 Name: Foo 532 Type: wasm 533 Customer ID: mycustomerid 534 Last edited (UTC): 2021-06-15 23:00 535 Active version: 2 536 Versions: 2 537 Version 1/2 538 Number: 1 539 Comment: a 540 Service ID: b 541 Active: false 542 Locked: false 543 Deployed: false 544 Staging: false 545 Testing: false 546 Created (UTC): 2021-06-15 23:00 547 Last edited (UTC): 2021-06-15 23:00 548 Deleted (UTC): 2021-06-15 23:00 549 Version 2/2 550 Number: 2 551 Comment: c 552 Service ID: d 553 Active: true 554 Locked: false 555 Deployed: true 556 Staging: false 557 Testing: false 558 Created (UTC): 2021-06-15 23:00 559 Last edited (UTC): 2021-06-15 23:00 560 561 Service 2/3 562 ID: 456 563 Name: Bar 564 Type: wasm 565 Customer ID: mycustomerid 566 Last edited (UTC): 2021-06-15 23:00 567 Active version: 1 568 Versions: 0 569 570 Service 3/3 571 ID: 789 572 Name: Baz 573 Type: vcl 574 Customer ID: mycustomerid 575 Active version: 1 576 Versions: 0 577 `) + "\n\n" 578 579 func getServiceOK(_ *fastly.GetServiceInput) (*fastly.Service, error) { 580 return &fastly.Service{ 581 ServiceID: fastly.ToPointer("12345"), 582 Name: fastly.ToPointer("Foo"), 583 Comment: fastly.ToPointer("Bar"), 584 }, nil 585 } 586 587 func describeServiceOK(_ *fastly.GetServiceInput) (*fastly.ServiceDetail, error) { 588 return &fastly.ServiceDetail{ 589 ServiceID: fastly.ToPointer("123"), 590 Name: fastly.ToPointer("Foo"), 591 Type: fastly.ToPointer("wasm"), 592 Comment: fastly.ToPointer("example"), 593 CustomerID: fastly.ToPointer("mycustomerid"), 594 ActiveVersion: &fastly.Version{ 595 Number: fastly.ToPointer(2), 596 Comment: fastly.ToPointer("c"), 597 ServiceID: fastly.ToPointer("d"), 598 Active: fastly.ToPointer(true), 599 Deployed: fastly.ToPointer(true), 600 CreatedAt: testutil.MustParseTimeRFC3339("2001-03-03T04:05:06Z"), 601 UpdatedAt: testutil.MustParseTimeRFC3339("2001-03-04T04:05:06Z"), 602 }, 603 UpdatedAt: testutil.MustParseTimeRFC3339("2010-11-15T19:01:02Z"), 604 Versions: []*fastly.Version{ 605 { 606 Number: fastly.ToPointer(1), 607 Comment: fastly.ToPointer("a"), 608 ServiceID: fastly.ToPointer("b"), 609 CreatedAt: testutil.MustParseTimeRFC3339("2001-02-03T04:05:06Z"), 610 UpdatedAt: testutil.MustParseTimeRFC3339("2001-02-04T04:05:06Z"), 611 DeletedAt: testutil.MustParseTimeRFC3339("2001-02-05T04:05:06Z"), 612 }, 613 { 614 Number: fastly.ToPointer(2), 615 Comment: fastly.ToPointer("c"), 616 ServiceID: fastly.ToPointer("d"), 617 Active: fastly.ToPointer(true), 618 Deployed: fastly.ToPointer(true), 619 CreatedAt: testutil.MustParseTimeRFC3339("2001-03-03T04:05:06Z"), 620 UpdatedAt: testutil.MustParseTimeRFC3339("2001-03-04T04:05:06Z"), 621 }, 622 }, 623 }, nil 624 } 625 626 func describeServiceError(_ *fastly.GetServiceInput) (*fastly.ServiceDetail, error) { 627 return nil, errTest 628 } 629 630 var describeServiceShortOutput = strings.TrimSpace(` 631 ID: 123 632 Name: Foo 633 Type: wasm 634 Comment: example 635 Customer ID: mycustomerid 636 Last edited (UTC): 2010-11-15 19:01 637 Active version: 638 Number: 2 639 Comment: c 640 Service ID: d 641 Active: true 642 Deployed: true 643 Created (UTC): 2001-03-03 04:05 644 Last edited (UTC): 2001-03-04 04:05 645 Versions: 2 646 Version 1/2 647 Number: 1 648 Comment: a 649 Service ID: b 650 Created (UTC): 2001-02-03 04:05 651 Last edited (UTC): 2001-02-04 04:05 652 Deleted (UTC): 2001-02-05 04:05 653 Version 2/2 654 Number: 2 655 Comment: c 656 Service ID: d 657 Active: true 658 Deployed: true 659 Created (UTC): 2001-03-03 04:05 660 Last edited (UTC): 2001-03-04 04:05 661 `) + "\n" 662 663 var describeServiceVerboseOutput = strings.TrimSpace(` 664 Fastly API endpoint: https://api.fastly.com 665 Fastly API token provided via config file (profile: user) 666 667 Service ID (via --service-id): 123 668 669 ID: 123 670 Name: Foo 671 Type: wasm 672 Comment: example 673 Customer ID: mycustomerid 674 Last edited (UTC): 2010-11-15 19:01 675 Active version: 676 Number: 2 677 Comment: c 678 Service ID: d 679 Active: true 680 Deployed: true 681 Created (UTC): 2001-03-03 04:05 682 Last edited (UTC): 2001-03-04 04:05 683 Versions: 2 684 Version 1/2 685 Number: 1 686 Comment: a 687 Service ID: b 688 Created (UTC): 2001-02-03 04:05 689 Last edited (UTC): 2001-02-04 04:05 690 Deleted (UTC): 2001-02-05 04:05 691 Version 2/2 692 Number: 2 693 Comment: c 694 Service ID: d 695 Active: true 696 Deployed: true 697 Created (UTC): 2001-03-03 04:05 698 Last edited (UTC): 2001-03-04 04:05 699 `) + "\n" 700 701 func searchServiceOK(_ *fastly.SearchServiceInput) (*fastly.Service, error) { 702 return &fastly.Service{ 703 ServiceID: fastly.ToPointer("123"), 704 Name: fastly.ToPointer("Foo"), 705 Type: fastly.ToPointer("wasm"), 706 CustomerID: fastly.ToPointer("mycustomerid"), 707 UpdatedAt: testutil.MustParseTimeRFC3339("2010-11-15T19:01:02Z"), 708 Versions: []*fastly.Version{ 709 { 710 Number: fastly.ToPointer(1), 711 Comment: fastly.ToPointer("a"), 712 ServiceID: fastly.ToPointer("b"), 713 CreatedAt: testutil.MustParseTimeRFC3339("2001-02-03T04:05:06Z"), 714 UpdatedAt: testutil.MustParseTimeRFC3339("2001-02-04T04:05:06Z"), 715 DeletedAt: testutil.MustParseTimeRFC3339("2001-02-05T04:05:06Z"), 716 }, 717 { 718 Number: fastly.ToPointer(2), 719 Comment: fastly.ToPointer("c"), 720 ServiceID: fastly.ToPointer("d"), 721 Active: fastly.ToPointer(true), 722 Deployed: fastly.ToPointer(true), 723 CreatedAt: testutil.MustParseTimeRFC3339("2001-03-03T04:05:06Z"), 724 UpdatedAt: testutil.MustParseTimeRFC3339("2001-03-04T04:05:06Z"), 725 }, 726 }, 727 }, nil 728 } 729 730 var searchServiceShortOutput = strings.TrimSpace(` 731 ID: 123 732 Name: Foo 733 Type: wasm 734 Customer ID: mycustomerid 735 Last edited (UTC): 2010-11-15 19:01 736 Versions: 2 737 Version 1/2 738 Number: 1 739 Comment: a 740 Service ID: b 741 Created (UTC): 2001-02-03 04:05 742 Last edited (UTC): 2001-02-04 04:05 743 Deleted (UTC): 2001-02-05 04:05 744 Version 2/2 745 Number: 2 746 Comment: c 747 Service ID: d 748 Active: true 749 Deployed: true 750 Created (UTC): 2001-03-03 04:05 751 Last edited (UTC): 2001-03-04 04:05 752 `) + "\n" 753 754 var searchServiceVerboseOutput = strings.TrimSpace(` 755 Fastly API endpoint: https://api.fastly.com 756 Fastly API token provided via config file (profile: user) 757 758 ID: 123 759 Name: Foo 760 Type: wasm 761 Customer ID: mycustomerid 762 Last edited (UTC): 2010-11-15 19:01 763 Versions: 2 764 Version 1/2 765 Number: 1 766 Comment: a 767 Service ID: b 768 Created (UTC): 2001-02-03 04:05 769 Last edited (UTC): 2001-02-04 04:05 770 Deleted (UTC): 2001-02-05 04:05 771 Version 2/2 772 Number: 2 773 Comment: c 774 Service ID: d 775 Active: true 776 Deployed: true 777 Created (UTC): 2001-03-03 04:05 778 Last edited (UTC): 2001-03-04 04:05 779 `) + "\n" 780 781 func updateServiceOK(_ *fastly.UpdateServiceInput) (*fastly.Service, error) { 782 return &fastly.Service{ 783 ServiceID: fastly.ToPointer("12345"), 784 }, nil 785 } 786 787 func updateServiceError(*fastly.UpdateServiceInput) (*fastly.Service, error) { 788 return nil, errTest 789 } 790 791 func deleteServiceOK(*fastly.DeleteServiceInput) error { 792 return nil 793 } 794 795 func deleteServiceError(*fastly.DeleteServiceInput) error { 796 return errTest 797 }