...

Source file src/edge-infra.dev/pkg/edge/edgeadmin/commands/operatorintervention/add/add_test.go

Documentation: edge-infra.dev/pkg/edge/edgeadmin/commands/operatorintervention/add

     1  package add
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"edge-infra.dev/pkg/edge/api/fake"
    14  	"edge-infra.dev/pkg/edge/api/graph/model"
    15  	"edge-infra.dev/pkg/edge/edgeadmin/commands/operatorintervention/add/mocks"
    16  	"edge-infra.dev/pkg/edge/edgecli"
    17  	"edge-infra.dev/pkg/edge/edgecli/flagutil"
    18  	"edge-infra.dev/pkg/lib/cli/rags"
    19  )
    20  
    21  // testing helper type
    22  type helper interface {
    23  	Helper()
    24  }
    25  
    26  func EqualError(message string) assert.ErrorAssertionFunc {
    27  	return func(t assert.TestingT, err error, i ...interface{}) bool {
    28  		if help, ok := t.(helper); ok {
    29  			help.Helper()
    30  		}
    31  
    32  		return assert.EqualError(t, err, message, i...)
    33  	}
    34  }
    35  
    36  // Set a dummy token in a fake banner context so that we bypass the
    37  // ValidateConnectionFlags check which would otherwise do a login
    38  // mutation to the api server, something which is not supported by
    39  // the fake server
    40  func testConfig(endpointURL string) *edgecli.Config {
    41  	future := time.Now().Add(time.Hour * 24)
    42  	return &edgecli.Config{
    43  		CurrentBannerContext: "fakeBanner",
    44  		BannerContexts: map[string]*edgecli.BannerContext{
    45  			"fakeBanner": {
    46  				TokenTime: future.Format(time.RFC3339),
    47  				Token:     "fakeToken",
    48  				Endpoint:  endpointURL,
    49  			},
    50  		},
    51  	}
    52  }
    53  
    54  func TestSubCommands(t *testing.T) {
    55  	t.Parallel()
    56  
    57  	tests := map[string]struct {
    58  		subcommand SubCommand
    59  		callback   fake.APIRequestsCallback
    60  		flagFunc   func(rags *rags.RagSet) error
    61  		errAssert  assert.ErrorAssertionFunc
    62  	}{
    63  		"Command: One Value": {
    64  			subcommand: &Command{},
    65  			callback:   mocks.CreateOperatorInterventionCommand,
    66  			flagFunc: func(rags *rags.RagSet) error {
    67  				return flagutil.SetFlag(rags, flagutil.OICommand, "val")
    68  			},
    69  			errAssert: assert.NoError,
    70  		},
    71  		"Command: Multiple Values": {
    72  			subcommand: &Command{},
    73  			callback:   mocks.CreateOperatorInterventionCommand,
    74  			flagFunc: func(rags *rags.RagSet) error {
    75  				return errors.Join(
    76  					flagutil.SetFlag(rags, flagutil.OICommand, "val1"),
    77  					flagutil.SetFlag(rags, flagutil.OICommand, "val2"),
    78  					flagutil.SetFlag(rags, flagutil.OICommand, "val3"),
    79  				)
    80  			},
    81  			errAssert: assert.NoError,
    82  		},
    83  		"Command: Nil": {
    84  			subcommand: &Command{},
    85  			callback:   mocks.CreateOperatorInterventionCommand,
    86  			flagFunc: func(_ *rags.RagSet) error {
    87  				return nil
    88  			},
    89  			errAssert: EqualError(fmt.Sprintf("Flag '%s' is required", flagutil.OICommand)),
    90  		},
    91  		"Privilege: One Value": {
    92  			subcommand: &Privilege{},
    93  			callback:   mocks.CreateOperatorInterventionPrivilege,
    94  			flagFunc: func(rags *rags.RagSet) error {
    95  				return flagutil.SetFlag(rags, flagutil.OIPrivilege, "val")
    96  			},
    97  			errAssert: assert.NoError,
    98  		},
    99  		"Privilege: Multiple Values": {
   100  			subcommand: &Privilege{},
   101  			callback:   mocks.CreateOperatorInterventionPrivilege,
   102  			flagFunc: func(rags *rags.RagSet) error {
   103  				return errors.Join(
   104  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val1"),
   105  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val2"),
   106  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val3"),
   107  				)
   108  			},
   109  			errAssert: assert.NoError,
   110  		},
   111  		"Privilege: Nil": {
   112  			subcommand: &Privilege{},
   113  			callback:   mocks.CreateOperatorInterventionPrivilege,
   114  			flagFunc: func(_ *rags.RagSet) error {
   115  				return nil
   116  			},
   117  			errAssert: EqualError(fmt.Sprintf("Flag '%s' is required", flagutil.OIPrivilege)),
   118  		},
   119  		"Rule: One Command": {
   120  			subcommand: &Rule{},
   121  			callback:   mocks.UpdateOperatorInterventionRule,
   122  			flagFunc: func(rags *rags.RagSet) error {
   123  				return errors.Join(
   124  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val"),
   125  					flagutil.SetFlag(rags, flagutil.OICommand, "val"),
   126  				)
   127  			},
   128  			errAssert: assert.NoError,
   129  		},
   130  		"Rule: Multiple Commands": {
   131  			subcommand: &Rule{},
   132  			callback:   mocks.UpdateOperatorInterventionRule,
   133  			flagFunc: func(rags *rags.RagSet) error {
   134  				return errors.Join(
   135  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val"),
   136  					flagutil.SetFlag(rags, flagutil.OICommand, "val1"),
   137  					flagutil.SetFlag(rags, flagutil.OICommand, "val2"),
   138  					flagutil.SetFlag(rags, flagutil.OICommand, "val3"),
   139  				)
   140  			},
   141  			errAssert: assert.NoError,
   142  		},
   143  		"Rule: No Privilege": {
   144  			subcommand: &Rule{},
   145  			callback:   mocks.UpdateOperatorInterventionRule,
   146  			flagFunc: func(rags *rags.RagSet) error {
   147  				return flagutil.SetFlag(rags, flagutil.OICommand, "val")
   148  			},
   149  			errAssert: EqualError(fmt.Sprintf("Flag '%s' is required", flagutil.OIPrivilege)),
   150  		},
   151  		"Rule: No Command": {
   152  			subcommand: &Rule{},
   153  			callback:   mocks.UpdateOperatorInterventionRule,
   154  			flagFunc: func(rags *rags.RagSet) error {
   155  				return flagutil.SetFlag(rags, flagutil.OIPrivilege, "val")
   156  			},
   157  			errAssert: EqualError(fmt.Sprintf("Flag '%s' is required", flagutil.OICommand)),
   158  		},
   159  		"RoleMapping: One Privilege": {
   160  			subcommand: &RoleMapping{},
   161  			callback:   mocks.UpdateOperatorInterventionRoleMapping,
   162  			flagFunc: func(rags *rags.RagSet) error {
   163  				return errors.Join(
   164  					flagutil.SetFlag(rags, flagutil.OIRole, "val"),
   165  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val"),
   166  				)
   167  			},
   168  			errAssert: assert.NoError,
   169  		},
   170  		"RoleMapping: Multiple Privileges": {
   171  			subcommand: &RoleMapping{},
   172  			callback:   mocks.UpdateOperatorInterventionRoleMapping,
   173  			flagFunc: func(rags *rags.RagSet) error {
   174  				return errors.Join(
   175  					flagutil.SetFlag(rags, flagutil.OIRole, "val"),
   176  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val1"),
   177  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val2"),
   178  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val3"),
   179  				)
   180  			},
   181  			errAssert: assert.NoError,
   182  		},
   183  		"RoleMapping: No Role": {
   184  			subcommand: &RoleMapping{},
   185  			callback:   mocks.UpdateOperatorInterventionRoleMapping,
   186  			flagFunc: func(rags *rags.RagSet) error {
   187  				return flagutil.SetFlag(rags, flagutil.OIPrivilege, "val")
   188  			},
   189  			errAssert: EqualError(fmt.Sprintf("Flag '%s' is required", flagutil.OIRole)),
   190  		},
   191  		"RoleMapping: No Privilege": {
   192  			subcommand: &RoleMapping{},
   193  			callback:   mocks.UpdateOperatorInterventionRoleMapping,
   194  			flagFunc: func(rags *rags.RagSet) error {
   195  				return flagutil.SetFlag(rags, flagutil.OIRole, "val")
   196  			},
   197  			errAssert: EqualError(fmt.Sprintf("Flag '%s' is required", flagutil.OIPrivilege)),
   198  		},
   199  	}
   200  
   201  	for name, tc := range tests {
   202  		tc := tc
   203  		t.Run(name, func(t *testing.T) {
   204  			t.Parallel()
   205  
   206  			// Create mock API server with mock callback method
   207  			mockServer := fake.GetMockAPIServer(tc.callback)
   208  			serverURL := mockServer.URL + "/api/v2"
   209  			defer mockServer.Close()
   210  
   211  			cmd := newSubcommand(tc.subcommand, testConfig(serverURL))
   212  			// Must run cmd.Command() to initialise cmd.Rags
   213  			cmd.Command()
   214  
   215  			// Set required flags for test
   216  			require.NoError(t, tc.flagFunc(cmd.Rags))
   217  
   218  			// Test that fake_server is reached with OK status
   219  			err := cmd.Command().Exec(context.Background(), nil)
   220  			tc.errAssert(t, err)
   221  		})
   222  	}
   223  }
   224  
   225  // Test that flags are parsed correctly and expected variables map is generated
   226  func TestVariables(t *testing.T) {
   227  	t.Parallel()
   228  
   229  	tests := map[string]struct {
   230  		subcommand        SubCommand
   231  		flagFunc          func(rags *rags.RagSet) error
   232  		expectedVariables map[string]interface{}
   233  	}{
   234  		"Command": {
   235  			subcommand: &Command{},
   236  			flagFunc: func(rags *rags.RagSet) error {
   237  				return errors.Join(
   238  					flagutil.SetFlag(rags, flagutil.OICommand, "val1"),
   239  					flagutil.SetFlag(rags, flagutil.OICommand, "val2"),
   240  					flagutil.SetFlag(rags, flagutil.OICommand, "val3"),
   241  				)
   242  			},
   243  			expectedVariables: map[string]interface{}{
   244  				"commands": []model.OperatorInterventionCommandInput{
   245  					{Name: "val1"},
   246  					{Name: "val2"},
   247  					{Name: "val3"},
   248  				},
   249  			},
   250  		},
   251  		"Privilege": {
   252  			subcommand: &Privilege{},
   253  			flagFunc: func(rags *rags.RagSet) error {
   254  				return errors.Join(
   255  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val1"),
   256  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val2"),
   257  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val3"),
   258  				)
   259  			},
   260  			expectedVariables: map[string]interface{}{
   261  				"privileges": []model.OperatorInterventionPrivilegeInput{
   262  					{Name: "val1"},
   263  					{Name: "val2"},
   264  					{Name: "val3"},
   265  				},
   266  			},
   267  		},
   268  		"Rule": {
   269  			subcommand: &Rule{},
   270  			flagFunc: func(rags *rags.RagSet) error {
   271  				return errors.Join(
   272  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val"),
   273  					flagutil.SetFlag(rags, flagutil.OICommand, "val1"),
   274  					flagutil.SetFlag(rags, flagutil.OICommand, "val2"),
   275  					flagutil.SetFlag(rags, flagutil.OICommand, "val3"),
   276  				)
   277  			},
   278  			expectedVariables: map[string]interface{}{
   279  				"rules": []model.UpdateOperatorInterventionRuleInput{
   280  					{
   281  						Privilege: &model.OperatorInterventionPrivilegeInput{Name: "val"},
   282  						Commands: []*model.OperatorInterventionCommandInput{
   283  							{Name: "val1"},
   284  							{Name: "val2"},
   285  							{Name: "val3"},
   286  						},
   287  					},
   288  				},
   289  			},
   290  		},
   291  		"RoleMapping": {
   292  			subcommand: &RoleMapping{},
   293  			flagFunc: func(rags *rags.RagSet) error {
   294  				return errors.Join(
   295  					flagutil.SetFlag(rags, flagutil.OIRole, "val"),
   296  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val1"),
   297  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val2"),
   298  					flagutil.SetFlag(rags, flagutil.OIPrivilege, "val3"),
   299  				)
   300  			},
   301  			expectedVariables: map[string]interface{}{
   302  				"roleMappings": []model.UpdateOperatorInterventionRoleMappingInput{
   303  					{
   304  						Role: "val",
   305  						Privileges: []*model.OperatorInterventionPrivilegeInput{
   306  							{Name: "val1"},
   307  							{Name: "val2"},
   308  							{Name: "val3"},
   309  						},
   310  					},
   311  				},
   312  			},
   313  		},
   314  	}
   315  
   316  	for name, tc := range tests {
   317  		tc := tc
   318  		t.Run(name, func(t *testing.T) {
   319  			t.Parallel()
   320  
   321  			cmd := newSubcommand(tc.subcommand, testConfig(""))
   322  			// Must run cmd.Command() to initialise cmd.Rags
   323  			cmd.Command()
   324  
   325  			require.NoError(t, tc.flagFunc(cmd.Rags))
   326  
   327  			assert.Equal(t, tc.expectedVariables, tc.subcommand.Variables())
   328  		})
   329  	}
   330  }
   331  

View as plain text