|
| 1 | +package main |
| 2 | + |
| 3 | +import ( |
| 4 | + "bytes" |
| 5 | + "fmt" |
| 6 | + "os" |
| 7 | + "os/exec" |
| 8 | + "path/filepath" |
| 9 | + "runtime" |
| 10 | + "strings" |
| 11 | + "testing" |
| 12 | + |
| 13 | + "github.com/creativeprojects/resticprofile/config" |
| 14 | + "github.com/creativeprojects/resticprofile/term" |
| 15 | + "github.com/stretchr/testify/assert" |
| 16 | + "github.com/stretchr/testify/require" |
| 17 | +) |
| 18 | + |
| 19 | +var ( |
| 20 | + echoBinary string |
| 21 | +) |
| 22 | + |
| 23 | +func init() { |
| 24 | + // build restic mock |
| 25 | + cmd := exec.Command("go", "build", "./shell/echo") |
| 26 | + cmd.Run() |
| 27 | + if runtime.GOOS == "windows" { |
| 28 | + echoBinary = "echo.exe" |
| 29 | + } else { |
| 30 | + echoBinary = "./echo" |
| 31 | + } |
| 32 | +} |
| 33 | + |
| 34 | +// TestFromConfigFileToCommandLine loads all examples/integration_test.* configuration files |
| 35 | +// and run some commands to display all the arguments that were sent |
| 36 | +func TestFromConfigFileToCommandLine(t *testing.T) { |
| 37 | + files, err := filepath.Glob("./examples/integration_test.*") |
| 38 | + require.NoError(t, err) |
| 39 | + require.Greater(t, len(files), 0) |
| 40 | + |
| 41 | + // we can use the same files to test a glob pattern |
| 42 | + globFiles := "\"" + strings.Join(files, "\" \"") + "\"" |
| 43 | + |
| 44 | + integrationData := []struct { |
| 45 | + profileName string |
| 46 | + commandName string |
| 47 | + cmdlineArgs []string |
| 48 | + expected string |
| 49 | + expectedOnWindows string |
| 50 | + }{ |
| 51 | + { |
| 52 | + "default", |
| 53 | + "snapshots", |
| 54 | + []string{}, |
| 55 | + `"snapshots" "--password-file" "key" "--repo" "rest:http://user:password@localhost:8000/path"`, |
| 56 | + "", |
| 57 | + }, |
| 58 | + { |
| 59 | + "simple", |
| 60 | + "backup", |
| 61 | + []string{"--option"}, |
| 62 | + `"backup" "--exclude" "/**/.git" "--password-file" "key" "--repo" "rest:http://user:password@localhost:8000/path" "--option" "/source"`, |
| 63 | + "", |
| 64 | + }, |
| 65 | + { |
| 66 | + "spaces", |
| 67 | + "backup", |
| 68 | + []string{"some path"}, |
| 69 | + `"backup" "--exclude" "My Documents" "--password-file" "key" "--repo" "rest:http://user:password@localhost:8000/path" "some" "path" "/source" "dir"`, |
| 70 | + `"backup" "--exclude" "My Documents" "--password-file" "key" "--repo" "rest:http://user:password@localhost:8000/path" "some path" "/source dir"`, |
| 71 | + }, |
| 72 | + { |
| 73 | + "quotes", |
| 74 | + "backup", |
| 75 | + []string{"quo'te", "quo\"te"}, |
| 76 | + `"backup" "--exclude" "MyDocuments --exclude My\"Documents --password-file key --repo rest:http://user:password@localhost:8000/path quote" "quote /source'dir /sourcedir"`, |
| 77 | + `"backup" "--exclude" "My'Documents" "--exclude" "My\"Documents" "--password-file" "key" "--repo" "rest:http://user:password@localhost:8000/path" "quo'te" "quo\"te" "/source'dir" "/source\"dir"`, |
| 78 | + }, |
| 79 | + { |
| 80 | + "glob", |
| 81 | + "backup", |
| 82 | + []string{"examples/integration*"}, |
| 83 | + `"backup" "--exclude" ` + globFiles + ` "--password-file" "key" "--repo" "rest:http://user:password@localhost:8000/path" ` + globFiles + " " + globFiles, |
| 84 | + `"backup" "--exclude" "examples/integration*" "--password-file" "key" "--repo" "rest:http://user:password@localhost:8000/path" "examples/integration*" "examples/integration*"`, |
| 85 | + }, |
| 86 | + { |
| 87 | + "mixed", |
| 88 | + "backup", |
| 89 | + []string{"/path/with space; echo foo"}, |
| 90 | + `"backup" "--exclude" "examples/integration*" "--password-file" "key" "--repo" "rest:http://user:password@localhost:8000/path" ` + globFiles + " " + globFiles, |
| 91 | + `"backup" "--exclude" "examples/integration*" "--password-file" "key" "--repo" "rest:http://user:password@localhost:8000/path" "/path/with space; echo foo" "/Côte d'Ivoire"`, |
| 92 | + }, |
| 93 | + } |
| 94 | + |
| 95 | + // try all the config files one by one |
| 96 | + for _, configFile := range files { |
| 97 | + t.Run(configFile, func(t *testing.T) { |
| 98 | + cfg, err := config.LoadFile(configFile, "") |
| 99 | + require.NoError(t, err) |
| 100 | + require.NotNil(t, cfg) |
| 101 | + |
| 102 | + // try all the fixtures one by one (on each file) |
| 103 | + for _, fixture := range integrationData { |
| 104 | + t.Run(fixture.profileName+"/"+fixture.commandName, func(t *testing.T) { |
| 105 | + profile, err := cfg.GetProfile(fixture.profileName) |
| 106 | + require.NoError(t, err) |
| 107 | + require.NotNil(t, profile) |
| 108 | + |
| 109 | + wrapper := newResticWrapper( |
| 110 | + echoBinary, |
| 111 | + false, |
| 112 | + profile, |
| 113 | + fixture.commandName, |
| 114 | + fixture.cmdlineArgs, |
| 115 | + nil, |
| 116 | + ) |
| 117 | + buffer := &bytes.Buffer{} |
| 118 | + // setting the output via the package global setter could lead to some issues |
| 119 | + // when some tests are running in parallel. I should fix that at some point :-/ |
| 120 | + term.SetOutput(buffer) |
| 121 | + err = wrapper.runCommand(fixture.commandName) |
| 122 | + term.SetOutput(os.Stdout) |
| 123 | + |
| 124 | + // allow a fail temporarily |
| 125 | + if err != nil && err.Error() == fmt.Sprintf("%s on profile '%s': exit status 2", fixture.commandName, fixture.profileName) { |
| 126 | + t.Skip("shell failed to interpret command line") |
| 127 | + } |
| 128 | + require.NoError(t, err) |
| 129 | + |
| 130 | + expected := "[" + fixture.expected + "]" |
| 131 | + if fixture.expectedOnWindows != "" && runtime.GOOS == "windows" { |
| 132 | + expected = "[" + fixture.expectedOnWindows + "]" |
| 133 | + } |
| 134 | + assert.Equal(t, expected, strings.TrimSpace(buffer.String())) |
| 135 | + }) |
| 136 | + } |
| 137 | + }) |
| 138 | + } |
| 139 | +} |
0 commit comments