// Copyright 2024 Matthew Rich . All rights reserved. package client import ( "github.com/stretchr/testify/assert" "os" "os/user" "os/exec" "testing" "decl/internal/tempdir" "log" "decl/internal/folio" _ "decl/internal/fan" "decl/internal/codec" "decl/internal/data" "decl/internal/ext" "context" "fmt" "log/slog" "archive/tar" "compress/gzip" "bytes" "io" ) var programLevel = new(slog.LevelVar) var TempDir tempdir.Path = "jx_client" var ProcessTestUserName string var ProcessTestGroupName string func TestMain(m *testing.M) { LoggerConfig() err := TempDir.Create() if err != nil || TempDir == "" { log.Fatal(err) } ProcessTestUserName, ProcessTestGroupName = ProcessUserName() rc := m.Run() TempDir.Remove() os.Exit(rc) } func LoggerConfig() { logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel})) slog.SetDefault(logger) programLevel.Set(slog.LevelDebug) } func ProcessUserName() (string, string) { processUser, userErr := user.Current() if userErr != nil { panic(userErr) } processGroup, groupErr := user.LookupGroupId(processUser.Gid) if groupErr != nil { panic(groupErr) } return processUser.Username, processGroup.Name } func ExitError(e error) string { if e != nil { switch v := e.(type) { case *exec.ExitError: return string(v.Stderr) default: return e.Error() } } return "" } // jx import ... func TestClientImport(t *testing.T) { c := NewClient() assert.NotNil(t, c) importDocuments := []string{ "file://../../examples/file.jx.yaml", "file://../../examples/user.jx.yaml", } assert.Nil(t, c.Import(importDocuments)) for index, uri := range importDocuments { u := folio.URI(uri) r, readerErr := u.ContentReaderStream() assert.Nil(t, readerErr) assert.NotNil(t, r) doc := folio.DocumentRegistry.NewDocument(folio.URI(uri)) assert.Nil(t, doc.LoadReader(r, codec.FormatYaml)) imported := c.Documents[index] assert.NotNil(t, imported) assert.Equal(t, uri, imported.GetURI()) assert.Equal(t, doc.Len(), imported.Len()) } } // jx import --resource func TestClientImportResource(t *testing.T) { ctx := context.Background() c := NewClient() assert.NotNil(t, c) importResources := []string{ "file://../../COPYRIGHT", } for _, uri := range importResources { assert.Nil(t, c.ImportResource(ctx, uri)) } imported := c.Documents[0] assert.NotNil(t, imported) for _, uri := range importResources { assert.NotNil(t, imported.(*folio.Document).GetResource(uri)) } } func TestClientEmit(t *testing.T) { //ctx := context.Background() c := NewClient() assert.NotNil(t, c) importDocuments := []string{ "file://../../examples/file.jx.yaml", "file://../../examples/user.jx.yaml", } assert.Nil(t, c.Import(importDocuments)) targetFile := TempDir.FilePath("jx_emit_output.jx.yaml") targetFileURI := fmt.Sprintf("file://%s", targetFile) assert.Nil(t, c.SetOutput(targetFile)) assert.Nil(t, c.Emit()) assert.FileExists(t, targetFile) u := folio.URI(targetFileURI) r, readerErr := u.ContentReaderStream() assert.Nil(t, readerErr) assert.NotNil(t, r) extractor, err := folio.DocumentRegistry.ConverterTypes.New(targetFileURI) assert.Nil(t, err) assert.NotNil(t, extractor) targetResource, resErr := u.NewResource(nil) assert.Nil(t, resErr) docs, exErr := extractor.(data.ManyExtractor).ExtractMany(targetResource, nil) assert.Nil(t, exErr) assert.Equal(t, 2, len(docs)) assert.Equal(t, 1, docs[1].Len()) } func BenchmarkClientSystemConfigurations(b *testing.B) { assert.Nil(b, TempDir.Mkdir("benchconfig", 0700)) ConfDir := tempdir.Path(TempDir.FilePath("benchconfig")) assert.Nil(b, ConfDir.CreateFile("cfg.jx.yaml", ` configurations: - name: files values: prefix: /usr `)) configDirURI := fmt.Sprintf("file://%s", ConfDir) programLevel.Set(slog.LevelError) b.Run("systemconfiguration", func(b *testing.B) { for i := 0; i < b.N; i++ { c := NewClient() _ = c.SystemConfiguration(configDirURI) } }) programLevel.Set(slog.LevelDebug) } func TestClientSystemConfiguration(t *testing.T) { c := NewClient() assert.NotNil(t, c) assert.Nil(t, TempDir.Mkdir("config", 0700)) ConfDir := tempdir.Path(TempDir.FilePath("config")) assert.Nil(t, ConfDir.CreateFile("cfg.jx.yaml", ` configurations: - name: files values: prefix: /usr `)) //configDirURI := fmt.Sprintf("file://%s", ConfDir) configErr := c.SystemConfiguration(string(ConfDir)) assert.Nil(t, configErr) assert.NotNil(t, c.Config) slog.Info("TestClientSystemConfiguration", "config", c.Config) cfg := c.Config.GetConfig("files") assert.NotNil(t, cfg) value, valueErr := cfg.GetValue("prefix") assert.Nil(t, valueErr) assert.Equal(t, "/usr", value.(string)) } func TestClientApply(t *testing.T) { ctx := context.Background() c := NewClient() assert.NotNil(t, c) assert.Nil(t, TempDir.Mkdir("apply", 0700)) ApplyDir := tempdir.Path(TempDir.FilePath("apply")) DocSource := ApplyDir.FilePath("res.jx.yaml") TestFile := ApplyDir.FilePath("testfile.txt") assert.Nil(t, ApplyDir.CreateFile("res.jx.yaml", fmt.Sprintf(` resources: - type: file transition: create attributes: path: %s content: | a test string owner: %s group: %s mode: 0644 `, TestFile, ProcessTestUserName, ProcessTestGroupName))) assert.Nil(t, c.Import([]string{DocSource})) assert.Nil(t, c.LoadDocumentImports()) assert.Nil(t, c.Apply(ctx, false)) assert.FileExists(t, TestFile) assert.Nil(t, c.Apply(ctx, true)) assert.NoFileExists(t, TestFile) } var tarArchiveBuffer bytes.Buffer func TarArchive(compress bool) (err error) { var fileWriter io.WriteCloser if compress { gz := gzip.NewWriter(&tarArchiveBuffer) defer gz.Close() fileWriter = gz } else { fileWriter = ext.WriteNopCloser(&tarArchiveBuffer) } tw := tar.NewWriter(fileWriter) fileContent := "test file content" if err = tw.WriteHeader(&tar.Header{ Name: "testfile", Mode: 0600, Size: int64(len(fileContent)), }); err == nil { _, err = tw.Write([]byte(fileContent)) } tw.Close() return } func TestClientConverters(t *testing.T) { for _, v := range []struct { Expected data.TypeName; URI string } { { Expected: data.TypeName("dir"), URI: "file:///tmp" }, { Expected: data.TypeName("http"), URI: "https://localhost/test" }, { Expected: data.TypeName("iptable"), URI: "iptable://filter/INPUT" }, { Expected: data.TypeName("jx"), URI: "file:///tmp/test.jx.yaml" }, { Expected: data.TypeName("package"), URI: "package://" }, { Expected: data.TypeName("container"), URI: "container://" }, { Expected: data.TypeName("user"), URI: "user://" }, { Expected: data.TypeName("group"), URI: "group://" }, { Expected: data.TypeName("tar"), URI: "tar://" }, { Expected: data.TypeName("tar"), URI: "file:///tmp/foo.tar" }, { Expected: data.TypeName("tar"), URI: "file:///tmp/foo.tar.gz" }, { Expected: data.TypeName("tar"), URI: "file:///tmp/foo.tgz" }, } { c, e := folio.DocumentRegistry.ConverterTypes.New(v.URI) assert.Nil(t, e) assert.NotNil(t, c) assert.Equal(t, v.Expected, c.Type()) } } func TestClientImportTar(t *testing.T) { c := NewClient() assert.NotNil(t, c) e := TarArchive(true) assert.Nil(t, e) assert.Greater(t, tarArchiveBuffer.Len(), 0) path, err := TempDir.CreateFileFromReader("test.tar.gz", &tarArchiveBuffer) assert.Nil(t, err) uri := fmt.Sprintf("file://%s", path) d := folio.NewDeclaration() assert.Nil(t, d.NewResource(&uri)) docs, importErr := c.ImportSource(uri) assert.Nil(t, importErr) assert.Greater(t, len(docs), 0) }