github.com/nginxinc/kubernetes-ingress@v1.12.5/internal/k8s/appprotect/app_protect_resources_test.go (about)

     1  package appprotect
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  	"testing"
     7  
     8  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
     9  )
    10  
    11  func TestValidateRequiredFields(t *testing.T) {
    12  	tests := []struct {
    13  		obj        *unstructured.Unstructured
    14  		fieldsList [][]string
    15  		expectErr  bool
    16  		msg        string
    17  	}{
    18  		{
    19  			obj: &unstructured.Unstructured{
    20  				Object: map[string]interface{}{
    21  					"a": map[string]interface{}{},
    22  					"b": map[string]interface{}{},
    23  				},
    24  			},
    25  			fieldsList: [][]string{{"a"}, {"b"}},
    26  			expectErr:  false,
    27  			msg:        "valid object with 2 fields",
    28  		},
    29  		{
    30  			obj: &unstructured.Unstructured{
    31  				Object: map[string]interface{}{
    32  					"a": map[string]interface{}{},
    33  				},
    34  			},
    35  			fieldsList: [][]string{{"a"}, {"b"}},
    36  			expectErr:  true,
    37  			msg:        "invalid object with a missing field",
    38  		},
    39  		{
    40  			obj: &unstructured.Unstructured{
    41  				Object: map[string]interface{}{
    42  					"a": map[string]interface{}{},
    43  					"x": map[string]interface{}{},
    44  				},
    45  			},
    46  			fieldsList: [][]string{{"a"}, {"b"}},
    47  			expectErr:  true,
    48  			msg:        "invalid object with a wrong field",
    49  		},
    50  		{
    51  			obj: &unstructured.Unstructured{
    52  				Object: map[string]interface{}{
    53  					"a": map[string]interface{}{
    54  						"b": map[string]interface{}{},
    55  					},
    56  				},
    57  			},
    58  			fieldsList: [][]string{{"a", "b"}},
    59  			expectErr:  false,
    60  			msg:        "valid object with nested field",
    61  		},
    62  		{
    63  			obj: &unstructured.Unstructured{
    64  				Object: map[string]interface{}{
    65  					"a": map[string]interface{}{
    66  						"x": map[string]interface{}{},
    67  					},
    68  				},
    69  			},
    70  			fieldsList: [][]string{{"a", "b"}},
    71  			expectErr:  true,
    72  			msg:        "invalid object with a wrong nested field",
    73  		},
    74  		{
    75  			obj: &unstructured.Unstructured{
    76  				Object: map[string]interface{}{},
    77  			},
    78  			fieldsList: nil,
    79  			expectErr:  false,
    80  			msg:        "valid object with no validation",
    81  		},
    82  		{
    83  			obj: &unstructured.Unstructured{
    84  				Object: map[string]interface{}{
    85  					"a": "wrong-type", // must be map[string]interface{}
    86  				},
    87  			},
    88  			fieldsList: [][]string{{"a"}},
    89  			expectErr:  true,
    90  			msg:        "invalid object with a field of wrong type",
    91  		},
    92  	}
    93  
    94  	for _, test := range tests {
    95  		err := validateRequiredFields(test.obj, test.fieldsList)
    96  		if test.expectErr && err == nil {
    97  			t.Errorf("validateRequiredFields() returned no error for the case of %s", test.msg)
    98  		}
    99  		if !test.expectErr && err != nil {
   100  			t.Errorf("validateRequiredFields() returned unexpected error %v for the case of %s", err, test.msg)
   101  		}
   102  	}
   103  }
   104  
   105  func TestValidateRequiredSlices(t *testing.T) {
   106  	tests := []struct {
   107  		obj        *unstructured.Unstructured
   108  		fieldsList [][]string
   109  		expectErr  bool
   110  		msg        string
   111  	}{
   112  		{
   113  			obj: &unstructured.Unstructured{
   114  				Object: map[string]interface{}{
   115  					"a": []interface{}{},
   116  					"b": []interface{}{},
   117  				},
   118  			},
   119  			fieldsList: [][]string{{"a"}, {"b"}},
   120  			expectErr:  false,
   121  			msg:        "valid object with 2 fields",
   122  		},
   123  		{
   124  			obj: &unstructured.Unstructured{
   125  				Object: map[string]interface{}{
   126  					"a": []interface{}{},
   127  				},
   128  			},
   129  			fieldsList: [][]string{{"a"}, {"b"}},
   130  			expectErr:  true,
   131  			msg:        "invalid object with a field",
   132  		},
   133  		{
   134  			obj: &unstructured.Unstructured{
   135  				Object: map[string]interface{}{
   136  					"a": []interface{}{},
   137  					"x": []interface{}{},
   138  				},
   139  			},
   140  			fieldsList: [][]string{{"a"}, {"b"}},
   141  			expectErr:  true,
   142  			msg:        "invalid object with a wrong field",
   143  		},
   144  		{
   145  			obj: &unstructured.Unstructured{
   146  				Object: map[string]interface{}{
   147  					"a": map[string]interface{}{
   148  						"b": []interface{}{},
   149  					},
   150  				},
   151  			},
   152  			fieldsList: [][]string{{"a", "b"}},
   153  			expectErr:  false,
   154  			msg:        "valid object with nested field",
   155  		},
   156  		{
   157  			obj: &unstructured.Unstructured{
   158  				Object: map[string]interface{}{
   159  					"a": map[string]interface{}{
   160  						"x": []interface{}{},
   161  					},
   162  				},
   163  			},
   164  			fieldsList: [][]string{{"a", "b"}},
   165  			expectErr:  true,
   166  			msg:        "invalid object with a wrong nested field",
   167  		},
   168  		{
   169  			obj: &unstructured.Unstructured{
   170  				Object: map[string]interface{}{},
   171  			},
   172  			fieldsList: nil,
   173  			expectErr:  false,
   174  			msg:        "valid object with no validation",
   175  		},
   176  		{
   177  			obj: &unstructured.Unstructured{
   178  				Object: map[string]interface{}{
   179  					"a": "wrong-type", // must be [string]interface{}
   180  				},
   181  			},
   182  			fieldsList: [][]string{{"a"}},
   183  			expectErr:  true,
   184  			msg:        "invalid object with a field of wrong type",
   185  		},
   186  	}
   187  
   188  	for _, test := range tests {
   189  		err := validateRequiredSlices(test.obj, test.fieldsList)
   190  		if test.expectErr && err == nil {
   191  			t.Errorf("validateRequiredSlices() returned no error for the case of %s", test.msg)
   192  		}
   193  		if !test.expectErr && err != nil {
   194  			t.Errorf("validateRequiredSlices() returned unexpected error %v for the case of %s", err, test.msg)
   195  		}
   196  	}
   197  }
   198  
   199  func TestValidateAppProtectPolicy(t *testing.T) {
   200  	tests := []struct {
   201  		policy    *unstructured.Unstructured
   202  		expectErr bool
   203  		msg       string
   204  	}{
   205  		{
   206  			policy: &unstructured.Unstructured{
   207  				Object: map[string]interface{}{
   208  					"spec": map[string]interface{}{
   209  						"policy": map[string]interface{}{},
   210  					},
   211  				},
   212  			},
   213  			expectErr: false,
   214  			msg:       "valid policy",
   215  		},
   216  		{
   217  			policy: &unstructured.Unstructured{
   218  				Object: map[string]interface{}{
   219  					"spec": map[string]interface{}{
   220  						"something": map[string]interface{}{},
   221  					},
   222  				},
   223  			},
   224  			expectErr: true,
   225  			msg:       "invalid policy with no policy field",
   226  		},
   227  		{
   228  			policy: &unstructured.Unstructured{
   229  				Object: map[string]interface{}{
   230  					"something": map[string]interface{}{
   231  						"policy": map[string]interface{}{},
   232  					},
   233  				},
   234  			},
   235  			expectErr: true,
   236  			msg:       "invalid policy with no spec field",
   237  		},
   238  	}
   239  
   240  	for _, test := range tests {
   241  		err := validateAppProtectPolicy(test.policy)
   242  		if test.expectErr && err == nil {
   243  			t.Errorf("validateAppProtectPolicy() returned no error for the case of %s", test.msg)
   244  		}
   245  		if !test.expectErr && err != nil {
   246  			t.Errorf("validateAppProtectPolicy() returned unexpected error %v for the case of %s", err, test.msg)
   247  		}
   248  	}
   249  }
   250  
   251  func TestValidateAppProtectLogConf(t *testing.T) {
   252  	tests := []struct {
   253  		logConf   *unstructured.Unstructured
   254  		expectErr bool
   255  		msg       string
   256  	}{
   257  		{
   258  			logConf: &unstructured.Unstructured{
   259  				Object: map[string]interface{}{
   260  					"spec": map[string]interface{}{
   261  						"content": map[string]interface{}{},
   262  						"filter":  map[string]interface{}{},
   263  					},
   264  				},
   265  			},
   266  			expectErr: false,
   267  			msg:       "valid log conf",
   268  		},
   269  		{
   270  			logConf: &unstructured.Unstructured{
   271  				Object: map[string]interface{}{
   272  					"spec": map[string]interface{}{
   273  						"filter": map[string]interface{}{},
   274  					},
   275  				},
   276  			},
   277  			expectErr: true,
   278  			msg:       "invalid log conf with no content field",
   279  		},
   280  		{
   281  			logConf: &unstructured.Unstructured{
   282  				Object: map[string]interface{}{
   283  					"spec": map[string]interface{}{
   284  						"content": map[string]interface{}{},
   285  					},
   286  				},
   287  			},
   288  			expectErr: true,
   289  			msg:       "invalid log conf with no filter field",
   290  		},
   291  		{
   292  			logConf: &unstructured.Unstructured{
   293  				Object: map[string]interface{}{
   294  					"something": map[string]interface{}{
   295  						"content": map[string]interface{}{},
   296  						"filter":  map[string]interface{}{},
   297  					},
   298  				},
   299  			},
   300  			expectErr: true,
   301  			msg:       "invalid log conf with no spec field",
   302  		},
   303  	}
   304  
   305  	for _, test := range tests {
   306  		err := validateAppProtectLogConf(test.logConf)
   307  		if test.expectErr && err == nil {
   308  			t.Errorf("validateAppProtectLogConf() returned no error for the case of %s", test.msg)
   309  		}
   310  		if !test.expectErr && err != nil {
   311  			t.Errorf("validateAppProtectLogConf() returned unexpected error %v for the case of %s", err, test.msg)
   312  		}
   313  	}
   314  }
   315  
   316  func TestValidateAppProtectLogDestinationAnnotation(t *testing.T) {
   317  	// Positive test cases
   318  	var posDstAntns = []string{"stderr", "syslog:server=localhost:9000", "syslog:server=10.1.1.2:9000", "/var/log/ap.log"}
   319  
   320  	// Negative test cases item, expected error message
   321  	var negDstAntns = [][]string{
   322  		{"stdout", "Log Destination did not follow format"},
   323  		{"syslog:server=localhost:99999", "not a valid port number"},
   324  		{"syslog:server=999.99.99.99:5678", "is not a valid ip address"},
   325  	}
   326  
   327  	for _, tCase := range posDstAntns {
   328  		err := ValidateAppProtectLogDestination(tCase)
   329  		if err != nil {
   330  			t.Errorf("got %v expected nil", err)
   331  		}
   332  	}
   333  	for _, nTCase := range negDstAntns {
   334  		err := ValidateAppProtectLogDestination(nTCase[0])
   335  		if err == nil {
   336  			t.Errorf("got no error expected error containing %s", nTCase[1])
   337  		} else {
   338  			if !strings.Contains(err.Error(), nTCase[1]) {
   339  				t.Errorf("got %v expected to contain: %s", err, nTCase[1])
   340  			}
   341  		}
   342  	}
   343  }
   344  
   345  func TestValidateAppProtectUserSig(t *testing.T) {
   346  	tests := []struct {
   347  		userSig   *unstructured.Unstructured
   348  		expectErr bool
   349  		msg       string
   350  	}{
   351  		{
   352  			userSig: &unstructured.Unstructured{
   353  				Object: map[string]interface{}{
   354  					"spec": map[string]interface{}{
   355  						"signatures": []interface{}{},
   356  					},
   357  				},
   358  			},
   359  			expectErr: false,
   360  			msg:       "valid user sig",
   361  		},
   362  		{
   363  			userSig: &unstructured.Unstructured{
   364  				Object: map[string]interface{}{
   365  					"spec": map[string]interface{}{
   366  						"something": []interface{}{},
   367  					},
   368  				},
   369  			},
   370  			expectErr: true,
   371  			msg:       "invalid user sig with no signatures",
   372  		},
   373  		{
   374  			userSig: &unstructured.Unstructured{
   375  				Object: map[string]interface{}{
   376  					"something": map[string]interface{}{
   377  						"signatures": []interface{}{},
   378  					},
   379  				},
   380  			},
   381  			expectErr: true,
   382  			msg:       "invalid user sign with no spec field",
   383  		},
   384  	}
   385  
   386  	for _, test := range tests {
   387  		err := validateAppProtectUserSig(test.userSig)
   388  		if test.expectErr && err == nil {
   389  			t.Errorf("validateAppProtectUserSig() returned no error for the case of %s", test.msg)
   390  		}
   391  		if !test.expectErr && err != nil {
   392  			t.Errorf("validateAppProtectUserSig() returned unexpected error %v for the case of %s", err, test.msg)
   393  		}
   394  	}
   395  }
   396  
   397  func TestParseResourceReferenceAnnotation(t *testing.T) {
   398  	tests := []struct {
   399  		ns, antn, expected string
   400  	}{
   401  		{
   402  			ns:       "default",
   403  			antn:     "resource",
   404  			expected: "default/resource",
   405  		},
   406  		{
   407  			ns:       "default",
   408  			antn:     "ns-1/resource",
   409  			expected: "ns-1/resource",
   410  		},
   411  	}
   412  
   413  	for _, test := range tests {
   414  		result := ParseResourceReferenceAnnotation(test.ns, test.antn)
   415  		if result != test.expected {
   416  			t.Errorf("ParseResourceReferenceAnnotation(%q,%q) returned %q but expected %q", test.ns, test.antn, result, test.expected)
   417  		}
   418  	}
   419  }
   420  
   421  func TestGenNsName(t *testing.T) {
   422  	obj := &unstructured.Unstructured{
   423  		Object: map[string]interface{}{
   424  			"metadata": map[string]interface{}{
   425  				"namespace": "default",
   426  				"name":      "resource",
   427  			},
   428  		},
   429  	}
   430  
   431  	expected := "default/resource"
   432  
   433  	result := GetNsName(obj)
   434  	if result != expected {
   435  		t.Errorf("GetNsName() returned %q but expected %q", result, expected)
   436  	}
   437  }
   438  
   439  func TestParseResourceReferenceAnnotationList(t *testing.T) {
   440  	namespace := "test_ns"
   441  	tests := []struct {
   442  		annotation string
   443  		expected   []string
   444  		msg        string
   445  	}{
   446  		{
   447  			annotation: "test",
   448  			expected:   []string{namespace + "/test"},
   449  			msg:        "single resource no namespace",
   450  		},
   451  		{
   452  			annotation: "different_ns/test",
   453  			expected:   []string{"different_ns/test"},
   454  			msg:        "single resource with namespace",
   455  		},
   456  		{
   457  			annotation: "test,test1",
   458  			expected:   []string{namespace + "/test", namespace + "/test1"},
   459  			msg:        "multiple resource no namespace",
   460  		},
   461  		{
   462  			annotation: "different_ns/test,different_ns/test1",
   463  			expected:   []string{"different_ns/test", "different_ns/test1"},
   464  			msg:        "multiple resource with namespaces",
   465  		},
   466  		{
   467  			annotation: "different_ns/test,test1",
   468  			expected:   []string{"different_ns/test", namespace + "/test1"},
   469  			msg:        "multiple resource with mixed namespaces",
   470  		},
   471  	}
   472  	for _, test := range tests {
   473  		result := ParseResourceReferenceAnnotationList(namespace, test.annotation)
   474  		if !reflect.DeepEqual(result, test.expected) {
   475  			t.Errorf("Error in test case %s: got: %v, expected: %v", test.msg, result, test.expected)
   476  		}
   477  	}
   478  }