mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 11:07:10 +00:00
Device prep now disables the AOSP cached-app freezer, phantom-process killer, and Doze (and exempts the driver) so OEM background management stops suspending the driver mid-run. Adds ReinstallApp for clear-state on ROMs that deny pm clear, and teaches focus detection to report the notification shade as systemui so the scope guard can dismiss it.
232 lines
6.3 KiB
Go
232 lines
6.3 KiB
Go
package android
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseAdbDevices_OnlineOnly(t *testing.T) {
|
|
output := `List of devices attached
|
|
emulator-5554 device
|
|
emulator-5556 offline
|
|
physical-abc device
|
|
`
|
|
|
|
got := parseAdbDevices(output)
|
|
want := []string{"emulator-5554", "physical-abc"}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("got %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestParseAdbDevices_Empty(t *testing.T) {
|
|
output := "List of devices attached\n\n"
|
|
|
|
got := parseAdbDevices(output)
|
|
if len(got) != 0 {
|
|
t.Fatalf("got %v, want empty", got)
|
|
}
|
|
}
|
|
|
|
func TestPickDevice_RequestedOnline(t *testing.T) {
|
|
serial, found, err := pickDevice("physical-abc", []string{"emulator-5554", "physical-abc"})
|
|
if err != nil || !found || serial != "physical-abc" {
|
|
t.Fatalf("got (%q, %v, %v), want (physical-abc, true, nil)", serial, found, err)
|
|
}
|
|
}
|
|
|
|
func TestPickDevice_RequestedNotConnected(t *testing.T) {
|
|
_, found, err := pickDevice("physical-abc", []string{"emulator-5554"})
|
|
if err == nil {
|
|
t.Fatal("expected error for a serial that is not connected")
|
|
}
|
|
if found {
|
|
t.Fatal("found must be false when the requested device is absent")
|
|
}
|
|
}
|
|
|
|
func TestPickDevice_NoRequestUsesFirst(t *testing.T) {
|
|
serial, found, err := pickDevice("", []string{"emulator-5554", "physical-abc"})
|
|
if err != nil || !found || serial != "emulator-5554" {
|
|
t.Fatalf("got (%q, %v, %v), want (emulator-5554, true, nil)", serial, found, err)
|
|
}
|
|
}
|
|
|
|
func TestPickDevice_NoneConnectedFallsBackToAVD(t *testing.T) {
|
|
serial, found, err := pickDevice("", nil)
|
|
if err != nil || found || serial != "" {
|
|
t.Fatalf("got (%q, %v, %v), want (\"\", false, nil)", serial, found, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAVDList_DropsInfoLines(t *testing.T) {
|
|
output := `INFO | Storing crashdata in: /tmp/x
|
|
Medium_Phone_API_36.0
|
|
sanderling_test
|
|
`
|
|
|
|
got := parseAVDList(output)
|
|
want := []string{"Medium_Phone_API_36.0", "sanderling_test"}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("got %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestPickAVD_ExplicitName(t *testing.T) {
|
|
got, err := pickAVD("Pixel_7", []string{"Pixel_7", "sanderling_test"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != "Pixel_7" {
|
|
t.Fatalf("got %q, want Pixel_7", got)
|
|
}
|
|
}
|
|
|
|
func TestPickAVD_ExplicitMissing(t *testing.T) {
|
|
_, err := pickAVD("Nope", []string{"Pixel_7"})
|
|
if err == nil {
|
|
t.Fatal("expected error")
|
|
}
|
|
}
|
|
|
|
func TestPickAVD_SingleAvailable(t *testing.T) {
|
|
got, err := pickAVD("", []string{"sanderling_test"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != "sanderling_test" {
|
|
t.Fatalf("got %q, want sanderling_test", got)
|
|
}
|
|
}
|
|
|
|
func TestPickAVD_AmbiguousWithoutHint(t *testing.T) {
|
|
_, err := pickAVD("", []string{"a", "b"})
|
|
if err == nil {
|
|
t.Fatal("expected error when multiple AVDs and no --avd")
|
|
}
|
|
}
|
|
|
|
func TestPickAVD_NoneAvailable(t *testing.T) {
|
|
_, err := pickAVD("", nil)
|
|
if err == nil {
|
|
t.Fatal("expected error when no AVDs exist")
|
|
}
|
|
}
|
|
|
|
func TestPathContains(t *testing.T) {
|
|
path := "/usr/bin:/opt/tools:/usr/local/bin"
|
|
if !pathContains(path, "/opt/tools") {
|
|
t.Error("expected /opt/tools in PATH")
|
|
}
|
|
if pathContains(path, "/nope") {
|
|
t.Error("did not expect /nope in PATH")
|
|
}
|
|
}
|
|
|
|
func TestParseForegroundPackage(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
dumpsys string
|
|
want string
|
|
}{
|
|
{
|
|
name: "mResumedActivity folio",
|
|
dumpsys: " Stack #0:\n mResumedActivity: ActivityRecord{a1b2c3 u0 app.folio/.MainActivity t42}\n",
|
|
want: "app.folio",
|
|
},
|
|
{
|
|
name: "topResumedActivity chrome",
|
|
dumpsys: "ResumedActivity: ActivityRecord{ff u0 com.android.chrome/com.google.android.apps.chrome.Main t9}\n topResumedActivity=ActivityRecord{ff u0 com.android.chrome/com.google.android.apps.chrome.Main}",
|
|
want: "com.android.chrome",
|
|
},
|
|
{
|
|
name: "launcher",
|
|
dumpsys: " mResumedActivity: ActivityRecord{x u0 com.google.android.apps.nexuslauncher/.NexusLauncherActivity t1}",
|
|
want: "com.google.android.apps.nexuslauncher",
|
|
},
|
|
{
|
|
name: "no resumed activity",
|
|
dumpsys: " some unrelated dumpsys output\n with no resumed line\n",
|
|
want: "",
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got := parseForegroundPackage(tc.dumpsys); got != tc.want {
|
|
t.Errorf("parseForegroundPackage = %q, want %q", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseFocusedWindowPackage(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
dumpsys string
|
|
want string
|
|
}{
|
|
{
|
|
name: "folio focused",
|
|
dumpsys: " mCurrentFocus=Window{e00f63a u0 app.folio/app.folio.MainActivity}\n mFocusedApp=ActivityRecord{c0 u0 app.folio/.MainActivity t202}",
|
|
want: "app.folio",
|
|
},
|
|
{
|
|
name: "settings focused",
|
|
dumpsys: " mCurrentFocus=Window{709 u0 com.android.settings/com.android.settings.SubSettings}",
|
|
want: "com.android.settings",
|
|
},
|
|
{
|
|
name: "no focused window mid-launch",
|
|
dumpsys: " mCurrentFocus=null\n mFocusedApp=null",
|
|
want: "",
|
|
},
|
|
{
|
|
name: "no focus line",
|
|
dumpsys: " some unrelated dumpsys window output\n",
|
|
want: "",
|
|
},
|
|
{
|
|
name: "notification shade focused",
|
|
dumpsys: " mCurrentFocus=Window{885e289 u0 NotificationShade}",
|
|
want: "com.android.systemui",
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got := parseFocusedWindowPackage(tc.dumpsys); got != tc.want {
|
|
t.Errorf("parseFocusedWindowPackage = %q, want %q", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAntiFreezeCommands_DisablesFreezersAndExemptsDriver(t *testing.T) {
|
|
commands := antiFreezeCommands()
|
|
joined := make([]string, len(commands))
|
|
for i, c := range commands {
|
|
joined[i] = strings.Join(c, " ")
|
|
}
|
|
all := strings.Join(joined, "\n")
|
|
|
|
wantContains := []string{
|
|
"device_config set_sync_disabled_for_tests persistent",
|
|
"device_config put activity_manager_native_boot use_freezer false",
|
|
"settings put global settings_enable_monitor_phantom_procs false",
|
|
"dumpsys deviceidle disable",
|
|
}
|
|
for _, want := range wantContains {
|
|
if !strings.Contains(all, want) {
|
|
t.Errorf("anti-freeze commands missing %q\ngot:\n%s", want, all)
|
|
}
|
|
}
|
|
for _, pkg := range driverPackages {
|
|
if !strings.Contains(all, "freeze_exempt_inst_pkg") || !strings.Contains(all, pkg) {
|
|
t.Errorf("driver package %q not exempted from freezer\ngot:\n%s", pkg, all)
|
|
}
|
|
if !strings.Contains(all, "deviceidle whitelist +"+pkg) {
|
|
t.Errorf("driver package %q not whitelisted from doze\ngot:\n%s", pkg, all)
|
|
}
|
|
}
|
|
}
|