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  }