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  }