Appium : Set custom time programatically on emulator or saucelabs - android

I'm trying to set the emulator system time to a predefined date every time i run the test cases.
I've found the command adb shell date --set= which changes time but couldn't implement it using appium API's.
Any help in figuring out how to implement it or other alternatives is much appreciated.
I've also opened a thread on appium discuss for the same.

In Ruby, i'm doing the following for avds:
# set time using adb shell command
# defaults to Time.now
# mm == month, mn == minute
# Note: formatting must include leading zeros for single character results
def self.android_set_time(yy = Time.now.strftime('%y'),
yyyy = Time.now.strftime('%Y'),
mm = Time.now.strftime('%m'),
dd = Time.now.strftime('%e'),
hh = Time.now.strftime('%H'),
mn = Time.now.strftime('%M'))
version = driver_attributes[:caps][:platformVersion].to_f
if version >= 6.0
system("adb shell 'date #{mm}#{dd}#{hh}#{mn}#{yy}.00'")
else
system("adb shell date -s '#{yyyy}#{mm}#{dd}.#{hh}#{mn}00'")
end
end
Note: you must use Kernel.system vs Kernel.exec.
Kernel.exec # Replaces the current process by running the given external _command_...
Kernel.system # Executes _command..._ in a subshell.
Unknown if it works in saucelabs or not.

There is currently no way to do this in Appium. It has not been implemented as an endpoint, and Appium does not allow ad hoc adb command execution, for security reasons.

Related

Enable/Disable wifi using Xamarin UiTest

I try to enable/disable wifi programmatically within my Xamarin Ui Test.
I already found this: Android: How to Enable/Disable Wifi or Internet Connection Programmatically. But it seems not to work within the UiTest.
I also tried something like this:
Context appContext = Android.App.Application.Context;
var wifiManager = (WifiManager)appContext.GetSystemService(Context.WifiService);
bool status = false;
wifiManager.SetWifiEnabled(status);
The first line (Android.App.Application.Context) throws an exception:
Message: System.IO.FileNotFoundException : Could not load file or assembly 'Java.Interop, Version=0.1.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065' or one of its dependencies. The system cannot find the file specified.
I'm using following namespaces:
using Android.Net.Wifi;
using Android.Content;
My project has a reference to Mono.Android.
The backdoor approach works fine for me.
The solution that works for me was a combination of:
Android: How to Enable/Disable Wifi or Internet Connection Programmatically
https://learn.microsoft.com/en-us/appcenter/test-cloud/uitest/working-with-backdoors
Some small own changes (for appcontext/context). Just context did not work for me.
1.: Add following line to the AndroidManifest.xml file of the Android project:
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
2.: Add following lines to the MainActivity.cs of the Android project:
using Java.Interop;
using Android.Net.Wifi;
[Export("ChangeWifiState")]
public void ChangeWifiState(bool state)
{
Context appContext = Android.App.Application.Context;
var wifiManager = (WifiManager)appContext.GetSystemService(WifiService);
wifiManager.SetWifiEnabled(state);
}
3.: Call following method out of the Xamarin Ui Test:
app.Invoke("ChangeWifiState", false); // true to enable wifi, false to disable wifi
PS: I use Xamarin Forms. I've got four different projects: a core project, an Android project, a Ui project, and a test project.
I just found a second solution without using the actual app.
It uses ADB commands to enable/disable wifi:
var process = new System.Diagnostics.Process();
var startInfo = new System.Diagnostics.ProcessStartInfo
{
WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
FileName = "cmd.exe",
Arguments = "/C adb shell am start -a android.intent.action.MAIN -n com.android.settings/.wifi.WifiSettings adb shell input keyevent 19 & adb shell input keyevent 19 & adb shell input keyevent 23 & adb shell input keyevent 82 & adb shell input tap 500 1000"
};
process.StartInfo = startInfo;
process.Start();
This can be used without a rooted device :).
Steps explained:
adb shell am start -a android.intent.action.MAIN -n com.android.settings/.wifi.WifiSettings opens the wifi settings.
adb shell input keyevent 23 enables/disables wifi.
I'm not sure why the command adb shell input keyevent 19 is used, but it works.
adb shell input keyevent 82 clicks the menu button to change back to the original app.
adb shell input tap 500 1000 clicks the coordinate x=500, y=1000 (center of screen).This may need be changed for different solutions.
Sources for this solution:
How to turn off Wifi via ADB?
ADB Shell Input Events
Run Command Prompt Commands

