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  }