Add end-to-end integration test with fake external binaries
Exercises the full run() pipeline using fake shell scripts on PATH that record their argv to a temp RECORD_DIR. Verifies all external commands were invoked, outputs contain the expected version/app/artifact values, ditto was called twice (pre- and post-staple), and security delete-keychain ran during cleanup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
445c99e6c4
commit
22aa4d6069
117
cmd/wails-release/integration_test.go
Normal file
117
cmd/wails-release/integration_test.go
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRun_EndToEnd_FakeBinaries(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("integration test skipped in -short mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
repoRoot, _ := os.Getwd() // cmd/wails-release
|
||||||
|
binDir := filepath.Join(repoRoot, "testdata", "bin")
|
||||||
|
sampleSrc := filepath.Join(repoRoot, "testdata", "sample-app")
|
||||||
|
|
||||||
|
// Copy the sample app to a writable temp dir so the build step can
|
||||||
|
// drop output into it without mutating testdata.
|
||||||
|
work := t.TempDir()
|
||||||
|
copyTree(t, sampleSrc, work)
|
||||||
|
|
||||||
|
record := t.TempDir()
|
||||||
|
outputs := filepath.Join(record, "outputs")
|
||||||
|
must(t, os.WriteFile(outputs, nil, 0o600))
|
||||||
|
|
||||||
|
t.Setenv("PATH", binDir+string(os.PathListSeparator)+os.Getenv("PATH"))
|
||||||
|
t.Setenv("RECORD_DIR", record)
|
||||||
|
t.Setenv("WORK_DIR", work)
|
||||||
|
t.Setenv("GITHUB_OUTPUT", outputs)
|
||||||
|
t.Setenv("GITHUB_REF", "refs/tags/v1.2.3")
|
||||||
|
t.Setenv("GITHUB_SHA", "0123456789abcdef")
|
||||||
|
|
||||||
|
for k, v := range map[string]string{
|
||||||
|
"INPUT_WORKING_DIRECTORY": work,
|
||||||
|
"INPUT_DEVELOPER_ID_CERT_BASE64": base64.StdEncoding.EncodeToString([]byte("not-a-real-p12")),
|
||||||
|
"INPUT_DEVELOPER_ID_CERT_PASSWORD": "x",
|
||||||
|
"INPUT_NOTARIZATION_METHOD": "api-key",
|
||||||
|
"INPUT_NOTARIZATION_API_KEY_BASE64": base64.StdEncoding.EncodeToString([]byte("not-a-real-p8")),
|
||||||
|
"INPUT_NOTARIZATION_API_KEY_ID": "K",
|
||||||
|
"INPUT_NOTARIZATION_API_ISSUER_ID": "I",
|
||||||
|
} {
|
||||||
|
t.Setenv(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := run(context.Background()); err != nil {
|
||||||
|
t.Fatalf("run: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each external command must have been called.
|
||||||
|
for _, name := range []string{"wails.log", "security.log", "codesign.log", "ditto.log", "xcrun.log"} {
|
||||||
|
path := filepath.Join(record, name)
|
||||||
|
b, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected %s, got error: %v", name, err)
|
||||||
|
}
|
||||||
|
if len(b) == 0 {
|
||||||
|
t.Fatalf("%s was empty", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Outputs file should contain version=1.2.3.
|
||||||
|
out, err := os.ReadFile(outputs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read outputs: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(out), "version=1.2.3") {
|
||||||
|
t.Fatalf("expected version=1.2.3 in outputs, got %q", out)
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(out), "app-name=SampleApp") {
|
||||||
|
t.Fatalf("expected app-name=SampleApp in outputs, got %q", out)
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(out), "artifact-filename=SampleApp-1.2.3.app.zip") {
|
||||||
|
t.Fatalf("expected artifact-filename in outputs, got %q", out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ditto must have been invoked twice (pre-staple + post-staple).
|
||||||
|
dittoLog, _ := os.ReadFile(filepath.Join(record, "ditto.log"))
|
||||||
|
if strings.Count(string(dittoLog), "\n") < 2 {
|
||||||
|
t.Fatalf("expected ditto called at least twice, log:\n%s", dittoLog)
|
||||||
|
}
|
||||||
|
|
||||||
|
// security delete-keychain must have run during cleanup.
|
||||||
|
secLog, _ := os.ReadFile(filepath.Join(record, "security.log"))
|
||||||
|
if !strings.Contains(string(secLog), "delete-keychain") {
|
||||||
|
t.Fatalf("expected security delete-keychain in cleanup, log:\n%s", secLog)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func must(t *testing.T, err error) {
|
||||||
|
t.Helper()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyTree(t *testing.T, src, dst string) {
|
||||||
|
t.Helper()
|
||||||
|
must(t, filepath.Walk(src, func(p string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rel, _ := filepath.Rel(src, p)
|
||||||
|
out := filepath.Join(dst, rel)
|
||||||
|
if info.IsDir() {
|
||||||
|
return os.MkdirAll(out, 0o755)
|
||||||
|
}
|
||||||
|
b, err := os.ReadFile(p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return os.WriteFile(out, b, info.Mode())
|
||||||
|
}))
|
||||||
|
}
|
||||||
3
cmd/wails-release/testdata/bin/codesign
vendored
Executable file
3
cmd/wails-release/testdata/bin/codesign
vendored
Executable file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
echo "$0 $*" >> "$RECORD_DIR/codesign.log"
|
||||||
|
exit 0
|
||||||
7
cmd/wails-release/testdata/bin/ditto
vendored
Executable file
7
cmd/wails-release/testdata/bin/ditto
vendored
Executable file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
echo "$0 $*" >> "$RECORD_DIR/ditto.log"
|
||||||
|
# Last argument is the output path; create it.
|
||||||
|
out="${@: -1}"
|
||||||
|
mkdir -p "$(dirname "$out")"
|
||||||
|
echo "fake-zip" > "$out"
|
||||||
|
exit 0
|
||||||
9
cmd/wails-release/testdata/bin/go
vendored
Executable file
9
cmd/wails-release/testdata/bin/go
vendored
Executable file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/bash
|
||||||
|
echo "$0 $*" >> "$RECORD_DIR/go.log"
|
||||||
|
# install: pretend success.
|
||||||
|
# env GOPATH: print a tmp value (not actually used in the test path).
|
||||||
|
case "$1" in
|
||||||
|
install) ;;
|
||||||
|
env) echo "/tmp" ;;
|
||||||
|
esac
|
||||||
|
exit 0
|
||||||
6
cmd/wails-release/testdata/bin/security
vendored
Executable file
6
cmd/wails-release/testdata/bin/security
vendored
Executable file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
echo "$0 $*" >> "$RECORD_DIR/security.log"
|
||||||
|
if [[ "$1" == "find-identity" ]]; then
|
||||||
|
echo ' 1) AAAA1111 "Developer ID Application: Acme Inc (TEAM1234)"'
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
9
cmd/wails-release/testdata/bin/wails
vendored
Executable file
9
cmd/wails-release/testdata/bin/wails
vendored
Executable file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/bash
|
||||||
|
echo "$0 $*" >> "$RECORD_DIR/wails.log"
|
||||||
|
case "$1" in
|
||||||
|
-v) echo "Wails CLI v2.11.0" ;;
|
||||||
|
build)
|
||||||
|
mkdir -p "$WORK_DIR/build/bin/SampleApp.app/Contents/MacOS"
|
||||||
|
touch "$WORK_DIR/build/bin/SampleApp.app/Contents/MacOS/SampleApp"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
12
cmd/wails-release/testdata/bin/xcrun
vendored
Executable file
12
cmd/wails-release/testdata/bin/xcrun
vendored
Executable file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
echo "$0 $*" >> "$RECORD_DIR/xcrun.log"
|
||||||
|
case "$1" in
|
||||||
|
notarytool)
|
||||||
|
case "$2" in
|
||||||
|
submit) echo '{"id":"sub-1","status":"Accepted"}' ;;
|
||||||
|
log) echo '{}' ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
stapler) ;;
|
||||||
|
esac
|
||||||
|
exit 0
|
||||||
5
cmd/wails-release/testdata/sample-app/go.mod
vendored
Normal file
5
cmd/wails-release/testdata/sample-app/go.mod
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
module example.com/sample
|
||||||
|
|
||||||
|
go 1.22.0
|
||||||
|
|
||||||
|
require github.com/wailsapp/wails/v2 v2.11.0
|
||||||
1
cmd/wails-release/testdata/sample-app/go.sum
vendored
Normal file
1
cmd/wails-release/testdata/sample-app/go.sum
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
github.com/wailsapp/wails/v2 v2.11.0/go.mod h1:jrf0ZaM6+GBc1wRmXsM8cIvzlg0karYin3erahI4+0k=
|
||||||
1
cmd/wails-release/testdata/sample-app/wails.json
vendored
Normal file
1
cmd/wails-release/testdata/sample-app/wails.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{ "name": "SampleApp" }
|
||||||
Loading…
Reference in a new issue