...

Source file src/cloud.google.com/go/logging/resource_test.go

Documentation: cloud.google.com/go/logging

     1  // Copyright 2022 Google LLC
     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  //      https://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 logging
    16  
    17  import (
    18  	"sync"
    19  	"testing"
    20  
    21  	"github.com/google/go-cmp/cmp"
    22  	"github.com/google/go-cmp/cmp/cmpopts"
    23  	mrpb "google.golang.org/genproto/googleapis/api/monitoredres"
    24  )
    25  
    26  const (
    27  	there               = "anyvalue"
    28  	projectID           = "test-project"
    29  	zoneID              = "test-region-zone"
    30  	regionID            = "test-region"
    31  	serviceName         = "test-service"
    32  	version             = "1.0"
    33  	instanceName        = "test-12345"
    34  	qualifiedZoneName   = "projects/" + projectID + "/zones/" + zoneID
    35  	qualifiedRegionName = "projects/" + projectID + "/regions/" + regionID
    36  	funcSignature       = "test-cf-signature"
    37  	funcTarget          = "test-cf-target"
    38  	crConfig            = "test-cr-config"
    39  	clusterName         = "test-k8s-cluster"
    40  	podName             = "test-k8s-pod-name"
    41  	containerName       = "test-k8s-container-name"
    42  	namespaceName       = "test-k8s-namespace-name"
    43  	instanceID          = "test-instance-12345"
    44  )
    45  
    46  // fakeResourceGetter mocks internal.ResourceAtttributesGetter interface to retrieve env vars and metadata
    47  type fakeResourceGetter struct {
    48  	envVars  map[string]string
    49  	metaVars map[string]string
    50  	fsPaths  map[string]string
    51  }
    52  
    53  func (g *fakeResourceGetter) EnvVar(name string) string {
    54  	if g.envVars != nil {
    55  		if v, ok := g.envVars[name]; ok {
    56  			return v
    57  		}
    58  	}
    59  	return ""
    60  }
    61  
    62  func (g *fakeResourceGetter) Metadata(path string) string {
    63  	if g.metaVars != nil {
    64  		if v, ok := g.metaVars[path]; ok {
    65  			return v
    66  		}
    67  	}
    68  	return ""
    69  }
    70  
    71  func (g *fakeResourceGetter) ReadAll(path string) string {
    72  	if g.fsPaths != nil {
    73  		if v, ok := g.fsPaths[path]; ok {
    74  			return v
    75  		}
    76  	}
    77  	return ""
    78  }
    79  
    80  // setupDetectResource resets sync.Once on detectResource and enforces mocked resource attribute getter
    81  func setupDetectedResource(envVars, metaVars, fsPaths map[string]string) {
    82  	detectedResource.once = new(sync.Once)
    83  	detectedResource.attrs = &fakeResourceGetter{
    84  		envVars:  envVars,
    85  		metaVars: metaVars,
    86  		fsPaths:  fsPaths,
    87  	}
    88  	detectedResource.pb = nil
    89  }
    90  
    91  func TestResourceDetection(t *testing.T) {
    92  	tests := []struct {
    93  		name     string
    94  		envVars  map[string]string
    95  		metaVars map[string]string
    96  		fsPaths  map[string]string
    97  		want     *mrpb.MonitoredResource
    98  	}{
    99  		{
   100  			name:     "detect GAE resource",
   101  			envVars:  map[string]string{"GAE_SERVICE": serviceName, "GAE_VERSION": version, "GAE_INSTANCE": instanceName},
   102  			metaVars: map[string]string{"": there, "project/project-id": projectID, "instance/zone": qualifiedZoneName, "instance/attributes/gae_app_bucket": there},
   103  			want: &mrpb.MonitoredResource{
   104  				Type: "gae_app",
   105  				Labels: map[string]string{
   106  					"project_id": projectID,
   107  					"module_id":  serviceName,
   108  					"version_id": version,
   109  					"zone":       zoneID,
   110  				},
   111  			},
   112  		},
   113  		{
   114  			name:     "detect Cloud Function resource",
   115  			envVars:  map[string]string{"FUNCTION_TARGET": funcTarget, "FUNCTION_SIGNATURE_TYPE": funcSignature, "K_SERVICE": serviceName},
   116  			metaVars: map[string]string{"": there, "project/project-id": projectID, "instance/region": qualifiedRegionName},
   117  			want: &mrpb.MonitoredResource{
   118  				Type: "cloud_function",
   119  				Labels: map[string]string{
   120  					"project_id":    projectID,
   121  					"region":        regionID,
   122  					"function_name": serviceName,
   123  				},
   124  			},
   125  		},
   126  		{
   127  			name:     "detect Cloud Run service resource",
   128  			envVars:  map[string]string{"K_CONFIGURATION": crConfig, "K_SERVICE": serviceName, "K_REVISION": version},
   129  			metaVars: map[string]string{"": there, "project/project-id": projectID, "instance/region": qualifiedRegionName},
   130  			want: &mrpb.MonitoredResource{
   131  				Type: "cloud_run_revision",
   132  				Labels: map[string]string{
   133  					"project_id":         projectID,
   134  					"location":           regionID,
   135  					"service_name":       serviceName,
   136  					"revision_name":      version,
   137  					"configuration_name": crConfig,
   138  				},
   139  			},
   140  		},
   141  		{
   142  			name:     "detect Cloud Run job resource",
   143  			envVars:  map[string]string{"CLOUD_RUN_JOB": serviceName, "CLOUD_RUN_EXECUTION": crConfig, "CLOUD_RUN_TASK_INDEX": version, "CLOUD_RUN_TASK_ATTEMPT": instanceID},
   144  			metaVars: map[string]string{"": there, "project/project-id": projectID, "instance/region": qualifiedRegionName},
   145  			want: &mrpb.MonitoredResource{
   146  				Type: "cloud_run_job",
   147  				Labels: map[string]string{
   148  					"project_id": projectID,
   149  					"location":   regionID,
   150  					"job_name":   serviceName,
   151  				},
   152  			},
   153  		},
   154  		{
   155  			name:     "detect GKE resource for a zonal cluster",
   156  			envVars:  map[string]string{"HOSTNAME": podName},
   157  			metaVars: map[string]string{"": there, "project/project-id": projectID, "instance/attributes/cluster-location": zoneID, "instance/attributes/cluster-name": clusterName},
   158  			fsPaths:  map[string]string{"/var/run/secrets/kubernetes.io/serviceaccount/namespace": namespaceName},
   159  			want: &mrpb.MonitoredResource{
   160  				Type: "k8s_container",
   161  				Labels: map[string]string{
   162  					"cluster_name":   clusterName,
   163  					"location":       zoneID,
   164  					"project_id":     projectID,
   165  					"pod_name":       podName,
   166  					"namespace_name": namespaceName,
   167  					"container_name": "",
   168  				},
   169  			},
   170  		},
   171  		{
   172  			name:     "detect GKE resource for a regional cluster",
   173  			envVars:  map[string]string{"HOSTNAME": podName},
   174  			metaVars: map[string]string{"": there, "project/project-id": projectID, "instance/attributes/cluster-location": regionID, "instance/attributes/cluster-name": clusterName},
   175  			fsPaths:  map[string]string{"/var/run/secrets/kubernetes.io/serviceaccount/namespace": namespaceName},
   176  			want: &mrpb.MonitoredResource{
   177  				Type: "k8s_container",
   178  				Labels: map[string]string{
   179  					"cluster_name":   clusterName,
   180  					"location":       regionID,
   181  					"project_id":     projectID,
   182  					"pod_name":       podName,
   183  					"namespace_name": namespaceName,
   184  					"container_name": "",
   185  				},
   186  			},
   187  		},
   188  		{
   189  			name:     "detect GKE resource with custom container and namespace config",
   190  			envVars:  map[string]string{"HOSTNAME": podName, "CONTAINER_NAME": containerName, "NAMESPACE_NAME": namespaceName},
   191  			metaVars: map[string]string{"": there, "project/project-id": projectID, "instance/attributes/cluster-location": zoneID, "instance/attributes/cluster-name": clusterName},
   192  			want: &mrpb.MonitoredResource{
   193  				Type: "k8s_container",
   194  				Labels: map[string]string{
   195  					"cluster_name":   clusterName,
   196  					"location":       zoneID,
   197  					"project_id":     projectID,
   198  					"pod_name":       podName,
   199  					"namespace_name": namespaceName,
   200  					"container_name": containerName,
   201  				},
   202  			},
   203  		},
   204  		{
   205  			name:     "detect Compute Engine resource",
   206  			envVars:  map[string]string{},
   207  			metaVars: map[string]string{"": there, "project/project-id": projectID, "instance/id": instanceID, "instance/zone": qualifiedZoneName, "instance/preempted": there, "instance/cpu-platform": there},
   208  			want: &mrpb.MonitoredResource{
   209  				Type: "gce_instance",
   210  				Labels: map[string]string{
   211  					"project_id":  projectID,
   212  					"instance_id": instanceID,
   213  					"zone":        zoneID,
   214  				},
   215  			},
   216  		},
   217  		{
   218  			name:     "detect GAE resource by product name",
   219  			envVars:  map[string]string{},
   220  			metaVars: map[string]string{"": there, "project/project-id": projectID, "instance/zone": qualifiedZoneName, "instance/attributes/gae_app_bucket": there},
   221  			fsPaths:  map[string]string{"/sys/class/dmi/id/product_name": "Google App Engine"},
   222  			want: &mrpb.MonitoredResource{
   223  				Type: "gae_app",
   224  				Labels: map[string]string{
   225  					"project_id": projectID,
   226  					"module_id":  "",
   227  					"version_id": "",
   228  					"zone":       zoneID,
   229  				},
   230  			},
   231  		},
   232  		{
   233  			name:     "detect Cloud Function resource by product name",
   234  			envVars:  map[string]string{},
   235  			metaVars: map[string]string{"": there, "project/project-id": projectID, "instance/region": qualifiedRegionName},
   236  			fsPaths:  map[string]string{"/sys/class/dmi/id/product_name": "Google Cloud Functions"},
   237  			want: &mrpb.MonitoredResource{
   238  				Type: "cloud_function",
   239  				Labels: map[string]string{
   240  					"project_id":    projectID,
   241  					"region":        regionID,
   242  					"function_name": "",
   243  				},
   244  			},
   245  		},
   246  		{
   247  			name:     "unknown resource detection",
   248  			envVars:  map[string]string{},
   249  			metaVars: map[string]string{"": there, "project/project-id": projectID},
   250  			want:     nil,
   251  		},
   252  		{
   253  			name:     "resource without metadata detection",
   254  			envVars:  map[string]string{},
   255  			metaVars: map[string]string{},
   256  			want:     nil,
   257  		},
   258  	}
   259  
   260  	// cleanup
   261  	oldAttrs := detectedResource.attrs
   262  	defer func() {
   263  		detectedResource.attrs = oldAttrs
   264  		detectedResource.once = new(sync.Once)
   265  	}()
   266  	for _, tc := range tests {
   267  		t.Run(tc.name, func(t *testing.T) {
   268  			setupDetectedResource(tc.envVars, tc.metaVars, tc.fsPaths)
   269  			got := detectResource()
   270  			if diff := cmp.Diff(got, tc.want, cmpopts.IgnoreUnexported(mrpb.MonitoredResource{})); diff != "" {
   271  				t.Errorf("got(-),want(+):\n%s", diff)
   272  			}
   273  		})
   274  	}
   275  }
   276  
   277  var benchmarkResultHolder *mrpb.MonitoredResource
   278  
   279  func BenchmarkDetectResource(b *testing.B) {
   280  	var result *mrpb.MonitoredResource
   281  
   282  	for n := 0; n < b.N; n++ {
   283  		result = detectResource()
   284  	}
   285  
   286  	benchmarkResultHolder = result
   287  }
   288  

View as plain text