github.com/khulnasoft/cli@v0.0.0-20240402070845-01bcad7beefa/cli/context/store/store_test.go (about)

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