-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(product): Add 'product' commands for each Fastly product. #1362
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,6 +79,7 @@ kv-store-entry | |
log-tail | ||
logging | ||
pops | ||
product | ||
products | ||
profile | ||
purge | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package bot_management | ||
|
||
import ( | ||
"io" | ||
|
||
"github.com/fastly/go-fastly/v9/fastly" | ||
"github.com/fastly/go-fastly/v9/fastly/products/bot_management" | ||
|
||
"github.com/fastly/cli/pkg/api" | ||
"github.com/fastly/cli/pkg/argparser" | ||
"github.com/fastly/cli/pkg/global" | ||
"github.com/fastly/cli/pkg/manifest" | ||
"github.com/fastly/cli/pkg/text" | ||
) | ||
|
||
// DisableFn is a dependency-injection point for unit tests to provide | ||
// a mock implementation of the API operation. | ||
var DisableFn = func(client api.Interface, serviceID string) error { | ||
return bot_management.Disable(client.(*fastly.Client), serviceID) | ||
} | ||
kpfleming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// DisableCommand calls the Fastly API to disable the product. | ||
type DisableCommand struct { | ||
argparser.Base | ||
Manifest manifest.Data | ||
|
||
serviceName argparser.OptionalServiceNameID | ||
} | ||
|
||
// NewDisableCommand returns a usable command registered under the parent. | ||
func NewDisableCommand(parent argparser.Registerer, g *global.Data) *DisableCommand { | ||
c := DisableCommand{ | ||
Base: argparser.Base{ | ||
Globals: g, | ||
}, | ||
} | ||
c.CmdClause = parent.Command("disable", "Disable the "+bot_management.ProductName+" product") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At first, I was rather confused until I realized that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was confused by that when I started working in Go; if you're in package A, and you've also imported a package named A, then qualified references like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might I suggest an alias is probably appropriate here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is what got me down the road of using a 'generic' import alias in the other project; if there are 9 packages that all import their corresponding 'API' functionality from another module, they could use the same import alias, to keep things consistent for the reader. What crosses my mind is that if I see There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Try it and see what feels best, I guess! |
||
|
||
// Optional. | ||
c.RegisterFlag(argparser.StringFlagOpts{ | ||
Name: argparser.FlagServiceIDName, | ||
Description: argparser.FlagServiceIDDesc, | ||
Dst: &g.Manifest.Flag.ServiceID, | ||
Short: 's', | ||
}) | ||
c.RegisterFlag(argparser.StringFlagOpts{ | ||
Action: c.serviceName.Set, | ||
Name: argparser.FlagServiceName, | ||
Description: argparser.FlagServiceNameDesc, | ||
Dst: &c.serviceName.Value, | ||
}) | ||
return &c | ||
} | ||
|
||
// Exec invokes the application logic for the command. | ||
func (c *DisableCommand) Exec(_ io.Reader, out io.Writer) error { | ||
serviceID, source, flag, err := argparser.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) | ||
if err != nil { | ||
c.Globals.ErrLog.Add(err) | ||
return err | ||
} | ||
|
||
if c.Globals.Verbose() { | ||
argparser.DisplayServiceID(serviceID, flag, source, out) | ||
} | ||
|
||
err = DisableFn(c.Globals.APIClient, serviceID) | ||
if err != nil { | ||
c.Globals.ErrLog.Add(err) | ||
return err | ||
} | ||
|
||
text.Success(out, | ||
"Disabled "+bot_management.ProductName+" on service %s", serviceID) | ||
|
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// Package bot_management contains commands to enable and disable the | ||
// Fastly Bot Management product. | ||
package bot_management | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package bot_management | ||
|
||
import ( | ||
"io" | ||
|
||
"github.com/fastly/go-fastly/v9/fastly" | ||
"github.com/fastly/go-fastly/v9/fastly/products/bot_management" | ||
|
||
"github.com/fastly/cli/pkg/api" | ||
"github.com/fastly/cli/pkg/argparser" | ||
"github.com/fastly/cli/pkg/global" | ||
"github.com/fastly/cli/pkg/manifest" | ||
"github.com/fastly/cli/pkg/text" | ||
) | ||
|
||
// EnableFn is a dependency-injection point for unit tests to provide | ||
// a mock implementation of the API operation. | ||
var EnableFn = func(client api.Interface, serviceID string) (*bot_management.EnableOutput, error) { | ||
return bot_management.Enable(client.(*fastly.Client), serviceID) | ||
} | ||
|
||
// EnableCommand calls the Fastly API to enable the product. | ||
type EnableCommand struct { | ||
argparser.Base | ||
Manifest manifest.Data | ||
|
||
serviceName argparser.OptionalServiceNameID | ||
} | ||
|
||
// NewEnableCommand returns a usable command registered under the parent. | ||
func NewEnableCommand(parent argparser.Registerer, g *global.Data) *EnableCommand { | ||
c := EnableCommand{ | ||
Base: argparser.Base{ | ||
Globals: g, | ||
}, | ||
} | ||
c.CmdClause = parent.Command("enable", "Enable the "+bot_management.ProductName+" product") | ||
|
||
// Optional. | ||
c.RegisterFlag(argparser.StringFlagOpts{ | ||
Name: argparser.FlagServiceIDName, | ||
Description: argparser.FlagServiceIDDesc, | ||
Dst: &g.Manifest.Flag.ServiceID, | ||
Short: 's', | ||
}) | ||
c.RegisterFlag(argparser.StringFlagOpts{ | ||
Action: c.serviceName.Set, | ||
Name: argparser.FlagServiceName, | ||
Description: argparser.FlagServiceNameDesc, | ||
Dst: &c.serviceName.Value, | ||
}) | ||
return &c | ||
} | ||
|
||
// Exec invokes the application logic for the command. | ||
func (c *EnableCommand) Exec(_ io.Reader, out io.Writer) error { | ||
serviceID, source, flag, err := argparser.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) | ||
if err != nil { | ||
c.Globals.ErrLog.Add(err) | ||
return err | ||
} | ||
|
||
if c.Globals.Verbose() { | ||
argparser.DisplayServiceID(serviceID, flag, source, out) | ||
} | ||
|
||
_, err = EnableFn(c.Globals.APIClient, serviceID) | ||
if err != nil { | ||
c.Globals.ErrLog.Add(err) | ||
return err | ||
} | ||
|
||
text.Success(out, | ||
"Enabled "+bot_management.ProductName+" on service %s", serviceID) | ||
|
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
package bot_management_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/fastly/go-fastly/v9/fastly" | ||
"github.com/fastly/go-fastly/v9/fastly/products/bot_management" | ||
|
||
"github.com/fastly/cli/pkg/api" | ||
root "github.com/fastly/cli/pkg/commands/product" | ||
sub "github.com/fastly/cli/pkg/commands/product/bot_management" | ||
"github.com/fastly/cli/pkg/global" | ||
"github.com/fastly/cli/pkg/testutil" | ||
) | ||
|
||
func TestProductEnablement(t *testing.T) { | ||
scenarios := []testutil.CLIScenario{ | ||
{ | ||
Name: "validate missing Service ID: enable", | ||
Args: "enable", | ||
WantError: "error reading service: no service ID found", | ||
}, | ||
{ | ||
Name: "validate missing Service ID: disable", | ||
Args: "enable", | ||
WantError: "error reading service: no service ID found", | ||
}, | ||
{ | ||
Name: "validate missing Service ID: status", | ||
Args: "enable", | ||
WantError: "error reading service: no service ID found", | ||
}, | ||
{ | ||
Name: "validate invalid json/verbose flag combo: status", | ||
Args: "status --service-id 123 --json --verbose", | ||
WantError: "invalid flag combination, --verbose and --json", | ||
}, | ||
{ | ||
Name: "validate success for enabling product", | ||
Setup: func(t *testing.T, scenario *testutil.CLIScenario, opts *global.Data) { | ||
sub.EnableFn = func(_ api.Interface, _ string) (*bot_management.EnableOutput, error) { | ||
return nil, nil | ||
} | ||
kpfleming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}, | ||
Args: "enable --service-id 123", | ||
WantOutput: "SUCCESS: Enabled " + bot_management.ProductName + " on service 123", | ||
}, | ||
{ | ||
Name: "validate failure for enabling product", | ||
Setup: func(t *testing.T, scenario *testutil.CLIScenario, opts *global.Data) { | ||
sub.EnableFn = func(_ api.Interface, _ string) (*bot_management.EnableOutput, error) { | ||
return nil, testutil.Err | ||
} | ||
}, | ||
Args: "enable --service-id 123", | ||
WantError: "test error", | ||
}, | ||
{ | ||
Name: "validate success for disabling product", | ||
Setup: func(t *testing.T, scenario *testutil.CLIScenario, opts *global.Data) { | ||
sub.DisableFn = func(_ api.Interface, _ string) error { | ||
return nil | ||
} | ||
}, | ||
Args: "disable --service-id 123", | ||
WantOutput: "SUCCESS: Disabled " + bot_management.ProductName + " on service 123", | ||
}, | ||
{ | ||
Name: "validate failure for disabling product", | ||
Setup: func(t *testing.T, scenario *testutil.CLIScenario, opts *global.Data) { | ||
sub.DisableFn = func(_ api.Interface, _ string) error { | ||
return testutil.Err | ||
} | ||
}, | ||
Args: "disable --service-id 123", | ||
WantError: "test error", | ||
}, | ||
{ | ||
Name: "validate regular status output for enabled product", | ||
Setup: func(t *testing.T, scenario *testutil.CLIScenario, opts *global.Data) { | ||
sub.GetFn = func(_ api.Interface, _ string) (*bot_management.EnableOutput, error) { | ||
return nil, nil | ||
} | ||
}, | ||
Args: "status --service-id 123", | ||
WantOutput: "INFO: " + bot_management.ProductName + " is enabled on service 123", | ||
}, | ||
{ | ||
Name: "validate JSON status output for enabled product", | ||
Setup: func(t *testing.T, scenario *testutil.CLIScenario, opts *global.Data) { | ||
sub.GetFn = func(_ api.Interface, _ string) (*bot_management.EnableOutput, error) { | ||
return nil, nil | ||
} | ||
}, | ||
Args: "status --service-id 123 --json", | ||
WantOutput: "{\n \"enabled\": true\n}", | ||
}, | ||
{ | ||
Name: "validate regular status output for disabled product", | ||
Setup: func(t *testing.T, scenario *testutil.CLIScenario, opts *global.Data) { | ||
sub.GetFn = func(_ api.Interface, _ string) (*bot_management.EnableOutput, error) { | ||
// The API returns a 'Bad Request' error when the | ||
// product has not been enabled on the service | ||
return nil, &fastly.HTTPError{StatusCode: 400} | ||
} | ||
}, | ||
Args: "status --service-id 123", | ||
WantOutput: "INFO: " + bot_management.ProductName + " is disabled on service 123", | ||
}, | ||
{ | ||
Name: "validate JSON status output for disabled product", | ||
Setup: func(t *testing.T, scenario *testutil.CLIScenario, opts *global.Data) { | ||
sub.GetFn = func(_ api.Interface, _ string) (*bot_management.EnableOutput, error) { | ||
// The API returns a 'Bad Request' error when the | ||
// product has not been enabled on the service | ||
return nil, &fastly.HTTPError{StatusCode: 400} | ||
} | ||
}, | ||
Args: "status --service-id 123 --json", | ||
WantOutput: "{\n \"enabled\": false\n}", | ||
}, | ||
} | ||
|
||
testutil.RunCLIScenarios(t, []string{root.CommandName, sub.CommandName}, scenarios) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably a Go idiom or just a style preference of my own from familiarity with the standard library, but i suggest
DisableFunc
and friends.