...

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

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

     1  package msgdata
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/assert"
     7  
     8  	"edge-infra.dev/pkg/sds/emergencyaccess/apierror"
     9  	"edge-infra.dev/pkg/sds/emergencyaccess/eaconst"
    10  )
    11  
    12  type helper interface {
    13  	Helper()
    14  }
    15  
    16  func EqualError(message string) assert.ErrorAssertionFunc {
    17  	return func(t assert.TestingT, err error, i ...interface{}) bool {
    18  		if help, ok := t.(helper); ok {
    19  			help.Helper()
    20  		}
    21  		return assert.EqualError(t, err, message, i...)
    22  	}
    23  }
    24  
    25  // assert.ErrorAssertionFunc that asserts the error is an api error with the given
    26  // code, and contains the given message in the error string
    27  func APIError(code apierror.ErrorCode, message string, userError ...string) assert.ErrorAssertionFunc {
    28  	return func(tt assert.TestingT, err error, i ...interface{}) bool {
    29  		if help, ok := tt.(helper); ok {
    30  			help.Helper()
    31  		}
    32  
    33  		if !assert.ErrorContains(tt, err, message, i...) {
    34  			return false
    35  		}
    36  
    37  		if !assert.Implements(tt, (*apierror.APIError)(nil), err, i...) {
    38  			return false
    39  		}
    40  
    41  		e := err.(apierror.APIError)
    42  		assert.Equal(tt, userError, e.UserError())
    43  		return assert.Equal(tt, code, e.Code(), i...)
    44  	}
    45  }
    46  
    47  func TestNewRequest(t *testing.T) {
    48  	t.Parallel()
    49  
    50  	tests := map[string]struct {
    51  		data       []byte
    52  		attributes map[string]string
    53  		expected   Request
    54  		errAssert  assert.ErrorAssertionFunc
    55  	}{
    56  		"1.0: Success": {
    57  			data: []byte(`{
    58  				"command": "echo hello world"
    59  			}`),
    60  			attributes: map[string]string{
    61  				eaconst.VersionKey:     string(eaconst.MessageVersion1_0),
    62  				eaconst.RequestTypeKey: string(eaconst.Command),
    63  			},
    64  			expected: v1_0Request{
    65  				ReqData: v1Data{
    66  					Command: "echo hello world",
    67  				},
    68  				ReqAttr: map[string]string{
    69  					eaconst.VersionKey:     string(eaconst.MessageVersion1_0),
    70  					eaconst.RequestTypeKey: string(eaconst.Command),
    71  				},
    72  				command: "echo",
    73  			},
    74  			errAssert: assert.NoError,
    75  		},
    76  		"1.0: Bad Data": {
    77  			data: []byte(`{
    78  				"command": "echo hel`),
    79  			attributes: map[string]string{
    80  				eaconst.VersionKey:     string(eaconst.MessageVersion1_0),
    81  				eaconst.RequestTypeKey: string(eaconst.Command),
    82  			},
    83  			errAssert: EqualError(`failed to unmarshal: unexpected end of JSON input`),
    84  		},
    85  		"1.0: No Command": {
    86  			data: []byte(`{
    87  				"something": "something"
    88  			}`),
    89  			attributes: map[string]string{
    90  				eaconst.VersionKey:     string(eaconst.MessageVersion1_0),
    91  				eaconst.RequestTypeKey: string(eaconst.Command),
    92  			},
    93  			errAssert: APIError(apierror.ErrInvalidCommand, `payload cannot be empty`),
    94  		},
    95  		"1.0: No Command Identified": {
    96  			data: []byte(`{
    97  				"command": "\"\" echo hello there"
    98  			}`),
    99  			attributes: map[string]string{
   100  				eaconst.VersionKey:     string(eaconst.MessageVersion1_0),
   101  				eaconst.RequestTypeKey: string(eaconst.Command),
   102  			},
   103  			errAssert: APIError(apierror.ErrInvalidCommand, "command is empty", `No command identified`),
   104  		},
   105  		"2.0 Command: Success": {
   106  			data: []byte(`{
   107  				"command": "echo",
   108  				"args": ["hello", "world"]
   109  			}`),
   110  			attributes: map[string]string{
   111  				eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
   112  				eaconst.RequestTypeKey: string(eaconst.Command),
   113  			},
   114  			expected: v2_0CommandRequest{
   115  				ReqData: v2Command{
   116  					Command: "echo",
   117  					Args:    []string{"hello", "world"},
   118  				},
   119  				ReqAttr: map[string]string{
   120  					eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
   121  					eaconst.RequestTypeKey: string(eaconst.Command),
   122  				},
   123  			},
   124  			errAssert: assert.NoError,
   125  		},
   126  		"2.0 Command: Bad Data": {
   127  			data: []byte(`{
   128  				"command": "ech`),
   129  			attributes: map[string]string{
   130  				eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
   131  				eaconst.RequestTypeKey: string(eaconst.Command),
   132  			},
   133  			errAssert: EqualError(`failed to unmarshal data: unexpected end of JSON input`),
   134  		},
   135  		"2.0 Command: Invalid": {
   136  			data: []byte(`{
   137  				"args": ["hello", "world"]
   138  			}`),
   139  			attributes: map[string]string{
   140  				eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
   141  				eaconst.RequestTypeKey: string(eaconst.Command),
   142  			},
   143  			errAssert: APIError(apierror.ErrInvalidCommand, "command is empty", `No command identified`),
   144  		},
   145  		"2.0 Executable: Success": {
   146  			data: []byte(`{
   147  				"executable": {
   148  					"name": "myScript"
   149  				},
   150  				"args": ["hello", "world"]
   151  			}`),
   152  			attributes: map[string]string{
   153  				eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
   154  				eaconst.RequestTypeKey: string(eaconst.Executable),
   155  			},
   156  			expected: &v2_0ExecutableRequest{
   157  				ReqData: v2Executable{
   158  					Executable: executable{
   159  						Name: "myScript",
   160  					},
   161  					Args: []string{"hello", "world"},
   162  				},
   163  				ReqAttr: map[string]string{
   164  					eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
   165  					eaconst.RequestTypeKey: string(eaconst.Executable),
   166  				},
   167  			},
   168  			errAssert: assert.NoError,
   169  		},
   170  		"2.0 Executable: Bad Data": {
   171  			data: []byte(`{
   172  				"executable": {`),
   173  			attributes: map[string]string{
   174  				eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
   175  				eaconst.RequestTypeKey: string(eaconst.Executable),
   176  			},
   177  			errAssert: EqualError(`failed to unmarshal data: unexpected end of JSON input`),
   178  		},
   179  		"2.0 Executable: Invalid": {
   180  			data: []byte(`{
   181  				"args": ["hello", "world"]
   182  			}`),
   183  			attributes: map[string]string{
   184  				eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
   185  				eaconst.RequestTypeKey: string(eaconst.Executable),
   186  			},
   187  			errAssert: APIError(apierror.ErrInvalidCommand, "executable name is empty", `No executable name identified`),
   188  		},
   189  		"2.0: Unsupported Type": {
   190  			attributes: map[string]string{
   191  				eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
   192  				eaconst.RequestTypeKey: string(notAType),
   193  			},
   194  			errAssert: EqualError(`received version 2.0 message with unsupported request type "not-a-type"`),
   195  		},
   196  		"No Message Version": {
   197  			attributes: map[string]string{
   198  				eaconst.RequestTypeKey: string(eaconst.Command),
   199  			},
   200  			errAssert: EqualError(`failed to find version attribute`),
   201  		},
   202  		"No Request Type": {
   203  			attributes: map[string]string{
   204  				eaconst.VersionKey: string(eaconst.MessageVersion1_0),
   205  			},
   206  			errAssert: EqualError(`failed to find requestType attribute`),
   207  		},
   208  		"Unsupported Message Version": {
   209  			attributes: map[string]string{
   210  				eaconst.VersionKey:     "0.1",
   211  				eaconst.RequestTypeKey: string(eaconst.Command),
   212  			},
   213  			errAssert: EqualError(`received unsupported request message version "0.1"`),
   214  		},
   215  	}
   216  
   217  	for name, tc := range tests {
   218  		tc := tc
   219  		t.Run(name, func(t *testing.T) {
   220  			t.Parallel()
   221  
   222  			req, err := NewRequest(tc.data, tc.attributes)
   223  			tc.errAssert(t, err)
   224  			assert.Equal(t, tc.expected, req)
   225  		})
   226  	}
   227  }
   228  
   229  func TestParsePayload(t *testing.T) {
   230  	t.Parallel()
   231  
   232  	tests := map[string]struct {
   233  		input     string
   234  		expName   string
   235  		expArgs   []string
   236  		errAssert assert.ErrorAssertionFunc
   237  	}{
   238  		"Only command": {
   239  			input:     "echo",
   240  			expName:   "echo",
   241  			expArgs:   []string{},
   242  			errAssert: assert.NoError,
   243  		},
   244  		"Multiple words": {
   245  			input:     "echo hello there",
   246  			expName:   "echo",
   247  			expArgs:   []string{"hello", "there"},
   248  			errAssert: assert.NoError,
   249  		},
   250  		"Command with space": {
   251  			input:     "\"echo hello\"",
   252  			expName:   "echo hello",
   253  			expArgs:   []string{},
   254  			errAssert: assert.NoError,
   255  		},
   256  		"Command with space 2": {
   257  			input:     "echo\\ hello",
   258  			expName:   "echo hello",
   259  			expArgs:   []string{},
   260  			errAssert: assert.NoError,
   261  		},
   262  		"Full Path": {
   263  			input:     "/bin/mybinary hello",
   264  			expName:   "/bin/mybinary",
   265  			expArgs:   []string{"hello"},
   266  			errAssert: assert.NoError,
   267  		},
   268  		"Relative path": {
   269  			input:     "./mybinary hello",
   270  			expName:   "./mybinary",
   271  			expArgs:   []string{"hello"},
   272  			errAssert: assert.NoError,
   273  		},
   274  		"Env Var": {
   275  			input:     "a=b c",
   276  			expName:   "a=b",
   277  			expArgs:   []string{"c"},
   278  			errAssert: assert.NoError,
   279  		},
   280  		"Env Var with underscore": {
   281  			input:     "_a=b c",
   282  			expName:   "_a=b",
   283  			expArgs:   []string{"c"},
   284  			errAssert: assert.NoError,
   285  		},
   286  		"Env Var with number": {
   287  			input:     "a3=b c",
   288  			expName:   "a3=b",
   289  			expArgs:   []string{"c"},
   290  			errAssert: assert.NoError,
   291  		},
   292  		"Not a var number": {
   293  			input:     "1a=b c",
   294  			expName:   "1a=b",
   295  			expArgs:   []string{"c"},
   296  			errAssert: assert.NoError,
   297  		},
   298  		"Not a var special character": {
   299  			input:     "a=f|3 echo 8",
   300  			expName:   "a=f|3",
   301  			expArgs:   []string{"echo", "8"},
   302  			errAssert: assert.NoError,
   303  		},
   304  		"2 Env Var": {
   305  			input:     "_a=b KA=3 c",
   306  			expName:   "_a=b",
   307  			expArgs:   []string{"KA=3", "c"},
   308  			errAssert: assert.NoError,
   309  		},
   310  		"Leading space": {
   311  			input:     " _a=b KA=3 c",
   312  			expName:   "_a=b",
   313  			expArgs:   []string{"KA=3", "c"},
   314  			errAssert: assert.NoError,
   315  		},
   316  		"Trailing space": {
   317  			input:     " _a=b KA=3 c ",
   318  			expName:   "_a=b",
   319  			expArgs:   []string{"KA=3", "c"},
   320  			errAssert: assert.NoError,
   321  		},
   322  		"No command": {
   323  			input:     " KA=3 ",
   324  			expName:   "KA=3",
   325  			expArgs:   []string{},
   326  			errAssert: assert.NoError,
   327  		},
   328  		"Unicode number": {
   329  			input:     "aⅧ=3 echo 8",
   330  			expName:   "aⅧ=3",
   331  			expArgs:   []string{"echo", "8"},
   332  			errAssert: assert.NoError,
   333  		},
   334  		"Unicode digit": {
   335  			input:     "a৩=3 echo 8",
   336  			expName:   "a৩=3",
   337  			expArgs:   []string{"echo", "8"},
   338  			errAssert: assert.NoError,
   339  		},
   340  		"Unicode letter": {
   341  			input:     "aḸ=3 echo 8",
   342  			expName:   "aḸ=3",
   343  			expArgs:   []string{"echo", "8"},
   344  			errAssert: assert.NoError,
   345  		},
   346  		"Empty Payload": {
   347  			errAssert: EqualError("payload cannot be empty"),
   348  		},
   349  	}
   350  
   351  	for name, tc := range tests {
   352  		t.Run(name, func(t *testing.T) {
   353  			t.Parallel()
   354  
   355  			name, args, err := parsePayload(tc.input)
   356  			tc.errAssert(t, err)
   357  			assert.Equal(t, tc.expName, name)
   358  			assert.Equal(t, tc.expArgs, args)
   359  		})
   360  	}
   361  }
   362  

View as plain text