...

Source file src/edge-infra.dev/pkg/sds/emergencyaccess/msgdata/v2_request_test.go

Documentation: edge-infra.dev/pkg/sds/emergencyaccess/msgdata

     1  package msgdata
     2  
     3  import (
     4  	"encoding/base64"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  
    10  	"edge-infra.dev/pkg/sds/emergencyaccess/apierror"
    11  	"edge-infra.dev/pkg/sds/emergencyaccess/eaconst"
    12  )
    13  
    14  const (
    15  	notAType = eaconst.RequestType("not-a-type")
    16  )
    17  
    18  var (
    19  	defaultV2_0CommandRequest = v2_0CommandRequest{
    20  		ReqData: v2Command{
    21  			Command: "echo",
    22  			Args:    []string{"hello", "world"},
    23  		},
    24  		ReqAttr: map[string]string{
    25  			eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
    26  			eaconst.RequestTypeKey: string(eaconst.Command),
    27  		},
    28  	}
    29  	defaultV2_0ExecutableRequest = v2_0ExecutableRequest{
    30  		ReqData: v2Executable{
    31  			Executable: executable{
    32  				Name:     "myScript",
    33  				Contents: "<base64 encoded contents>",
    34  			},
    35  			Args: []string{"hello", "world"},
    36  		},
    37  		ReqAttr: map[string]string{
    38  			eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
    39  			eaconst.RequestTypeKey: string(eaconst.Executable),
    40  		},
    41  	}
    42  )
    43  
    44  func TestNewV2_0Request(t *testing.T) {
    45  	t.Parallel()
    46  
    47  	tests := map[string]struct {
    48  		payload     string
    49  		requestType eaconst.RequestType
    50  		expected    Request
    51  		errAssert   assert.ErrorAssertionFunc
    52  	}{
    53  		"Command": {
    54  			payload: "echo hello world",
    55  			expected: v2_0CommandRequest{
    56  				ReqData: v2Command{
    57  					Command: "echo",
    58  					Args:    []string{"hello", "world"},
    59  				},
    60  				ReqAttr: map[string]string{
    61  					eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
    62  					eaconst.RequestTypeKey: string(eaconst.Command),
    63  				},
    64  			},
    65  			errAssert: assert.NoError,
    66  		},
    67  		"Executable": {
    68  			payload: "./myScript hello world",
    69  			expected: &v2_0ExecutableRequest{
    70  				ReqData: v2Executable{
    71  					Executable: executable{
    72  						Name: "myScript",
    73  					},
    74  					Args: []string{"hello", "world"},
    75  				},
    76  				ReqAttr: map[string]string{
    77  					eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
    78  					eaconst.RequestTypeKey: string(eaconst.Executable),
    79  				},
    80  			},
    81  			errAssert: assert.NoError,
    82  		},
    83  		"Can't Parse Payload": {
    84  			errAssert: APIError(apierror.ErrInvalidCommand, "payload cannot be empty"),
    85  		},
    86  		"Invalid Command": {
    87  			payload:   "\"\" echo hello world",
    88  			errAssert: APIError(apierror.ErrInvalidCommand, "command is empty", "No command identified"),
    89  		},
    90  		"Invalid Executable Name": {
    91  			payload:   "./\"\" hello world",
    92  			errAssert: APIError(apierror.ErrInvalidCommand, "executable name is empty", "No executable name identified"),
    93  		},
    94  	}
    95  
    96  	for name, tc := range tests {
    97  		tc := tc
    98  		t.Run(name, func(t *testing.T) {
    99  			t.Parallel()
   100  
   101  			actual, err := NewV2_0Request(tc.payload)
   102  			tc.errAssert(t, err)
   103  			assert.Equal(t, tc.expected, actual)
   104  		})
   105  	}
   106  }
   107  
   108  func TestV2_0RequestData(t *testing.T) {
   109  	t.Parallel()
   110  
   111  	tests := map[string]struct {
   112  		req      Request
   113  		expected string
   114  	}{
   115  		"Command": {
   116  			req: defaultV2_0CommandRequest,
   117  			expected: `{
   118  				"command": "echo",
   119  				"args": ["hello", "world"]
   120  			}`,
   121  		},
   122  		"Executable": {
   123  			req: &defaultV2_0ExecutableRequest,
   124  			expected: `{
   125  				"executable": {
   126  					"name": "myScript",
   127  					"contents": "<base64 encoded contents>"
   128  				},
   129  				"args": ["hello", "world"]
   130  			}`,
   131  		},
   132  	}
   133  
   134  	for name, tc := range tests {
   135  		tc := tc
   136  		t.Run(name, func(t *testing.T) {
   137  			t.Parallel()
   138  
   139  			data, err := tc.req.Data()
   140  			assert.NoError(t, err)
   141  			assert.JSONEq(t, tc.expected, string(data))
   142  		})
   143  	}
   144  }
   145  
   146  func TestV2_0CommandRequestAttributes(t *testing.T) {
   147  	t.Parallel()
   148  
   149  	req := defaultV2_0CommandRequest
   150  	assert.Equal(t, req.ReqAttr, req.Attributes())
   151  }
   152  
   153  func TestV2_0ExecutableRequestAttributes(t *testing.T) {
   154  	t.Parallel()
   155  
   156  	req := defaultV2_0ExecutableRequest
   157  	assert.Equal(t, req.ReqAttr, req.Attributes())
   158  }
   159  
   160  func TestV2_0CommandRequestAddAttribute(t *testing.T) {
   161  	t.Parallel()
   162  
   163  	req := v2_0CommandRequest{
   164  		ReqAttr: deepCopyMap(defaultV2_0CommandRequest.ReqAttr),
   165  		ReqData: defaultV2_0CommandRequest.ReqData,
   166  	}
   167  	attr := req.Attributes()
   168  
   169  	req.AddAttribute(defaultKey, defaultVal)
   170  	assert.NotEqual(t, attr, req.Attributes())
   171  	attr[defaultKey] = defaultVal
   172  	assert.Equal(t, attr, req.Attributes())
   173  
   174  	// Test Attributes do not get updated with a changed value
   175  	req.AddAttribute(defaultKey, updatedVal)
   176  	assert.Equal(t, attr, req.Attributes())
   177  	attr[defaultKey] = updatedVal
   178  	assert.NotEqual(t, attr, req.Attributes())
   179  }
   180  
   181  func TestV2_0ExectuableRequestAddAttribute(t *testing.T) {
   182  	t.Parallel()
   183  
   184  	req := v2_0ExecutableRequest{
   185  		ReqAttr: deepCopyMap(defaultV2_0ExecutableRequest.ReqAttr),
   186  		ReqData: defaultV2_0ExecutableRequest.ReqData,
   187  	}
   188  	attr := req.Attributes()
   189  
   190  	req.AddAttribute(defaultKey, defaultVal)
   191  	assert.NotEqual(t, attr, req.Attributes())
   192  	attr[defaultKey] = defaultVal
   193  	assert.Equal(t, attr, req.Attributes())
   194  
   195  	// Test Attributes do not get updated with a changed value
   196  	req.AddAttribute(defaultKey, updatedVal)
   197  	assert.Equal(t, attr, req.Attributes())
   198  	attr[defaultKey] = updatedVal
   199  	assert.NotEqual(t, attr, req.Attributes())
   200  }
   201  
   202  func TestV2_0CommandRequestCommandToBeAuthorized(t *testing.T) {
   203  	t.Parallel()
   204  
   205  	req := defaultV2_0CommandRequest
   206  	assert.Equal(t, req.ReqData.Command, req.CommandToBeAuthorized())
   207  }
   208  
   209  func TestV2_0ExecutableRequestCommandToBeAuthorized(t *testing.T) {
   210  	t.Parallel()
   211  
   212  	req := defaultV2_0ExecutableRequest
   213  	assert.Equal(t, req.ReqData.Executable.Name, req.CommandToBeAuthorized())
   214  }
   215  
   216  func TestV2_0CommandRequestType(t *testing.T) {
   217  	t.Parallel()
   218  
   219  	req := defaultV2_0CommandRequest
   220  	assert.Equal(t, eaconst.Command, req.RequestType())
   221  }
   222  
   223  func TestV2_0ExecutableRequestType(t *testing.T) {
   224  	t.Parallel()
   225  
   226  	req := defaultV2_0ExecutableRequest
   227  	assert.Equal(t, eaconst.Executable, req.RequestType())
   228  }
   229  
   230  func TestV2_0CommandRequestValidate(t *testing.T) {
   231  	t.Parallel()
   232  
   233  	tests := map[string]struct {
   234  		req       v2_0CommandRequest
   235  		errAssert assert.ErrorAssertionFunc
   236  	}{
   237  		"Valid": {
   238  			req: v2_0CommandRequest{
   239  				ReqData: v2Command{
   240  					Command: "echo hello world",
   241  				},
   242  				ReqAttr: map[string]string{
   243  					eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
   244  					eaconst.RequestTypeKey: string(eaconst.Command),
   245  				},
   246  			},
   247  			errAssert: assert.NoError,
   248  		},
   249  		"All Invalid": {
   250  			errAssert: APIError(
   251  				apierror.ErrInvalidCommand,
   252  				"command is empty\nversion attribute \"\" should be \"2.0\"\ntype attribute \"\" should be \"command\"",
   253  				"No command identified",
   254  			),
   255  		},
   256  	}
   257  
   258  	for name, tc := range tests {
   259  		tc := tc
   260  		t.Run(name, func(t *testing.T) {
   261  			t.Parallel()
   262  
   263  			tc.errAssert(t, tc.req.validate())
   264  		})
   265  	}
   266  }
   267  
   268  func TestV2_0ExecutableRequestValidate(t *testing.T) {
   269  	t.Parallel()
   270  
   271  	tests := map[string]struct {
   272  		req       v2_0ExecutableRequest
   273  		errAssert assert.ErrorAssertionFunc
   274  	}{
   275  		"Valid": {
   276  			req: v2_0ExecutableRequest{
   277  				ReqData: v2Executable{
   278  					Executable: executable{
   279  						Name: "myScript",
   280  					},
   281  				},
   282  				ReqAttr: map[string]string{
   283  					eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
   284  					eaconst.RequestTypeKey: string(eaconst.Executable),
   285  				},
   286  			},
   287  			errAssert: assert.NoError,
   288  		},
   289  		"Valid With Contents": {
   290  			req: v2_0ExecutableRequest{
   291  				ReqData: v2Executable{
   292  					Executable: executable{
   293  						Name:     "myScript",
   294  						Contents: base64.StdEncoding.EncodeToString([]byte("some contents")),
   295  					},
   296  				},
   297  				ReqAttr: map[string]string{
   298  					eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
   299  					eaconst.RequestTypeKey: string(eaconst.Executable),
   300  				},
   301  			},
   302  			errAssert: assert.NoError,
   303  		},
   304  		"All Invalid": {
   305  			errAssert: APIError(
   306  				apierror.ErrInvalidCommand,
   307  				"executable name is empty\nversion attribute \"\" should be \"2.0\"\ntype attribute \"\" should be \"executable\"",
   308  				"No executable name identified",
   309  			),
   310  		},
   311  	}
   312  
   313  	for name, tc := range tests {
   314  		tc := tc
   315  		t.Run(name, func(t *testing.T) {
   316  			t.Parallel()
   317  
   318  			tc.errAssert(t, tc.req.validate())
   319  		})
   320  	}
   321  }
   322  
   323  func TestV2_0ArtifactorWriteContents(t *testing.T) {
   324  	t.Parallel()
   325  
   326  	contents := "<example contents>"
   327  
   328  	// Take a copy of the default executable test - this avoids issues where we
   329  	// modify the default value used by other tests
   330  	v2Request := defaultV2_0ExecutableRequest
   331  
   332  	tests := map[string]struct {
   333  		req     Request
   334  		expOk   bool
   335  		expData string
   336  	}{
   337  		"Command": {
   338  			req:   defaultV2_0CommandRequest,
   339  			expOk: false,
   340  		},
   341  		"Executable": {
   342  			req:   &v2Request,
   343  			expOk: true,
   344  			expData: fmt.Sprintf(`{
   345  				"executable": {
   346  					"name": "myScript",
   347  					"contents": "%s"
   348  				},
   349  				"args": ["hello", "world"]
   350  			}`, contents),
   351  		},
   352  	}
   353  
   354  	for name, tc := range tests {
   355  		tc := tc
   356  		t.Run(name, func(t *testing.T) {
   357  			t.Parallel()
   358  
   359  			artifactor, ok := tc.req.(Artifactor)
   360  			assert.Equal(t, tc.expOk, ok)
   361  
   362  			if ok {
   363  				artifactor.WriteContents(contents)
   364  				data, err := tc.req.Data()
   365  				assert.NoError(t, err)
   366  				assert.JSONEq(t, tc.expData, string(data))
   367  			}
   368  		})
   369  	}
   370  }
   371  

View as plain text