github.com/apache/beam/sdks/v2@v2.48.2/go/container/boot_test.go (about)

     1  // Licensed to the Apache Software Foundation (ASF) under one or more
     2  // contributor license agreements.  See the NOTICE file distributed with
     3  // this work for additional information regarding copyright ownership.
     4  // The ASF licenses this file to You under the Apache License, Version 2.0
     5  // (the "License"); you may not use this file except in compliance with
     6  // the License.  You may obtain a copy of the License at
     7  //
     8  //    http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package main
    17  
    18  import (
    19  	"context"
    20  	"os"
    21  	"path/filepath"
    22  	"testing"
    23  
    24  	"github.com/apache/beam/sdks/v2/go/container/tools"
    25  	"github.com/apache/beam/sdks/v2/go/pkg/beam/artifact"
    26  	fnpb "github.com/apache/beam/sdks/v2/go/pkg/beam/model/fnexecution_v1"
    27  	pipepb "github.com/apache/beam/sdks/v2/go/pkg/beam/model/pipeline_v1"
    28  	"github.com/golang/protobuf/proto"
    29  )
    30  
    31  func TestEnsureEndpointsSet_AllSet(t *testing.T) {
    32  	provisionInfo := &fnpb.ProvisionInfo{
    33  		LoggingEndpoint:  &pipepb.ApiServiceDescriptor{Url: "testLoggingEndpointUrl"},
    34  		ArtifactEndpoint: &pipepb.ApiServiceDescriptor{Url: "testArtifactEndpointUrl"},
    35  		ControlEndpoint:  &pipepb.ApiServiceDescriptor{Url: "testControlEndpointUrl"},
    36  	}
    37  	*loggingEndpoint = ""
    38  	*artifactEndpoint = ""
    39  	*controlEndpoint = ""
    40  	err := ensureEndpointsSet(provisionInfo)
    41  	if err != nil {
    42  		t.Fatalf("ensureEndpointsSet() = %q, want nil", err)
    43  	}
    44  	if got, want := *loggingEndpoint, "testLoggingEndpointUrl"; got != want {
    45  		t.Fatalf("After ensureEndpointsSet(), *loggingEndpoint = %q, want %q", got, want)
    46  	}
    47  	if got, want := *artifactEndpoint, "testArtifactEndpointUrl"; got != want {
    48  		t.Fatalf("After ensureEndpointsSet(), *artifactEndpoint = %q, want %q", got, want)
    49  	}
    50  	if got, want := *controlEndpoint, "testControlEndpointUrl"; got != want {
    51  		t.Fatalf("After ensureEndpointsSet(), *controlEndpoint = %q, want %q", got, want)
    52  	}
    53  }
    54  
    55  func TestEnsureEndpointsSet_OneMissing(t *testing.T) {
    56  	provisionInfo := &fnpb.ProvisionInfo{
    57  		LoggingEndpoint:  &pipepb.ApiServiceDescriptor{Url: "testLoggingEndpointUrl"},
    58  		ArtifactEndpoint: &pipepb.ApiServiceDescriptor{Url: "testArtifactEndpointUrl"},
    59  		ControlEndpoint:  &pipepb.ApiServiceDescriptor{Url: ""},
    60  	}
    61  	*loggingEndpoint = ""
    62  	*artifactEndpoint = ""
    63  	*controlEndpoint = ""
    64  	err := ensureEndpointsSet(provisionInfo)
    65  	if err == nil {
    66  		t.Fatalf("ensureEndpointsSet() = nil, want non-nil error")
    67  	}
    68  	if got, want := *loggingEndpoint, "testLoggingEndpointUrl"; got != want {
    69  		t.Fatalf("After ensureEndpointsSet(), *loggingEndpoint = %q, want %q", got, want)
    70  	}
    71  	if got, want := *artifactEndpoint, "testArtifactEndpointUrl"; got != want {
    72  		t.Fatalf("After ensureEndpointsSet(), *artifactEndpoint = %q, want %q", got, want)
    73  	}
    74  	if got, want := *controlEndpoint, ""; got != want {
    75  		t.Fatalf("After ensureEndpointsSet(), *controlEndpoint = %q, want %q", got, want)
    76  	}
    77  }
    78  
    79  func TestGetGoWorkerArtifactName_NoArtifacts(t *testing.T) {
    80  	_, err := getGoWorkerArtifactName(context.Background(), &tools.Logger{}, []*pipepb.ArtifactInformation{})
    81  	if err == nil {
    82  		t.Fatalf("getGoWorkerArtifactName() = nil, want non-nil error")
    83  	}
    84  }
    85  
    86  func TestGetGoWorkerArtifactName_OneArtifact(t *testing.T) {
    87  	artifact := constructArtifactInformation(t, artifact.URNGoWorkerBinaryRole, "test/path", "sha")
    88  	artifacts := []*pipepb.ArtifactInformation{&artifact}
    89  
    90  	val, err := getGoWorkerArtifactName(context.Background(), &tools.Logger{}, artifacts)
    91  	if err != nil {
    92  		t.Fatalf("getGoWorkerArtifactName() = %v, want nil", err)
    93  	}
    94  	if got, want := val, "test/path"; got != want {
    95  		t.Fatalf("getGoWorkerArtifactName() = %v, want %v", got, want)
    96  	}
    97  }
    98  
    99  func TestGetGoWorkerArtifactName_MultipleArtifactsFirstIsWorker(t *testing.T) {
   100  	artifact1 := constructArtifactInformation(t, artifact.URNGoWorkerBinaryRole, "test/path", "sha")
   101  	artifact2 := constructArtifactInformation(t, "other role", "test/path2", "sha")
   102  	artifacts := []*pipepb.ArtifactInformation{&artifact1, &artifact2}
   103  
   104  	val, err := getGoWorkerArtifactName(context.Background(), &tools.Logger{}, artifacts)
   105  	if err != nil {
   106  		t.Fatalf("getGoWorkerArtifactName() = %v, want nil", err)
   107  	}
   108  	if got, want := val, "test/path"; got != want {
   109  		t.Fatalf("getGoWorkerArtifactName() = %v, want %v", got, want)
   110  	}
   111  }
   112  
   113  func TestGetGoWorkerArtifactName_MultipleArtifactsSecondIsWorker(t *testing.T) {
   114  	artifact1 := constructArtifactInformation(t, "other role", "test/path", "sha")
   115  	artifact2 := constructArtifactInformation(t, artifact.URNGoWorkerBinaryRole, "test/path2", "sha")
   116  	artifacts := []*pipepb.ArtifactInformation{&artifact1, &artifact2}
   117  
   118  	val, err := getGoWorkerArtifactName(context.Background(), &tools.Logger{}, artifacts)
   119  	if err != nil {
   120  		t.Fatalf("getGoWorkerArtifactName() = %v, want nil", err)
   121  	}
   122  	if got, want := val, "test/path2"; got != want {
   123  		t.Fatalf("getGoWorkerArtifactName() = %v, want %v", got, want)
   124  	}
   125  }
   126  
   127  func TestGetGoWorkerArtifactName_MultipleArtifactsLegacyWay(t *testing.T) {
   128  	artifact1 := constructArtifactInformation(t, "other role", "test/path", "sha")
   129  	artifact2 := constructArtifactInformation(t, "other role", "worker", "sha")
   130  	artifacts := []*pipepb.ArtifactInformation{&artifact1, &artifact2}
   131  
   132  	val, err := getGoWorkerArtifactName(context.Background(), &tools.Logger{}, artifacts)
   133  	if err != nil {
   134  		t.Fatalf("getGoWorkerArtifactName() = %v, want nil", err)
   135  	}
   136  	if got, want := val, "worker"; got != want {
   137  		t.Fatalf("getGoWorkerArtifactName() = %v, want %v", got, want)
   138  	}
   139  }
   140  
   141  func TestGetGoWorkerArtifactName_MultipleArtifactsNoneMatch(t *testing.T) {
   142  	artifact1 := constructArtifactInformation(t, "other role", "test/path", "sha")
   143  	artifact2 := constructArtifactInformation(t, "other role", "test/path2", "sha")
   144  	artifacts := []*pipepb.ArtifactInformation{&artifact1, &artifact2}
   145  
   146  	_, err := getGoWorkerArtifactName(context.Background(), &tools.Logger{}, artifacts)
   147  	if err == nil {
   148  		t.Fatalf("getGoWorkerArtifactName() = nil, want non-nil error")
   149  	}
   150  }
   151  
   152  func TestCopyExe(t *testing.T) {
   153  	testExeContent := []byte("testContent")
   154  
   155  	// Make temp directory to cleanup at the end
   156  	d, err := os.MkdirTemp(os.Getenv("TEST_TMPDIR"), "copyExe-*")
   157  	if err != nil {
   158  		t.Fatalf("failed to make temp directory, got %v", err)
   159  	}
   160  	t.Cleanup(func() { os.RemoveAll(d) })
   161  
   162  	// Make our source file and write to it
   163  	src, err := os.CreateTemp(d, "src.exe")
   164  	if err != nil {
   165  		t.Fatalf("failed to make temp file, got %v", err)
   166  	}
   167  	if _, err := src.Write(testExeContent); err != nil {
   168  		t.Fatalf("failed to write to temp file, got %v", err)
   169  	}
   170  	if err := src.Close(); err != nil {
   171  		t.Fatalf("failed to close temp file, got %v", err)
   172  	}
   173  
   174  	// Make sure our destination path doesn't exist already
   175  	srcPath, destPath := src.Name(), filepath.Join(d, "dest.exe")
   176  	if _, err := os.Stat(destPath); err == nil {
   177  		t.Fatalf("dest file %v already exists", destPath)
   178  	}
   179  
   180  	err = copyExe(srcPath, destPath)
   181  	if err != nil {
   182  		t.Fatalf("copyExe() = %v, want nil", err)
   183  	}
   184  	if _, err := os.Stat(destPath); err != nil {
   185  		t.Fatalf("After running copyExe, os.Stat() = %v, want nil", err)
   186  	}
   187  	destContents, err := os.ReadFile(destPath)
   188  	if err != nil {
   189  		t.Fatalf("After running copyExe, os.ReadFile() = %v, want nil", err)
   190  	}
   191  	if got, want := string(destContents), string(testExeContent); got != want {
   192  		t.Fatalf("After running copyExe, os.ReadFile() = %v, want %v", got, want)
   193  	}
   194  }
   195  
   196  func constructArtifactInformation(t *testing.T, roleUrn string, path string, sha string) pipepb.ArtifactInformation {
   197  	t.Helper()
   198  
   199  	typePayload, _ := proto.Marshal(&pipepb.ArtifactFilePayload{Path: path, Sha256: sha})
   200  
   201  	return pipepb.ArtifactInformation{
   202  		RoleUrn:     roleUrn,
   203  		TypeUrn:     artifact.URNFileArtifact,
   204  		TypePayload: typePayload,
   205  	}
   206  }
   207  
   208  func TestConfigureGoogleCloudProfilerEnvVars(t *testing.T) {
   209  	tests := []struct {
   210  		name          string
   211  		inputMetadata map[string]string
   212  		expectedName  string
   213  		expectedID    string
   214  		expectedError string
   215  	}{
   216  		{
   217  			"nil metadata",
   218  			nil,
   219  			"",
   220  			"",
   221  			"enable_google_cloud_profiler is set to true, but no metadata is received from provision server, profiling will not be enabled",
   222  		},
   223  		{
   224  			"missing name",
   225  			map[string]string{"job_id": "12345"},
   226  			"",
   227  			"",
   228  			"required job_name missing from metadata, profiling will not be enabled without it",
   229  		},
   230  		{
   231  			"missing id",
   232  			map[string]string{"job_name": "my_job"},
   233  			"",
   234  			"",
   235  			"required job_id missing from metadata, profiling will not be enabled without it",
   236  		},
   237  		{
   238  			"correct",
   239  			map[string]string{"job_name": "my_job", "job_id": "42"},
   240  			"my_job",
   241  			"42",
   242  			"",
   243  		},
   244  	}
   245  	for _, test := range tests {
   246  		t.Run(test.name, func(t *testing.T) {
   247  			t.Cleanup(os.Clearenv)
   248  			err := configureGoogleCloudProfilerEnvVars(context.Background(), &tools.Logger{}, test.inputMetadata)
   249  			if err != nil {
   250  				if got, want := err.Error(), test.expectedError; got != want {
   251  					t.Errorf("got error %v, want error %v", got, want)
   252  				}
   253  			}
   254  			if got, want := os.Getenv(cloudProfilingJobName), test.expectedName; got != want {
   255  				t.Errorf("got job name %v, want %v", got, want)
   256  			}
   257  			if got, want := os.Getenv(cloudProfilingJobID), test.expectedID; got != want {
   258  				t.Errorf("got job id %v, want %v", got, want)
   259  			}
   260  		})
   261  	}
   262  }