Android weird test sharding

I'm experimenting with test sharding on Android and I'm getting pretty weird results:
+ adb -s emulator-5580 shell am instrument -e numShards 2 -e shardIndex 0 -e class com.package.etc.automation.Tests.SanityTest.SanityTest -w com.package.etc.test/android.support.test.runner.AndroidJUnitRunner
com.package.etc.automation.Tests.SanityTest.SanityTest:..........
Time: 306.578
OK (10 tests)
+ adb -s emulator-5582 shell am instrument -e numShards 2 -e shardIndex 1 -e class com.package.etc.automation.Tests.SanityTest.SanityTest -w com.package.etc.test/android.support.test.runner.AndroidJUnitRunner
com.package.etc.automation.Tests.SanityTest.SanityTest:......................
Time: 645.723
OK (22 tests)
As you can see, adb split the tests into two uneven groups. The second one has twice as many tests as the first one and executes twice as long. Not the best parallelism if you ask me.
Is there a possibility to control the distribution of tests, or at least force adb to split the tests evenly?
Let's trace it down.
When test suite is started, TestRequestBuilder is built upon JUnit Filters. ShardingFilter is one of them and is added. Adding it means that previously added Filter is "intersected" with new one - method public boolean shouldRun(Description description) is invoked. If you look at it, more likely at this fragment:
if (description.isTest()) {
return (Math.abs(description.hashCode()) % mNumShards) == mShardIndex;
}
And substituting with your numbers (numShards=2), you'll notice, that this is just a parity test. Statistically it might happen, that generated HashCode parity distribution is not 50%. Moreover, when some of the tests on your test class are ignored, disabled and are interweaving with enabled tests, you can even more disturb particular method hashcode (Junit Description uniqueId is generated from method and class name).
That is just statistics matter. As you might see in this answer:
How the groups are divided is arbitrary

Enabling HCI Bluetooth snoop log programmatically

