When running CulebraTestCase tests, this line in the AdbClient#shell() seems to cause deadlocks between main thread and RunTestsThread thread, as it should have either with self.lock or separate self.lock.acquire() and self.lock.release() statements, but not both.
Long version:
I have an issue with running code generated by Culebra Tester.
I'm currently trying to setup some python tests using Culebra Tester and AndroidViewClient.
The following code, generated by Culebra Tester app (after recording a couple of user clicks), gets stuck without ever reaching the test function itself:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
Copyright (C) 2013-2018 Diego Torres Milano
Created on 2018-08-02 by CulebraTester
__ __ __ __
/ \ / \ / \ / \
____________________/ __\/ __\/ __\/ __\_____________________________
___________________/ /__/ /__/ /__/ /________________________________
| / \ / \ / \ / \ \___
|/ \_/ \_/ \_/ \ o \
\_____/--<
@author: Diego Torres Milano
@author: Jennifer E. Swofford (ascii art snake)
'''
import re
import sys
import os
import unittest
try:
sys.path.insert(0, os.path.join(os.environ['ANDROID_VIEW_CLIENT_HOME'], 'src'))
except:
pass
import pkg_resources
pkg_resources.require('androidviewclient>=12.4.0')
from com.dtmilano.android.viewclient import ViewClient, CulebraTestCase
from com.dtmilano.android.uiautomator.uiautomatorhelper import UiAutomatorHelper, UiScrollable, UiObject, UiObject2
TAG = 'CULEBRA'
class CulebraTests(CulebraTestCase):
@classmethod
def setUpClass(cls):
cls.kwargs1 = {'ignoreversioncheck': False, 'verbose': False, 'ignoresecuredevice': False}
cls.kwargs2 = {'forceviewserveruse': False, 'useuiautomatorhelper': True, 'ignoreuiautomatorkilled': True, 'autodump': False, 'startviewserver': True, 'compresseddump': True}
cls.options = {'start-activity': None, 'concertina': False, 'device-art': None, 'use-jar': False, 'multi-device': False, 'unit-test-class': True, 'save-screenshot': None, 'use-dictionary': False, 'glare': False, 'dictionary-keys-from': 'id', 'scale': 1, 'find-views-with-content-description': True, 'window': -1, 'orientation-locked': None, 'save-view-screenshots': None, 'find-views-by-id': True, 'log-actions': False, 'use-regexps': False, 'null-back-end': False, 'auto-regexps': None, 'do-not-verify-screen-dump': True, 'verbose-comments': False, 'gui': False, 'find-views-with-text': True, 'prepend-to-sys-path': False, 'install-apk': None, 'drop-shadow': False, 'output': None, 'unit-test-method': None,'interactive': False}
cls.sleep = 5
def setUp(self):
super(CulebraTests, self).setUp()
def tearDown(self):
super(CulebraTests, self).tearDown()
def preconditions(self):
if not super(CulebraTests, self).preconditions():
return False
return True
def test_something(self):
print("Something") # Execution doesn't even reach this point
if not self.preconditions():
self.fail('Preconditions failed')
_s = CulebraTests.sleep
_v = CulebraTests.verbose
# a few UI clicks recorded here by Culebra Tester ...
self.fail("Fail") # added fail statement here
pass
if __name__ == '__main__':
CulebraTests.main()
After tracing the AndroidViewClient code, enabling DEBUG logs in viewclient.py, uiautomatorhelper.py, adbclient.py and debugging the code execution, turns out there's a deadlock between UiAutomatorHelper#__connectSession() and RunTestsThread#run().
Adding some log statements for adb shell executions shows that AdbClient#shell() command is not releasing its lock properly, as RunTestsThread gets stuck on that lock when it tries to execute its force-stop shell command:
That part should have either with self.lock or separate self.lock.acquire() and self.lock.release() statements, but not both.
That force-stop command is the first one executed from a separate thread, so naturally as the lock in AdbClient is a re-entrant lock, all previous shell commands (executed from main thread) re-acquire lock normally.
TL;DR:
When running
CulebraTestCase
tests, this line in theAdbClient#shell()
seems to cause deadlocks between main thread and RunTestsThread thread, as it should have eitherwith self.lock
or separateself.lock.acquire()
andself.lock.release()
statements, but not both.Long version:
I have an issue with running code generated by Culebra Tester.
I'm currently trying to setup some python tests using Culebra Tester and AndroidViewClient. The following code, generated by Culebra Tester app (after recording a couple of user clicks), gets stuck without ever reaching the test function itself:
After tracing the AndroidViewClient code, enabling DEBUG logs in
viewclient.py
,uiautomatorhelper.py
,adbclient.py
and debugging the code execution, turns out there's a deadlock betweenUiAutomatorHelper#__connectSession()
andRunTestsThread#run()
.Adding some log statements for adb shell executions shows that AdbClient#shell() command is not releasing its lock properly, as RunTestsThread gets stuck on that lock when it tries to execute its
force-stop
shell command:The culprit here seems to be this line in the AdbClient#shell():
That part should have either
with self.lock
or separateself.lock.acquire()
andself.lock.release()
statements, but not both.That
force-stop
command is the first one executed from a separate thread, so naturally as the lock in AdbClient is a re-entrant lock, all previous shell commands (executed from main thread) re-acquire lock normally.I will send a pull request with a fix.