github.com/projectcontour/contour@v1.28.2/cmd/contour/serve_test.go (about)

     1  // Copyright Project Contour Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  //     http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package main
    15  
    16  import (
    17  	"testing"
    18  
    19  	contour_api_v1alpha1 "github.com/projectcontour/contour/apis/projectcontour/v1alpha1"
    20  	"github.com/projectcontour/contour/internal/dag"
    21  	"github.com/projectcontour/contour/internal/ref"
    22  	"github.com/sirupsen/logrus"
    23  	"github.com/stretchr/testify/assert"
    24  	"github.com/stretchr/testify/require"
    25  	"k8s.io/apimachinery/pkg/types"
    26  )
    27  
    28  func TestGetDAGBuilder(t *testing.T) {
    29  	commonAssertions := func(t *testing.T, builder *dag.Builder) {
    30  		t.Helper()
    31  
    32  		// note that these first two assertions will not hold when a gateway
    33  		// is configured, but we don't currently have test cases that cover
    34  		// that so it's OK to keep them in the "common" assertions for now.
    35  		assert.Len(t, builder.Processors, 4)
    36  		assert.IsType(t, &dag.ListenerProcessor{}, builder.Processors[0])
    37  
    38  		ingressProcessor := mustGetIngressProcessor(t, builder)
    39  		assert.True(t, ingressProcessor.SetSourceMetadataOnRoutes)
    40  
    41  		httpProxyProcessor := mustGetHTTPProxyProcessor(t, builder)
    42  		assert.True(t, httpProxyProcessor.SetSourceMetadataOnRoutes)
    43  	}
    44  
    45  	t.Run("all default options", func(t *testing.T) {
    46  		serve := &Server{
    47  			log: logrus.StandardLogger(),
    48  		}
    49  		got := serve.getDAGBuilder(dagBuilderConfig{rootNamespaces: []string{}, dnsLookupFamily: contour_api_v1alpha1.AutoClusterDNSFamily})
    50  		commonAssertions(t, got)
    51  		assert.Empty(t, got.Source.ConfiguredSecretRefs)
    52  	})
    53  
    54  	t.Run("client cert specified", func(t *testing.T) {
    55  		clientCert := &types.NamespacedName{Namespace: "client-ns", Name: "client-name"}
    56  
    57  		serve := &Server{
    58  			log: logrus.StandardLogger(),
    59  		}
    60  		got := serve.getDAGBuilder(dagBuilderConfig{rootNamespaces: []string{}, dnsLookupFamily: contour_api_v1alpha1.AutoClusterDNSFamily, clientCert: clientCert})
    61  		commonAssertions(t, got)
    62  		assert.ElementsMatch(t, got.Source.ConfiguredSecretRefs, []*types.NamespacedName{clientCert})
    63  	})
    64  
    65  	t.Run("fallback cert specified", func(t *testing.T) {
    66  		fallbackCert := &types.NamespacedName{Namespace: "fallback-ns", Name: "fallback-name"}
    67  
    68  		serve := &Server{
    69  			log: logrus.StandardLogger(),
    70  		}
    71  		got := serve.getDAGBuilder(dagBuilderConfig{rootNamespaces: []string{}, dnsLookupFamily: contour_api_v1alpha1.AutoClusterDNSFamily, fallbackCert: fallbackCert})
    72  		commonAssertions(t, got)
    73  		assert.ElementsMatch(t, got.Source.ConfiguredSecretRefs, []*types.NamespacedName{fallbackCert})
    74  	})
    75  
    76  	t.Run("client and fallback certs specified", func(t *testing.T) {
    77  		clientCert := &types.NamespacedName{Namespace: "client-ns", Name: "client-name"}
    78  		fallbackCert := &types.NamespacedName{Namespace: "fallback-ns", Name: "fallback-name"}
    79  
    80  		serve := &Server{
    81  			log: logrus.StandardLogger(),
    82  		}
    83  		got := serve.getDAGBuilder(dagBuilderConfig{rootNamespaces: []string{}, dnsLookupFamily: contour_api_v1alpha1.AutoClusterDNSFamily, clientCert: clientCert, fallbackCert: fallbackCert})
    84  		commonAssertions(t, got)
    85  		assert.ElementsMatch(t, got.Source.ConfiguredSecretRefs, []*types.NamespacedName{clientCert, fallbackCert})
    86  	})
    87  
    88  	t.Run("request and response headers policy specified", func(t *testing.T) {
    89  		policy := &contour_api_v1alpha1.PolicyConfig{
    90  			RequestHeadersPolicy: &contour_api_v1alpha1.HeadersPolicy{
    91  				Set: map[string]string{
    92  					"req-set-key-1": "req-set-val-1",
    93  					"req-set-key-2": "req-set-val-2",
    94  				},
    95  				Remove: []string{"req-remove-key-1", "req-remove-key-2"},
    96  			},
    97  			ResponseHeadersPolicy: &contour_api_v1alpha1.HeadersPolicy{
    98  				Set: map[string]string{
    99  					"res-set-key-1": "res-set-val-1",
   100  					"res-set-key-2": "res-set-val-2",
   101  				},
   102  				Remove: []string{"res-remove-key-1", "res-remove-key-2"},
   103  			},
   104  			ApplyToIngress: ref.To(false),
   105  		}
   106  
   107  		serve := &Server{
   108  			log: logrus.StandardLogger(),
   109  		}
   110  		got := serve.getDAGBuilder(dagBuilderConfig{rootNamespaces: []string{}, dnsLookupFamily: contour_api_v1alpha1.AutoClusterDNSFamily, headersPolicy: policy})
   111  		commonAssertions(t, got)
   112  
   113  		httpProxyProcessor := mustGetHTTPProxyProcessor(t, got)
   114  		assert.EqualValues(t, policy.RequestHeadersPolicy.Set, httpProxyProcessor.RequestHeadersPolicy.Set)
   115  		assert.ElementsMatch(t, policy.RequestHeadersPolicy.Remove, httpProxyProcessor.RequestHeadersPolicy.Remove)
   116  		assert.EqualValues(t, policy.ResponseHeadersPolicy.Set, httpProxyProcessor.ResponseHeadersPolicy.Set)
   117  		assert.ElementsMatch(t, policy.ResponseHeadersPolicy.Remove, httpProxyProcessor.ResponseHeadersPolicy.Remove)
   118  
   119  		ingressProcessor := mustGetIngressProcessor(t, got)
   120  		assert.EqualValues(t, map[string]string(nil), ingressProcessor.RequestHeadersPolicy.Set)
   121  		assert.ElementsMatch(t, map[string]string(nil), ingressProcessor.RequestHeadersPolicy.Remove)
   122  		assert.EqualValues(t, map[string]string(nil), ingressProcessor.ResponseHeadersPolicy.Set)
   123  		assert.ElementsMatch(t, map[string]string(nil), ingressProcessor.ResponseHeadersPolicy.Remove)
   124  	})
   125  
   126  	t.Run("GlobalCircuitBreakerDefaults specified for all processors", func(t *testing.T) {
   127  		g := contour_api_v1alpha1.GlobalCircuitBreakerDefaults{
   128  			MaxConnections: 100,
   129  		}
   130  
   131  		serve := &Server{
   132  			log: logrus.StandardLogger(),
   133  		}
   134  		got := serve.getDAGBuilder(dagBuilderConfig{
   135  			gatewayControllerName:        "projectcontour.io/gateway-controller",
   136  			rootNamespaces:               []string{},
   137  			dnsLookupFamily:              contour_api_v1alpha1.AutoClusterDNSFamily,
   138  			globalCircuitBreakerDefaults: &g,
   139  		})
   140  
   141  		iProcessor := mustGetIngressProcessor(t, got)
   142  		assert.EqualValues(t, iProcessor.GlobalCircuitBreakerDefaults, &g)
   143  
   144  		hProcessor := mustGetHTTPProxyProcessor(t, got)
   145  		assert.EqualValues(t, hProcessor.GlobalCircuitBreakerDefaults, &g)
   146  
   147  		gProcessor := mustGetGatewayAPIProcessor(t, got)
   148  		assert.EqualValues(t, gProcessor.GlobalCircuitBreakerDefaults, &g)
   149  	})
   150  
   151  	t.Run("request and response headers policy specified for ingress", func(t *testing.T) {
   152  		policy := &contour_api_v1alpha1.PolicyConfig{
   153  			RequestHeadersPolicy: &contour_api_v1alpha1.HeadersPolicy{
   154  				Set: map[string]string{
   155  					"req-set-key-1": "req-set-val-1",
   156  					"req-set-key-2": "req-set-val-2",
   157  				},
   158  				Remove: []string{"req-remove-key-1", "req-remove-key-2"},
   159  			},
   160  			ResponseHeadersPolicy: &contour_api_v1alpha1.HeadersPolicy{
   161  				Set: map[string]string{
   162  					"res-set-key-1": "res-set-val-1",
   163  					"res-set-key-2": "res-set-val-2",
   164  				},
   165  				Remove: []string{"res-remove-key-1", "res-remove-key-2"},
   166  			},
   167  			ApplyToIngress: ref.To(true),
   168  		}
   169  
   170  		serve := &Server{
   171  			log: logrus.StandardLogger(),
   172  		}
   173  		got := serve.getDAGBuilder(dagBuilderConfig{
   174  			rootNamespaces:  []string{},
   175  			dnsLookupFamily: contour_api_v1alpha1.AutoClusterDNSFamily,
   176  			headersPolicy:   policy,
   177  		})
   178  		commonAssertions(t, got)
   179  
   180  		ingressProcessor := mustGetIngressProcessor(t, got)
   181  		assert.EqualValues(t, policy.RequestHeadersPolicy.Set, ingressProcessor.RequestHeadersPolicy.Set)
   182  		assert.ElementsMatch(t, policy.RequestHeadersPolicy.Remove, ingressProcessor.RequestHeadersPolicy.Remove)
   183  		assert.EqualValues(t, policy.ResponseHeadersPolicy.Set, ingressProcessor.ResponseHeadersPolicy.Set)
   184  		assert.ElementsMatch(t, policy.ResponseHeadersPolicy.Remove, ingressProcessor.ResponseHeadersPolicy.Remove)
   185  	})
   186  
   187  	t.Run("single ingress class specified", func(t *testing.T) {
   188  		ingressClassNames := []string{"aclass"}
   189  
   190  		serve := &Server{
   191  			log: logrus.StandardLogger(),
   192  		}
   193  		got := serve.getDAGBuilder(dagBuilderConfig{
   194  			rootNamespaces:    []string{},
   195  			dnsLookupFamily:   contour_api_v1alpha1.AutoClusterDNSFamily,
   196  			ingressClassNames: ingressClassNames,
   197  		})
   198  		commonAssertions(t, got)
   199  		assert.EqualValues(t, ingressClassNames, got.Source.IngressClassNames)
   200  	})
   201  
   202  	t.Run("multiple comma-separated ingress classes specified", func(t *testing.T) {
   203  		ingressClassNames := []string{"aclass", "bclass", "cclass"}
   204  
   205  		serve := &Server{
   206  			log: logrus.StandardLogger(),
   207  		}
   208  		got := serve.getDAGBuilder(dagBuilderConfig{
   209  			rootNamespaces:    []string{},
   210  			dnsLookupFamily:   contour_api_v1alpha1.AutoClusterDNSFamily,
   211  			ingressClassNames: ingressClassNames,
   212  		})
   213  		commonAssertions(t, got)
   214  		assert.EqualValues(t, ingressClassNames, got.Source.IngressClassNames)
   215  	})
   216  
   217  	// TODO(3453): test additional properties of the DAG builder (processor fields, cache fields, Gateway tests (requires a client fake))
   218  }
   219  
   220  func mustGetGatewayAPIProcessor(t *testing.T, builder *dag.Builder) *dag.GatewayAPIProcessor {
   221  	t.Helper()
   222  	for i := range builder.Processors {
   223  		found, ok := builder.Processors[i].(*dag.GatewayAPIProcessor)
   224  		if ok {
   225  			return found
   226  		}
   227  	}
   228  
   229  	require.FailNow(t, "GatewayAPIProcessor not found in list of DAG builder's processors")
   230  	return nil
   231  }
   232  
   233  func mustGetHTTPProxyProcessor(t *testing.T, builder *dag.Builder) *dag.HTTPProxyProcessor {
   234  	t.Helper()
   235  	for i := range builder.Processors {
   236  		found, ok := builder.Processors[i].(*dag.HTTPProxyProcessor)
   237  		if ok {
   238  			return found
   239  		}
   240  	}
   241  
   242  	require.FailNow(t, "HTTPProxyProcessor not found in list of DAG builder's processors")
   243  	return nil
   244  }
   245  
   246  func mustGetIngressProcessor(t *testing.T, builder *dag.Builder) *dag.IngressProcessor {
   247  	t.Helper()
   248  	for i := range builder.Processors {
   249  		found, ok := builder.Processors[i].(*dag.IngressProcessor)
   250  		if ok {
   251  			return found
   252  		}
   253  	}
   254  
   255  	require.FailNow(t, "IngressProcessor not found in list of DAG builder's processors")
   256  	return nil
   257  }