github.com/SaurabhDubey-Groww/go-cloud@v0.0.0-20221124105541-b26c29285fd8/runtimevar/gcpruntimeconfig/gcpruntimeconfig_test.go (about) 1 // Copyright 2018 The Go Cloud Development Kit 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 // 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 gcpruntimeconfig 16 17 import ( 18 "context" 19 "errors" 20 "fmt" 21 "testing" 22 23 "gocloud.dev/internal/testing/setup" 24 "gocloud.dev/runtimevar" 25 "gocloud.dev/runtimevar/driver" 26 "gocloud.dev/runtimevar/drivertest" 27 pb "google.golang.org/genproto/googleapis/cloud/runtimeconfig/v1beta1" 28 "google.golang.org/grpc/codes" 29 "google.golang.org/grpc/status" 30 ) 31 32 // This constant records the project used for the last --record. 33 // If you want to use --record mode, 34 // 1. Update this constant to your GCP project ID. 35 // 2. Ensure that the "Runtime Configuration API" is enabled for your project. 36 // TODO(issue #300): Use Terraform to get this. 37 const projectID = "go-cloud-test-216917" 38 39 const ( 40 // configID is the runtimeconfig high-level config that variables sit under. 41 configID = "go_cloud_runtimeconfigurator_test" 42 ) 43 44 func configPath() string { 45 return fmt.Sprintf("projects/%s/configs/%s", projectID, configID) 46 } 47 48 func variableKey(variableName string) string { 49 return VariableKey(projectID, configID, variableName) 50 } 51 52 type harness struct { 53 client pb.RuntimeConfigManagerClient 54 closer func() 55 } 56 57 func newHarness(t *testing.T) (drivertest.Harness, error) { 58 ctx := context.Background() 59 conn, done := setup.NewGCPgRPCConn(ctx, t, endPoint, "runtimevar") 60 client := pb.NewRuntimeConfigManagerClient(conn) 61 // Ignore errors if the config already exists. 62 _, _ = client.CreateConfig(ctx, &pb.CreateConfigRequest{ 63 Parent: "projects/" + projectID, 64 Config: &pb.RuntimeConfig{ 65 Name: configPath(), 66 Description: t.Name(), 67 }, 68 }) 69 return &harness{ 70 client: client, 71 closer: func() { 72 _, _ = client.DeleteConfig(ctx, &pb.DeleteConfigRequest{Name: configPath()}) 73 done() 74 }, 75 }, nil 76 } 77 78 func (h *harness) MakeWatcher(ctx context.Context, name string, decoder *runtimevar.Decoder) (driver.Watcher, error) { 79 return newWatcher(h.client, variableKey(name), decoder, nil) 80 } 81 82 func (h *harness) CreateVariable(ctx context.Context, name string, val []byte) error { 83 _, err := h.client.CreateVariable(ctx, &pb.CreateVariableRequest{ 84 Parent: configPath(), 85 Variable: &pb.Variable{ 86 Name: variableKey(name), 87 Contents: &pb.Variable_Value{Value: val}, 88 }, 89 }) 90 return err 91 } 92 93 func (h *harness) UpdateVariable(ctx context.Context, name string, val []byte) error { 94 _, err := h.client.UpdateVariable(ctx, &pb.UpdateVariableRequest{ 95 Name: variableKey(name), 96 Variable: &pb.Variable{ 97 Contents: &pb.Variable_Value{Value: val}, 98 }, 99 }) 100 return err 101 } 102 103 func (h *harness) DeleteVariable(ctx context.Context, name string) error { 104 _, err := h.client.DeleteVariable(ctx, &pb.DeleteVariableRequest{Name: variableKey(name)}) 105 return err 106 } 107 108 func (h *harness) Close() { 109 h.closer() 110 } 111 112 func (h *harness) Mutable() bool { return true } 113 114 func TestConformance(t *testing.T) { 115 drivertest.RunConformanceTests(t, newHarness, []drivertest.AsTest{verifyAs{}}) 116 } 117 118 type verifyAs struct{} 119 120 func (verifyAs) Name() string { 121 return "verify As" 122 } 123 124 func (verifyAs) SnapshotCheck(s *runtimevar.Snapshot) error { 125 var v *pb.Variable 126 if !s.As(&v) { 127 return errors.New("Snapshot.As failed") 128 } 129 return nil 130 } 131 132 func (verifyAs) ErrorCheck(v *runtimevar.Variable, err error) error { 133 var s *status.Status 134 if !v.ErrorAs(err, &s) { 135 return errors.New("runtimevar.ErrorAs failed") 136 } 137 return nil 138 } 139 140 // Runtimeconfigurator-specific tests. 141 142 func TestEquivalentError(t *testing.T) { 143 tests := []struct { 144 Err1, Err2 error 145 Want bool 146 }{ 147 {Err1: errors.New("not grpc"), Err2: errors.New("not grpc"), Want: true}, 148 {Err1: errors.New("not grpc"), Err2: errors.New("not grpc but different")}, 149 {Err1: errors.New("not grpc"), Err2: status.Errorf(codes.Internal, "fail")}, 150 {Err1: status.Errorf(codes.Internal, "fail"), Err2: status.Errorf(codes.InvalidArgument, "fail")}, 151 {Err1: status.Errorf(codes.Internal, "fail"), Err2: status.Errorf(codes.Internal, "fail"), Want: true}, 152 } 153 154 for _, test := range tests { 155 got := equivalentError(test.Err1, test.Err2) 156 if got != test.Want { 157 t.Errorf("%v vs %v: got %v want %v", test.Err1, test.Err2, got, test.Want) 158 } 159 } 160 } 161 162 func TestNoConnectionError(t *testing.T) { 163 ctx := context.Background() 164 creds, err := setup.FakeGCPCredentials(ctx) 165 if err != nil { 166 t.Fatal(err) 167 } 168 169 // Connect to the Runtime Configurator service. 170 client, cleanup, err := Dial(ctx, creds.TokenSource) 171 if err != nil { 172 t.Fatal(err) 173 } 174 defer cleanup() 175 176 variableKey := VariableKey("gcp-project-id", "cfg-name", "cfg-variable-name") 177 v, err := OpenVariable(client, variableKey, nil, nil) 178 if err != nil { 179 t.Fatal(err) 180 } 181 defer v.Close() 182 _, err = v.Watch(context.Background()) 183 if err == nil { 184 t.Error("got nil want error") 185 } 186 } 187 188 func TestOpenVariable(t *testing.T) { 189 cleanup := setup.FakeGCPDefaultCredentials(t) 190 defer cleanup() 191 192 tests := []struct { 193 URL string 194 WantErr bool 195 }{ 196 // OK. 197 {"gcpruntimeconfig://projects/myproject/configs/mycfg/variables/myvar", false}, 198 // OK, hierarchical key name. 199 {"gcpruntimeconfig://projects/myproject/configs/mycfg/variables/myvar1/myvar2", false}, 200 // OK, setting decoder. 201 {"gcpruntimeconfig://projects/myproject/configs/mycfg/variables/myvar?decoder=string", false}, 202 // Missing projects prefix. 203 {"gcpruntimeconfig://project/myproject/configs/mycfg/variables/myvar", true}, 204 // Missing project. 205 {"gcpruntimeconfig://projects//configs/mycfg/variables/myvar", true}, 206 // Missing configs. 207 {"gcpruntimeconfig://projects/myproject/mycfg/variables/myvar", true}, 208 // Missing configID. 209 {"gcpruntimeconfig://projects/myproject/configs//variables/myvar", true}, 210 // Missing variables. 211 {"gcpruntimeconfig://projects/myproject/configs/mycfg//myvar", true}, 212 // Missing variable name. 213 {"gcpruntimeconfig://projects/myproject/configs/mycfg/variables/", true}, 214 // Invalid decoder. 215 {"gcpruntimeconfig://myproject/mycfg/myvar?decoder=notadecoder", true}, 216 // Invalid param. 217 {"gcpruntimeconfig://myproject/mycfg/myvar?param=value", true}, 218 // OK, setting wait. 219 {"gcpruntimeconfig://projects/myproject/configs/mycfg/variables/myvar?wait=1m", false}, 220 // Invalid wait. 221 {"gcpruntimeconfig://projects/myproject/configs/mycfg/variables/myvar?wait=xx", true}, 222 } 223 224 ctx := context.Background() 225 for _, test := range tests { 226 v, err := runtimevar.OpenVariable(ctx, test.URL) 227 if v != nil { 228 defer v.Close() 229 } 230 if (err != nil) != test.WantErr { 231 t.Errorf("%s: got error %v, want error %v", test.URL, err, test.WantErr) 232 } 233 } 234 }