This is an automated email from the ASF dual-hosted git repository.

riteshghorse pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git


The following commit(s) were added to refs/heads/master by this push:
     new c5d6183cee1 Implement environment variable type (#27407)
c5d6183cee1 is described below

commit c5d6183cee1c22c572cbf51ec4a2c1490dafafe8
Author: Damon <damondoug...@users.noreply.github.com>
AuthorDate: Mon Jul 10 14:10:43 2023 -0700

    Implement environment variable type (#27407)
---
 .test-infra/pipelines/go.mod                       |  21 ++
 .test-infra/pipelines/go.sum                       |   2 +
 .../src/main/go/internal/environment/variable.go   |  81 +++++
 .../main/go/internal/environment/variable_test.go  | 358 +++++++++++++++++++++
 4 files changed, 462 insertions(+)

diff --git a/.test-infra/pipelines/go.mod b/.test-infra/pipelines/go.mod
new file mode 100644
index 00000000000..0204d037a4c
--- /dev/null
+++ b/.test-infra/pipelines/go.mod
@@ -0,0 +1,21 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This module contains all Go code for internal use by .test-infra pipelines.
+module github.com/apache/beam/test-infra/pipelines
+
+go 1.20
+
+require github.com/google/go-cmp v0.5.9 // indirect
diff --git a/.test-infra/pipelines/go.sum b/.test-infra/pipelines/go.sum
new file mode 100644
index 00000000000..62841cdb151
--- /dev/null
+++ b/.test-infra/pipelines/go.sum
@@ -0,0 +1,2 @@
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod 
h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
diff --git a/.test-infra/pipelines/src/main/go/internal/environment/variable.go 
b/.test-infra/pipelines/src/main/go/internal/environment/variable.go
new file mode 100644
index 00000000000..1e81a2e2ce8
--- /dev/null
+++ b/.test-infra/pipelines/src/main/go/internal/environment/variable.go
@@ -0,0 +1,81 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package environment provides helpers for interacting with environment 
variables.
+package environment
+
+import (
+       "fmt"
+       "os"
+       "strings"
+)
+
+// Variable defines an environment variable via a string type alias.
+// Variable's string defaultValue assigns the system environment variable key.
+type Variable string
+
+// Default a defaultValue to the system environment.
+func (v Variable) Default(value string) error {
+       if v.Missing() {
+               return os.Setenv((string)(v), value)
+       }
+       return nil
+}
+
+// Missing reports whether the system environment variable is an empty string.
+func (v Variable) Missing() bool {
+       return v.Value() == ""
+}
+
+// Key returns the system environment variable key.
+func (v Variable) Key() string {
+       return (string)(v)
+}
+
+// Value returns the system environment variable defaultValue.
+func (v Variable) Value() string {
+       return os.Getenv((string)(v))
+}
+
+// KeyValue returns a concatenated string of the system environment variable's
+// <key>=<defaultValue>.
+func (v Variable) KeyValue() string {
+       return fmt.Sprintf("%s=%s", (string)(v), v.Value())
+}
+
+// Missing reports as an error listing all Variable among vars that are
+// not assigned in the system environment.
+func Missing(vars ...Variable) error {
+       var missing []string
+       for _, v := range vars {
+               if v.Missing() {
+                       missing = append(missing, v.KeyValue())
+               }
+       }
+       if len(missing) > 0 {
+               return fmt.Errorf("variables empty but expected from 
environment: %s", strings.Join(missing, "; "))
+       }
+       return nil
+}
+
+// Map converts a slice of Variable into a map.
+// Its usage is for logging purposes.
+func Map(vars ...Variable) map[string]interface{} {
+       result := map[string]interface{}{}
+       for _, v := range vars {
+               result[(string)(v)] = v.Value()
+       }
+       return result
+}
diff --git 
a/.test-infra/pipelines/src/main/go/internal/environment/variable_test.go 
b/.test-infra/pipelines/src/main/go/internal/environment/variable_test.go
new file mode 100644
index 00000000000..6675b39ab26
--- /dev/null
+++ b/.test-infra/pipelines/src/main/go/internal/environment/variable_test.go
@@ -0,0 +1,358 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package environment
+
+import (
+       "errors"
+       "github.com/google/go-cmp/cmp"
+       "os"
+       "testing"
+)
+
+func TestMap(t *testing.T) {
+       type args struct {
+               vars   []Variable
+               values []string
+       }
+       tests := []struct {
+               name string
+               args args
+               want map[string]interface{}
+       }{
+               {
+                       name: "{}",
+                       args: args{},
+                       want: map[string]interface{}{},
+               },
+               {
+                       name: "{A=1; B=2; C=3}",
+                       args: args{
+                               vars: []Variable{
+                                       "A",
+                                       "B",
+                                       "C",
+                               },
+                               values: []string{
+                                       "1",
+                                       "2",
+                                       "3",
+                               },
+                       },
+                       want: map[string]interface{}{
+                               "A": "1",
+                               "B": "2",
+                               "C": "3",
+                       },
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       clear(tt.args.vars...)
+                       set(t, tt.args.vars, tt.args.values)
+                       got := Map(tt.args.vars...)
+                       if diff := cmp.Diff(got, tt.want); diff != "" {
+                               t.Errorf("Map() = %v, want %v, diff:\n%v", got, 
tt.want, diff)
+                       }
+               })
+       }
+}
+
+func TestMissing(t *testing.T) {
+       type args struct {
+               vars   []Variable
+               values []string
+       }
+       tests := []struct {
+               name string
+               args args
+               want error
+       }{
+               {
+                       name: "{}",
+                       args: args{},
+               },
+               {
+                       name: "{A=}",
+                       args: args{
+                               vars: []Variable{
+                                       "A",
+                               },
+                               values: []string{
+                                       "",
+                               },
+                       },
+                       want: errors.New("variables empty but expected from 
environment: A="),
+               },
+               {
+                       name: "{A=1}",
+                       args: args{
+                               vars: []Variable{
+                                       "A",
+                               },
+                               values: []string{
+                                       "1",
+                               },
+                       },
+                       want: nil,
+               },
+               {
+                       name: "{A=; B=}",
+                       args: args{
+                               vars: []Variable{
+                                       "A",
+                                       "B",
+                               },
+                               values: []string{
+                                       "",
+                                       "",
+                               },
+                       },
+                       want: errors.New("variables empty but expected from 
environment: A=; B="),
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       var got, want string
+                       clear(tt.args.vars...)
+                       set(t, tt.args.vars, tt.args.values)
+                       err := Missing(tt.args.vars...)
+                       if err != nil {
+                               got = err.Error()
+                       }
+                       if tt.want != nil {
+                               want = tt.want.Error()
+                       }
+                       if diff := cmp.Diff(got, want); diff != "" {
+                               t.Errorf("Missing() error = %v, want %v, 
diff:\n%s", err, tt.want, diff)
+                       }
+               })
+       }
+}
+
+func TestVariable_Default(t *testing.T) {
+       type args struct {
+               setValue     string
+               defaultValue string
+       }
+       tests := []struct {
+               name string
+               v    Variable
+               args args
+               want string
+       }{
+               {
+                       name: "environment variable not set",
+                       v:    "A",
+                       args: args{
+                               defaultValue: "1",
+                       },
+                       want: "1",
+               },
+               {
+                       name: "environment variable default is overridden by 
set value",
+                       v:    "A",
+                       args: args{
+                               setValue:     "2",
+                               defaultValue: "1",
+                       },
+                       want: "2",
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       clear(tt.v)
+                       if tt.args.setValue != "" {
+                               set(t, []Variable{tt.v}, 
[]string{tt.args.setValue})
+                       }
+                       if err := tt.v.Default(tt.args.defaultValue); err != 
nil {
+                               t.Fatalf("could not set default environment 
variable value during test execution: %v", err)
+                       }
+                       got := os.Getenv(tt.v.Key())
+                       if diff := cmp.Diff(got, tt.want); diff != "" {
+                               t.Errorf("Default() = %s, want %s, diff:\n%s", 
got, tt.want, diff)
+                       }
+               })
+       }
+}
+
+func TestVariable_KeyValue(t *testing.T) {
+       tests := []struct {
+               name  string
+               v     Variable
+               value string
+               want  string
+       }{
+               {
+                       name: "environment variable not set",
+                       v:    "A",
+                       want: "A=",
+               },
+               {
+                       name:  "environment variable is set",
+                       v:     "A",
+                       value: "1",
+                       want:  "A=1",
+               },
+       }
+       for _, tt := range tests {
+               clear(tt.v)
+               t.Run(tt.name, func(t *testing.T) {
+                       set(t, []Variable{tt.v}, []string{tt.value})
+                       got := tt.v.KeyValue()
+                       if diff := cmp.Diff(got, tt.want); diff != "" {
+                               t.Errorf("KeyValue() = %v, want %v, diff:\n%s", 
got, tt.want, diff)
+                       }
+               })
+       }
+}
+
+func TestVariable_Missing(t *testing.T) {
+       type args struct {
+               setValue     string
+               defaultValue string
+       }
+       tests := []struct {
+               name string
+               args args
+               v    Variable
+               want bool
+       }{
+               {
+                       name: "no default and not set",
+                       args: args{},
+                       v:    "A",
+                       want: true,
+               },
+               {
+                       name: "has default but not set",
+                       args: args{
+                               defaultValue: "1",
+                       },
+                       v:    "A",
+                       want: false,
+               },
+               {
+                       name: "no default but set",
+                       args: args{
+                               setValue: "1",
+                       },
+                       v:    "A",
+                       want: false,
+               },
+               {
+                       name: "has default and set",
+                       args: args{
+                               setValue:     "2",
+                               defaultValue: "1",
+                       },
+                       v:    "A",
+                       want: false,
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       clear(tt.v)
+                       if tt.args.defaultValue != "" {
+                               if err := tt.v.Default(tt.args.defaultValue); 
err != nil {
+                                       t.Fatalf("could not set default 
environment variable value during test execution: %v", err)
+                               }
+                       }
+                       if tt.args.setValue != "" {
+                               set(t, []Variable{tt.v}, 
[]string{tt.args.setValue})
+                       }
+                       if got := tt.v.Missing(); got != tt.want {
+                               t.Errorf("Missing() = %v, want %v", got, 
tt.want)
+                       }
+               })
+       }
+}
+
+func TestVariable_Value(t *testing.T) {
+       type args struct {
+               setValue     string
+               defaultValue string
+       }
+       tests := []struct {
+               name string
+               args args
+               v    Variable
+               want string
+       }{
+               {
+                       name: "no default and not set",
+                       args: args{},
+                       v:    "A",
+                       want: "",
+               },
+               {
+                       name: "has default but not set",
+                       args: args{
+                               defaultValue: "1",
+                       },
+                       v:    "A",
+                       want: "1",
+               },
+               {
+                       name: "no default but set",
+                       args: args{
+                               setValue: "1",
+                       },
+                       v:    "A",
+                       want: "1",
+               },
+               {
+                       name: "has default and set",
+                       args: args{
+                               setValue:     "2",
+                               defaultValue: "1",
+                       },
+                       v:    "A",
+                       want: "2",
+               },
+       }
+       for _, tt := range tests {
+               clear(tt.v)
+               if tt.args.defaultValue != "" {
+                       if err := tt.v.Default(tt.args.defaultValue); err != 
nil {
+                               t.Fatalf("could not set default environment 
variable value during test execution: %v", err)
+                       }
+               }
+               if tt.args.setValue != "" {
+                       set(t, []Variable{tt.v}, []string{tt.args.setValue})
+               }
+               t.Run(tt.name, func(t *testing.T) {
+                       if got := tt.v.Value(); got != tt.want {
+                               t.Errorf("Value() = %v, want %v", got, tt.want)
+                       }
+               })
+       }
+}
+
+func clear(vars ...Variable) {
+       for _, k := range vars {
+               _ = os.Setenv(k.Key(), "")
+       }
+}
+
+func set(t *testing.T, vars []Variable, values []string) {
+       if len(vars) != len(values) {
+               t.Fatalf("test cases should be configured with matching 
args.vars and args.values: len(tt.args.vars): %v != len(tt.args.values): %v", 
len(vars), len(values))
+       }
+       for i := range vars {
+               key := vars[i].Key()
+               value := values[i]
+               _ = os.Setenv(key, value)
+       }
+}

Reply via email to