...

Source file src/github.com/datawire/ambassador/v2/cmd/entrypoint/testutil_fake_test_test.go

Documentation: github.com/datawire/ambassador/v2/cmd/entrypoint

     1  package entrypoint_test
     2  
     3  import (
     4  	"encoding/json"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"github.com/datawire/ambassador/v2/cmd/entrypoint"
    11  	v3bootstrap "github.com/datawire/ambassador/v2/pkg/api/envoy/config/bootstrap/v3"
    12  	v3 "github.com/datawire/ambassador/v2/pkg/api/envoy/type/v3"
    13  	"github.com/datawire/ambassador/v2/pkg/kates"
    14  	"github.com/datawire/ambassador/v2/pkg/snapshot/v1"
    15  )
    16  
    17  func AnySnapshot(_ *snapshot.Snapshot) bool {
    18  	return true
    19  }
    20  
    21  func AnyConfig(_ *v3bootstrap.Bootstrap) bool {
    22  	return true
    23  }
    24  
    25  func TestFake(t *testing.T) {
    26  	f := entrypoint.RunFake(t, entrypoint.FakeConfig{EnvoyConfig: true}, nil)
    27  	assert.NoError(t, f.UpsertFile("testdata/snapshot.yaml"))
    28  	f.AutoFlush(true)
    29  
    30  	snapshot, err := f.GetSnapshot(AnySnapshot)
    31  	require.NoError(t, err)
    32  	LogJSON(t, snapshot)
    33  
    34  	envoyConfig, err := f.GetEnvoyConfig(AnyConfig)
    35  	require.NoError(t, err)
    36  	LogJSON(t, envoyConfig)
    37  
    38  	assert.NoError(t, f.Delete("Mapping", "default", "foo"))
    39  
    40  	snapshot, err = f.GetSnapshot(AnySnapshot)
    41  	require.NoError(t, err)
    42  	LogJSON(t, snapshot)
    43  
    44  	envoyConfig, err = f.GetEnvoyConfig(AnyConfig)
    45  	require.NoError(t, err)
    46  	LogJSON(t, envoyConfig)
    47  
    48  	/*f.ConsulEndpoints(endpointsBlob)
    49  	f.ApplyFile()
    50  	f.ApplyResources()
    51  	f.Snapshot(snapshot1)
    52  	f.Snapshot(snapshot2)
    53  	f.Snapshot(snapshot3)
    54  	f.Delete(namespace, name)
    55  	f.Upsert(katesObject)
    56  	f.UpsertString("kind: blah")*/
    57  
    58  	// bluescape: create 50 hosts in different namespaces vs 50 hosts in the same namespace
    59  	// consul data center other than dc1
    60  
    61  }
    62  
    63  func assertRoutePresent(t *testing.T, envoyConfig *v3bootstrap.Bootstrap, cluster string, weight int) {
    64  	t.Helper()
    65  
    66  	listener := mustFindListenerByName(t, envoyConfig, "ambassador-listener-8080")
    67  	routes := mustFindRoutesToCluster(t, listener, cluster)
    68  
    69  	for _, r := range routes {
    70  		assert.Equal(t, uint32(weight), r.Match.RuntimeFraction.DefaultValue.Numerator)
    71  		assert.Equal(t, v3.FractionalPercent_HUNDRED, r.Match.RuntimeFraction.DefaultValue.Denominator)
    72  	}
    73  }
    74  
    75  func assertRouteNotPresent(t *testing.T, envoyConfig *v3bootstrap.Bootstrap, cluster string) {
    76  	t.Helper()
    77  
    78  	listener := mustFindListenerByName(t, envoyConfig, "ambassador-listener-8080")
    79  	routes := findRoutesToCluster(listener, cluster)
    80  
    81  	assert.Empty(t, routes)
    82  }
    83  
    84  func TestWeightWithCache(t *testing.T) {
    85  	get_envoy_config := func(f *entrypoint.Fake, want_foo bool, want_bar bool) (*v3bootstrap.Bootstrap, error) {
    86  		return f.GetEnvoyConfig(func(config *v3bootstrap.Bootstrap) bool {
    87  			c_foo := FindCluster(config, ClusterNameContains("cluster_foo_"))
    88  			c_bar := FindCluster(config, ClusterNameContains("cluster_bar_"))
    89  
    90  			has_foo := c_foo != nil
    91  			has_bar := c_bar != nil
    92  
    93  			return (has_foo == want_foo) && (has_bar == want_bar)
    94  		})
    95  	}
    96  
    97  	f := entrypoint.RunFake(t, entrypoint.FakeConfig{EnvoyConfig: true, DiagdDebug: false}, nil)
    98  	assert.NoError(t, f.UpsertYAML(`
    99  ---
   100  apiVersion: getambassador.io/v3alpha1
   101  kind: Listener
   102  metadata:
   103   name: ambassador-listener-8080
   104   namespace: default
   105  spec:
   106   port: 8080
   107   protocol: HTTP
   108   securityModel: XFP
   109   hostBinding:
   110    namespace:
   111     from: ALL
   112  ---
   113  apiVersion: getambassador.io/v3alpha1
   114  kind: Host
   115  metadata:
   116   name: test-host
   117   namespace: default
   118  spec:
   119   mappingSelector:
   120    matchLabels:
   121     host: minimal
   122   hostname: foo.example.com
   123   requestPolicy:
   124    insecure:
   125     action: Route
   126  ---
   127  apiVersion: getambassador.io/v3alpha1
   128  kind: Mapping
   129  metadata:
   130   name: mapping-foo
   131   namespace: default
   132   labels:
   133    host: minimal
   134  spec:
   135   prefix: /foo/
   136   service: foo.default
   137  `))
   138  
   139  	f.Flush()
   140  
   141  	// We need an Envoy config that has a foo cluster, but not a bar cluster.
   142  	envoyConfig, err := get_envoy_config(f, true, false)
   143  	require.NoError(t, err)
   144  	assert.NotNil(t, envoyConfig)
   145  
   146  	// Now we need to check the weights for our routes.
   147  	assertRoutePresent(t, envoyConfig, "cluster_foo_default_default", 100)
   148  	assertRouteNotPresent(t, envoyConfig, "cluster_bar_default_default")
   149  
   150  	// Now add a bar mapping at weight 10.
   151  	assert.NoError(t, f.UpsertYAML(`
   152  ---
   153  apiVersion: getambassador.io/v3alpha1
   154  kind: Mapping
   155  metadata:
   156   name: mapping-bar
   157   namespace: default
   158   labels:
   159    host: minimal
   160  spec:
   161   prefix: /foo/
   162   service: bar.default
   163   weight: 10
   164  `))
   165  
   166  	f.Flush()
   167  
   168  	// We need an Envoy config that has a foo cluster and a bar cluster.
   169  	envoyConfig, err = get_envoy_config(f, true, true)
   170  	require.NoError(t, err)
   171  	assert.NotNil(t, envoyConfig)
   172  
   173  	// Check the weights in order: we should see the bar cluster at 10%, then the foo
   174  	// cluster at 100%.
   175  	assertRoutePresent(t, envoyConfig, "cluster_bar_default_default", 10)
   176  	assertRoutePresent(t, envoyConfig, "cluster_foo_default_default", 100)
   177  
   178  	// Now ramp the bar mapping to weight 50.
   179  	assert.NoError(t, f.UpsertYAML(`
   180  ---
   181  apiVersion: getambassador.io/v3alpha1
   182  kind: Mapping
   183  metadata:
   184   name: mapping-bar
   185   namespace: default
   186   labels:
   187    host: minimal
   188  spec:
   189   prefix: /foo/
   190   service: bar.default
   191   weight: 50
   192  `))
   193  
   194  	f.Flush()
   195  
   196  	// We need an Envoy config that has a foo cluster and a bar cluster.
   197  	envoyConfig, err = get_envoy_config(f, true, true)
   198  	require.NoError(t, err)
   199  	assert.NotNil(t, envoyConfig)
   200  
   201  	// Here we expect bar at 50%, then foo at 100%.
   202  	assertRoutePresent(t, envoyConfig, "cluster_bar_default_default", 50)
   203  	assertRoutePresent(t, envoyConfig, "cluster_foo_default_default", 100)
   204  
   205  	assert.NoError(t, f.Delete("Mapping", "default", "mapping-foo"))
   206  	f.Flush()
   207  
   208  	// We need an Envoy config that has a bar cluster, but not a foo cluster...
   209  	envoyConfig, err = get_envoy_config(f, false, true)
   210  	require.NoError(t, err)
   211  	assert.NotNil(t, envoyConfig)
   212  
   213  	// ...and we should see the bar cluster at 100%.
   214  	assertRoutePresent(t, envoyConfig, "cluster_bar_default_default", 100)
   215  	assertRouteNotPresent(t, envoyConfig, "cluster_foo_default_default")
   216  
   217  	// Now change bar's weight...
   218  	assert.NoError(t, f.UpsertYAML(`
   219  ---
   220  apiVersion: getambassador.io/v3alpha1
   221  kind: Mapping
   222  metadata:
   223   name: mapping-bar
   224   namespace: default
   225   labels:
   226    host: minimal
   227  spec:
   228   prefix: /foo/
   229   service: bar.default
   230   weight: 20 
   231  `))
   232  
   233  	f.Flush()
   234  
   235  	// ...and that should have absolutely no effect on what we see so far. We should
   236  	// still see the bar cluster at 100% and no foo cluster.
   237  	envoyConfig, err = get_envoy_config(f, false, true)
   238  	require.NoError(t, err)
   239  	assert.NotNil(t, envoyConfig)
   240  
   241  	assertRoutePresent(t, envoyConfig, "cluster_bar_default_default", 100)
   242  	assertRouteNotPresent(t, envoyConfig, "cluster_foo_default_default")
   243  
   244  	// Now re-add the foo mapping.
   245  	assert.NoError(t, f.UpsertYAML(`
   246  ---
   247  apiVersion: getambassador.io/v3alpha1
   248  kind: Mapping
   249  metadata:
   250   name: mapping-foo
   251   namespace: default
   252   labels:
   253    host: minimal
   254  spec:
   255   prefix: /foo/
   256   service: foo.default
   257  `))
   258  
   259  	f.Flush()
   260  
   261  	// Now we should see both the foo cluster and the bar cluster...
   262  	envoyConfig, err = get_envoy_config(f, true, true)
   263  	require.NoError(t, err)
   264  	assert.NotNil(t, envoyConfig)
   265  
   266  	// ...and we should see the bar cluster drop to 20%, with the foo cluster now
   267  	// at 100%.
   268  	assertRoutePresent(t, envoyConfig, "cluster_bar_default_default", 20)
   269  	assertRoutePresent(t, envoyConfig, "cluster_foo_default_default", 100)
   270  }
   271  
   272  func LogJSON(t testing.TB, obj interface{}) {
   273  	t.Helper()
   274  	bytes, err := json.MarshalIndent(obj, "", "  ")
   275  	require.NoError(t, err)
   276  	t.Log(string(bytes))
   277  }
   278  
   279  func TestFakeIstioCert(t *testing.T) {
   280  	// Don't ask for the EnvoyConfig yet, 'cause we don't use it.
   281  	f := entrypoint.RunFake(t, entrypoint.FakeConfig{EnvoyConfig: false}, nil)
   282  	f.AutoFlush(true)
   283  
   284  	assert.NoError(t, f.UpsertFile("testdata/tls-snap.yaml"))
   285  
   286  	// t.Log(f.GetSnapshotString())
   287  
   288  	snapshot, err := f.GetSnapshot(AnySnapshot)
   289  	require.NoError(t, err)
   290  	k := snapshot.Kubernetes
   291  
   292  	if len(k.Secrets) != 1 {
   293  		t.Errorf("needed 1 secret, got %d", len(k.Secrets))
   294  	}
   295  
   296  	istioSecret := kates.Secret{
   297  		TypeMeta: kates.TypeMeta{
   298  			APIVersion: "v1",
   299  			Kind:       "Secret",
   300  		},
   301  		ObjectMeta: kates.ObjectMeta{
   302  			Name:      "test-istio-secret",
   303  			Namespace: "default",
   304  		},
   305  		Type: kates.SecretTypeTLS,
   306  		Data: map[string][]byte{
   307  			"tls.crt": k.Secrets[0].Data["tls.crt"],
   308  			"tls.key": k.Secrets[0].Data["tls.key"],
   309  		},
   310  	}
   311  
   312  	f.SendIstioCertUpdate(entrypoint.IstioCertUpdate{
   313  		Op:        "update",
   314  		Name:      "test-istio-secret",
   315  		Namespace: "default",
   316  		Secret:    &istioSecret,
   317  	})
   318  
   319  	snapshot, err = f.GetSnapshot(AnySnapshot)
   320  	require.NoError(t, err)
   321  	k = snapshot.Kubernetes
   322  	LogJSON(t, k)
   323  
   324  	if len(k.Secrets) != 2 {
   325  		t.Errorf("needed 2 secrets, got %d", len(k.Secrets))
   326  	}
   327  }
   328  

View as plain text