backend/system resolves config and data from $HOME or the OS equivalent, and Android has neither: buildUserDirPath switches on runtime.GOOS with cases for darwin, linux and windows and a default returning errUnsupportedOS. So NewYellowJacketApp failed and main() called os.Exit(1) about six milliseconds after the JNI bridge came up. That failure is invisible in all three places anyone would look. There is no panic, no AndroidRuntime stack and no tombstone, because os.Exit is not a crash; Go's stdout does not reach logcat, so the slog line naming the error is discarded; and ActivityManager respawns the process fast enough that pidof always answers, so a crash-looping app looks alive. main() now sets the override before anything asks for a path. application.Mobile.StoragePath() is the platform's own answer -- getFilesDir() on Android, Application Support on iOS -- and returns "" on desktop, where UseHomeOverride is a no-op, so this needs no build tag and changes nothing off mobile. resolveUserDirPath already honours YJ_HOME on every OS, so there was a seam for it. The knowledge stays in main(): backend/system gains no import of the Wails application package, for the same reason backend/events is split by the indexbuild tag. UseHomeOverride's two rules are tested because nothing else would notice them breaking. An empty base does nothing, which is exactly the desktop case. And an override already set wins, so YJ_HOME still relocates a sandbox on the one platform that would otherwise decide for itself. This is not the end of the port. The app now reaches the database and takes SIGSYS on the x86_64 emulator -- modernc.org/libc issues a raw lstat syscall on linux/amd64 and Android's seccomp forbids it. arm64, which is what ships to phones, has no lstat syscall at all and routes through fstatat, so it is structurally unaffected. See NOTES.md.
90 lines
2.4 KiB
Go
90 lines
2.4 KiB
Go
package system
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestResolveUserDirPath_HomeOverride(t *testing.T) {
|
|
home := t.TempDir()
|
|
t.Setenv(envHomeOverride, home)
|
|
|
|
tests := []struct {
|
|
name string
|
|
dt dirType
|
|
want string
|
|
}{
|
|
{name: "config", dt: dirTypeConfig, want: filepath.Join(home, "config")},
|
|
{name: "data", dt: dirTypeData, want: filepath.Join(home, "data")},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := resolveUserDirPath(tt.dt)
|
|
if err != nil {
|
|
t.Fatalf("resolveUserDirPath(%q) returned error: %v", tt.dt, err)
|
|
}
|
|
|
|
if got != tt.want {
|
|
t.Errorf("resolveUserDirPath(%q) = %q, want %q", tt.dt, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestResolveUserDirPath_NoOverrideUsesOSPath(t *testing.T) {
|
|
t.Setenv(envHomeOverride, "")
|
|
|
|
got, err := resolveUserDirPath(dirTypeConfig)
|
|
if err != nil {
|
|
t.Fatalf("resolveUserDirPath returned error: %v", err)
|
|
}
|
|
|
|
// Without the override the path must fall back to the OS-specific
|
|
// yellowjacket location, not a bare "<home>/config" base dir.
|
|
if !filepath.IsAbs(got) || !strings.HasSuffix(got, "yellowjacket") {
|
|
t.Errorf(
|
|
"resolveUserDirPath fallback = %q, want absolute path ending in %q",
|
|
got, "yellowjacket",
|
|
)
|
|
}
|
|
}
|
|
|
|
// UseHomeOverride carries two rules that a mobile launch depends on and
|
|
// that nothing else would notice breaking: an empty base must do
|
|
// nothing, because that is precisely what StoragePath() returns on
|
|
// desktop, and an override already set must win, or YJ_HOME would stop
|
|
// relocating a sandbox on the platform that decides for itself.
|
|
func TestUseHomeOverride(t *testing.T) {
|
|
const (
|
|
storage = "/data/user/0/app.yellowjacket/files"
|
|
sandbox = "/tmp/sandbox"
|
|
)
|
|
|
|
tests := []struct {
|
|
name string
|
|
already string
|
|
base string
|
|
want string
|
|
}{
|
|
{name: "empty base is a no-op", already: "", base: "", want: ""},
|
|
{name: "sets the override when unset", already: "", base: storage, want: storage},
|
|
{name: "an existing override wins", already: sandbox, base: storage, want: sandbox},
|
|
{name: "empty base keeps an existing override", already: sandbox, base: "", want: sandbox},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Setenv(envHomeOverride, tt.already)
|
|
|
|
UseHomeOverride(tt.base)
|
|
|
|
if got := os.Getenv(envHomeOverride); got != tt.want {
|
|
t.Errorf("%s = %q, want %q", envHomeOverride, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|