There is a well known way to enable HCI Bluetooth snoop log from Developer options UI.
Is there any way to achieve this programmatically?
Using Developer Options:
If you enable Developer Options, then you can enable Bluetooth snoop Logging under those options as well. After reboot, you should find your log files under /data/misc/bluetooth/logs/ (Not sure if you need root to access these files),
Using bt_stack.conf (requires root) - (Updated for Android 8.0+)
bt_stack.conf is found under /system/etc/bluetooth and existing conf files are also found under /data/misc/bluedroid.
In most cases, you'll have to disable verity using the following steps:
adb -s <DEVICE> root
adb -s <DEVICE> disable-verity
adb -s <DEVICE> reboot (To apply changes)
Next enter root again, after reboot: adb -s <DEVICE> root
Then remount, adb -s <DEVICE> remount
You can also remount using command mount -o rw,remount <PARTITION>
Then you'll be able to push the files, then you can make the changes + reboot.
Edit bt_stack.conf file (set BtSnoopLogOutput=true)
Disable and then enable Bluetooth - this will start the HCI snoop logging
When you decide it is enough, edit the file again while setting
BtSnoopLogOutput=false and reset the Bluetooth - this will stop the HCI snoop logging
What I usually do is pull the respective file, make the changes in my fav editor (Usually vi or VSCode) and then push it back using these commands
adb -s <DEVICE> pull /system/etc/bluetooth/bt_stack.conf
adb -s <DEVICE> push bt_stack.conf /system/etc/bluetooth/.
Along with BTSnoop logging, You can also enable all the stack traces using bt_stack.conf.
Here is what the files looks like on Android 9.0 r34, MSM Kernel 4.4:
root#console:/system/etc/bluetooth# cat bt_stack.conf
# Enable trace level reconfiguration function
# Must be present before any TRC_ trace level settings
TraceConf=true
# Trace level configuration
# BT_TRACE_LEVEL_NONE 0 ( No trace messages to be generated )
# BT_TRACE_LEVEL_ERROR 1 ( Error condition trace messages )
# BT_TRACE_LEVEL_WARNING 2 ( Warning condition trace messages )
# BT_TRACE_LEVEL_API 3 ( API traces )
# BT_TRACE_LEVEL_EVENT 4 ( Debug messages for events )
# BT_TRACE_LEVEL_DEBUG 5 ( Full debug messages )
# BT_TRACE_LEVEL_VERBOSE 6 ( Verbose messages ) - Currently supported for TRC_BTAPP only.
TRC_BTM=2
TRC_HCI=2
TRC_L2CAP=2
TRC_RFCOMM=2
TRC_OBEX=2
TRC_AVCT=2
TRC_AVDT=2
TRC_AVRC=2
TRC_AVDT_SCB=2
TRC_AVDT_CCB=2
TRC_A2D=2
TRC_SDP=2
TRC_SMP=2
TRC_BTAPP=2
TRC_BTIF=2
TRC_BNEP=2
TRC_PAN=2
TRC_HID_HOST=2
TRC_HID_DEV=2
# This is Log configuration for new C++ code using LOG() macros.
# See libchrome/base/logging.h for description on how to configure your logs.
# sample configuration:
#LoggingV=--v=0
#LoggingVModule=--vmodule=*/btm/*=1,btm_ble_multi*=2,btif_*=1
# PTS testing helpers
# Secure connections only mode.
# PTS_SecurePairOnly=true
# Disable LE Connection updates
#PTS_DisableConnUpdates=true
# Disable BR/EDR discovery after LE pairing to avoid cross key derivation errors
#PTS_DisableSDPOnLEPair=true
# SMP Pair options (formatted as hex bytes) auth, io, ikey, rkey, ksize
#PTS_SmpOptions=0xD,0x4,0xf,0xf,0x10
# PTS AVRCP Test mode
#PTS_AvrcpTest=true
# SMP Certification Failure Cases
# Set any of the following SMP error values (from smp_api_types.h)
# to induce pairing failues for various PTS SMP test cases.
# Setting PTS_SmpFailureCase to 0 means normal operation.
# Failure modes:
#
# SMP_PASSKEY_ENTRY_FAIL = 1
# SMP_PAIR_AUTH_FAIL = 3
# SMP_CONFIRM_VALUE_ERR = 4
# SMP_PAIR_NOT_SUPPORT = 5
# SMP_PAIR_FAIL_UNKNOWN = 8
# SMP_REPEATED_ATTEMPTS = 9
# SMP_NUMERIC_COMPAR_FAIL = 12
#PTS_SmpFailureCase=0
Using hidden Android API
Note that this approach will require your application to have BLUETOOTH_ADMIN permission.
If this is OK, you can use the same code Android system settings app uses.
private void writeBtHciSnoopLogOptions() {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
adapter.configHciSnoopLog(true);
}
configHciSnoopLog is a part of a hidden API of BluetoothAdapter class, so make sure you know how to enable it:
Using hidden Android API
android-hidden-api library
Using SL4A
SL4A brings scripting languages to Android by allowing you to edit and execute scripts and interactive interpreters directly on the Android device. These scripts have access to many of the APIs available to full-fledged Android applications, but with a greatly simplified interface that makes it easy to get things done.
If your Android image built with support for SL4A, you can use the following method of BluetoothFacade:
#Rpc(description = "Enable or disable the Bluetooth HCI snoop log")
public boolean bluetoothConfigHciSnoopLog(
#RpcParameter(name = "value", description = "enable or disable log")
Boolean value
) {
return mBluetoothAdapter.configHciSnoopLog(value);
}
Note that the API reference on Github is outdated, but you can see the latest in official AOSP repo (Common\src\com\googlecode\android_scripting\facade\bluetooth)
Python script that enables HCI snoop logs would look like this:
from android import Android
droid = Android()
droid.bluetoothConfigHciSnoopLog(True)
When done with logging, you can find the HCI Snoop log in /sdcard/btsnoop_hci.log

