package add import ( "context" "errors" "fmt" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "edge-infra.dev/pkg/edge/api/fake" "edge-infra.dev/pkg/edge/api/graph/model" "edge-infra.dev/pkg/edge/edgeadmin/commands/operatorintervention/add/mocks" "edge-infra.dev/pkg/edge/edgecli" "edge-infra.dev/pkg/edge/edgecli/flagutil" "edge-infra.dev/pkg/lib/cli/rags" ) // testing helper type type helper interface { Helper() } func EqualError(message string) assert.ErrorAssertionFunc { return func(t assert.TestingT, err error, i ...interface{}) bool { if help, ok := t.(helper); ok { help.Helper() } return assert.EqualError(t, err, message, i...) } } // Set a dummy token in a fake banner context so that we bypass the // ValidateConnectionFlags check which would otherwise do a login // mutation to the api server, something which is not supported by // the fake server func testConfig(endpointURL string) *edgecli.Config { future := time.Now().Add(time.Hour * 24) return &edgecli.Config{ CurrentBannerContext: "fakeBanner", BannerContexts: map[string]*edgecli.BannerContext{ "fakeBanner": { TokenTime: future.Format(time.RFC3339), Token: "fakeToken", Endpoint: endpointURL, }, }, } } func TestSubCommands(t *testing.T) { t.Parallel() tests := map[string]struct { subcommand SubCommand callback fake.APIRequestsCallback flagFunc func(rags *rags.RagSet) error errAssert assert.ErrorAssertionFunc }{ "Command: One Value": { subcommand: &Command{}, callback: mocks.CreateOperatorInterventionCommand, flagFunc: func(rags *rags.RagSet) error { return flagutil.SetFlag(rags, flagutil.OICommand, "val") }, errAssert: assert.NoError, }, "Command: Multiple Values": { subcommand: &Command{}, callback: mocks.CreateOperatorInterventionCommand, flagFunc: func(rags *rags.RagSet) error { return errors.Join( flagutil.SetFlag(rags, flagutil.OICommand, "val1"), flagutil.SetFlag(rags, flagutil.OICommand, "val2"), flagutil.SetFlag(rags, flagutil.OICommand, "val3"), ) }, errAssert: assert.NoError, }, "Command: Nil": { subcommand: &Command{}, callback: mocks.CreateOperatorInterventionCommand, flagFunc: func(_ *rags.RagSet) error { return nil }, errAssert: EqualError(fmt.Sprintf("Flag '%s' is required", flagutil.OICommand)), }, "Privilege: One Value": { subcommand: &Privilege{}, callback: mocks.CreateOperatorInterventionPrivilege, flagFunc: func(rags *rags.RagSet) error { return flagutil.SetFlag(rags, flagutil.OIPrivilege, "val") }, errAssert: assert.NoError, }, "Privilege: Multiple Values": { subcommand: &Privilege{}, callback: mocks.CreateOperatorInterventionPrivilege, flagFunc: func(rags *rags.RagSet) error { return errors.Join( flagutil.SetFlag(rags, flagutil.OIPrivilege, "val1"), flagutil.SetFlag(rags, flagutil.OIPrivilege, "val2"), flagutil.SetFlag(rags, flagutil.OIPrivilege, "val3"), ) }, errAssert: assert.NoError, }, "Privilege: Nil": { subcommand: &Privilege{}, callback: mocks.CreateOperatorInterventionPrivilege, flagFunc: func(_ *rags.RagSet) error { return nil }, errAssert: EqualError(fmt.Sprintf("Flag '%s' is required", flagutil.OIPrivilege)), }, "Rule: One Command": { subcommand: &Rule{}, callback: mocks.UpdateOperatorInterventionRule, flagFunc: func(rags *rags.RagSet) error { return errors.Join( flagutil.SetFlag(rags, flagutil.OIPrivilege, "val"), flagutil.SetFlag(rags, flagutil.OICommand, "val"), ) }, errAssert: assert.NoError, }, "Rule: Multiple Commands": { subcommand: &Rule{}, callback: mocks.UpdateOperatorInterventionRule, flagFunc: func(rags *rags.RagSet) error { return errors.Join( flagutil.SetFlag(rags, flagutil.OIPrivilege, "val"), flagutil.SetFlag(rags, flagutil.OICommand, "val1"), flagutil.SetFlag(rags, flagutil.OICommand, "val2"), flagutil.SetFlag(rags, flagutil.OICommand, "val3"), ) }, errAssert: assert.NoError, }, "Rule: No Privilege": { subcommand: &Rule{}, callback: mocks.UpdateOperatorInterventionRule, flagFunc: func(rags *rags.RagSet) error { return flagutil.SetFlag(rags, flagutil.OICommand, "val") }, errAssert: EqualError(fmt.Sprintf("Flag '%s' is required", flagutil.OIPrivilege)), }, "Rule: No Command": { subcommand: &Rule{}, callback: mocks.UpdateOperatorInterventionRule, flagFunc: func(rags *rags.RagSet) error { return flagutil.SetFlag(rags, flagutil.OIPrivilege, "val") }, errAssert: EqualError(fmt.Sprintf("Flag '%s' is required", flagutil.OICommand)), }, "RoleMapping: One Privilege": { subcommand: &RoleMapping{}, callback: mocks.UpdateOperatorInterventionRoleMapping, flagFunc: func(rags *rags.RagSet) error { return errors.Join( flagutil.SetFlag(rags, flagutil.OIRole, "val"), flagutil.SetFlag(rags, flagutil.OIPrivilege, "val"), ) }, errAssert: assert.NoError, }, "RoleMapping: Multiple Privileges": { subcommand: &RoleMapping{}, callback: mocks.UpdateOperatorInterventionRoleMapping, flagFunc: func(rags *rags.RagSet) error { return errors.Join( flagutil.SetFlag(rags, flagutil.OIRole, "val"), flagutil.SetFlag(rags, flagutil.OIPrivilege, "val1"), flagutil.SetFlag(rags, flagutil.OIPrivilege, "val2"), flagutil.SetFlag(rags, flagutil.OIPrivilege, "val3"), ) }, errAssert: assert.NoError, }, "RoleMapping: No Role": { subcommand: &RoleMapping{}, callback: mocks.UpdateOperatorInterventionRoleMapping, flagFunc: func(rags *rags.RagSet) error { return flagutil.SetFlag(rags, flagutil.OIPrivilege, "val") }, errAssert: EqualError(fmt.Sprintf("Flag '%s' is required", flagutil.OIRole)), }, "RoleMapping: No Privilege": { subcommand: &RoleMapping{}, callback: mocks.UpdateOperatorInterventionRoleMapping, flagFunc: func(rags *rags.RagSet) error { return flagutil.SetFlag(rags, flagutil.OIRole, "val") }, errAssert: EqualError(fmt.Sprintf("Flag '%s' is required", flagutil.OIPrivilege)), }, } for name, tc := range tests { tc := tc t.Run(name, func(t *testing.T) { t.Parallel() // Create mock API server with mock callback method mockServer := fake.GetMockAPIServer(tc.callback) serverURL := mockServer.URL + "/api/v2" defer mockServer.Close() cmd := newSubcommand(tc.subcommand, testConfig(serverURL)) // Must run cmd.Command() to initialise cmd.Rags cmd.Command() // Set required flags for test require.NoError(t, tc.flagFunc(cmd.Rags)) // Test that fake_server is reached with OK status err := cmd.Command().Exec(context.Background(), nil) tc.errAssert(t, err) }) } } // Test that flags are parsed correctly and expected variables map is generated func TestVariables(t *testing.T) { t.Parallel() tests := map[string]struct { subcommand SubCommand flagFunc func(rags *rags.RagSet) error expectedVariables map[string]interface{} }{ "Command": { subcommand: &Command{}, flagFunc: func(rags *rags.RagSet) error { return errors.Join( flagutil.SetFlag(rags, flagutil.OICommand, "val1"), flagutil.SetFlag(rags, flagutil.OICommand, "val2"), flagutil.SetFlag(rags, flagutil.OICommand, "val3"), ) }, expectedVariables: map[string]interface{}{ "commands": []model.OperatorInterventionCommandInput{ {Name: "val1"}, {Name: "val2"}, {Name: "val3"}, }, }, }, "Privilege": { subcommand: &Privilege{}, flagFunc: func(rags *rags.RagSet) error { return errors.Join( flagutil.SetFlag(rags, flagutil.OIPrivilege, "val1"), flagutil.SetFlag(rags, flagutil.OIPrivilege, "val2"), flagutil.SetFlag(rags, flagutil.OIPrivilege, "val3"), ) }, expectedVariables: map[string]interface{}{ "privileges": []model.OperatorInterventionPrivilegeInput{ {Name: "val1"}, {Name: "val2"}, {Name: "val3"}, }, }, }, "Rule": { subcommand: &Rule{}, flagFunc: func(rags *rags.RagSet) error { return errors.Join( flagutil.SetFlag(rags, flagutil.OIPrivilege, "val"), flagutil.SetFlag(rags, flagutil.OICommand, "val1"), flagutil.SetFlag(rags, flagutil.OICommand, "val2"), flagutil.SetFlag(rags, flagutil.OICommand, "val3"), ) }, expectedVariables: map[string]interface{}{ "rules": []model.UpdateOperatorInterventionRuleInput{ { Privilege: &model.OperatorInterventionPrivilegeInput{Name: "val"}, Commands: []*model.OperatorInterventionCommandInput{ {Name: "val1"}, {Name: "val2"}, {Name: "val3"}, }, }, }, }, }, "RoleMapping": { subcommand: &RoleMapping{}, flagFunc: func(rags *rags.RagSet) error { return errors.Join( flagutil.SetFlag(rags, flagutil.OIRole, "val"), flagutil.SetFlag(rags, flagutil.OIPrivilege, "val1"), flagutil.SetFlag(rags, flagutil.OIPrivilege, "val2"), flagutil.SetFlag(rags, flagutil.OIPrivilege, "val3"), ) }, expectedVariables: map[string]interface{}{ "roleMappings": []model.UpdateOperatorInterventionRoleMappingInput{ { Role: "val", Privileges: []*model.OperatorInterventionPrivilegeInput{ {Name: "val1"}, {Name: "val2"}, {Name: "val3"}, }, }, }, }, }, } for name, tc := range tests { tc := tc t.Run(name, func(t *testing.T) { t.Parallel() cmd := newSubcommand(tc.subcommand, testConfig("")) // Must run cmd.Command() to initialise cmd.Rags cmd.Command() require.NoError(t, tc.flagFunc(cmd.Rags)) assert.Equal(t, tc.expectedVariables, tc.subcommand.Variables()) }) } }