vitess.io/vitess@v0.16.2/go/vt/topo/test/file.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 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 17 package test 18 19 import ( 20 "context" 21 "reflect" 22 "strings" 23 "testing" 24 25 "vitess.io/vitess/go/vt/topo" 26 ) 27 28 // checkFile tests the file part of the Conn API. 29 func checkFile(t *testing.T, ts *topo.Server) { 30 ctx := context.Background() 31 32 // global cell 33 t.Logf("=== checkFileInCell global") 34 conn, err := ts.ConnForCell(ctx, topo.GlobalCell) 35 if err != nil { 36 t.Fatalf("ConnForCell(global) failed: %v", err) 37 } 38 checkFileInCell(t, conn, true /*hasCells*/) 39 40 // local cell 41 t.Logf("=== checkFileInCell global") 42 conn, err = ts.ConnForCell(ctx, LocalCellName) 43 if err != nil { 44 t.Fatalf("ConnForCell(test) failed: %v", err) 45 } 46 checkFileInCell(t, conn, false /*hasCells*/) 47 } 48 49 func checkFileInCell(t *testing.T, conn topo.Conn, hasCells bool) { 50 ctx := context.Background() 51 52 // ListDir root: nothing. 53 var expected []topo.DirEntry 54 if hasCells { 55 expected = append(expected, topo.DirEntry{ 56 Name: "cells", 57 Type: topo.TypeDirectory, 58 }) 59 } 60 checkListDir(ctx, t, conn, "/", expected) 61 62 // Get with no file -> ErrNoNode. 63 _, _, err := conn.Get(ctx, "/myfile") 64 if !topo.IsErrType(err, topo.NoNode) { 65 t.Errorf("Get(non-existent) didn't return ErrNoNode but: %v", err) 66 } 67 68 // Create a file. 69 version, err := conn.Create(ctx, "/myfile", []byte{'a'}) 70 if err != nil { 71 t.Fatalf("Create('/myfile') failed: %v", err) 72 } 73 74 // See it in the listing now. 75 expected = append(expected, topo.DirEntry{ 76 Name: "myfile", 77 Type: topo.TypeFile, 78 }) 79 checkListDir(ctx, t, conn, "/", expected) 80 81 // Get should work, get the right contents and version. 82 contents, getVersion, err := conn.Get(ctx, "/myfile") 83 if err != nil { 84 t.Errorf("Get('/myfile') returned an error: %v", err) 85 } else { 86 if len(contents) != 1 || contents[0] != 'a' { 87 t.Errorf("Get('/myfile') returned bad content: %v", contents) 88 } 89 if !reflect.DeepEqual(getVersion, version) { 90 t.Errorf("Get('/myfile') returned bad version: got %v expected %v", getVersion, version) 91 } 92 } 93 94 // Update it, make sure version changes. 95 newVersion, err := conn.Update(ctx, "/myfile", []byte{'b'}, version) 96 if err != nil { 97 t.Fatalf("Update('/myfile') failed: %v", err) 98 } 99 if reflect.DeepEqual(version, newVersion) { 100 t.Errorf("Version didn't change, stayed %v", newVersion) 101 } 102 103 // Get should work, get the right contents and version. 104 contents, getVersion, err = conn.Get(ctx, "/myfile") 105 if err != nil { 106 t.Errorf("Get('/myfile') returned an error: %v", err) 107 } else { 108 if len(contents) != 1 || contents[0] != 'b' { 109 t.Errorf("Get('/myfile') returned bad content: %v", contents) 110 } 111 if !reflect.DeepEqual(getVersion, newVersion) { 112 t.Errorf("Get('/myfile') returned bad version: got %v expected %v", getVersion, newVersion) 113 } 114 } 115 116 // Try to update again with wrong version, should fail. 117 if _, err = conn.Update(ctx, "/myfile", []byte{'b'}, version); !topo.IsErrType(err, topo.BadVersion) { 118 t.Errorf("Update(bad version) didn't return ErrBadVersion but: %v", err) 119 } 120 121 // Try to update again with nil version, should work. 122 newVersion, err = conn.Update(ctx, "/myfile", []byte{'c'}, nil) 123 if err != nil { 124 t.Errorf("Update(nil version) should have worked but got: %v", err) 125 } 126 127 // Get should work, get the right contents and version. 128 contents, getVersion, err = conn.Get(ctx, "/myfile") 129 if err != nil { 130 t.Errorf("Get('/myfile') returned an error: %v", err) 131 } else { 132 if len(contents) != 1 || contents[0] != 'c' { 133 t.Errorf("Get('/myfile') returned bad content: %v", contents) 134 } 135 if !reflect.DeepEqual(getVersion, newVersion) { 136 t.Errorf("Get('/myfile') returned bad version: got %v expected %v", getVersion, newVersion) 137 } 138 } 139 140 // Try to update again with empty content, should work. 141 newVersion, err = conn.Update(ctx, "/myfile", nil, newVersion) 142 if err != nil { 143 t.Fatalf("Update(empty content) should have worked but got: %v", err) 144 } 145 contents, getVersion, err = conn.Get(ctx, "/myfile") 146 if err != nil || len(contents) != 0 || !reflect.DeepEqual(getVersion, newVersion) { 147 t.Errorf("Get('/myfile') expecting empty content got bad result: %v %v %v", contents, getVersion, err) 148 } 149 150 // Try to delete with wrong version, should fail. 151 if err = conn.Delete(ctx, "/myfile", version); !topo.IsErrType(err, topo.BadVersion) { 152 t.Errorf("Delete('/myfile', wrong version) returned bad error: %v", err) 153 } 154 155 // Now delete it. 156 if err = conn.Delete(ctx, "/myfile", newVersion); err != nil { 157 t.Fatalf("Delete('/myfile') failed: %v", err) 158 } 159 160 // ListDir root: nothing. 161 expected = expected[:len(expected)-1] 162 checkListDir(ctx, t, conn, "/", expected) 163 164 // Try to delete again, should fail. 165 if err = conn.Delete(ctx, "/myfile", newVersion); !topo.IsErrType(err, topo.NoNode) { 166 t.Errorf("Delete(already gone) returned bad error: %v", err) 167 } 168 169 // Create again, with unconditional update. 170 version, err = conn.Update(ctx, "/myfile", []byte{'d'}, nil) 171 if err != nil { 172 t.Fatalf("Update('/myfile', nil) failed: %v", err) 173 } 174 175 // Check contents. 176 contents, getVersion, err = conn.Get(ctx, "/myfile") 177 if err != nil { 178 t.Errorf("Get('/myfile') returned an error: %v", err) 179 } else { 180 if len(contents) != 1 || contents[0] != 'd' { 181 t.Errorf("Get('/myfile') returned bad content: %v", contents) 182 } 183 if !reflect.DeepEqual(getVersion, version) { 184 t.Errorf("Get('/myfile') returned bad version: got %v expected %v", getVersion, version) 185 } 186 } 187 188 // See it in the listing now. 189 expected = append(expected, topo.DirEntry{ 190 Name: "myfile", 191 Type: topo.TypeFile, 192 }) 193 checkListDir(ctx, t, conn, "/", expected) 194 195 // Unconditional delete. 196 if err = conn.Delete(ctx, "/myfile", nil); err != nil { 197 t.Errorf("Delete('/myfile', nil) failed: %v", err) 198 } 199 200 // ListDir root: nothing. 201 expected = expected[:len(expected)-1] 202 checkListDir(ctx, t, conn, "/", expected) 203 } 204 205 // checkList tests the file part of the Conn API. 206 func checkList(t *testing.T, ts *topo.Server) { 207 ctx := context.Background() 208 // global cell 209 conn, err := ts.ConnForCell(ctx, LocalCellName) 210 if err != nil { 211 t.Fatalf("ConnForCell(LocalCellName) failed: %v", err) 212 } 213 214 _, err = conn.Create(ctx, "/some/arbitrary/file", []byte{'a'}) 215 if err != nil { 216 t.Fatalf("Create('/myfile') failed: %v", err) 217 } 218 219 _, err = conn.List(ctx, "/") 220 if topo.IsErrType(err, topo.NoImplementation) { 221 // If this is not supported, skip the test 222 t.Skipf("%T does not support List()", conn) 223 return 224 } 225 if err != nil { 226 t.Fatalf("List(test) failed: %v", err) 227 } 228 229 _, err = conn.Create(ctx, "/toplevel/nested/myfile", []byte{'a'}) 230 if err != nil { 231 t.Fatalf("Create('/myfile') failed: %v", err) 232 } 233 234 for _, path := range []string{"/top", "/toplevel", "/toplevel/", "/toplevel/nes", "/toplevel/nested/myfile"} { 235 entries, err := conn.List(ctx, path) 236 if err != nil { 237 t.Fatalf("List failed(path: %q): %v", path, err) 238 } 239 240 if len(entries) != 1 { 241 t.Fatalf("List(test) returned incorrect number of elements for path %q. Expected 1, got %d: %v", path, len(entries), entries) 242 } 243 244 if !strings.HasSuffix(string(entries[0].Key), "/toplevel/nested/myfile") { 245 t.Fatalf("found entry doesn't end with /toplevel/nested/myfile for path %q: %s", path, string(entries[0].Key)) 246 } 247 248 if string(entries[0].Value) != "a" { 249 t.Fatalf("found entry doesn't have value \"a\" for path %q: %s", path, string(entries[0].Value)) 250 } 251 } 252 }