github.com/thiagoyeds/go-cloud@v0.26.0/runtimevar/blobvar/blobvar_test.go (about) 1 // Copyright 2019 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 blobvar 16 17 import ( 18 "context" 19 "errors" 20 "io/ioutil" 21 "net/url" 22 "os" 23 "path" 24 "path/filepath" 25 "strings" 26 "testing" 27 28 "github.com/google/go-cmp/cmp" 29 "gocloud.dev/blob" 30 "gocloud.dev/blob/fileblob" 31 "gocloud.dev/runtimevar" 32 "gocloud.dev/runtimevar/driver" 33 "gocloud.dev/runtimevar/drivertest" 34 ) 35 36 type harness struct { 37 dir string 38 bucket *blob.Bucket 39 } 40 41 func newHarness(t *testing.T) (drivertest.Harness, error) { 42 dir := path.Join(os.TempDir(), "go-cloud-blobvar") 43 if err := os.MkdirAll(dir, os.ModePerm); err != nil { 44 return nil, err 45 } 46 b, err := fileblob.OpenBucket(dir, nil) 47 if err != nil { 48 return nil, err 49 } 50 return &harness{dir: dir, bucket: b}, nil 51 } 52 53 func (h *harness) MakeWatcher(ctx context.Context, name string, decoder *runtimevar.Decoder) (driver.Watcher, error) { 54 return newWatcher(h.bucket, name, decoder, nil, nil), nil 55 } 56 57 func (h *harness) CreateVariable(ctx context.Context, name string, val []byte) error { 58 return h.bucket.WriteAll(ctx, name, val, nil) 59 } 60 61 func (h *harness) UpdateVariable(ctx context.Context, name string, val []byte) error { 62 return h.bucket.WriteAll(ctx, name, val, nil) 63 } 64 65 func (h *harness) DeleteVariable(ctx context.Context, name string) error { 66 return h.bucket.Delete(ctx, name) 67 } 68 69 func (h *harness) Close() { 70 h.bucket.Close() 71 _ = os.RemoveAll(h.dir) 72 } 73 74 func (h *harness) Mutable() bool { return true } 75 76 func TestConformance(t *testing.T) { 77 drivertest.RunConformanceTests(t, newHarness, []drivertest.AsTest{verifyAs{}}) 78 } 79 80 type verifyAs struct{} 81 82 func (verifyAs) Name() string { 83 return "verify As" 84 } 85 86 func (verifyAs) SnapshotCheck(s *runtimevar.Snapshot) error { 87 return nil 88 } 89 90 func (verifyAs) ErrorCheck(v *runtimevar.Variable, err error) error { 91 var perr *os.PathError 92 if !v.ErrorAs(err, &perr) { 93 return errors.New("runtimevar.ErrorAs failed with *os.PathError") 94 } 95 return nil 96 } 97 98 func TestOpenVariable(t *testing.T) { 99 dir, err := ioutil.TempDir("", "gcdk-blob-var-example") 100 if err != nil { 101 t.Fatal(err) 102 } 103 if err := ioutil.WriteFile(filepath.Join(dir, "myvar.json"), []byte(`{"Foo": "Bar"}`), 0666); err != nil { 104 t.Fatal(err) 105 } 106 if err := ioutil.WriteFile(filepath.Join(dir, "myvar.txt"), []byte("hello world!"), 0666); err != nil { 107 t.Fatal(err) 108 } 109 defer os.RemoveAll(dir) 110 111 // Convert dir to a URL path, adding a leading "/" if needed on Windows 112 // (on Unix, dirpath already has a leading "/"). 113 dirpath := filepath.ToSlash(dir) 114 if os.PathSeparator != '/' && !strings.HasPrefix(dirpath, "/") { 115 dirpath = "/" + dirpath 116 } 117 bucketURL := "file://" + dirpath 118 119 tests := []struct { 120 BucketURL string 121 URL string 122 WantErr bool 123 WantWatchErr bool 124 Want interface{} 125 }{ 126 // myvar does not exist. 127 {"mem://", "blob://myvar", false, true, nil}, 128 // badscheme does not exist. 129 {"badscheme://", "blob://myvar", true, false, nil}, 130 // directory dirnotfound does not exist, so Bucket creation fails. 131 {"file:///dirnotfound", "blob://myvar.txt", true, false, nil}, 132 // filenotfound does not exist so Watch returns an error. 133 {bucketURL, "blob://filenotfound", false, true, nil}, 134 // Missing bucket env variable. 135 {"", "blob://myvar.txt", true, false, nil}, 136 // Invalid decoder. 137 {bucketURL, "blob://myvar.txt?decoder=notadecoder", true, false, nil}, 138 // Invalid arg. 139 {bucketURL, "blob://myvar.txt?param=value", true, false, nil}, 140 // Working example with default decoder. 141 {bucketURL, "blob://myvar.txt", false, false, []byte("hello world!")}, 142 // Working example with string decoder. 143 {bucketURL, "blob://myvar.txt?decoder=string", false, false, "hello world!"}, 144 // Working example with JSON decoder. 145 {bucketURL, "blob://myvar.json?decoder=jsonmap", false, false, &map[string]interface{}{"Foo": "Bar"}}, 146 } 147 148 ctx := context.Background() 149 for _, test := range tests { 150 t.Run(test.BucketURL, func(t *testing.T) { 151 os.Setenv("BLOBVAR_BUCKET_URL", test.BucketURL) 152 153 opener := &defaultOpener{} 154 defer func() { 155 if opener.opener != nil && opener.opener.Bucket != nil { 156 opener.opener.Bucket.Close() 157 } 158 }() 159 u, err := url.Parse(test.URL) 160 if err != nil { 161 t.Error(err) 162 } 163 v, err := opener.OpenVariableURL(ctx, u) 164 if v != nil { 165 defer v.Close() 166 } 167 if (err != nil) != test.WantErr { 168 t.Errorf("BucketURL %s URL %s: got error %v, want error %v", test.BucketURL, test.URL, err, test.WantErr) 169 } 170 if err != nil { 171 return 172 } 173 defer v.Close() 174 snapshot, err := v.Watch(ctx) 175 if (err != nil) != test.WantWatchErr { 176 t.Errorf("BucketURL %s URL %s: got Watch error %v, want error %v", test.BucketURL, test.URL, err, test.WantWatchErr) 177 } 178 if err != nil { 179 return 180 } 181 if !cmp.Equal(snapshot.Value, test.Want) { 182 t.Errorf("BucketURL %s URL %s: got snapshot value\n%v\n want\n%v", test.BucketURL, test.URL, snapshot.Value, test.Want) 183 } 184 }) 185 } 186 }