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  }