restictray/restic/wrapper_test.go

218 lines
5.1 KiB
Go

package restic
import (
"bytes"
"encoding/json"
"fmt"
"github.com/rs/zerolog/log"
"github.com/stretchr/testify/assert"
"os"
"os/exec"
"testing"
"time"
)
func TestWrapper_LastSnapshot(t *testing.T) {
shot1 := ResticSnapshot{
Id: "shot1",
Time: time.Date(2020, 10, 10, 10, 10, 10, 10, time.UTC),
}
shot2 := ResticSnapshot{
Id: "shot2",
Time: time.Date(2022, 11, 11, 11, 11, 11, 11, time.UTC),
}
cases := []struct {
label string
snapshots []ResticSnapshot
expected ResticSnapshot
}{
{
"None yet",
[]ResticSnapshot{},
ResticSnapshot{
Id: "(no snapshots yet)",
Time: time.Time{},
},
},
{
"take the last from the array",
[]ResticSnapshot{shot1, shot2},
shot2,
},
}
for _, tc := range cases {
t.Run(tc.label, func(t *testing.T) {
wrapper := Wrapper{
LatestSnapshots: tc.snapshots,
}
last := wrapper.LastSnapshot()
assert.Equal(t, tc.expected.Id, last.Id)
assert.Equal(t, tc.expected.Time.Hour(), last.Time.Hour())
assert.Equal(t, tc.expected.Time.Minute(), last.Time.Minute())
})
}
}
// a very clever way to test exec.Command in go: https://jamiethompson.me/posts/Unit-Testing-Exec-Command-In-Golang/
func fakeExecCommand(whichTest string) func(args ...string) *exec.Cmd {
return func(args ...string) *exec.Cmd {
cs := []string{"-test.run=" + whichTest, "--", "restic"}
cs = append(cs, args...)
cmd := exec.Command(os.Args[0], cs...)
cmd.Env = []string{"GO_TEST_PROCESS=1"}
return cmd
}
}
func TestCmdnapshotSuccessWithinTime(t *testing.T) {
if os.Getenv("GO_TEST_PROCESS") != "1" {
return
}
snapshots := []ResticSnapshot{
{
Id: "id1",
Time: timeNow(),
Tree: "tree",
Paths: []string{
"/path/one",
"/path/two",
},
},
{
Id: "id2",
Time: timeNow(),
Tree: "tree2",
Paths: []string{
"/path2/one",
"/path2/two",
},
},
}
bytes, _ := json.Marshal(snapshots)
fmt.Fprintf(os.Stdout, string(bytes))
os.Exit(0)
}
func TestCmdSuccessWithinTime(t *testing.T) {
if os.Getenv("GO_TEST_PROCESS") != "1" {
return
}
fmt.Fprintf(os.Stdout, "some output\n")
os.Exit(0)
}
func TestCmdExitCode1WithinTime(t *testing.T) {
if os.Getenv("GO_TEST_PROCESS") != "1" {
return
}
fmt.Fprintf(os.Stdout, "some output\n")
os.Exit(1)
}
func TestCmdExitCode3WithinTime(t *testing.T) {
if os.Getenv("GO_TEST_PROCESS") != "1" {
return
}
fmt.Fprintf(os.Stdout, "some output\n")
os.Exit(3)
}
func TestCmdTakesLongerThan2sButOutputsFaster(t *testing.T) {
if os.Getenv("GO_TEST_PROCESS") != "1" {
return
}
// don't forget \n as the scanner splits on ScanLines
time.Sleep(1 * time.Second)
fmt.Fprintf(os.Stdout, "some output after 1s\n")
time.Sleep(2 * time.Second)
fmt.Fprintf(os.Stdout, "some output after 3s\n")
os.Exit(0)
}
func TestCmdTakesLongerThan2sToOutputAnything(t *testing.T) {
if os.Getenv("GO_TEST_PROCESS") != "1" {
return
}
time.Sleep(3 * time.Second)
fmt.Fprintf(os.Stdout, "some output, too late!\n")
os.Exit(0)
}
func TestBackup_ExitCode1_ReturnsError(t *testing.T) {
resticCmd = fakeExecCommand("TestCmdExitCode1WithinTime")
wrapper := Wrapper{}
err := wrapper.Backup(&Config{})
assert.Error(t, err)
}
func TestBackup_ExitCode3_IssuesWarning(t *testing.T) {
resticCmd = fakeExecCommand("TestCmdExitCode3WithinTime")
var logBuffer bytes.Buffer
log.Logger = log.Output(&logBuffer)
wrapper := Wrapper{}
err := wrapper.Backup(&Config{})
assert.NoError(t, err)
assert.Contains(t, logBuffer.String(), "permission problem?")
}
func TestBackup_OutputsAndFinishesAsExpected(t *testing.T) {
resticCmd = fakeExecCommand("TestCmdSuccessWithinTime")
var logBuffer bytes.Buffer
log.Logger = log.Output(&logBuffer)
wrapper := Wrapper{}
err := wrapper.Backup(&Config{})
assert.NoError(t, err)
assert.Contains(t, logBuffer.String(), "some output")
}
func TestBackup_OutputsBefore2sButStillTakesLonger(t *testing.T) {
resticCmd = fakeExecCommand("TestCmdTakesLongerThan2sButOutputsFaster")
cmdTimeout = 2 * time.Second
wrapper := Wrapper{}
err := wrapper.Backup(&Config{})
assert.NoError(t, err)
}
func TestBackup_TakesLongerThanNeededToOutput_TimesOut(t *testing.T) {
resticCmd = fakeExecCommand("TestCmdTakesLongerThan2sToOutputAnything")
cmdTimeout = 2 * time.Second
wrapper := Wrapper{}
err := wrapper.Backup(&Config{})
assert.ErrorIs(t, err, ResticCmdTimeoutError)
}
func TestUpdateLatestSnapshot_TakesLongerThanNeededToOutput_TimesOut(t *testing.T) {
resticCmd = fakeExecCommand("TestCmdTakesLongerThan2sToOutputAnything")
cmdTimeout = 2 * time.Second
wrapper := Wrapper{}
err := wrapper.UpdateLatestSnapshots(&Config{})
assert.Empty(t, wrapper.LatestSnapshots)
assert.ErrorIs(t, err, ResticCmdTimeoutError)
}
func TestUpdateLatestSnapshots_FromJSONOutputOfRestic(t *testing.T) {
resticCmd = fakeExecCommand("TestCmdnapshotSuccessWithinTime")
wrapper := Wrapper{}
err := wrapper.UpdateLatestSnapshots(&Config{})
assert.NoError(t, err)
assert.Equal(t, "id1", wrapper.LatestSnapshots[0].Id)
assert.Equal(t, "/path/two", wrapper.LatestSnapshots[0].Paths[1])
assert.Equal(t, "id2", wrapper.LatestSnapshots[1].Id)
assert.Equal(t, "/path2/two", wrapper.LatestSnapshots[1].Paths[1])
}