istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/model/telemetry_test.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package model
    16  
    17  import (
    18  	"strings"
    19  	"testing"
    20  	"time"
    21  
    22  	core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    23  	listener "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
    24  	fileaccesslog "github.com/envoyproxy/go-control-plane/envoy/extensions/access_loggers/file/v3"
    25  	httpwasm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/wasm/v3"
    26  	hcm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
    27  	wasmfilter "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/wasm/v3"
    28  	"github.com/google/go-cmp/cmp"
    29  	"google.golang.org/protobuf/types/known/durationpb"
    30  	"google.golang.org/protobuf/types/known/structpb"
    31  	wrappers "google.golang.org/protobuf/types/known/wrapperspb"
    32  	"k8s.io/apimachinery/pkg/types"
    33  
    34  	"istio.io/api/envoy/extensions/stats"
    35  	meshconfig "istio.io/api/mesh/v1alpha1"
    36  	tpb "istio.io/api/telemetry/v1alpha1"
    37  	"istio.io/api/type/v1beta1"
    38  	"istio.io/istio/pilot/pkg/networking"
    39  	"istio.io/istio/pkg/config"
    40  	"istio.io/istio/pkg/config/mesh"
    41  	"istio.io/istio/pkg/config/schema/collection"
    42  	"istio.io/istio/pkg/config/schema/gvk"
    43  	"istio.io/istio/pkg/ptr"
    44  	"istio.io/istio/pkg/test/util/assert"
    45  	"istio.io/istio/pkg/util/protomarshal"
    46  )
    47  
    48  var (
    49  	jsonTextProvider = &meshconfig.MeshConfig_ExtensionProvider{
    50  		Name: "envoy-json",
    51  		Provider: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLog{
    52  			EnvoyFileAccessLog: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider{
    53  				Path: "/dev/stdout",
    54  				LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat{
    55  					LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat_Labels{
    56  						Labels: &structpb.Struct{},
    57  					},
    58  				},
    59  			},
    60  		},
    61  	}
    62  
    63  	textFormattersProvider = &meshconfig.MeshConfig_ExtensionProvider{
    64  		Name: "envoy-text-formatters",
    65  		Provider: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLog{
    66  			EnvoyFileAccessLog: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider{
    67  				Path: "/dev/stdout",
    68  				LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat{
    69  					LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat_Text{
    70  						Text: "%REQ_WITHOUT_QUERY(key1:val1)% REQ_WITHOUT_QUERY(key2:val1)% %METADATA(UPSTREAM_HOST:istio)% %METADATA(CLUSTER:istio)%\n",
    71  					},
    72  				},
    73  			},
    74  		},
    75  	}
    76  
    77  	jsonFormattersProvider = &meshconfig.MeshConfig_ExtensionProvider{
    78  		Name: "envoy-json-formatters",
    79  		Provider: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLog{
    80  			EnvoyFileAccessLog: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider{
    81  				Path: "/dev/stdout",
    82  				LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat{
    83  					LogFormat: &meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider_LogFormat_Labels{
    84  						Labels: &structpb.Struct{
    85  							Fields: map[string]*structpb.Value{
    86  								"req1": {Kind: &structpb.Value_StringValue{StringValue: "%REQ_WITHOUT_QUERY(key1:val1)%"}},
    87  								"req2": {Kind: &structpb.Value_StringValue{StringValue: "%REQ_WITHOUT_QUERY(key2:val1)%"}},
    88  								"key1": {Kind: &structpb.Value_StringValue{StringValue: "%METADATA(CLUSTER:istio)%"}},
    89  								"key2": {Kind: &structpb.Value_StringValue{StringValue: "%METADATA(UPSTREAM_HOST:istio)%"}},
    90  							},
    91  						},
    92  					},
    93  				},
    94  			},
    95  		},
    96  	}
    97  
    98  	defaultJSONLabelsOut = &fileaccesslog.FileAccessLog{
    99  		Path: "/dev/stdout",
   100  		AccessLogFormat: &fileaccesslog.FileAccessLog_LogFormat{
   101  			LogFormat: &core.SubstitutionFormatString{
   102  				Format: &core.SubstitutionFormatString_JsonFormat{
   103  					JsonFormat: EnvoyJSONLogFormatIstio,
   104  				},
   105  				JsonFormatOptions: &core.JsonFormatOptions{SortProperties: true},
   106  			},
   107  		},
   108  	}
   109  
   110  	formattersJSONLabelsOut = &fileaccesslog.FileAccessLog{
   111  		Path: "/dev/stdout",
   112  		AccessLogFormat: &fileaccesslog.FileAccessLog_LogFormat{
   113  			LogFormat: &core.SubstitutionFormatString{
   114  				Formatters: []*core.TypedExtensionConfig{
   115  					reqWithoutQueryFormatter,
   116  					metadataFormatter,
   117  				},
   118  				Format: &core.SubstitutionFormatString_JsonFormat{
   119  					JsonFormat: &structpb.Struct{
   120  						Fields: map[string]*structpb.Value{
   121  							"req1": {Kind: &structpb.Value_StringValue{StringValue: "%REQ_WITHOUT_QUERY(key1:val1)%"}},
   122  							"req2": {Kind: &structpb.Value_StringValue{StringValue: "%REQ_WITHOUT_QUERY(key2:val1)%"}},
   123  							"key1": {Kind: &structpb.Value_StringValue{StringValue: "%METADATA(CLUSTER:istio)%"}},
   124  							"key2": {Kind: &structpb.Value_StringValue{StringValue: "%METADATA(UPSTREAM_HOST:istio)%"}},
   125  						},
   126  					},
   127  				},
   128  				JsonFormatOptions: &core.JsonFormatOptions{SortProperties: true},
   129  			},
   130  		},
   131  	}
   132  
   133  	formattersTextLabelsOut = &fileaccesslog.FileAccessLog{
   134  		Path: "/dev/stdout",
   135  		AccessLogFormat: &fileaccesslog.FileAccessLog_LogFormat{
   136  			LogFormat: &core.SubstitutionFormatString{
   137  				Formatters: []*core.TypedExtensionConfig{
   138  					reqWithoutQueryFormatter,
   139  					metadataFormatter,
   140  				},
   141  				Format: &core.SubstitutionFormatString_TextFormatSource{
   142  					TextFormatSource: &core.DataSource{
   143  						Specifier: &core.DataSource_InlineString{
   144  							InlineString: "%REQ_WITHOUT_QUERY(key1:val1)% REQ_WITHOUT_QUERY(key2:val1)% %METADATA(UPSTREAM_HOST:istio)% %METADATA(CLUSTER:istio)%\n",
   145  						},
   146  					},
   147  				},
   148  			},
   149  		},
   150  	}
   151  )
   152  
   153  func createTestTelemetries(configs []config.Config, t *testing.T) (*Telemetries, *PushContext) {
   154  	t.Helper()
   155  
   156  	store := &telemetryStore{}
   157  	for _, cfg := range configs {
   158  		store.add(cfg)
   159  	}
   160  	m := mesh.DefaultMeshConfig()
   161  
   162  	m.ExtensionProviders = append(m.ExtensionProviders, jsonTextProvider, textFormattersProvider, jsonFormattersProvider)
   163  
   164  	environment := &Environment{
   165  		ConfigStore: store,
   166  		Watcher:     mesh.NewFixedWatcher(m),
   167  	}
   168  	telemetries := getTelemetries(environment)
   169  
   170  	ctx := NewPushContext()
   171  	ctx.Mesh = m
   172  	return telemetries, ctx
   173  }
   174  
   175  func newTelemetry(ns string, spec config.Spec) config.Config {
   176  	return config.Config{
   177  		Meta: config.Meta{
   178  			GroupVersionKind: gvk.Telemetry,
   179  			Name:             "default",
   180  			Namespace:        ns,
   181  		},
   182  		Spec: spec,
   183  	}
   184  }
   185  
   186  type telemetryStore struct {
   187  	ConfigStore
   188  
   189  	data []struct {
   190  		typ config.GroupVersionKind
   191  		ns  string
   192  		cfg config.Config
   193  	}
   194  }
   195  
   196  func (ts *telemetryStore) add(cfg config.Config) {
   197  	ts.data = append(ts.data, struct {
   198  		typ config.GroupVersionKind
   199  		ns  string
   200  		cfg config.Config
   201  	}{
   202  		typ: cfg.GroupVersionKind,
   203  		ns:  cfg.Namespace,
   204  		cfg: cfg,
   205  	})
   206  }
   207  
   208  func (ts *telemetryStore) Schemas() collection.Schemas {
   209  	return collection.SchemasFor()
   210  }
   211  
   212  func (ts *telemetryStore) Get(_ config.GroupVersionKind, _, _ string) *config.Config {
   213  	return nil
   214  }
   215  
   216  func (ts *telemetryStore) List(typ config.GroupVersionKind, namespace string) []config.Config {
   217  	var configs []config.Config
   218  	for _, data := range ts.data {
   219  		if data.typ == typ {
   220  			if namespace != "" && data.ns == namespace {
   221  				continue
   222  			}
   223  			configs = append(configs, data.cfg)
   224  		}
   225  	}
   226  	return configs
   227  }
   228  
   229  func newTracingConfig(providerName string, disabled bool) *TracingConfig {
   230  	return &TracingConfig{
   231  		ClientSpec: TracingSpec{
   232  			Provider:                     &meshconfig.MeshConfig_ExtensionProvider{Name: providerName},
   233  			Disabled:                     disabled,
   234  			UseRequestIDForTraceSampling: true,
   235  		},
   236  		ServerSpec: TracingSpec{
   237  			Provider:                     &meshconfig.MeshConfig_ExtensionProvider{Name: providerName},
   238  			Disabled:                     disabled,
   239  			UseRequestIDForTraceSampling: true,
   240  		},
   241  	}
   242  }
   243  
   244  const (
   245  	reportingEnabled  = false
   246  	reportingDisabled = !reportingEnabled
   247  )
   248  
   249  func TestTracing(t *testing.T) {
   250  	sidecar := &Proxy{
   251  		ConfigNamespace: "default",
   252  		Labels:          map[string]string{"app": "test"},
   253  		Metadata:        &NodeMetadata{Labels: map[string]string{"app": "test"}},
   254  	}
   255  	envoy := &tpb.Telemetry{
   256  		Tracing: []*tpb.Tracing{
   257  			{
   258  				Providers: []*tpb.ProviderRef{
   259  					{
   260  						Name: "envoy",
   261  					},
   262  				},
   263  			},
   264  		},
   265  	}
   266  	stackdriver := &tpb.Telemetry{
   267  		Tracing: []*tpb.Tracing{
   268  			{
   269  				Providers: []*tpb.ProviderRef{
   270  					{
   271  						Name: "stackdriver",
   272  					},
   273  				},
   274  			},
   275  		},
   276  	}
   277  	empty := &tpb.Telemetry{
   278  		Tracing: []*tpb.Tracing{{}},
   279  	}
   280  	disabled := &tpb.Telemetry{
   281  		Tracing: []*tpb.Tracing{
   282  			{
   283  				DisableSpanReporting: &wrappers.BoolValue{Value: true},
   284  			},
   285  		},
   286  	}
   287  	overidesA := &tpb.Telemetry{
   288  		Tracing: []*tpb.Tracing{
   289  			{
   290  				RandomSamplingPercentage: &wrappers.DoubleValue{Value: 50.0},
   291  				CustomTags: map[string]*tpb.Tracing_CustomTag{
   292  					"foo": {},
   293  					"bar": {},
   294  				},
   295  				UseRequestIdForTraceSampling: &wrappers.BoolValue{Value: false},
   296  			},
   297  		},
   298  	}
   299  	overidesB := &tpb.Telemetry{
   300  		Tracing: []*tpb.Tracing{
   301  			{
   302  				RandomSamplingPercentage: &wrappers.DoubleValue{Value: 80.0},
   303  				CustomTags: map[string]*tpb.Tracing_CustomTag{
   304  					"foo": {},
   305  					"baz": {},
   306  				},
   307  				UseRequestIdForTraceSampling: &wrappers.BoolValue{Value: true},
   308  			},
   309  		},
   310  	}
   311  	overridesWithDefaultSampling := &tpb.Telemetry{
   312  		Tracing: []*tpb.Tracing{
   313  			{
   314  				CustomTags: map[string]*tpb.Tracing_CustomTag{
   315  					"foo": {},
   316  					"baz": {},
   317  				},
   318  			},
   319  		},
   320  	}
   321  	nonExistant := &tpb.Telemetry{
   322  		Tracing: []*tpb.Tracing{
   323  			{
   324  				Providers: []*tpb.ProviderRef{
   325  					{
   326  						Name: "custom-provider",
   327  					},
   328  				},
   329  			},
   330  		},
   331  	}
   332  	clientSideSampling := &tpb.Telemetry{
   333  		Tracing: []*tpb.Tracing{
   334  			{
   335  				Match: &tpb.Tracing_TracingSelector{
   336  					Mode: tpb.WorkloadMode_CLIENT,
   337  				},
   338  				Providers: []*tpb.ProviderRef{
   339  					{
   340  						Name: "stackdriver",
   341  					},
   342  				},
   343  				RandomSamplingPercentage: &wrappers.DoubleValue{Value: 99.9},
   344  			},
   345  		},
   346  	}
   347  	serverSideDisabled := &tpb.Telemetry{
   348  		Tracing: []*tpb.Tracing{
   349  			{
   350  				Match: &tpb.Tracing_TracingSelector{
   351  					Mode: tpb.WorkloadMode_SERVER,
   352  				},
   353  				DisableSpanReporting: &wrappers.BoolValue{Value: true},
   354  			},
   355  		},
   356  	}
   357  
   358  	tests := []struct {
   359  		name             string
   360  		cfgs             []config.Config
   361  		proxy            *Proxy
   362  		defaultProviders []string
   363  		want             *TracingConfig
   364  	}{
   365  		{
   366  			"empty",
   367  			nil,
   368  			sidecar,
   369  			nil,
   370  			nil,
   371  		},
   372  		{
   373  			"default provider only",
   374  			nil,
   375  			sidecar,
   376  			[]string{"envoy"},
   377  			newTracingConfig("envoy", reportingEnabled),
   378  		},
   379  		{
   380  			"provider only",
   381  			[]config.Config{newTelemetry("istio-system", envoy)},
   382  			sidecar,
   383  			nil,
   384  			newTracingConfig("envoy", reportingEnabled),
   385  		},
   386  		{
   387  			"override default",
   388  			[]config.Config{newTelemetry("istio-system", envoy)},
   389  			sidecar,
   390  			[]string{"stackdriver"},
   391  			newTracingConfig("envoy", reportingEnabled),
   392  		},
   393  		{
   394  			"override namespace",
   395  			[]config.Config{newTelemetry("istio-system", envoy), newTelemetry("default", stackdriver)},
   396  			sidecar,
   397  			nil,
   398  			newTracingConfig("stackdriver", reportingEnabled),
   399  		},
   400  		{
   401  			"empty config inherits",
   402  			[]config.Config{newTelemetry("istio-system", envoy), newTelemetry("default", empty)},
   403  			sidecar,
   404  			nil,
   405  			newTracingConfig("envoy", reportingEnabled),
   406  		},
   407  		{
   408  			"disable config",
   409  			[]config.Config{newTelemetry("istio-system", envoy), newTelemetry("default", disabled)},
   410  			sidecar,
   411  			nil,
   412  			newTracingConfig("envoy", reportingDisabled),
   413  		},
   414  		{
   415  			"disable default",
   416  			[]config.Config{newTelemetry("default", disabled)},
   417  			sidecar,
   418  			[]string{"envoy"},
   419  			newTracingConfig("envoy", reportingDisabled),
   420  		},
   421  		{
   422  			"non existing",
   423  			[]config.Config{newTelemetry("default", nonExistant)},
   424  			sidecar,
   425  			[]string{"envoy"},
   426  			&TracingConfig{
   427  				ClientSpec: TracingSpec{Disabled: true, UseRequestIDForTraceSampling: true},
   428  				ServerSpec: TracingSpec{Disabled: true, UseRequestIDForTraceSampling: true},
   429  			},
   430  		},
   431  		{
   432  			"overrides",
   433  			[]config.Config{newTelemetry("istio-system", overidesA)},
   434  			sidecar,
   435  			[]string{"envoy"},
   436  			&TracingConfig{
   437  				ClientSpec: TracingSpec{
   438  					Provider:                 &meshconfig.MeshConfig_ExtensionProvider{Name: "envoy"},
   439  					RandomSamplingPercentage: ptr.Of(50.0),
   440  					CustomTags: map[string]*tpb.Tracing_CustomTag{
   441  						"foo": {},
   442  						"bar": {},
   443  					},
   444  					UseRequestIDForTraceSampling: false,
   445  				}, ServerSpec: TracingSpec{
   446  					Provider:                 &meshconfig.MeshConfig_ExtensionProvider{Name: "envoy"},
   447  					RandomSamplingPercentage: ptr.Of(50.0),
   448  					CustomTags: map[string]*tpb.Tracing_CustomTag{
   449  						"foo": {},
   450  						"bar": {},
   451  					},
   452  					UseRequestIDForTraceSampling: false,
   453  				},
   454  			},
   455  		},
   456  		{
   457  			"overrides with default sampling",
   458  			[]config.Config{newTelemetry("istio-system", overridesWithDefaultSampling)},
   459  			sidecar,
   460  			[]string{"envoy"},
   461  			&TracingConfig{
   462  				ClientSpec: TracingSpec{
   463  					Provider: &meshconfig.MeshConfig_ExtensionProvider{Name: "envoy"},
   464  					CustomTags: map[string]*tpb.Tracing_CustomTag{
   465  						"foo": {},
   466  						"baz": {},
   467  					},
   468  					UseRequestIDForTraceSampling: true,
   469  				}, ServerSpec: TracingSpec{
   470  					Provider: &meshconfig.MeshConfig_ExtensionProvider{Name: "envoy"},
   471  					CustomTags: map[string]*tpb.Tracing_CustomTag{
   472  						"foo": {},
   473  						"baz": {},
   474  					},
   475  					UseRequestIDForTraceSampling: true,
   476  				},
   477  			},
   478  		},
   479  		{
   480  			"multi overrides",
   481  			[]config.Config{
   482  				newTelemetry("istio-system", overidesA),
   483  				newTelemetry("default", overidesB),
   484  			},
   485  			sidecar,
   486  			[]string{"envoy"},
   487  			&TracingConfig{
   488  				ClientSpec: TracingSpec{
   489  					Provider:                 &meshconfig.MeshConfig_ExtensionProvider{Name: "envoy"},
   490  					RandomSamplingPercentage: ptr.Of(80.0),
   491  					CustomTags: map[string]*tpb.Tracing_CustomTag{
   492  						"foo": {},
   493  						"baz": {},
   494  					},
   495  					UseRequestIDForTraceSampling: true,
   496  				},
   497  				ServerSpec: TracingSpec{
   498  					Provider:                 &meshconfig.MeshConfig_ExtensionProvider{Name: "envoy"},
   499  					RandomSamplingPercentage: ptr.Of(80.0),
   500  					CustomTags: map[string]*tpb.Tracing_CustomTag{
   501  						"foo": {},
   502  						"baz": {},
   503  					},
   504  					UseRequestIDForTraceSampling: true,
   505  				},
   506  			},
   507  		},
   508  		{
   509  			"client-only override",
   510  			[]config.Config{newTelemetry("istio-system", envoy), newTelemetry("default", clientSideSampling)},
   511  			sidecar,
   512  			[]string{"envoy"},
   513  			&TracingConfig{
   514  				ClientSpec: TracingSpec{
   515  					Provider: &meshconfig.MeshConfig_ExtensionProvider{
   516  						Name: "stackdriver",
   517  						Provider: &meshconfig.MeshConfig_ExtensionProvider_Stackdriver{
   518  							Stackdriver: &meshconfig.MeshConfig_ExtensionProvider_StackdriverProvider{},
   519  						},
   520  					},
   521  					RandomSamplingPercentage:     ptr.Of(99.9),
   522  					UseRequestIDForTraceSampling: true,
   523  				},
   524  				ServerSpec: TracingSpec{
   525  					Provider:                     &meshconfig.MeshConfig_ExtensionProvider{Name: "envoy"},
   526  					UseRequestIDForTraceSampling: true,
   527  				},
   528  			},
   529  		},
   530  		{
   531  			"server-only override",
   532  			[]config.Config{newTelemetry("istio-system", envoy), newTelemetry("default", serverSideDisabled)},
   533  			sidecar,
   534  			[]string{"envoy"},
   535  			&TracingConfig{
   536  				ClientSpec: TracingSpec{
   537  					Provider:                     &meshconfig.MeshConfig_ExtensionProvider{Name: "envoy"},
   538  					UseRequestIDForTraceSampling: true,
   539  				},
   540  				ServerSpec: TracingSpec{
   541  					Provider:                     &meshconfig.MeshConfig_ExtensionProvider{Name: "envoy"},
   542  					Disabled:                     true,
   543  					UseRequestIDForTraceSampling: true,
   544  				},
   545  			},
   546  		},
   547  	}
   548  	for _, tt := range tests {
   549  		t.Run(tt.name, func(t *testing.T) {
   550  			telemetry, _ := createTestTelemetries(tt.cfgs, t)
   551  			telemetry.meshConfig.DefaultProviders.Tracing = tt.defaultProviders
   552  			got := telemetry.Tracing(tt.proxy, nil)
   553  			if got != nil && got.ServerSpec.Provider != nil {
   554  				// We don't match on this, just the name for test simplicity
   555  				got.ServerSpec.Provider.Provider = nil
   556  			}
   557  			assert.Equal(t, got, tt.want)
   558  		})
   559  	}
   560  }
   561  
   562  func TestTelemetryFilters(t *testing.T) {
   563  	overrides := []*tpb.MetricsOverrides{{
   564  		Match: &tpb.MetricSelector{
   565  			MetricMatch: &tpb.MetricSelector_Metric{
   566  				Metric: tpb.MetricSelector_REQUEST_COUNT,
   567  			},
   568  		},
   569  		TagOverrides: map[string]*tpb.MetricsOverrides_TagOverride{
   570  			"remove": {
   571  				Operation: tpb.MetricsOverrides_TagOverride_REMOVE,
   572  			},
   573  			"add": {
   574  				Operation: tpb.MetricsOverrides_TagOverride_UPSERT,
   575  				Value:     "bar",
   576  			},
   577  		},
   578  	}}
   579  	sidecar := &Proxy{
   580  		ConfigNamespace: "default",
   581  		Labels:          map[string]string{"app": "test"},
   582  		Metadata:        &NodeMetadata{Labels: map[string]string{"app": "test"}},
   583  	}
   584  	emptyPrometheus := &tpb.Telemetry{
   585  		Metrics: []*tpb.Metrics{
   586  			{
   587  				Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
   588  			},
   589  		},
   590  	}
   591  	overridesPrometheus := &tpb.Telemetry{
   592  		Metrics: []*tpb.Metrics{
   593  			{
   594  				Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
   595  				Overrides: overrides,
   596  			},
   597  		},
   598  	}
   599  	reportingInterval := &tpb.Telemetry{
   600  		Metrics: []*tpb.Metrics{
   601  			{
   602  				Providers:         []*tpb.ProviderRef{{Name: "prometheus"}},
   603  				ReportingInterval: durationpb.New(15 * time.Second),
   604  			},
   605  		},
   606  	}
   607  	overridesInterval := &tpb.Telemetry{
   608  		Metrics: []*tpb.Metrics{
   609  			{
   610  				Providers:         []*tpb.ProviderRef{{Name: "prometheus"}},
   611  				ReportingInterval: durationpb.New(10 * time.Second),
   612  			},
   613  		},
   614  	}
   615  	overridesEmptyProvider := &tpb.Telemetry{
   616  		Metrics: []*tpb.Metrics{
   617  			{
   618  				Overrides: overrides,
   619  			},
   620  		},
   621  	}
   622  	disabledAllMetrics := &tpb.Telemetry{
   623  		Metrics: []*tpb.Metrics{
   624  			{
   625  				Overrides: []*tpb.MetricsOverrides{{
   626  					Match: &tpb.MetricSelector{
   627  						MetricMatch: &tpb.MetricSelector_Metric{
   628  							Metric: tpb.MetricSelector_ALL_METRICS,
   629  						},
   630  					},
   631  					Disabled: &wrappers.BoolValue{
   632  						Value: true,
   633  					},
   634  				}},
   635  
   636  				Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
   637  			},
   638  		},
   639  	}
   640  	disabledAllMetricsImplicit := &tpb.Telemetry{
   641  		Metrics: []*tpb.Metrics{
   642  			{
   643  				Overrides: []*tpb.MetricsOverrides{{
   644  					Disabled: &wrappers.BoolValue{
   645  						Value: true,
   646  					},
   647  				}},
   648  
   649  				Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
   650  			},
   651  		},
   652  	}
   653  	cfg := `{"metrics":[{"dimensions":{"add":"bar"},"name":"requests_total","tags_to_remove":["remove"]}]}`
   654  
   655  	tests := []struct {
   656  		name             string
   657  		cfgs             []config.Config
   658  		proxy            *Proxy
   659  		class            networking.ListenerClass
   660  		protocol         networking.ListenerProtocol
   661  		defaultProviders *meshconfig.MeshConfig_DefaultProviders
   662  		want             map[string]string
   663  	}{
   664  		{
   665  			"empty",
   666  			nil,
   667  			sidecar,
   668  			networking.ListenerClassSidecarOutbound,
   669  			networking.ListenerProtocolHTTP,
   670  			nil,
   671  			map[string]string{},
   672  		},
   673  		{
   674  			"disabled-prometheus",
   675  			[]config.Config{newTelemetry("istio-system", disabledAllMetrics)},
   676  			sidecar,
   677  			networking.ListenerClassSidecarOutbound,
   678  			networking.ListenerProtocolHTTP,
   679  			nil,
   680  			map[string]string{},
   681  		},
   682  		{
   683  			"disabled-prometheus-implicit",
   684  			[]config.Config{newTelemetry("istio-system", disabledAllMetricsImplicit)},
   685  			sidecar,
   686  			networking.ListenerClassSidecarOutbound,
   687  			networking.ListenerProtocolHTTP,
   688  			nil,
   689  			map[string]string{},
   690  		},
   691  		{
   692  			"disabled-then-empty",
   693  			[]config.Config{
   694  				newTelemetry("istio-system", disabledAllMetrics),
   695  				newTelemetry("default", emptyPrometheus),
   696  			},
   697  			sidecar,
   698  			networking.ListenerClassSidecarOutbound,
   699  			networking.ListenerProtocolHTTP,
   700  			nil,
   701  			map[string]string{},
   702  		},
   703  		{
   704  			"disabled-then-overrides",
   705  			[]config.Config{
   706  				newTelemetry("istio-system", disabledAllMetrics),
   707  				newTelemetry("default", overridesPrometheus),
   708  			},
   709  			sidecar,
   710  			networking.ListenerClassSidecarOutbound,
   711  			networking.ListenerProtocolHTTP,
   712  			nil,
   713  			map[string]string{
   714  				"istio.stats": cfg,
   715  			},
   716  		},
   717  		{
   718  			"default prometheus",
   719  			[]config.Config{newTelemetry("istio-system", emptyPrometheus)},
   720  			sidecar,
   721  			networking.ListenerClassSidecarOutbound,
   722  			networking.ListenerProtocolHTTP,
   723  			nil,
   724  			map[string]string{
   725  				"istio.stats": "{}",
   726  			},
   727  		},
   728  		{
   729  			"default provider prometheus",
   730  			[]config.Config{},
   731  			sidecar,
   732  			networking.ListenerClassSidecarOutbound,
   733  			networking.ListenerProtocolHTTP,
   734  			&meshconfig.MeshConfig_DefaultProviders{Metrics: []string{"prometheus"}},
   735  			map[string]string{
   736  				"istio.stats": "{}",
   737  			},
   738  		},
   739  		{
   740  			"prometheus overrides",
   741  			[]config.Config{newTelemetry("istio-system", overridesPrometheus)},
   742  			sidecar,
   743  			networking.ListenerClassSidecarOutbound,
   744  			networking.ListenerProtocolHTTP,
   745  			nil,
   746  			map[string]string{
   747  				"istio.stats": cfg,
   748  			},
   749  		},
   750  		{
   751  			"prometheus overrides all metrics",
   752  			[]config.Config{newTelemetry("istio-system", &tpb.Telemetry{
   753  				Metrics: []*tpb.Metrics{
   754  					{
   755  						Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
   756  						Overrides: []*tpb.MetricsOverrides{
   757  							{
   758  								TagOverrides: map[string]*tpb.MetricsOverrides_TagOverride{
   759  									"remove": {
   760  										Operation: tpb.MetricsOverrides_TagOverride_REMOVE,
   761  									},
   762  									"add": {
   763  										Operation: tpb.MetricsOverrides_TagOverride_UPSERT,
   764  										Value:     "bar",
   765  									},
   766  								},
   767  							},
   768  						},
   769  					},
   770  				},
   771  			})},
   772  			sidecar,
   773  			networking.ListenerClassSidecarOutbound,
   774  			networking.ListenerProtocolHTTP,
   775  			nil,
   776  			// TODO: the following should be simple to `{"metrics":[{"dimensions":{"add":"bar"},"tags_to_remove":["remove"]}]}`
   777  			map[string]string{
   778  				"istio.stats": `{"metrics":[` +
   779  					`{"dimensions":{"add":"bar"},"name":"request_messages_total","tags_to_remove":["remove"]},` +
   780  					`{"dimensions":{"add":"bar"},"name":"response_messages_total","tags_to_remove":["remove"]},` +
   781  					`{"dimensions":{"add":"bar"},"name":"requests_total","tags_to_remove":["remove"]},` +
   782  					`{"dimensions":{"add":"bar"},"name":"request_duration_milliseconds","tags_to_remove":["remove"]},` +
   783  					`{"dimensions":{"add":"bar"},"name":"request_bytes","tags_to_remove":["remove"]},` +
   784  					`{"dimensions":{"add":"bar"},"name":"response_bytes","tags_to_remove":["remove"]},` +
   785  					`{"dimensions":{"add":"bar"},"name":"tcp_connections_closed_total","tags_to_remove":["remove"]},` +
   786  					`{"dimensions":{"add":"bar"},"name":"tcp_connections_opened_total","tags_to_remove":["remove"]},` +
   787  					`{"dimensions":{"add":"bar"},"name":"tcp_received_bytes_total","tags_to_remove":["remove"]},` +
   788  					`{"dimensions":{"add":"bar"},"name":"tcp_sent_bytes_total","tags_to_remove":["remove"]}` +
   789  					`]}`,
   790  			},
   791  		},
   792  		{
   793  			"prometheus overrides all metrics first",
   794  			[]config.Config{newTelemetry("istio-system", &tpb.Telemetry{
   795  				Metrics: []*tpb.Metrics{
   796  					{
   797  						Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
   798  						Overrides: []*tpb.MetricsOverrides{
   799  							{
   800  								TagOverrides: map[string]*tpb.MetricsOverrides_TagOverride{
   801  									"remove": {
   802  										Operation: tpb.MetricsOverrides_TagOverride_REMOVE,
   803  									},
   804  									"add": {
   805  										Operation: tpb.MetricsOverrides_TagOverride_UPSERT,
   806  										Value:     "bar",
   807  									},
   808  								},
   809  							},
   810  							{
   811  								Match: &tpb.MetricSelector{
   812  									MetricMatch: &tpb.MetricSelector_Metric{
   813  										Metric: tpb.MetricSelector_REQUEST_COUNT,
   814  									},
   815  								},
   816  								TagOverrides: map[string]*tpb.MetricsOverrides_TagOverride{
   817  									"add": {
   818  										Value: "add-override",
   819  									},
   820  								},
   821  							},
   822  						},
   823  					},
   824  				},
   825  			})},
   826  			sidecar,
   827  			networking.ListenerClassSidecarOutbound,
   828  			networking.ListenerProtocolHTTP,
   829  			nil,
   830  			map[string]string{
   831  				"istio.stats": `{"metrics":[` +
   832  					`{"dimensions":{"add":"bar"},"name":"request_messages_total","tags_to_remove":["remove"]},` +
   833  					`{"dimensions":{"add":"bar"},"name":"response_messages_total","tags_to_remove":["remove"]},` +
   834  					`{"dimensions":{"add":"add-override"},"name":"requests_total","tags_to_remove":["remove"]},` +
   835  					`{"dimensions":{"add":"bar"},"name":"request_duration_milliseconds","tags_to_remove":["remove"]},` +
   836  					`{"dimensions":{"add":"bar"},"name":"request_bytes","tags_to_remove":["remove"]},` +
   837  					`{"dimensions":{"add":"bar"},"name":"response_bytes","tags_to_remove":["remove"]},` +
   838  					`{"dimensions":{"add":"bar"},"name":"tcp_connections_closed_total","tags_to_remove":["remove"]},` +
   839  					`{"dimensions":{"add":"bar"},"name":"tcp_connections_opened_total","tags_to_remove":["remove"]},` +
   840  					`{"dimensions":{"add":"bar"},"name":"tcp_received_bytes_total","tags_to_remove":["remove"]},` +
   841  					`{"dimensions":{"add":"bar"},"name":"tcp_sent_bytes_total","tags_to_remove":["remove"]}` +
   842  					`]}`,
   843  			},
   844  		},
   845  		{
   846  			"prometheus overrides all metrics secondary",
   847  			[]config.Config{newTelemetry("istio-system", &tpb.Telemetry{
   848  				Metrics: []*tpb.Metrics{
   849  					{
   850  						Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
   851  						Overrides: []*tpb.MetricsOverrides{
   852  							{
   853  								Match: &tpb.MetricSelector{
   854  									MetricMatch: &tpb.MetricSelector_Metric{
   855  										Metric: tpb.MetricSelector_REQUEST_COUNT,
   856  									},
   857  								},
   858  								TagOverrides: map[string]*tpb.MetricsOverrides_TagOverride{
   859  									"add": {
   860  										Value: "add-override",
   861  									},
   862  								},
   863  							},
   864  							{
   865  								TagOverrides: map[string]*tpb.MetricsOverrides_TagOverride{
   866  									"remove": {
   867  										Operation: tpb.MetricsOverrides_TagOverride_REMOVE,
   868  									},
   869  									"add": {
   870  										Operation: tpb.MetricsOverrides_TagOverride_UPSERT,
   871  										Value:     "bar",
   872  									},
   873  								},
   874  							},
   875  						},
   876  					},
   877  				},
   878  			})},
   879  			sidecar,
   880  			networking.ListenerClassSidecarOutbound,
   881  			networking.ListenerProtocolHTTP,
   882  			nil,
   883  			map[string]string{
   884  				"istio.stats": `{"metrics":[` +
   885  					`{"dimensions":{"add":"bar"},"name":"request_messages_total","tags_to_remove":["remove"]},` +
   886  					`{"dimensions":{"add":"bar"},"name":"response_messages_total","tags_to_remove":["remove"]},` +
   887  					`{"dimensions":{"add":"bar"},"name":"requests_total","tags_to_remove":["remove"]},` +
   888  					`{"dimensions":{"add":"bar"},"name":"request_duration_milliseconds","tags_to_remove":["remove"]},` +
   889  					`{"dimensions":{"add":"bar"},"name":"request_bytes","tags_to_remove":["remove"]},` +
   890  					`{"dimensions":{"add":"bar"},"name":"response_bytes","tags_to_remove":["remove"]},` +
   891  					`{"dimensions":{"add":"bar"},"name":"tcp_connections_closed_total","tags_to_remove":["remove"]},` +
   892  					`{"dimensions":{"add":"bar"},"name":"tcp_connections_opened_total","tags_to_remove":["remove"]},` +
   893  					`{"dimensions":{"add":"bar"},"name":"tcp_received_bytes_total","tags_to_remove":["remove"]},` +
   894  					`{"dimensions":{"add":"bar"},"name":"tcp_sent_bytes_total","tags_to_remove":["remove"]}` +
   895  					`]}`,
   896  			},
   897  		},
   898  		{
   899  			"prometheus overrides TCP",
   900  			[]config.Config{newTelemetry("istio-system", overridesPrometheus)},
   901  			sidecar,
   902  			networking.ListenerClassSidecarOutbound,
   903  			networking.ListenerProtocolTCP,
   904  			nil,
   905  			map[string]string{
   906  				"istio.stats": cfg,
   907  			},
   908  		},
   909  		{
   910  			"reporting-interval",
   911  			[]config.Config{newTelemetry("istio-system", reportingInterval)},
   912  			sidecar,
   913  			networking.ListenerClassSidecarOutbound,
   914  			networking.ListenerProtocolHTTP,
   915  			nil,
   916  			map[string]string{
   917  				"istio.stats": `{"tcp_reporting_duration":"15s"}`,
   918  			},
   919  		},
   920  		{
   921  			"override-interval",
   922  			[]config.Config{
   923  				newTelemetry("istio-system", reportingInterval),
   924  				newTelemetry("default", overridesInterval),
   925  			},
   926  			sidecar,
   927  			networking.ListenerClassSidecarOutbound,
   928  			networking.ListenerProtocolHTTP,
   929  			nil,
   930  			map[string]string{
   931  				"istio.stats": `{"tcp_reporting_duration":"10s"}`,
   932  			},
   933  		},
   934  		{
   935  			"namespace overrides merge without provider",
   936  			[]config.Config{
   937  				newTelemetry("istio-system", emptyPrometheus),
   938  				newTelemetry("default", overridesEmptyProvider),
   939  			},
   940  			sidecar,
   941  			networking.ListenerClassSidecarOutbound,
   942  			networking.ListenerProtocolHTTP,
   943  			nil,
   944  			map[string]string{
   945  				"istio.stats": cfg,
   946  			},
   947  		},
   948  		{
   949  			"namespace overrides merge with default provider",
   950  			[]config.Config{
   951  				newTelemetry("default", overridesEmptyProvider),
   952  			},
   953  			sidecar,
   954  			networking.ListenerClassSidecarOutbound,
   955  			networking.ListenerProtocolHTTP,
   956  			&meshconfig.MeshConfig_DefaultProviders{Metrics: []string{"prometheus"}},
   957  			map[string]string{
   958  				"istio.stats": cfg,
   959  			},
   960  		},
   961  	}
   962  	for _, tt := range tests {
   963  		t.Run(tt.name, func(t *testing.T) {
   964  			telemetry, _ := createTestTelemetries(tt.cfgs, t)
   965  			telemetry.meshConfig.DefaultProviders = tt.defaultProviders
   966  			got := telemetry.telemetryFilters(tt.proxy, tt.class, tt.protocol, nil)
   967  			res := map[string]string{}
   968  			http, ok := got.([]*hcm.HttpFilter)
   969  			if ok {
   970  				for _, f := range http {
   971  					if strings.HasSuffix(f.GetTypedConfig().GetTypeUrl(), "/stats.PluginConfig") {
   972  						w := &stats.PluginConfig{}
   973  						if err := f.GetTypedConfig().UnmarshalTo(w); err != nil {
   974  							t.Fatal(err)
   975  						}
   976  						cfgJSON, _ := protomarshal.MarshalProtoNames(w)
   977  						res[f.GetName()] = string(cfgJSON)
   978  					} else {
   979  						w := &httpwasm.Wasm{}
   980  
   981  						if err := f.GetTypedConfig().UnmarshalTo(w); err != nil {
   982  							t.Fatal(err)
   983  						}
   984  						cfg := &wrappers.StringValue{}
   985  						if err := w.GetConfig().GetConfiguration().UnmarshalTo(cfg); err != nil {
   986  							t.Fatal(err)
   987  						}
   988  						if _, dupe := res[f.GetName()]; dupe {
   989  							t.Fatalf("duplicate filter found: %v", f.GetName())
   990  						}
   991  						res[f.GetName()] = cfg.GetValue()
   992  					}
   993  				}
   994  			}
   995  			tcp, ok := got.([]*listener.Filter)
   996  			if ok {
   997  				for _, f := range tcp {
   998  					if strings.HasSuffix(f.GetTypedConfig().GetTypeUrl(), "/stats.PluginConfig") {
   999  						w := &stats.PluginConfig{}
  1000  						if err := f.GetTypedConfig().UnmarshalTo(w); err != nil {
  1001  							t.Fatal(err)
  1002  						}
  1003  						cfgJSON, _ := protomarshal.MarshalProtoNames(w)
  1004  						res[f.GetName()] = string(cfgJSON)
  1005  					} else {
  1006  						w := &wasmfilter.Wasm{}
  1007  
  1008  						if err := f.GetTypedConfig().UnmarshalTo(w); err != nil {
  1009  							t.Fatal(err)
  1010  						}
  1011  						cfg := &wrappers.StringValue{}
  1012  						if err := w.GetConfig().GetConfiguration().UnmarshalTo(cfg); err != nil {
  1013  							t.Fatal(err)
  1014  						}
  1015  						if _, dupe := res[f.GetName()]; dupe {
  1016  							t.Fatalf("duplicate filter found: %v", f.GetName())
  1017  						}
  1018  						res[f.GetName()] = cfg.GetValue()
  1019  					}
  1020  				}
  1021  			}
  1022  			if diff := cmp.Diff(res, tt.want); diff != "" {
  1023  				t.Errorf("got diff: %v", diff)
  1024  			}
  1025  		})
  1026  	}
  1027  }
  1028  
  1029  func TestGetInterval(t *testing.T) {
  1030  	cases := []struct {
  1031  		name              string
  1032  		input, defaultVal time.Duration
  1033  		expected          *durationpb.Duration
  1034  	}{
  1035  		{
  1036  			name:       "return nil",
  1037  			input:      0,
  1038  			defaultVal: 0,
  1039  			expected:   nil,
  1040  		},
  1041  		{
  1042  			name:       "return input",
  1043  			input:      1 * time.Second,
  1044  			defaultVal: 0,
  1045  			expected:   durationpb.New(1 * time.Second),
  1046  		},
  1047  	}
  1048  
  1049  	for _, tc := range cases {
  1050  		t.Run(tc.name, func(t *testing.T) {
  1051  			actual := getInterval(tc.input, tc.defaultVal)
  1052  			assert.Equal(t, tc.expected, actual)
  1053  		})
  1054  	}
  1055  }
  1056  
  1057  func Test_appendApplicableTelemetries(t *testing.T) {
  1058  	namespacedName := types.NamespacedName{
  1059  		Name:      "my-telemetry",
  1060  		Namespace: "my-namespace",
  1061  	}
  1062  	emptyStackDriverTracing := &tpb.Tracing{
  1063  		Match: &tpb.Tracing_TracingSelector{
  1064  			Mode: tpb.WorkloadMode_CLIENT,
  1065  		},
  1066  		Providers: []*tpb.ProviderRef{
  1067  			{
  1068  				Name: "stackdriver",
  1069  			},
  1070  		},
  1071  	}
  1072  	prometheusMetrics := &tpb.Metrics{
  1073  		Providers:         []*tpb.ProviderRef{{Name: "prometheus"}},
  1074  		ReportingInterval: durationpb.New(15 * time.Second),
  1075  	}
  1076  	emptyEnvoyLogging := &tpb.AccessLogging{
  1077  		Providers: []*tpb.ProviderRef{
  1078  			{
  1079  				Name: "envoy",
  1080  			},
  1081  		},
  1082  	}
  1083  	testComputeAccessLogging := &computedAccessLogging{
  1084  		telemetryKey: telemetryKey{
  1085  			Workload: namespacedName,
  1086  		},
  1087  		Logging: []*tpb.AccessLogging{
  1088  			emptyEnvoyLogging,
  1089  		},
  1090  	}
  1091  	validTelemetryConfigurationWithTargetRef := &tpb.Telemetry{
  1092  		TargetRef: &v1beta1.PolicyTargetReference{
  1093  			Group: gvk.KubernetesGateway.Group,
  1094  			Kind:  gvk.KubernetesGateway.Kind,
  1095  			Name:  "my-gateway",
  1096  		},
  1097  		Tracing: []*tpb.Tracing{
  1098  			emptyStackDriverTracing,
  1099  		},
  1100  		Metrics: []*tpb.Metrics{
  1101  			prometheusMetrics,
  1102  		},
  1103  		AccessLogging: []*tpb.AccessLogging{
  1104  			emptyEnvoyLogging,
  1105  		},
  1106  	}
  1107  	validTelemetryConfiguration := &tpb.Telemetry{
  1108  		Tracing: []*tpb.Tracing{
  1109  			emptyStackDriverTracing,
  1110  		},
  1111  		Metrics: []*tpb.Metrics{
  1112  			prometheusMetrics,
  1113  		},
  1114  		AccessLogging: []*tpb.AccessLogging{
  1115  			emptyEnvoyLogging,
  1116  		},
  1117  	}
  1118  	type args struct {
  1119  		ct   *computedTelemetries
  1120  		tel  Telemetry
  1121  		spec *tpb.Telemetry
  1122  	}
  1123  
  1124  	tests := []struct {
  1125  		name string
  1126  		args args
  1127  		want *computedTelemetries
  1128  	}{
  1129  		{
  1130  			name: "empty telemetry configuration",
  1131  			args: args{
  1132  				ct:   &computedTelemetries{},
  1133  				tel:  Telemetry{},
  1134  				spec: &tpb.Telemetry{},
  1135  			},
  1136  			want: &computedTelemetries{},
  1137  		},
  1138  		{
  1139  			name: "targetRef is defined, telemetry configurations are added to empty computed telemetries",
  1140  			args: args{
  1141  				ct: &computedTelemetries{},
  1142  				tel: Telemetry{
  1143  					Name:      "my-telemetry",
  1144  					Namespace: "my-namespace",
  1145  					Spec:      validTelemetryConfigurationWithTargetRef,
  1146  				},
  1147  				spec: validTelemetryConfigurationWithTargetRef,
  1148  			},
  1149  			want: &computedTelemetries{
  1150  				telemetryKey: telemetryKey{Workload: namespacedName},
  1151  				Metrics:      []*tpb.Metrics{prometheusMetrics},
  1152  				Logging:      []*computedAccessLogging{testComputeAccessLogging},
  1153  				Tracing:      []*tpb.Tracing{emptyStackDriverTracing},
  1154  			},
  1155  		},
  1156  		{
  1157  			name: "targetRef is not defined, telemetry configurations are added to empty computed telemetries",
  1158  			args: args{
  1159  				ct: &computedTelemetries{},
  1160  				tel: Telemetry{
  1161  					Name:      "my-telemetry",
  1162  					Namespace: "my-namespace",
  1163  					Spec:      validTelemetryConfiguration,
  1164  				},
  1165  				spec: validTelemetryConfiguration,
  1166  			},
  1167  			want: &computedTelemetries{
  1168  				telemetryKey: telemetryKey{
  1169  					Workload: namespacedName,
  1170  				},
  1171  				Metrics: []*tpb.Metrics{prometheusMetrics},
  1172  				Logging: []*computedAccessLogging{testComputeAccessLogging},
  1173  				Tracing: []*tpb.Tracing{emptyStackDriverTracing},
  1174  			},
  1175  		},
  1176  	}
  1177  	for _, tt := range tests {
  1178  		t.Run(tt.name, func(t *testing.T) {
  1179  			if got := appendApplicableTelemetries(tt.args.ct, tt.args.tel, tt.args.spec); !cmp.Equal(got, tt.want) {
  1180  				t.Errorf("appendApplicableTelemetries() = want %v", cmp.Diff(got, tt.want))
  1181  			}
  1182  		})
  1183  	}
  1184  }
  1185  
  1186  func Test_computedTelemetries_Equal(t *testing.T) {
  1187  	type args struct {
  1188  		other *computedTelemetries
  1189  	}
  1190  
  1191  	tests := []struct {
  1192  		name                string
  1193  		computedTelemetries *computedTelemetries
  1194  		args                args
  1195  		want                bool
  1196  	}{
  1197  		{
  1198  			name:                "nil",
  1199  			computedTelemetries: nil,
  1200  			args: args{
  1201  				other: nil,
  1202  			},
  1203  			want: true,
  1204  		},
  1205  		{
  1206  			name:                "empty",
  1207  			computedTelemetries: &computedTelemetries{},
  1208  			args: args{
  1209  				other: &computedTelemetries{},
  1210  			},
  1211  			want: true,
  1212  		},
  1213  		{
  1214  			name:                "computedTelemetries is nil and other computedTelemetries is not",
  1215  			computedTelemetries: nil,
  1216  			args: args{
  1217  				other: &computedTelemetries{
  1218  					Metrics: []*tpb.Metrics{
  1219  						{
  1220  							Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
  1221  						},
  1222  					},
  1223  				},
  1224  			},
  1225  			want: false,
  1226  		},
  1227  		{
  1228  			name: "other computedTelemetries is nil and computedTelemetries is not",
  1229  			computedTelemetries: &computedTelemetries{
  1230  				Metrics: []*tpb.Metrics{
  1231  					{
  1232  						Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
  1233  					},
  1234  				},
  1235  			},
  1236  			args: args{
  1237  				other: nil,
  1238  			},
  1239  			want: false,
  1240  		},
  1241  		{
  1242  			name: "different length in metrics slice comparison",
  1243  			computedTelemetries: &computedTelemetries{
  1244  				Metrics: []*tpb.Metrics{
  1245  					{
  1246  						Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
  1247  					},
  1248  				},
  1249  			},
  1250  			args: args{
  1251  				other: &computedTelemetries{
  1252  					Metrics: []*tpb.Metrics{
  1253  						{
  1254  							Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
  1255  						},
  1256  						{
  1257  							Providers: []*tpb.ProviderRef{{Name: "stackdriver"}},
  1258  						},
  1259  					},
  1260  				},
  1261  			},
  1262  			want: false,
  1263  		},
  1264  		{
  1265  			name: "different length in tracing slice comparison",
  1266  			computedTelemetries: &computedTelemetries{
  1267  				Tracing: []*tpb.Tracing{
  1268  					{
  1269  						Providers: []*tpb.ProviderRef{{Name: "stackdriver"}},
  1270  					},
  1271  				},
  1272  			},
  1273  			args: args{
  1274  				other: &computedTelemetries{
  1275  					Tracing: []*tpb.Tracing{
  1276  						{
  1277  							Providers: []*tpb.ProviderRef{{Name: "stackdriver"}},
  1278  						},
  1279  						{
  1280  							Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
  1281  						},
  1282  					},
  1283  				},
  1284  			},
  1285  			want: false,
  1286  		},
  1287  		{
  1288  			name: "different length in logging slice comparison",
  1289  			computedTelemetries: &computedTelemetries{
  1290  				Logging: []*computedAccessLogging{
  1291  					{
  1292  						Logging: []*tpb.AccessLogging{
  1293  							{
  1294  								Providers: []*tpb.ProviderRef{{Name: "stackdriver"}},
  1295  							},
  1296  						},
  1297  					},
  1298  				},
  1299  			},
  1300  			args: args{
  1301  				other: &computedTelemetries{
  1302  					Logging: []*computedAccessLogging{
  1303  						{
  1304  							Logging: []*tpb.AccessLogging{
  1305  								{
  1306  									Providers: []*tpb.ProviderRef{{Name: "stackdriver"}},
  1307  								},
  1308  							},
  1309  						},
  1310  						{
  1311  							Logging: []*tpb.AccessLogging{
  1312  								{
  1313  									Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
  1314  								},
  1315  							},
  1316  						},
  1317  					},
  1318  				},
  1319  			},
  1320  			want: false,
  1321  		},
  1322  		{
  1323  			name: "different metrics",
  1324  			computedTelemetries: &computedTelemetries{
  1325  				Metrics: []*tpb.Metrics{
  1326  					{
  1327  						Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
  1328  					},
  1329  				},
  1330  			},
  1331  			args: args{
  1332  				other: &computedTelemetries{
  1333  					Metrics: []*tpb.Metrics{
  1334  						{
  1335  							Providers: []*tpb.ProviderRef{{Name: "stackdriver"}},
  1336  						},
  1337  					},
  1338  				},
  1339  			},
  1340  			want: false,
  1341  		},
  1342  		{
  1343  			name: "different metrics reporting interval",
  1344  			computedTelemetries: &computedTelemetries{
  1345  				Metrics: []*tpb.Metrics{
  1346  					{
  1347  						Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
  1348  						ReportingInterval: &durationpb.Duration{
  1349  							Seconds: 10,
  1350  						},
  1351  					},
  1352  				},
  1353  			},
  1354  			args: args{
  1355  				other: &computedTelemetries{
  1356  					Metrics: []*tpb.Metrics{
  1357  						{
  1358  							Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
  1359  							ReportingInterval: &durationpb.Duration{
  1360  								Seconds: 15,
  1361  							},
  1362  						},
  1363  					},
  1364  				},
  1365  			},
  1366  			want: false,
  1367  		},
  1368  		{
  1369  			name: "different tracing providers",
  1370  			computedTelemetries: &computedTelemetries{
  1371  				Tracing: []*tpb.Tracing{
  1372  					{
  1373  						Providers: []*tpb.ProviderRef{{Name: "stackdriver"}},
  1374  					},
  1375  				},
  1376  			},
  1377  			args: args{
  1378  				other: &computedTelemetries{
  1379  					Tracing: []*tpb.Tracing{
  1380  						{
  1381  							Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
  1382  						},
  1383  					},
  1384  				},
  1385  			},
  1386  			want: false,
  1387  		},
  1388  		{
  1389  			name: "different tracing match",
  1390  			computedTelemetries: &computedTelemetries{
  1391  				Tracing: []*tpb.Tracing{
  1392  					{
  1393  						Providers: []*tpb.ProviderRef{{Name: "stackdriver"}},
  1394  						Match: &tpb.Tracing_TracingSelector{
  1395  							Mode: tpb.WorkloadMode_CLIENT,
  1396  						},
  1397  					},
  1398  				},
  1399  			},
  1400  			args: args{
  1401  				other: &computedTelemetries{
  1402  					Tracing: []*tpb.Tracing{
  1403  						{
  1404  							Providers: []*tpb.ProviderRef{{Name: "stackdriver"}},
  1405  							Match: &tpb.Tracing_TracingSelector{
  1406  								Mode: tpb.WorkloadMode_SERVER,
  1407  							},
  1408  						},
  1409  					},
  1410  				},
  1411  			},
  1412  			want: false,
  1413  		},
  1414  		{
  1415  			name: "different logging providers",
  1416  			computedTelemetries: &computedTelemetries{
  1417  				Logging: []*computedAccessLogging{
  1418  					{
  1419  						Logging: []*tpb.AccessLogging{
  1420  							{
  1421  								Providers: []*tpb.ProviderRef{{Name: "stackdriver"}},
  1422  							},
  1423  						},
  1424  					},
  1425  				},
  1426  			},
  1427  			args: args{
  1428  				other: &computedTelemetries{
  1429  					Logging: []*computedAccessLogging{
  1430  						{
  1431  							Logging: []*tpb.AccessLogging{
  1432  								{
  1433  									Providers: []*tpb.ProviderRef{{Name: "prometheus"}},
  1434  								},
  1435  							},
  1436  						},
  1437  					},
  1438  				},
  1439  			},
  1440  			want: false,
  1441  		},
  1442  		{
  1443  			name: "different logging telemetryKey",
  1444  			computedTelemetries: &computedTelemetries{
  1445  				Logging: []*computedAccessLogging{
  1446  					{
  1447  						telemetryKey: telemetryKey{
  1448  							Workload: types.NamespacedName{
  1449  								Name:      "my-telemetry",
  1450  								Namespace: "my-namespace",
  1451  							},
  1452  						},
  1453  					},
  1454  				},
  1455  			},
  1456  			args: args{
  1457  				other: &computedTelemetries{
  1458  					Logging: []*computedAccessLogging{
  1459  						{
  1460  							telemetryKey: telemetryKey{
  1461  								Workload: types.NamespacedName{
  1462  									Name:      "my-telemetry",
  1463  									Namespace: "my-namespace-2",
  1464  								},
  1465  							},
  1466  						},
  1467  					},
  1468  				},
  1469  			},
  1470  			want: false,
  1471  		},
  1472  	}
  1473  	for _, tt := range tests {
  1474  		t.Run(tt.name, func(t *testing.T) {
  1475  			if got := tt.computedTelemetries.Equal(tt.args.other); got != tt.want {
  1476  				t.Errorf("computedTelemetries.Equal() = %v, want %v", got, tt.want)
  1477  			}
  1478  		})
  1479  	}
  1480  }