I am using Appium to test the App in the Android mobile phone with Android 12 version. There i have a case where i want to restart the mobile phone.
My setup is where my c# code lies in windows which in turn connected with Macbook throuh WLAN and macbook controls the Android phone through Appium. That is the reason why I cannot execute adb commands directly on the Android mobile phone.
For that i am using the Executescript function from Appium as following
driver.ExecuteScript("mobile:shell", new AdbCommand("reboot"));
But this command throws an illegal argument exception as follows
Exception thrown: 'System.ArgumentException' in WebDriver.dll
An exception of type 'System.ArgumentException' occurred in WebDriver.dll but was not handled in user code
Argument is of an illegal type{"command":"reboot","args":[]}
Relaxed security is ON and adb commands should work in this case.
Any help appreciated regarding this problem.
Regarding Adb Class which does nothing but provides a provision to enter arguments in json format in C# and this has been copied from an example from automatetheplanet.com
public class AdbCommand
{
public AdbCommand(string command)
{
Command = command;
Args = new List();
}
public AdbCommand(string command, params string[] args)
{
Command = command;
Args = new List(args);
}
[JsonProperty("command")]
public string Command { get; set; }
[JsonProperty("args")]
public List Args { get; set; }
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
Related
I encountered a strange problem when trying to unpair and pair again with my smartphone. Currently I write a C# application on UWP (Windows 10) for BLE connection with a remote device. I use my smartphone with nRF Connect App as the peripheral.
After being paired for a while (and being inactive), when unpairing and pairing again, the application gets stuck when trying to pair again.
I broke everything down to the most basal application I could create. This is a Console App that scans the existing devices and then unpairs and pairs with the selected device:
using BLE_Test;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static async Task Main(string[] args)
{
Dictionary<ulong, string> uuidDict = BleModule.Scan().Result;
Console.WriteLine("Devices found:");
int i = 0;
foreach (var uuid in uuidDict.Keys)
Console.WriteLine(string.Format("ID: {0}, UUID: {1}, Local Name: {2}", i++, uuid, uuidDict[uuid]));
Console.WriteLine("Select ID!");
int id = int.Parse(Console.ReadLine());
ulong selectedUuid = (uuidDict.ElementAt(id)).Key;
await BleModule.Unpair(selectedUuid);
await BleModule.Pair(selectedUuid);
Console.ReadLine();
}
}
}
It calls an UWP DLL called "BLE_Test" with the class "BleModule":
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Enumeration;
namespace BLE_Test
{
public class BleModule
{
public static async Task<Dictionary<ulong, string>> Scan()
{
var uuidDict = new Dictionary<ulong, string>();
BluetoothLEAdvertisementWatcher watcher = new BluetoothLEAdvertisementWatcher();
watcher.Received += (BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
=> AddAdvertisement(eventArgs, uuidDict);
watcher.Start();
await Task.Delay(10000);
watcher.Stop();
return uuidDict;
}
private static void AddAdvertisement(BluetoothLEAdvertisementReceivedEventArgs eventArgs, Dictionary<ulong, string> uuidDict)
{
if (uuidDict.ContainsKey(eventArgs.BluetoothAddress) == false)
uuidDict.Add(eventArgs.BluetoothAddress, eventArgs.Advertisement.LocalName);
}
public static async Task Pair(ulong uuid)
{
Console.WriteLine("Pairing...");
var bluetoothLEDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(uuid);
if (bluetoothLEDevice == null)
{
Console.WriteLine("UUID not found!");
return;
}
DeviceInformationCustomPairing customPairing = bluetoothLEDevice.DeviceInformation.Pairing.Custom;
customPairing.PairingRequested += (DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs args) => args.Accept(); // We auto-accept numeric comparison result for the sake of simplicity
DevicePairingResult result = await customPairing.PairAsync(DevicePairingKinds.ConfirmPinMatch);
Console.WriteLine("Pairing Result: " + result.Status.ToString());
}
public static async Task Unpair(ulong uuid)
{
Console.WriteLine("Unpairing...");
var bluetoothLEDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(uuid);
if (bluetoothLEDevice == null)
{
Console.WriteLine("UUID not found!");
return;
}
DeviceUnpairingResult result = await bluetoothLEDevice.DeviceInformation.Pairing.UnpairAsync();
Console.WriteLine("Unpairing Result: " + result.Status.ToString());
}
}
}
If I start the program for the first time, the pairing works fine (the unpairing will be ignored as the devices are not paired yet). If I start it immediately again afterwards, it also works fine. Unpairing and pairing will both take place. But if I wait a while (typically 5-10 minutes) while not doing anything, when I start the program again, it will unpair, but then it will wait indefinitely for PairAsync() to return. No coupling request will show on the nRF Connect App, and no PairingRequested event will appear.
Aborting the stuck program and restarting it won't help. In this case, even though the smartphone is found by the BluetoothLEAdvertisementWatcher, BluetoothLEDevice.FromBluetoothAddressAsync(uuid) will return null and the device can't be paired anymore. This can only be resolved by restarting the computer or switching off and on the advertisement in the nRF Connect App, as in this case a new random BLE Address is created for the device.
I have taken a snapshot of the BLE events using Btetlparse and Wireshark. It seems that there is a problem with a malformed package:
However, I don't really understand what is going wrong. Is this a problem of the nRF Connect App? Or the UWP commands? Or did I do something wrong? I tried two different smartphones (a Samsung Galaxy and an Oppo), so I doubt that it is a problem of the smartphone. I also added a DeviceWatcher, but this didn't change anything. Can anyone help me here?
I have an appium server created in NODE.JS. I am working out to make the appium test to run an emulator and install the apk. Not able to find any particular examples online that has example on how to do it using Node server. Mostly examples are with the desktop installed appium server. I need some guidelines on how to do that. To further break it down, I want to perform following things using the appium Node server (Not to right any test case in the application source code)
Start the emulator or possible if can do it on real device
Install the APK on the emulator/device
Fire an intent that launches the app on emulator/device . Intent also contains data in bundle
Perform a click on a button inside the app.
start appium server in your terminal
appium
Output of above command like below on your terminal
Sample code here :
public class AppTest {
AppiumDriver driver;
MobileElement appTitle;
#Before
public void setup() throws MalformedURLException {
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
desiredCapabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
desiredCapabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.0");
desiredCapabilities.setCapability(MobileCapabilityType.NO_RESET, true);
desiredCapabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Moto");
desiredCapabilities.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "com.android.vending");
desiredCapabilities.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, "com.google.android.finsky.activities.MainActivity");
driver = new AndroidDriver(new URL("http://0.0.0.0:4723/wd/hub"), desiredCapabilities);
}
#Test
public void testGooglePlayApp() throws InterruptedException {
String appName = "Amazon Now - Grocery Shopping";
//How to scroll to specific text
MobileElement scrollToText = (MobileElement) driver.findElement(MobileBy.AndroidUIAutomator("new UiScrollable(new UiSelector()).scrollIntoView(new UiSelector().text(\"" + appName + "\"));"));
scrollToText.click();
// Verifying the app detail page
appTitle = (MobileElement) driver.findElementById("com.android.vending:id/title_title");
Assert.assertTrue(appName.equals(appTitle.getText().trim()));
driver.navigate().back();
//Clicking the search bar icon
MobileElement scrollToElement = (MobileElement) driver.findElement(MobileBy.AndroidUIAutomator("new UiScrollable(new UiSelector()).scrollIntoView(new UiSelector().description(\"Search\"));"));
scrollToElement.click();
MobileElement editText = (MobileElement) driver.findElementById("com.android.vending:id/search_box_text_input");
editText.sendKeys(appName);
Thread.sleep(1000);
List<MobileElement> listOfSuggestedResults = driver.findElementsById("com.android.vending:id/suggest_text");
for (MobileElement element : listOfSuggestedResults) {
if (appName.equals(element.getText().trim())) {
element.click();
break;
}
}
appTitle = (MobileElement) driver.findElementById("com.android.vending:id/title_title");
Assert.assertTrue(appName.equals(appTitle.getText().trim()));
}
#After
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
Sample code in github : https://github.com/tech-tock-tech/apptest
hope above will help if you still facing issue please check below video link -
https://www.youtube.com/watch?v=jP2NAY8ylp8
I've seen a bit everywhere the Selenium Grid solution to run parallel test but I don't know if this works with physical devices or only virtual and what I need is to test on multiple physical devices.
So I tried to do it "my way" for the moment what I have done is creating a selenium server & driver for each of my physical devices and run my tests but the main issue I encounter is that the test are not really parallel ...
Step 1 Server one open & driver one is created
Step 2 Server two open & driver two is created
Step 3 test1 start on driver one until it finish
Step 4 test1 start on driver two until it finish
Step 5 test2 start on driver one
....
Is there a way to make it really parallel ?
Here is my code :
Create server
public static AppiumServer startServer (String deviceName){
String port="";
String boostrapPort="";
switch (deviceName){
case ONEPLUS_ONE :
port = ONEPLUS_ONE_PORT;
boostrapPort = ONEPLUS_ONE_BOOTSTRAP_PORT;
break;
.....
}
ServerArguments serverArguments = new ServerArguments();
serverArguments.setArgument("--address", "127.0.0.1");
serverArguments.setArgument("--port", port);
serverArguments.setArgument("--bootstrap-port", boostrapPort);
AppiumServer appiumServer = new AppiumServer(serverArguments);
appiumServer.startServer();
return appiumServer;
}
Create driver :
#BeforeTest(alwaysRun = true)
public void setUp(){
AppiumServer samsung_S6_server = AppiumServerFactory.startServer(AppiumServerFactory.SAMSUNG_S6);
if(samsung_S6_server.isServerRunning()) {
AndroidDriver samsung_S6 = AndroidDriverFactory.getAndroidDriver(appPackage, appActivity, AppiumServerFactory.SAMSUNG_S6_PORT, AppiumServerFactory.SAMSUNG_S6);
serverList.add(samsung_S6_server);
driverList.add(samsung_S6);
} else {
System.out.println("Server running issue");
}
AppiumServer oneplus_one_server = AppiumServerFactory.startServer(AppiumServerFactory.ONEPLUS_ONE);
if(oneplus_one_server.isServerRunning()) {
AndroidDriver oneplus_one = AndroidDriverFactory.getAndroidDriver(appPackage, appActivity, AppiumServerFactory.ONEPLUS_ONE_PORT, AppiumServerFactory.ONEPLUS_ONE);
serverList.add(oneplus_one_server);
driverList.add(oneplus_one);
} else {
System.out.println("Server running issue");
}
The tests :
#Test
public void openArticle (){
for(AndroidDriver driver : driverList){
WebElement el = driver.findElements(By.id("..."));
el.click();
}
}
.....
I am intermittently getting Too many open files exceptions when I try to write to a text file in my Xamarin / Android app.
I understand that this is because each Android app has a limit on the number of files it can have open, and obviously my app is exceeding it in some circumstances. Hence I must be leaving some files open / not disposing of them properly somewhere.
I would like to know if I can programatically list the files that my app has open at any given time? Obviously the operating system knows this, is it possible to do this from within my app? This will help me find the problem.
Thanks to fiddler, this is how I solved it in case anyone else needs to do it in the future (in C# / Xamarin):
private static List<string> m_commandData;
private static void GetOpenedFiles()
{
m_commandData = new List<string>();
RunCommand("lsof");
RunCommand("ps | grep TestNoFilesOpen");
}
private static void RunCommand(string command)
{
string data;
using (Java.Lang.Process process = Java.Lang.Runtime.GetRuntime().Exec(command))
{
Stream stream = process.InputStream;
StreamReader bodyReader = new StreamReader(stream);
data = bodyReader.ReadToEnd();
}
m_commandData.Add(data);
}
private static void WriteCommands()
{
for (int i = 0; i < m_commandData.Count; i++)
{
using (TextWriter tw = new StreamWriter(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/NoFilesOpen/adb_" + i.ToString() + ".txt"))
{
tw.Write(m_commandData[i]);
tw.Close();
}
}
m_commandData = new List<string>();
}
You could use the Unix lsof command in the ADB shell.
1) Start the shell:
$ adb shell
2) Find the process ID of your app:
shell#android:/ $ ps | grep <packagename>
3) List files opened by your app:
shell#android:/ $ lsof <pid>
I've implemented a service that listens to commands issued through ADB. An example of a command sent through ADB could look like this:
adb shell am startservice -a com.testandroid.SEND_SMS -e number 123123123 -e message "åäö"
Now, the problem here is that the encoding of the string "åäö" seems to mess up. If I take that string extras and immediately output it to the log, I get a square "[]", unknown character. If I send this message I get chinese characters in the messages app. As long as I stick to non-umlaut characters (ASCII I guess), everything works fine.
I'm using Windows 7 and the command line for this. I have not touched the encoding of the command line and I've tried to process the extras string by getting the byte characters, passing in UTF-8 as an encoding argument, then creating a new String passing in UTF-8 as an encoding argument there as well. No dice, though.
The values of the bytes, when using getBytes() are å: -27, ä: -92, ö: -74
How do I get this to play nice so I can make use of at least the umlauts?
All of this works perfectly fine in Linux.
i ran into the same issue, but finally i got it work!
if you use for example C#, you have to do it like the following example:
02.12.2019
According to the protocol.txt, the ADB-Protocol supports "smart-sockets". Those sockets can be used to do all the stuff, the ADB-Client inside the adb.exe does. For example if you want upload an file, you have to request such an "smart-socket". After that, you have to follow the protocol assigned to the service (for an service overview see SERVICE.txt) as described, for example, in the SYNC.txt.
13.10.2014
public static List<string> ExecuteBG(string exe, string args, int timeOut = -1)
{
if (File.Exists(exe) || exe == "cmd.exe")
{
ProcessStartInfo StartInfo = new ProcessStartInfo();
StartInfo.FileName = exe;
StartInfo.Arguments = Encoding.Default.GetString(Encoding.UTF8.GetBytes(args));
StartInfo.CreateNoWindow = true;
StartInfo.UseShellExecute = false;
StartInfo.RedirectStandardError = true;
StartInfo.RedirectStandardOutput = true;
StartInfo.StandardErrorEncoding = Encoding.UTF8;
StartInfo.StandardOutputEncoding = Encoding.UTF8;
AutoResetEvent errorWaitHandle = new AutoResetEvent(false);
AutoResetEvent outputWaitHandle = new AutoResetEvent(false);
List<string> response = new List<string>();
Process proc = new Process();
proc.StartInfo = StartInfo;
proc.ErrorDataReceived += (s, e) =>
{
if (String.IsNullOrEmpty(e.Data))
{
errorWaitHandle.Set();
}
else
{
response.Add(e.Data);
}
};
proc.OutputDataReceived += (s, e) =>
{
if (String.IsNullOrEmpty(e.Data))
{
outputWaitHandle.Set();
}
else
{
response.Add(e.Data);
}
};
proc.Start();
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit(timeOut);
errorWaitHandle.WaitOne(timeOut);
outputWaitHandle.WaitOne(timeOut);
return response;
}
return new List<string>();
}
Really important is this part "StartInfo.Arguments = Encoding.Default.GetString(Encoding.UTF8.GetBytes(args));", here we convert the UTF8 string into the Windows "default" charset which is known by cmd. So we send a "destroyed" "default" encoded string to cmd and the Android shell will convert it back to UTF8. So we have the "umlauts" like "üöäÜÖÄàè etc.".
Hope this helps someone.
PS: If u need a working "Framework" which supports UTF8 push/pull for files/folders also have a look at my AndroidCtrl.dll it's C# .NET4 written.
Regards,
Sebastian
Concluding, either the problem is situated in cmd.exe or adb.exe. Until either one or both are updated to be more compliant with eachother I will sadly not be able to make use of this for the time being.