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 }