github.com/panekj/cli@v0.0.0-20230304125325-467dd2f3797e/cli/context/store/store_test.go (about) 1 package store 2 3 import ( 4 "archive/tar" 5 "archive/zip" 6 "bufio" 7 "bytes" 8 "crypto/rand" 9 "encoding/json" 10 "fmt" 11 "io" 12 "os" 13 "path" 14 "path/filepath" 15 "testing" 16 17 "github.com/docker/docker/errdefs" 18 "gotest.tools/v3/assert" 19 is "gotest.tools/v3/assert/cmp" 20 ) 21 22 type endpoint struct { 23 Foo string `json:"a_very_recognizable_field_name"` 24 } 25 26 type context struct { 27 Bar string `json:"another_very_recognizable_field_name"` 28 } 29 30 var testCfg = NewConfig(func() interface{} { return &context{} }, 31 EndpointTypeGetter("ep1", func() interface{} { return &endpoint{} }), 32 EndpointTypeGetter("ep2", func() interface{} { return &endpoint{} }), 33 ) 34 35 func TestExportImport(t *testing.T) { 36 s := New(t.TempDir(), testCfg) 37 err := s.CreateOrUpdate( 38 Metadata{ 39 Endpoints: map[string]interface{}{ 40 "ep1": endpoint{Foo: "bar"}, 41 }, 42 Metadata: context{Bar: "baz"}, 43 Name: "source", 44 }) 45 assert.NilError(t, err) 46 file1 := make([]byte, 1500) 47 rand.Read(file1) 48 file2 := make([]byte, 3700) 49 rand.Read(file2) 50 err = s.ResetEndpointTLSMaterial("source", "ep1", &EndpointTLSData{ 51 Files: map[string][]byte{ 52 "file1": file1, 53 "file2": file2, 54 }, 55 }) 56 assert.NilError(t, err) 57 r := Export("source", s) 58 defer r.Close() 59 err = Import("dest", s, r) 60 assert.NilError(t, err) 61 srcMeta, err := s.GetMetadata("source") 62 assert.NilError(t, err) 63 destMeta, err := s.GetMetadata("dest") 64 assert.NilError(t, err) 65 assert.DeepEqual(t, destMeta.Metadata, srcMeta.Metadata) 66 assert.DeepEqual(t, destMeta.Endpoints, srcMeta.Endpoints) 67 srcFileList, err := s.ListTLSFiles("source") 68 assert.NilError(t, err) 69 destFileList, err := s.ListTLSFiles("dest") 70 assert.NilError(t, err) 71 assert.Equal(t, 1, len(destFileList)) 72 assert.Equal(t, 1, len(srcFileList)) 73 assert.Equal(t, 2, len(destFileList["ep1"])) 74 assert.Equal(t, 2, len(srcFileList["ep1"])) 75 srcData1, err := s.GetTLSData("source", "ep1", "file1") 76 assert.NilError(t, err) 77 assert.DeepEqual(t, file1, srcData1) 78 srcData2, err := s.GetTLSData("source", "ep1", "file2") 79 assert.NilError(t, err) 80 assert.DeepEqual(t, file2, srcData2) 81 destData1, err := s.GetTLSData("dest", "ep1", "file1") 82 assert.NilError(t, err) 83 assert.DeepEqual(t, file1, destData1) 84 destData2, err := s.GetTLSData("dest", "ep1", "file2") 85 assert.NilError(t, err) 86 assert.DeepEqual(t, file2, destData2) 87 } 88 89 func TestRemove(t *testing.T) { 90 s := New(t.TempDir(), testCfg) 91 err := s.CreateOrUpdate( 92 Metadata{ 93 Endpoints: map[string]interface{}{ 94 "ep1": endpoint{Foo: "bar"}, 95 }, 96 Metadata: context{Bar: "baz"}, 97 Name: "source", 98 }) 99 assert.NilError(t, err) 100 assert.NilError(t, s.ResetEndpointTLSMaterial("source", "ep1", &EndpointTLSData{ 101 Files: map[string][]byte{ 102 "file1": []byte("test-data"), 103 }, 104 })) 105 assert.NilError(t, s.Remove("source")) 106 _, err = s.GetMetadata("source") 107 assert.Check(t, is.ErrorType(err, errdefs.IsNotFound)) 108 f, err := s.ListTLSFiles("source") 109 assert.NilError(t, err) 110 assert.Equal(t, 0, len(f)) 111 } 112 113 func TestListEmptyStore(t *testing.T) { 114 result, err := New(t.TempDir(), testCfg).List() 115 assert.NilError(t, err) 116 assert.Check(t, len(result) == 0) 117 } 118 119 func TestErrHasCorrectContext(t *testing.T) { 120 _, err := New(t.TempDir(), testCfg).GetMetadata("no-exists") 121 assert.ErrorContains(t, err, "no-exists") 122 assert.Check(t, is.ErrorType(err, errdefs.IsNotFound)) 123 } 124 125 func TestDetectImportContentType(t *testing.T) { 126 buf := new(bytes.Buffer) 127 r := bufio.NewReader(buf) 128 ct, err := getImportContentType(r) 129 assert.NilError(t, err) 130 assert.Assert(t, zipType != ct) 131 } 132 133 func TestImportTarInvalid(t *testing.T) { 134 testDir := t.TempDir() 135 tf := path.Join(testDir, "test.context") 136 137 f, err := os.Create(tf) 138 assert.NilError(t, err) 139 defer f.Close() 140 141 tw := tar.NewWriter(f) 142 hdr := &tar.Header{ 143 Name: "dummy-file", 144 Mode: 0o600, 145 Size: int64(len("hello world")), 146 } 147 err = tw.WriteHeader(hdr) 148 assert.NilError(t, err) 149 _, err = tw.Write([]byte("hello world")) 150 assert.NilError(t, err) 151 err = tw.Close() 152 assert.NilError(t, err) 153 154 source, err := os.Open(tf) 155 assert.NilError(t, err) 156 defer source.Close() 157 var r io.Reader = source 158 s := New(testDir, testCfg) 159 err = Import("tarInvalid", s, r) 160 assert.ErrorContains(t, err, "unexpected context file") 161 } 162 163 func TestImportZip(t *testing.T) { 164 testDir := t.TempDir() 165 zf := path.Join(testDir, "test.zip") 166 167 f, err := os.Create(zf) 168 assert.NilError(t, err) 169 defer f.Close() 170 w := zip.NewWriter(f) 171 172 meta, err := json.Marshal(Metadata{ 173 Endpoints: map[string]interface{}{ 174 "ep1": endpoint{Foo: "bar"}, 175 }, 176 Metadata: context{Bar: "baz"}, 177 Name: "source", 178 }) 179 assert.NilError(t, err) 180 files := []struct { 181 Name, Body string 182 }{ 183 {"meta.json", string(meta)}, 184 {path.Join("tls", "docker", "ca.pem"), string([]byte("ca.pem"))}, 185 } 186 187 for _, file := range files { 188 f, err := w.Create(file.Name) 189 assert.NilError(t, err) 190 _, err = f.Write([]byte(file.Body)) 191 assert.NilError(t, err) 192 } 193 194 err = w.Close() 195 assert.NilError(t, err) 196 197 source, err := os.Open(zf) 198 assert.NilError(t, err) 199 ct, err := getImportContentType(bufio.NewReader(source)) 200 assert.NilError(t, err) 201 assert.Equal(t, zipType, ct) 202 203 source, _ = os.Open(zf) 204 defer source.Close() 205 var r io.Reader = source 206 s := New(testDir, testCfg) 207 err = Import("zipTest", s, r) 208 assert.NilError(t, err) 209 } 210 211 func TestImportZipInvalid(t *testing.T) { 212 testDir := t.TempDir() 213 zf := path.Join(testDir, "test.zip") 214 215 f, err := os.Create(zf) 216 assert.NilError(t, err) 217 defer f.Close() 218 w := zip.NewWriter(f) 219 220 df, err := w.Create("dummy-file") 221 assert.NilError(t, err) 222 _, err = df.Write([]byte("hello world")) 223 assert.NilError(t, err) 224 err = w.Close() 225 assert.NilError(t, err) 226 227 source, err := os.Open(zf) 228 assert.NilError(t, err) 229 defer source.Close() 230 var r io.Reader = source 231 s := New(testDir, testCfg) 232 err = Import("zipInvalid", s, r) 233 assert.ErrorContains(t, err, "unexpected context file") 234 } 235 236 func TestCorruptMetadata(t *testing.T) { 237 tempDir := t.TempDir() 238 s := New(tempDir, testCfg) 239 err := s.CreateOrUpdate( 240 Metadata{ 241 Endpoints: map[string]interface{}{ 242 "ep1": endpoint{Foo: "bar"}, 243 }, 244 Metadata: context{Bar: "baz"}, 245 Name: "source", 246 }) 247 assert.NilError(t, err) 248 249 // Simulate the meta.json file getting corrupted 250 // by some external process. 251 contextDir := s.meta.contextDir(contextdirOf("source")) 252 contextFile := filepath.Join(contextDir, metaFile) 253 err = os.WriteFile(contextFile, nil, 0o600) 254 assert.NilError(t, err) 255 256 // Assert that the error message gives the user some clue where to look. 257 _, err = s.GetMetadata("source") 258 assert.ErrorContains(t, err, fmt.Sprintf("parsing %s: unexpected end of JSON input", contextFile)) 259 }