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