Efficiently build Android system service component

I'm trying to extend Android's PackageManager functionalities modifying this file:
frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java
When I perform a make clean && make after editing the file and I start the emulator, the changes are there, but this takes too long even with the cache enabled. I tried using mmm framework/base but it does not seem to rebuild the services.core module.
Does anyone know a reliable method to modify a system service and then rebuild efficiently?
mmm and submodules
Create the new classes.dex for the services.core module:
mmm frameworks/base/services/core
Creates the services.jar file including the services.core module that we just rebuilt:
mmm frameworks/base/services
Creates the new system.img for the emulator:
make snod
If the emulator (or the device) is already running, you can use the new services.jar with:
adb remount && adb sync && adb shell stop && adb shell start
In fact mm and mmm do not check for modified submodules, so rebuilding the services module (step 2) without previously rebuilding the services.core (step 1) module is not enough.
DEXPREOPT
If you see the message:
Warning: with dexpreopt enabled, you may need a full rebuild.
You have to turn off the dex preoptimization performing a make clean and then use the following flags in make and mm: WITH_DEXPREOPT=false and DISABLE_DEXPREOPT=true.

Start an Android Test from an Intent (or from SL4A)?

I'd like to run some android tests but I want to scedule or delay the execution of these tests. I'm trying to do this from SL4A. The idea is to install SL4A start the server from my laptop, run a special python script that will sleep for about 20 seconds then wakeup and launch the tests. I am performing some rather involved automation that requires my tests be run after I install them and disconnect the USB cable. I know I can issue intents from SL4A but I'm looking for the equivalent of:
adb shell am instrument \
-e class MyInstrumentationTestCase \
-w MyInstrumentationTestRunner
Can this be done via intent? Should I send a broadcast or use the start activity functions?
I've tried running a system command directly on the device from Python with this script but I get a "permission denied" error:
from subprocess import call
call(["am", "instrument", "-e", "class", "com.example.android.app.test.TestContactList", "-w", "com.example.app.test/com.zutubi.android.junitreport.JUnitReportTestRunner"])
UPDATE
I've also tried using os.system to run the command (see below modifications) and this gives a different error: soinfo_link_image(linker.cpp:1635): could not load library "libanroid_runtime.so" needed by "app_process"; caused by so info_relocate(linker.cpp:975): cannot locate symbol " sqlite3_stmt_readonly" referenced by "lib android_runtime.so"...CANNOT LINK EXECUTABLE
import os
#from subprocess import call
#call(["am", "instrument", "-e", "class", "com.example.android.app.test.TestContactList", "-w", "com.example.android.app.test/com.zutubi.android.junitreport.JUnitReportTestRunner"])
os.system('echo "Running tests"')
os.system('am instrument -e class com.example.android.app.test.TestContactList -w com.example.android.app.test/com.zutubi.android.junitreport.JUnitReportTestRunner')
What are any other options?
I have the following function, which will launch any SL4A script from within a Python SL4A script, as a separate process. You can not use subprocess for this type of thing.
You may be able to deduce what you need from this.
from android import Android
droid = Android()
def launch_script(path, visible=False):
visibilty = 'FORE' if visible else 'BACK'
activity = 'com.googlecode.android_scripting.action.LAUNCH_{0}GROUND_SCRIPT'.format(visibilty)
extras = {'com.googlecode.android_scripting.extra.SCRIPT_PATH': path}
packagename = 'com.googlecode.android_scripting'
classname = 'com.googlecode.android_scripting.activity.ScriptingLayerServiceLauncher'
intent = droid.makeIntent(activity, None, None, extras, None, packagename, classname).result
droid.startActivityIntent(intent)

Categories

Resources