commit 6f87a87a3c1f401ef11cde0c58a484918575c73a
parent 95d8c8a95f6975d7d1567695585d8795367711a0
Author: Sean Enck <sean@ttypty.com>
Date: Sun, 12 Mar 2023 10:16:27 -0400
moving back to bash for these tests
Diffstat:
8 files changed, 238 insertions(+), 383 deletions(-)
diff --git a/Makefile b/Makefile
@@ -13,9 +13,12 @@ $(TARGET): cmd/main.go internal/**/*.go go.* internal/cli/completions*
@git describe --tags --abbrev=0 | sha256sum | cut -c 1-7 | sed 's/^/version:/g'
@git tag --points-at HEAD | grep -q '' || echo "version:-1"
-check: $(TARGET)
+unittests:
go test -v ./...
+check: unittests $(TARGET)
+ cd tests && ./run.sh
+
clean:
rm -rf $(BUILD)
diff --git a/internal/test/expected.log b/internal/test/expected.log
@@ -1,107 +0,0 @@
-path can NOT end with separator
-exit status 1
-path can NOT be rooted
-exit status 1
-unwilling to operate on path with empty segment
-exit status 1
-key/a/one
-keys/k/one
-keys/k/one2
-keys2/k/three
-delete entry? (y/N)
-key/a/one
-keys/k/one2
-keys2/k/three
-key/a/one
-keys/k/one2
-keys2/k/three
-test2
-test3
-test4
-modtime: XXXX-XX-XX
-test/k
-XXXXXX
-key/a/one:
- modtime: XXXX-XX-XX
- hash: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff
-
-keys/k/one2:
- modtime: XXXX-XX-XX
- hash: 6d201beeefb589b08ef0672dac82353d0cbd9ad99e1642c83a1601f3d647bcca003257b5e8f31bdc1d73fbec84fb085c79d6e2677b7ff927e823a54e789140d9
-
-keys2/k/three:
- modtime: XXXX-XX-XX
- hash: 132ab0244293c495a027cec12d0050598616daca888449920fc652719be0987830827d069ef78cc613e348de37c9b592d3406e2fb8d99a6961bf0c58da8a334f
-
-test/k/totp:
- modtime: XXXX-XX-XX
- hash: 7ef183065ba70aaa417b87ea0a96b7e550a938a52440c640a07537f7794d8a89e50078eca6a7cbcfacabd97a2db06d11e82ddf7556ca909c4df9fc0d006013b1
-
-delete entry? (y/N)
-delete entry? (y/N)
-delete entry? (y/N) unable to remove: no entities given
-exit status 1
-
-
-keys/k/one2
-keyx/d/e
-delete entry? (y/N)
-keys/k/one2
-pre insert keys/k2/t2/one
-CALLED
-post insert keys/k2/t2/one
-CALLED
-
-keys/k/one2
-keys/k2/one
-keys/k2/one2
-keys/k2/t1/one
-keys/k2/t1/one2
-keys/k2/t2/one
-keys/k2/t2/one2
-selected entities:
- keys/k2/t1/one
- keys/k2/t1/one2
-
-delete entries? (y/N) pre rm keys/k2/t1/one
-CALLED
-pre rm keys/k2/t1/one2
-CALLED
-post rm keys/k2/t1/one
-CALLED
-post rm keys/k2/t1/one2
-CALLED
-
-keys/k/one2
-keys/k2/one
-keys/k2/one2
-keys/k2/t2/one
-keys/k2/t2/one2
-selected entities:
- keys/k2/one
- keys/k2/one2
- keys/k2/t2/one
- keys/k2/t2/one2
-
-delete entries? (y/N) pre rm keys/k2/one
-CALLED
-pre rm keys/k2/one2
-CALLED
-pre rm keys/k2/t2/one
-CALLED
-pre rm keys/k2/t2/one2
-CALLED
-post rm keys/k2/one
-CALLED
-post rm keys/k2/one2
-CALLED
-post rm keys/k2/t2/one
-CALLED
-post rm keys/k2/t2/one2
-CALLED
-
-keys/k/one2
-
-proceed with rekey? (y/N)
-keys/k/one2
-clipboard will clear in 5 seconds
diff --git a/internal/test/integration.go b/internal/test/integration.go
@@ -1,229 +0,0 @@
-// Package test has some integration tests for the binary lb variant
-package test
-
-import (
- "bytes"
- "errors"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "regexp"
- "strings"
- "time"
-
- "github.com/enckse/pgl/os/exit"
- "github.com/enckse/pgl/os/paths"
-)
-
-var yes = []string{"y"}
-
-const (
- testKey = "plaintextkey"
- clipRetry = 3
- clipWait = 1000
-)
-
-type (
- testRunner struct {
- file *os.File
- exe string
- }
-)
-
-func (r testRunner) runCommand(args []string, data []string) {
- p := exec.Command(r.exe, args...)
- var buf bytes.Buffer
- for _, d := range data {
- if _, err := buf.WriteString(fmt.Sprintf("%s\n", d)); err != nil {
- exit.Dief("failed to write stdin: %v", err)
- }
- }
- p.Stdout = r.file
- p.Stderr = r.file
- p.Stdin = &buf
- if err := p.Run(); err != nil {
- fmt.Fprintf(r.file, "%v\n", err)
- }
-}
-
-func (r testRunner) ls() {
- r.runCommand([]string{"ls"}, nil)
-}
-
-func (r testRunner) rm(k string) {
- r.runCommand([]string{"rm", k}, yes)
-}
-
-func (r testRunner) show(k string) {
- r.runCommand([]string{"show", k}, nil)
-}
-
-func (r testRunner) insert(k string, d []string) {
- r.runCommand([]string{"insert", k}, d)
-}
-
-func (r testRunner) totpList() {
- r.runCommand([]string{"totp", "-list"}, nil)
-}
-
-func (r testRunner) ln() {
- r.file.Write([]byte("\n"))
-}
-
-func replace(input string, re *regexp.Regexp, to string) string {
- matches := re.FindAllStringSubmatch(input, -1)
- res := input
- for _, match := range matches {
- for _, m := range match {
- res = strings.ReplaceAll(res, m, to)
- }
- }
- return res
-}
-
-// Cleanup will cleanup the data log outputs
-func Cleanup(dataFile string) error {
- data, err := os.ReadFile(dataFile)
- if err != nil {
- return err
- }
- totp, err := regexp.Compile("^[0-9][0-9][0-9][0-9][0-9][0-9]$")
- if err != nil {
- return err
- }
- date := fmt.Sprintf("modtime: %s", time.Now().Format("2006-01-02"))
- var results []string
- for _, l := range strings.Split(string(data), "\n") {
- payload := l
- payload = replace(payload, totp, "XXXXXX")
- if strings.Contains(payload, date) {
- prefix := ""
- if strings.HasPrefix(payload, " ") {
- prefix = " "
- }
- payload = fmt.Sprintf("%s%s", prefix, "modtime: XXXX-XX-XX")
- }
- results = append(results, payload)
- }
- return os.WriteFile(dataFile, []byte(strings.Join(results, "\n")), 0o644)
-}
-
-// Execute will run a test
-func Execute(keyFile bool, exe, dataPath, logFile string) error {
- f, err := os.Create(logFile)
- if err != nil {
- return err
- }
- defer f.Close()
- cwd, err := os.Getwd()
- if err != nil {
- return err
- }
- useKeyFile := ""
- if keyFile {
- useKeyFile = filepath.Join(dataPath, "test.key")
- if err := os.WriteFile(useKeyFile, []byte("thisisatest"), 0o644); err != nil {
- return err
- }
- }
- store := filepath.Join(dataPath, fmt.Sprintf("%s.kdbx", time.Now().Format("20060102150405")))
- os.Setenv("LOCKBOX_HOOKDIR", "")
- os.Setenv("LOCKBOX_STORE", store)
- os.Setenv("LOCKBOX_KEY", testKey)
- os.Setenv("LOCKBOX_TOTP", "totp")
- os.Setenv("LOCKBOX_INTERACTIVE", "no")
- os.Setenv("LOCKBOX_READONLY", "no")
- os.Setenv("LOCKBOX_KEYMODE", "plaintext")
- os.Setenv("LOCKBOX_KEYFILE", useKeyFile)
- runner := testRunner{file: f, exe: exe}
- runner.insert("keys/k/one2", []string{"test2"})
- for _, k := range []string{"keys/k/one", "key/a/one", "keys/k/one", "keys/k/one/", "/keys/k/one", "keys/aa/b//s///e"} {
- runner.insert(k, []string{"test"})
- }
- runner.insert("keys2/k/three", []string{"test3", "test4"})
- runner.ls()
- runner.rm("keys/k/one")
- runner.ln()
- runner.ls()
- runner.runCommand([]string{"find", "e"}, nil)
- runner.show("keys/k/one2")
- runner.show("keys2/k/three")
- runner.runCommand([]string{"stats", "keys2/k/three"}, nil)
- for _, k := range []string{"test/k", "test/k/totp"} {
- runner.runCommand([]string{"insert", "-totp", k}, []string{"5ae472abqdekjqykoyxk7hvc2leklq5n"})
- }
- runner.totpList()
- runner.runCommand([]string{"totp", "test/k"}, nil)
- runner.runCommand([]string{"hash", store}, nil)
- runner.rm("keys2/k/three")
- runner.ln()
- runner.rm("test/k/totp")
- runner.ln()
- runner.rm("test/k/one")
- runner.ln()
- runner.ln()
- runner.runCommand([]string{"mv", "key/a/one", "keyx/d/e"}, nil)
- runner.ls()
- runner.rm("keyx/d/e")
- runner.ln()
- runner.ls()
- runner.insert("keys/k2/one2", []string{"test2"})
- runner.insert("keys/k2/one", []string{"test"})
- runner.insert("keys/k2/t1/one2", []string{"test2"})
- runner.insert("keys/k2/t1/one", []string{"test"})
- runner.insert("keys/k2/t2/one2", []string{"test2"})
- os.Setenv("LOCKBOX_HOOKDIR", filepath.Join(cwd, "hooks"))
- runner.insert("keys/k2/t2/one", []string{"test"})
- runner.ln()
- runner.ls()
- runner.rm("keys/k2/t1/*")
- runner.ln()
- runner.ls()
- runner.rm("keys/k2/*")
- runner.ln()
- runner.ls()
- runner.ln()
- reKeyStore := fmt.Sprintf("%s.rekey.kdbx", store)
- reKey := "rekey"
- os.Setenv("LOCKBOX_STORE_NEW", reKeyStore)
- os.Setenv("LOCKBOX_KEY_NEW", reKey)
- os.Setenv("LOCKBOX_KEYMODE_NEW", "plaintext")
- os.Setenv("LOCKBOX_KEYFILE_NEW", "")
- runner.runCommand([]string{"rekey"}, yes)
- os.Setenv("LOCKBOX_STORE", reKeyStore)
- os.Setenv("LOCKBOX_KEYFILE", "")
- os.Setenv("LOCKBOX_KEY", reKey)
- runner.ln()
- runner.ls()
- return runner.clipboard(dataPath)
-}
-
-func (r testRunner) clipboard(dataPath string) error {
- clipCopyFile := filepath.Join(dataPath, "clipboard")
- clipPasteFile := clipCopyFile + ".paste"
- clipFiles := []string{clipCopyFile, clipPasteFile}
- os.Setenv("LOCKBOX_CLIP_COPY", fmt.Sprintf("touch %s", clipCopyFile))
- os.Setenv("LOCKBOX_CLIP_PASTE", fmt.Sprintf("touch %s", clipPasteFile))
- os.Setenv("LOCKBOX_CLIP_MAX", "5")
- r.runCommand([]string{"clip", "keys/k/one2"}, nil)
- clipDur := time.Duration(clipWait) * time.Millisecond
- tries := clipRetry
- for {
- if tries == 0 {
- return errors.New("missing clipboard files")
- }
- foundClipCount := 0
- for _, f := range clipFiles {
- if paths.Exist(f) {
- foundClipCount++
- }
- }
- if foundClipCount == len(clipFiles) {
- break
- }
- time.Sleep(clipDur)
- tries--
- }
- return nil
-}
diff --git a/internal/test/integration_test.go b/internal/test/integration_test.go
@@ -1,46 +0,0 @@
-package test_test
-
-import (
- "os"
- "os/exec"
- "path/filepath"
- "testing"
-
- "github.com/enckse/lockbox/internal/test"
- "github.com/enckse/pgl/os/paths"
-)
-
-const (
- testDir = "bin"
-)
-
-func runTest(t *testing.T, keyFile bool) {
- os.RemoveAll(testDir)
- os.Mkdir(testDir, 0o755)
- binary := filepath.Join("..", "..", testDir, "lb")
- if !paths.Exist(binary) {
- t.Error("no binary to test")
- return
- }
- logFile := filepath.Join(testDir, "actual.log")
- if err := test.Execute(keyFile, binary, testDir, logFile); err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if err := test.Cleanup(logFile); err != nil {
- t.Errorf("cleanup failed: %v", err)
- }
- diff := exec.Command("diff", "-u", logFile, "expected.log")
- diff.Stdout = os.Stdout
- diff.Stderr = os.Stderr
- if err := diff.Run(); err != nil {
- t.Errorf("diff failed: %v", err)
- }
-}
-
-func TestKeyFile(t *testing.T) {
- runTest(t, true)
-}
-
-func TestPasswordOnly(t *testing.T) {
- runTest(t, false)
-}
diff --git a/tests/expected.log b/tests/expected.log
@@ -0,0 +1,103 @@
+path can NOT end with separator
+path can NOT be rooted
+unwilling to operate on path with empty segment
+key/a/one
+keys/k/one
+keys/k/one2
+keys2/k/three
+delete entry? (y/N)
+key/a/one
+keys/k/one2
+keys2/k/three
+key/a/one
+keys/k/one2
+keys2/k/three
+test2
+test3
+test4
+modtime: XXXX-XX-XX
+test/k
+XXXXXX
+key/a/one:
+ modtime: XXXX-XX-XX
+ hash: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff
+
+keys/k/one2:
+ modtime: XXXX-XX-XX
+ hash: 6d201beeefb589b08ef0672dac82353d0cbd9ad99e1642c83a1601f3d647bcca003257b5e8f31bdc1d73fbec84fb085c79d6e2677b7ff927e823a54e789140d9
+
+keys2/k/three:
+ modtime: XXXX-XX-XX
+ hash: 132ab0244293c495a027cec12d0050598616daca888449920fc652719be0987830827d069ef78cc613e348de37c9b592d3406e2fb8d99a6961bf0c58da8a334f
+
+test/k/totp:
+ modtime: XXXX-XX-XX
+ hash: 7ef183065ba70aaa417b87ea0a96b7e550a938a52440c640a07537f7794d8a89e50078eca6a7cbcfacabd97a2db06d11e82ddf7556ca909c4df9fc0d006013b1
+
+delete entry? (y/N)
+delete entry? (y/N)
+delete entry? (y/N) unable to remove: no entities given
+
+
+keys/k/one2
+keyx/d/e
+delete entry? (y/N)
+keys/k/one2
+pre insert keys/k2/t2/one
+CALLED
+post insert keys/k2/t2/one
+CALLED
+
+keys/k/one2
+keys/k2/one
+keys/k2/one2
+keys/k2/t1/one
+keys/k2/t1/one2
+keys/k2/t2/one
+keys/k2/t2/one2
+selected entities:
+ keys/k2/t1/one
+ keys/k2/t1/one2
+
+delete entries? (y/N) pre rm keys/k2/t1/one
+CALLED
+pre rm keys/k2/t1/one2
+CALLED
+post rm keys/k2/t1/one
+CALLED
+post rm keys/k2/t1/one2
+CALLED
+
+keys/k/one2
+keys/k2/one
+keys/k2/one2
+keys/k2/t2/one
+keys/k2/t2/one2
+selected entities:
+ keys/k2/one
+ keys/k2/one2
+ keys/k2/t2/one
+ keys/k2/t2/one2
+
+delete entries? (y/N) pre rm keys/k2/one
+CALLED
+pre rm keys/k2/one2
+CALLED
+pre rm keys/k2/t2/one
+CALLED
+pre rm keys/k2/t2/one2
+CALLED
+post rm keys/k2/one
+CALLED
+post rm keys/k2/one2
+CALLED
+post rm keys/k2/t2/one
+CALLED
+post rm keys/k2/t2/one2
+CALLED
+
+keys/k/one2
+
+proceed with rekey? (y/N)
+keys/k/one2
+clipboard will clear in 5 seconds
diff --git a/internal/test/hooks/all.sh b/tests/hooks/all.sh
diff --git a/internal/test/hooks/test.sh b/tests/hooks/test.sh
diff --git a/tests/run.sh b/tests/run.sh
@@ -0,0 +1,131 @@
+#!/usr/bin/env bash
+LB_BINARY=../bin/lb
+DATA=bin
+CLIP_WAIT=1
+CLIP_TRIES=3
+CLIP_COPY="$DATA/clip.copy"
+CLIP_PASTE="$DATA/clip.paste"
+
+_execute() {
+ local rekey rekeyFile clipTries
+ export LOCKBOX_HOOKDIR=""
+ export LOCKBOX_STORE="${DATA}/passwords.kdbx"
+ export LOCKBOX_KEY="testingkey"
+ export LOCKBOX_TOTP=totp
+ export LOCKBOX_INTERACTIVE=no
+ export LOCKBOX_READONLY=no
+ export LOCKBOX_KEYMODE=plaintext
+ echo test2 |${LB_BINARY} insert keys/k/one2
+ echo test |${LB_BINARY} insert keys/k/one
+ echo test |${LB_BINARY} insert key/a/one
+ echo test |${LB_BINARY} insert keys/k/one
+ echo test |${LB_BINARY} insert keys/k/one/
+ echo test |${LB_BINARY} insert /keys/k/one
+ echo test |${LB_BINARY} insert keys/aa/b//s///e
+ printf "test3\ntest4\n" |${LB_BINARY} insert keys2/k/three
+ ${LB_BINARY} ls
+ echo y |${LB_BINARY} rm keys/k/one
+ echo
+ ${LB_BINARY} ls
+ ${LB_BINARY} find e
+ ${LB_BINARY} show keys/k/one2
+ ${LB_BINARY} show keys2/k/three
+ ${LB_BINARY} stats keys2/k/three
+ echo 5ae472abqdekjqykoyxk7hvc2leklq5n |${LB_BINARY} insert -totp test/k
+ echo 5ae472abqdekjqykoyxk7hvc2leklq5n |${LB_BINARY} insert -totp test/k/totp
+ ${LB_BINARY} totp -list
+ ${LB_BINARY} totp test/k
+ ${LB_BINARY} hash "$LOCKBOX_STORE"
+ echo y |${LB_BINARY} rm keys2/k/three
+ echo
+ echo y |${LB_BINARY} rm test/k/totp
+ echo
+ echo y |${LB_BINARY} rm test/k/one
+ echo
+ echo
+ ${LB_BINARY} mv key/a/one keyx/d/e
+ ${LB_BINARY} ls
+ echo y |${LB_BINARY} rm keyx/d/e
+ echo
+ ${LB_BINARY} ls
+ echo test2 |${LB_BINARY} insert keys/k2/one2
+ echo test |${LB_BINARY} insert keys/k2/one
+ echo test2 |${LB_BINARY} insert keys/k2/t1/one2
+ echo test |${LB_BINARY} insert keys/k2/t1/one
+ echo test2 |${LB_BINARY} insert keys/k2/t2/one2
+ export LOCKBOX_HOOKDIR="$PWD/hooks"
+ echo test |${LB_BINARY} insert keys/k2/t2/one
+ echo
+ ${LB_BINARY} ls
+ echo y |${LB_BINARY} rm keys/k2/t1/*
+ echo
+ ${LB_BINARY} ls
+ echo y |${LB_BINARY} rm keys/k2/*
+ echo
+ ${LB_BINARY} ls
+ echo
+ rekey="$LOCKBOX_STORE.rekey.kdbx"
+ rekeyFile=""
+ export LOCKBOX_STORE_NEW="$rekey"
+ export LOCKBOX_KEY_NEW="newkey"
+ export LOCKBOX_KEYMODE_NEW=plaintext
+ if [ -n "$LOCKBOX_KEYFILE" ]; then
+ rekeyFile="$DATA/newkeyfile"
+ echo "thisisanewkey" > "$rekeyFile"
+ fi
+ export LOCKBOX_KEYFILE_NEW="$rekeyFile"
+ echo y |${LB_BINARY} rekey
+ echo
+ ${LB_BINARY} ls
+ _clipboard
+}
+
+_clipboard() {
+ export LOCKBOX_CLIP_COPY="touch $CLIP_COPY"
+ export LOCKBOX_CLIP_PASTE="touch $CLIP_PASTE"
+ export LOCKBOX_CLIP_MAX=5
+ ${LB_BINARY} clip keys/k/one2
+ clipTries="$CLIP_TRIES"
+ while [ "$clipTries" -gt 0 ] ; do
+ if [ -e "$CLIP_COPY" ] && [ -e "$CLIP_PASTE" ]; then
+ return
+ fi
+ sleep "$CLIP_WAIT"
+ clipTries=$((clipTries-1))
+ done
+ echo "clipboard test failed"
+}
+
+_cleanup() {
+ mkdir -p "$DATA"
+ find "$DATA" -type f -delete
+}
+
+_evaluate() {
+ local logfile
+ logfile="$DATA/actual.log"
+ echo "$1"
+ echo "============"
+ _execute > "$logfile" 2>&1
+ sed -i 's/modtime: [0-9].*$/modtime: XXXX-XX-XX/g' "$logfile"
+ sed -i 's/^[0-9][0-9][0-9][0-9][0-9][0-9]$/XXXXXX/g' "$logfile"
+ if ! diff -u "$logfile" "expected.log"; then
+ echo "failed"
+ exit 1
+ fi
+ echo "passed"
+}
+
+_run() {
+ export LOCKBOX_KEYFILE=""
+ _cleanup
+ _evaluate "password"
+ echo
+ _cleanup
+ KEYFILE="$DATA/test.key"
+ echo "thisisatest" > "$KEYFILE"
+ export LOCKBOX_KEYFILE="$KEYFILE"
+ _evaluate "keyfile"
+}
+
+_run