diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py index 57433c7c..f52e4f05 100644 --- a/src/bitmessagekivy/mpybit.py +++ b/src/bitmessagekivy/mpybit.py @@ -1,4 +1,6 @@ import state +# import tempfile +# state.appdata = tempfile.gettempdir() print('state.appdata (mpybit.py line no. (1))....................................', state.appdata) # pylint: disable=too-many-lines,import-error,no-name-in-module,unused-argument # pylint: disable=too-many-ancestors,too-many-locals,useless-super-delegation @@ -19,6 +21,7 @@ from bitmessagekivy import identiconGeneration from bitmessagekivy import kivy_helper_search from bitmessagekivy.uikivysignaler import UIkivySignaler from bmconfigparser import BMConfigParser +from debug import logger from functools import partial from helper_sql import sqlExecute, sqlQuery from kivymd.app import MDApp @@ -85,7 +88,6 @@ from kivy.lang import Observable import gettext import l10n import locale -from debug import logger if platform != "android": from kivy.config import Config @@ -1944,6 +1946,8 @@ class NavigateApp(MDApp): # @staticmethod def clickNavDrawer(self): + # import tempfile + # state.appdata = tempfile.gettempdir() state.kivyapp.root.ids.nav_drawer.set_state('toggle') @staticmethod diff --git a/src/bitmessagekivy/tests/common_data.py b/src/bitmessagekivy/tests/common_data.py new file mode 100644 index 00000000..ee796a7b --- /dev/null +++ b/src/bitmessagekivy/tests/common_data.py @@ -0,0 +1,35 @@ +import os +import sys +import time +import unittest + + +_files = ( + 'keys.dat', 'debug.log', 'messages.dat', 'knownnodes.dat', + '.api_started', 'unittest.lock' +) + + +def cleanup(home=None, files=_files): + """Cleanup application files""" + if not home: + import state + home = state.appdata + for pfile in files: + try: + os.remove(os.path.join(home, pfile)) + print(__file__,'.........................................(clean)', pfile) + except OSError: + pass + + +def skip_python3(): + """Raise unittest.SkipTest() if detected python3""" + # if sys.hexversion >= 0x3000000: + # raise unittest.SkipTest('Module is not ported to python3') + + +def put_signal_file(path, filename): + """Creates file, presence of which is a signal about some event.""" + with open(os.path.join(path, filename), 'wb') as outfile: + outfile.write(b'%i' % time.time()) diff --git a/src/bitmessagekivy/tests/telenium_process.py b/src/bitmessagekivy/tests/telenium_process.py new file mode 100644 index 00000000..728581b8 --- /dev/null +++ b/src/bitmessagekivy/tests/telenium_process.py @@ -0,0 +1,15 @@ +import os +import tempfile +from telenium.tests import TeleniumTestCase +from bitmessagekivy.tests.test_process_data import TestProcessProto + +class TeleniumTestProcess(TestProcessProto, TeleniumTestCase): + """Setting Screen Functionality Testing""" + cmd_entrypoint = ['/home/cis/py3porting/Chatroom/PyBitmessage/src/main.py'] + + @classmethod + def setUpClass(cls): + print('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX') + os.environ["BITMESSAGE_HOME"] = tempfile.gettempdir() + TeleniumTestCase.start_process() + super(TeleniumTestProcess, cls).setUpClass() diff --git a/src/bitmessagekivy/tests/test_addressbook.py b/src/bitmessagekivy/tests/test_addressbook.py new file mode 100644 index 00000000..3cfdf716 --- /dev/null +++ b/src/bitmessagekivy/tests/test_addressbook.py @@ -0,0 +1,109 @@ +import time +from bitmessagekivy.tests.telenium_process import TeleniumTestProcess + + +class AddressBook(TeleniumTestProcess): + """AddressBook Screen Functionality Testing""" + + def test_save_address(self): + """Save Address On Address Book Screen/Window""" + print("=====================Test -Save Address In Address Book=====================") + time.sleep(6) + self.cli.execute('app.clickNavDrawer()') + time.sleep(4) + self.cli.drag("//NavigationItem[@text=\"Sent\"]","//NavigationItem[@text=\"Inbox\"]",1) + time.sleep(3) + self.cli.click_on('//NavigationItem[6]') + time.sleep(4) + self.cli.execute('app.addingtoaddressbook()') + time.sleep(3) + self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[0]') + time.sleep(4) + self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[1]') + time.sleep(4) + self.cli.click_on('//MDRaisedButton[0]') + time.sleep(4) + self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[0]') + time.sleep(3) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[0]','text','peter') + time.sleep(3) + self.cli.click_on('//MDRaisedButton[0]') + time.sleep(4) + self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[1]') + time.sleep(3) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]','text','sectorAppartment') + time.sleep(3) + self.cli.click_on('//MDRaisedButton[0]') + time.sleep(5) + self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[1]') + time.sleep(3) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]','text',data[0]) + time.sleep(3) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]','text','') + time.sleep(3) + self.cli.click_on('//MDRaisedButton[0]') + time.sleep(4) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]','text','BM-2cX78L9CZpb6GGC3rRVizYiUBwHELMLybd') + time.sleep(3) + self.cli.click_on('//MDRaisedButton[0]') + time.sleep(4) + + def test_cancel_address(self): + """Cancel Address""" + print("=====================Test -Cancel Address=====================") + time.sleep(3) + self.cli.execute('app.addingtoaddressbook()') + time.sleep(3) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[0]','text','prachi') + time.sleep(3) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]','text',data[0]) + time.sleep(3) + self.cli.click_on('//MDRaisedButton[1]') + + def test_send_message_to_addressbook(self): + """Directly Send Message To The User""" + print("=====================Test -Directly Send Message To The User=====================") + time.sleep(4) + self.cli.click_on('//AddressBook/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]') + time.sleep(3) + self.cli.click_on('//MDRaisedButton[0]') + time.sleep(3) + self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[0]/BoxLayout[0]/CustomSpinner[0]/ArrowImg[0]') + time.sleep(2) + self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]') + time.sleep(3) + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]', 'text', 'Second') + time.sleep(3) + random_label="" + for char in "Hey This is Message From Address Book": + random_label += char + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]', 'text', random_label) + time.sleep(0.2) + self.cli.click_on('//MDIconButton[2]') + time.sleep(2) + + def test_delete_address_from_address_contact(self): + """Delete Address From Address Book""" + print("=====================Test -Delete Address From Address Book=====================") + time.sleep(3) + self.cli.execute('app.clickNavDrawer()') + time.sleep(3) + self.cli.click_on('//NavigationItem[6]') + time.sleep(3) + self.cli.drag('//AddressBook/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]//TwoLineAvatarIconListItem[0]/BoxLayout[0]', + '//AddressBook/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]//TwoLineAvatarIconListItem[0]/BoxLayout[2]', 2) + time.sleep(2) + self.cli.click_on('//AddressBook/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]//Button[0]') + + def test_all_address_book_method(self): + self.test_save_address() + self.test_cancel_address() + self.test_send_message_to_addressbook() + self.test_delete_address_from_address_contact() + + +if __name__ == '__main__': + """Start Application""" + obj = AddressBook() + obj.setUpClass() + obj.test_all_address_book_method() diff --git a/src/bitmessagekivy/tests/test_allmail_message.py b/src/bitmessagekivy/tests/test_allmail_message.py new file mode 100644 index 00000000..7e0c4f09 --- /dev/null +++ b/src/bitmessagekivy/tests/test_allmail_message.py @@ -0,0 +1,32 @@ +import time +from bitmessagekivy.tests.telenium_process import TeleniumTestProcess + + +class AllMailMessage(TeleniumTestProcess): + """AllMail Screen Functionality Testing""" + + def test_select_all_mails(self): + """Show All Messages on Mail Screen/Window""" + print("=====================Test -Show Messages Of Mail Screen=====================") + time.sleep(5) + self.cli.execute('app.clickNavDrawer()') + time.sleep(4) + self.cli.click_on('//NavigationItem[5]') + time.sleep(4) + + def test_delete_message_from_draft(self): + """Delete Message From Message body of Mail Screen/Window""" + print("=====================Test -Delete Messages Of Mail Screen=====================") + time.sleep(4) + self.cli.click_on('//Allmails[0]/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]') + time.sleep(5) + self.cli.click_on('//MDToolbar/BoxLayout[2]/MDIconButton[0]') + time.sleep(3) + + +if __name__ == '__main__': + """Start Application""" + obj = AllMailMessage() + obj.setUpClass() + obj.test_select_all_mails() + obj.test_delete_message_from_draft() diff --git a/src/bitmessagekivy/tests/test_create_random_address.py b/src/bitmessagekivy/tests/test_create_random_address.py index a009efe1..c5f8a818 100644 --- a/src/bitmessagekivy/tests/test_create_random_address.py +++ b/src/bitmessagekivy/tests/test_create_random_address.py @@ -1,25 +1,18 @@ -import state +# import state import os import tempfile -state.appdata = tempfile.gettempdir() +# state.appdata = tempfile.gettempdir() import time from random import choice from string import ascii_lowercase -from telenium.tests import TeleniumTestCase -from tests.test_process import TestProcessProto, TestProcessShutdown +from bitmessagekivy.tests.telenium_process import TeleniumTestProcess -class CreateRandomAddress(TestProcessProto, TeleniumTestCase): - cmd_entrypoint = ['/home/cis/py3porting/Chatroom/PyBitmessage/src/main.py'] +class CreateRandomAddress(TeleniumTestProcess): - # @classmethod - # def setUpClass(cls): - # print('inside class Method..............................................9') - # pass - - def test_runTest(self): - """Test Run Method.""" - print(self,"=====================Welcome To Kivy Testing Application=====================") + @classmethod + def setUpClass(cls): + super(CreateRandomAddress, cls).setUpClass() def test_login_screen(self): """Clicking on Proceed Button to Proceed to Next Screen.""" @@ -81,13 +74,11 @@ class CreateRandomAddress(TestProcessProto, TeleniumTestCase): if __name__ == '__main__': """Start Application""" - TeleniumTestCase.start_process() obj = CreateRandomAddress() - obj.setUpClass() - print(state.appdata, '===================================^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^', os.environ['BITMESSAGE_HOME']) - obj.test_runTest() + obj.setUpClass() # this is for showing another process running error obj.test_login_screen() obj.test_random_screen() obj.test_create_new_address() obj.test_random_screen() obj.test_select_address() + obj.remove_temp_data() diff --git a/src/bitmessagekivy/tests/test_draft_message.py b/src/bitmessagekivy/tests/test_draft_message.py index f37297a7..b1a0cb52 100644 --- a/src/bitmessagekivy/tests/test_draft_message.py +++ b/src/bitmessagekivy/tests/test_draft_message.py @@ -1,13 +1,10 @@ import time -from telenium.tests import TeleniumTestCase +from bitmessagekivy.tests.telenium_process import TeleniumTestProcess -class DraftMessage(TeleniumTestCase): +class DraftMessage(TeleniumTestProcess): """Draft Screen Functionality Testing""" - def runTest(self): - print(self,"-------------Welcome To Kivy Testing Application Fourth Page-------------") - def test_select_draft_message(self): """Select A Draft Screen From Navigaion-Drawer-Box Then Send a drafted message """ @@ -100,10 +97,6 @@ class DraftMessage(TeleniumTestCase): if __name__ == '__main__': """Start Application""" - import tempfile - import state - state.appdata = tempfile.gettempdir() - print('state.appdata..........................(105)', state.appdata) - TeleniumTestCase.start_process() obj = DraftMessage() + obj.setUpClass() obj.test_all_draft_method() diff --git a/src/bitmessagekivy/tests/test_myaddress_screen.py b/src/bitmessagekivy/tests/test_myaddress_screen.py new file mode 100644 index 00000000..b1d0db83 --- /dev/null +++ b/src/bitmessagekivy/tests/test_myaddress_screen.py @@ -0,0 +1,58 @@ +import time +from bitmessagekivy.tests.telenium_process import TeleniumTestProcess + + +class MyAddressScreen(TeleniumTestProcess): + """MyAddress Screen Functionality Testing""" + + def test_select_myaddress_list(self): + """Select Address From List of Address""" + print("=====================Test -Select Address From List of Address=====================") + time.sleep(4) + self.cli.execute('app.clickNavDrawer()') + time.sleep(3) + self.cli.drag("//NavigationItem[@text=\"Sent\"]","//NavigationItem[@text=\"Inbox\"]",1) + time.sleep(3) + self.cli.click_on('//NavigationItem[11]') + time.sleep(4) + + def test_show_Qrcode(self): + """Show the Qr code of selected address""" + print("=====================Test -Show QR code of selected address=====================") + time.sleep(4) + self.cli.click_on('//MyAddress/BoxLayout[0]/FloatLayout[0]/MDScrollViewRefreshLayout[0]/MDList[0]/CustomTwoLineAvatarIconListItem[0]') + time.sleep(3) + self.cli.click_on('//MyaddDetailPopup/BoxLayout[1]/MDRaisedButton[1]/MDLabel[0]') + time.sleep(3) + self.cli.click_on('//MDToolbar/BoxLayout[0]/MDIconButton[0]') + time.sleep(3) + + def test_send_message_from(self): + """Send Message From Send Message From Button""" + print("=====================Test -Send Message From Send Message From Button=====================") + time.sleep(4) + self.cli.click_on('//MyAddress/BoxLayout[0]/FloatLayout[0]/MDScrollViewRefreshLayout[0]/MDList[0]/CustomTwoLineAvatarIconListItem[0]') + time.sleep(4) + self.cli.click_on('//MyaddDetailPopup/BoxLayout[1]/MDRaisedButton[0]/MDLabel[0]') + time.sleep(3) + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput', "text", data[1]) + time.sleep(3) + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]', 'text', 'Hey') + time.sleep(3) + random_label="" + for char in "Hey,i am sending message directly from MyAddress book": + random_label += char + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]', 'text', random_label) + time.sleep(0.2) + time.sleep(2) + self.cli.click_on('//MDIconButton[2]') + time.sleep(2) + + +if __name__ == '__main__': + """Start Application""" + obj = MyAddressScreen() + obj.setUpClass() + obj.test_select_myaddress_list() + obj.test_show_Qrcode() + obj.test_send_message_from() diff --git a/src/bitmessagekivy/tests/test_network_screen.py b/src/bitmessagekivy/tests/test_network_screen.py new file mode 100644 index 00000000..6e87eb96 --- /dev/null +++ b/src/bitmessagekivy/tests/test_network_screen.py @@ -0,0 +1,26 @@ +import time +from bitmessagekivy.tests.telenium_process import TeleniumTestProcess + + +class NetwrokStatusScreen(TeleniumTestProcess): + """NetwrokStatus Screen Functionality Testing""" + + def test_network_status(self): + """Show NetwrokStatus""" + print("=====================Test -Show NetwrokStatus=====================") + time.sleep(4) + self.cli.execute('app.clickNavDrawer()') + time.sleep(3) + self.cli.drag("//NavigationItem[@text=\"Sent\"]","//NavigationItem[@text=\"Inbox\"]",1) + time.sleep(3) + self.cli.click_on('//NavigationItem[10]') + time.sleep(4) + self.cli.click_on('//NetworkStat/MDTabs[0]/MDTabsBar[0]/MDTabsScrollView[0]/MDGridLayout[0]/MDTabsLabel[1]') + time.sleep(4) + + +if __name__ == '__main__': + """Start Application""" + obj = NetwrokStatusScreen() + obj.setUpClass() + obj.test_network_status() diff --git a/src/bitmessagekivy/tests/test_payment_subscription.py b/src/bitmessagekivy/tests/test_payment_subscription.py new file mode 100644 index 00000000..320733f0 --- /dev/null +++ b/src/bitmessagekivy/tests/test_payment_subscription.py @@ -0,0 +1,33 @@ +import time +from bitmessagekivy.tests.telenium_process import TeleniumTestProcess + + +class PaymentScreen(TeleniumTestProcess): + """SubscriptionPayment Screen Functionality Testing""" + + def test_select_subscripton(self): + """Select Subscripton From List of Subscriptons""" + print("=====================Test -Select Subscripton From List of Subscriptons=====================") + time.sleep(4) + self.cli.execute('app.clickNavDrawer()') + time.sleep(3) + self.cli.drag("//NavigationItem[@text=\"Sent\"]","//NavigationItem[@text=\"Inbox\"]",1) + time.sleep(3) + self.cli.click_on('//NavigationItem[8]') + time.sleep(3) + self.cli.drag('//Payment/BoxLayout[0]/ScrollView[0]/BoxLayout[0]/ProductCategoryLayout[0]/ProductLayout[1]', + '//Payment/BoxLayout[0]/ScrollView[0]/BoxLayout[0]/ProductCategoryLayout[0]/ProductLayout[0]', 1) + time.sleep(2) + self.cli.click_on('//MDRaisedButton[3]') + time.sleep(2) + self.cli.click_on('//ListItemWithLabel[0]') + time.sleep(2) + self.cli.click_on('//MDRaisedButton[3]') + time.sleep(2) + + +if __name__ == '__main__': + """Start Application""" + obj = PaymentScreen() + obj.setUpClass() + obj.test_select_subscripton() diff --git a/src/bitmessagekivy/tests/test_process_data.py b/src/bitmessagekivy/tests/test_process_data.py new file mode 100644 index 00000000..dc70507f --- /dev/null +++ b/src/bitmessagekivy/tests/test_process_data.py @@ -0,0 +1,203 @@ +""" +Common reusable code for tests and tests for pybitmessage process. +""" + +import os +import signal +import subprocess # nosec +import sys +import state +import tempfile +import time +import unittest + +import psutil + +from .common_data import cleanup, put_signal_file, skip_python3 + +skip_python3() + + +class TestProcessProto(unittest.TestCase): + """Test case implementing common logic for external testing: + it starts pybitmessage in setUpClass() and stops it in tearDownClass() + """ + _process_cmd = ['pybitmessage', '-d'] + _threads_count_min = 15 + _threads_count_max = 16 + _threads_names = [ + 'PyBitmessage', + 'addressGenerato', + 'singleWorker', + 'SQL', + 'objectProcessor', + 'singleCleaner', + 'singleAPI', + 'Asyncore', + 'ReceiveQueue_0', + 'ReceiveQueue_1', + 'ReceiveQueue_2', + 'Announcer', + 'InvBroadcaster', + 'AddrBroadcaster', + 'Downloader', + 'Uploader' + ] + _files = ( + 'keys.dat', 'debug.log', 'messages.dat', 'knownnodes.dat', + '.api_started', 'unittest.lock' + ) + home = None + + @classmethod + def setUpClass(cls): + """Setup environment and start pybitmessage""" + print('setUpClass.........................................(pass)', state.appdata) + # print('os.environ["BITMESSAGE_HOME"](test_process file)57...........................', os.environ['BITMESSAGE_HOME']) + print(__file__, 'cls.home..................................', cls.home) + cls.flag = False + # if os.environ.get('BITMESSAGE_HOME'): + # cls._cleanup_files() + # cls.home = os.environ.get('BITMESSAGE_HOME') + # else: + # if not cls.home: + # cls.home = tempfile.gettempdir() + # cls._cleanup_files() + # os.environ['BITMESSAGE_HOME'] = cls.home + cls.flag = False + if not cls.home: + cls.home = tempfile.gettempdir() + cls._cleanup_files() + os.environ['BITMESSAGE_HOME'] = cls.home + + print('os.environ["BITMESSAGE_HOME"](test_process file)65...........................', os.environ['BITMESSAGE_HOME']) + put_signal_file(cls.home, 'unittest.lock') + starttime = int(time.time()) - 0.5 + cls.process = psutil.Popen( + cls._process_cmd, stderr=subprocess.STDOUT) # nosec + + pidfile = os.path.join(cls.home, 'singleton.lock') + for _ in range(10): + time.sleep(1) + try: + pstat = os.stat(pidfile) + if starttime <= pstat.st_mtime and pstat.st_size > 0: + break # the pidfile is suitable + except OSError: + continue + + try: + pid = int(cls._get_readline('singleton.lock')) + cls.process = psutil.Process(pid) + time.sleep(5) + except (psutil.NoSuchProcess, TypeError): + cls.flag = True + + def setUp(self): + print('setUp.........................................(pass)') + if self.flag: + self.fail("%s is not started ):" % self._process_cmd) + + @classmethod + def _get_readline(cls, pfile): + print('_get_readline.........................................(pass)') + pfile = os.path.join(cls.home, pfile) + try: + return open(pfile, 'rb').readline().strip() + except (OSError, IOError): + pass + + @classmethod + def _stop_process(cls, timeout=5): + print('_stop_process.........................................(pass)') + cls.process.send_signal(signal.SIGTERM) + try: + cls.process.wait(timeout) + except psutil.TimeoutExpired: + return False + return True + + @classmethod + def _kill_process(cls, timeout=5): + print('_kill_process.........................................') + try: + cls.process.send_signal(signal.SIGKILL) + cls.process.wait(timeout) + # Windows or already dead + except (AttributeError, psutil.NoSuchProcess): + return True + # except psutil.TimeoutExpired propagates, it means something is very + # wrong + return True + + @classmethod + def _cleanup_files(cls): + print('_cleanup_files.........................................(pass)') + cleanup(cls.home, cls._files) + + @classmethod + def tearDownClass(cls): + """Ensures that pybitmessage stopped and removes files""" + print('tearDownClass.........................................(pass)') + try: + if not cls._stop_process(10): + processes = cls.process.children(recursive=True) + processes.append(cls.process) + for p in processes: + try: + p.kill() + except psutil.NoSuchProcess: + pass + except psutil.NoSuchProcess: + pass + finally: + cls._cleanup_files() + + def _test_threads(self): + """Test number and names of threads""" + + # pylint: disable=invalid-name + print('_test_threads.........................................(pass)') + self.longMessage = True + + try: + # using ps for posix platforms + # because of https://github.com/giampaolo/psutil/issues/613 + thread_names = subprocess.check_output([ + "ps", "-L", "-o", "comm=", "--pid", + str(self.process.pid) + ]).split() + except: # pylint: disable=bare-except + thread_names = [] + + running_threads = len(thread_names) + if 0 < running_threads < 30: # adequacy check + extra_threads = [] + missing_threads = [] + for thread_name in thread_names: + if thread_name not in self._threads_names: + extra_threads.append(thread_name) + for thread_name in self._threads_names: + if thread_name not in thread_names: + missing_threads.append(thread_name) + + msg = "Missing threads: {}, Extra threads: {}".format( + ",".join(missing_threads), ",".join(extra_threads)) + else: + running_threads = self.process.num_threads() + if sys.platform.startswith('win'): + running_threads -= 1 # one extra thread on Windows! + msg = "Unexpected running thread count" + + self.assertGreaterEqual( + running_threads, + self._threads_count_min, + msg) + + self.assertLessEqual( + running_threads, + self._threads_count_max, + msg) + + def remove_temp_data(self): + cleanup() diff --git a/src/bitmessagekivy/tests/test_send_message.py b/src/bitmessagekivy/tests/test_sent_message.py similarity index 74% rename from src/bitmessagekivy/tests/test_send_message.py rename to src/bitmessagekivy/tests/test_sent_message.py index 663ab350..5058560a 100644 --- a/src/bitmessagekivy/tests/test_send_message.py +++ b/src/bitmessagekivy/tests/test_sent_message.py @@ -1,20 +1,36 @@ +import os +import queues +import shutil +import tempfile import time + +from bitmessagekivy.tests.telenium_process import TeleniumTestProcess from bmconfigparser import BMConfigParser -from telenium.tests import TeleniumTestCase -class SendMessage(TeleniumTestCase): +class SendMessage(TeleniumTestProcess): """Sent Screen Functionality Testing""" - def runTest(self): - print(self,"-------------Welcome To Kivy Testing Application Thirds Page-------------") + def __init__(self): + print('you are inside telenium init...................................................................................') + # import pdb;pdb.set_trace() + old_source_file = os.path.join( + os.path.abspath(os.path.dirname(__file__)), 'sampleData', 'keys.dat') + # new_destination_file = os.path.join(tempfile.gettempdir(), 'keys.dat') + if not os.path.exists(os.environ['BITMESSAGE_HOME']): + os.mkdir(os.environ['BITMESSAGE_HOME']) + new_destination_file = os.path.join(os.environ['BITMESSAGE_HOME'], 'keys.dat') + shutil.copyfile(old_source_file, new_destination_file) + self.data = BMConfigParser().addresses() + # print(__file__, '...............................addreses in configfile', BMConfigParser().addresses()) def test_select_sent(self): """Sending Message From Inbox Screen opens a pop-up(screen)which send message from sender to reciever""" print("=====================Test - Sending Message From Inbox Screen=====================") time.sleep(2) - self.cli.execute('app.root.ids.nav_drawer.set_state("toggle")') + # self.cli.execute('app.root.ids.nav_drawer.set_state("toggle")') + self.cli.execute('app.clickNavDrawer()') time.sleep(1) self.cli.click_on('//NavigationItem[1]') time.sleep(1) @@ -54,7 +70,7 @@ class SendMessage(TeleniumTestCase): time.sleep(3) self.cli.click_on('//MDFlatButton[0]') time.sleep(6) - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]',"text",data[0]) + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]',"text",self.data[0]) time.sleep(3) self.cli.click_on('//MDIconButton[2]') time.sleep(3) @@ -66,7 +82,8 @@ class SendMessage(TeleniumTestCase): for testing the search and delete functionality for two messages on the screen""" print("=====================Test - Sending Message From Inbox Screen=====================") time.sleep(3) - self.cli.execute('app.root.ids.nav_drawer.set_state("toggle")') + # self.cli.execute('app.root.ids.nav_drawer.set_state("toggle")') + self.cli.execute('app.clickNavDrawer()') time.sleep(5) self.cli.click_on('//NavigationItem[1]') time.sleep(3) @@ -77,7 +94,7 @@ class SendMessage(TeleniumTestCase): self.cli.click_on('//MyTextInput[0]') time.sleep(3) data = BMConfigParser().addresses() - self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]', "text", data[0]) + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]', "text", self.data[0]) time.sleep(3) self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]', 'text', 'Second') time.sleep(3) @@ -97,7 +114,8 @@ class SendMessage(TeleniumTestCase): if __name__ == '__main__': """Start Application""" - TeleniumTestCase.start_process() obj = SendMessage() + obj.setUpClass() obj.test_select_sent() obj.test_sent_multiple_message() + obj.remove_temp_data() diff --git a/src/bitmessagekivy/tests/test_setting_screen.py b/src/bitmessagekivy/tests/test_setting_screen.py new file mode 100644 index 00000000..873b7b15 --- /dev/null +++ b/src/bitmessagekivy/tests/test_setting_screen.py @@ -0,0 +1,28 @@ +import time +from bitmessagekivy.tests.telenium_process import TeleniumTestProcess + + +class SettingScreen(TeleniumTestProcess): + """Setting Screen Functionality Testing""" + + @classmethod + def setUpClass(cls): + super(SettingScreen, cls).setUpClass() + + def test_setting_screen(self): + """Show Setting Screen""" + print("=====================Test -Show Setting Screen=====================") + time.sleep(4) + self.cli.execute('app.clickNavDrawer()') + time.sleep(3) + self.cli.drag("//NavigationItem[@text=\"Sent\"]","//NavigationItem[@text=\"Inbox\"]",1) + time.sleep(3) + self.cli.click_on('//NavigationItem[7]') + time.sleep(2) + + +if __name__ == '__main__': + """Start Application""" + obj = SettingScreen() + obj.setUpClass() + obj.test_setting_screen() diff --git a/src/bitmessagekivy/tests/test_tmp_db_setup.py b/src/bitmessagekivy/tests/test_tmp_db_setup.py new file mode 100644 index 00000000..409465e4 --- /dev/null +++ b/src/bitmessagekivy/tests/test_tmp_db_setup.py @@ -0,0 +1,240 @@ +""" +Common reusable code for tests and tests for pybitmessage process. +""" + +import os +import signal +import subprocess # nosec +import sys +import state +import tempfile +import time +import unittest + +import psutil + +from .common import cleanup, put_signal_file, skip_python3 + + +skip_python3() + + +class TestProcessProto(unittest.TestCase): + """Test case implementing common logic for external testing: + it starts pybitmessage in setUpClass() and stops it in tearDownClass() + """ + _process_cmd = ['pybitmessage', '-d'] + _threads_count_min = 15 + _threads_count_max = 16 + _threads_names = [ + 'PyBitmessage', + 'addressGenerato', + 'singleWorker', + 'SQL', + 'objectProcessor', + 'singleCleaner', + 'singleAPI', + 'Asyncore', + 'ReceiveQueue_0', + 'ReceiveQueue_1', + 'ReceiveQueue_2', + 'Announcer', + 'InvBroadcaster', + 'AddrBroadcaster', + 'Downloader', + 'Uploader' + ] + _files = ( + 'keys.dat', 'debug.log', 'messages.dat', 'knownnodes.dat', + '.api_started', 'unittest.lock' + ) + home = None + + @classmethod + def setUpClass(cls): + """Setup environment and start pybitmessage""" + print('setUpClass.........................................(pass)', state.appdata) + # print('os.environ["BITMESSAGE_HOME"](test_process file)57...........................', os.environ['BITMESSAGE_HOME']) + # import pdb;pdb.set_trace() + print(__file__, 'cls.home..................................', cls.home) + cls.flag = False + if not cls.home: + cls.home = tempfile.gettempdir() + cls._cleanup_files() + os.environ['BITMESSAGE_HOME'] = cls.home + # print("blabla {}".format(__file__)) + print('os.environ["BITMESSAGE_HOME"](test_process file)65...........................', os.environ['BITMESSAGE_HOME']) + put_signal_file(cls.home, 'unittest.lock') + starttime = int(time.time()) - 0.5 + cls.process = psutil.Popen( + cls._process_cmd, stderr=subprocess.STDOUT) # nosec + + pidfile = os.path.join(cls.home, 'singleton.lock') + for _ in range(10): + time.sleep(1) + try: + pstat = os.stat(pidfile) + if starttime <= pstat.st_mtime and pstat.st_size > 0: + break # the pidfile is suitable + except OSError: + continue + + try: + pid = int(cls._get_readline('singleton.lock')) + cls.process = psutil.Process(pid) + time.sleep(5) + except (psutil.NoSuchProcess, TypeError): + cls.flag = True + + def setUp(self): + print('setUp.........................................(pass)') + if self.flag: + self.fail("%s is not started ):" % self._process_cmd) + + @classmethod + def _get_readline(cls, pfile): + print('_get_readline.........................................(pass)') + pfile = os.path.join(cls.home, pfile) + try: + return open(pfile, 'rb').readline().strip() + except (OSError, IOError): + pass + + @classmethod + def _stop_process(cls, timeout=5): + print('_stop_process.........................................(pass)') + cls.process.send_signal(signal.SIGTERM) + try: + cls.process.wait(timeout) + except psutil.TimeoutExpired: + return False + return True + + @classmethod + def _kill_process(cls, timeout=5): + print('_kill_process.........................................') + try: + cls.process.send_signal(signal.SIGKILL) + cls.process.wait(timeout) + # Windows or already dead + except (AttributeError, psutil.NoSuchProcess): + return True + # except psutil.TimeoutExpired propagates, it means something is very + # wrong + return True + + @classmethod + def _cleanup_files(cls): + print('_cleanup_files.........................................(pass)') + cleanup(cls.home, cls._files) + + @classmethod + def tearDownClass(cls): + """Ensures that pybitmessage stopped and removes files""" + print('tearDownClass.........................................(pass)') + try: + if not cls._stop_process(10): + processes = cls.process.children(recursive=True) + processes.append(cls.process) + for p in processes: + try: + p.kill() + except psutil.NoSuchProcess: + pass + except psutil.NoSuchProcess: + pass + finally: + cls._cleanup_files() + + def _test_threads(self): + """Test number and names of threads""" + + # pylint: disable=invalid-name + print('_test_threads.........................................(pass)') + self.longMessage = True + + try: + # using ps for posix platforms + # because of https://github.com/giampaolo/psutil/issues/613 + thread_names = subprocess.check_output([ + "ps", "-L", "-o", "comm=", "--pid", + str(self.process.pid) + ]).split() + except: # pylint: disable=bare-except + thread_names = [] + + running_threads = len(thread_names) + if 0 < running_threads < 30: # adequacy check + extra_threads = [] + missing_threads = [] + for thread_name in thread_names: + if thread_name not in self._threads_names: + extra_threads.append(thread_name) + for thread_name in self._threads_names: + if thread_name not in thread_names: + missing_threads.append(thread_name) + + msg = "Missing threads: {}, Extra threads: {}".format( + ",".join(missing_threads), ",".join(extra_threads)) + else: + running_threads = self.process.num_threads() + if sys.platform.startswith('win'): + running_threads -= 1 # one extra thread on Windows! + msg = "Unexpected running thread count" + + self.assertGreaterEqual( + running_threads, + self._threads_count_min, + msg) + + self.assertLessEqual( + running_threads, + self._threads_count_max, + msg) + + +class TestProcessShutdown(TestProcessProto): + """Separate test case for SIGTERM""" + def test_shutdown(self): + """Send to pybitmessage SIGTERM and ensure it stopped""" + # longer wait time because it's not a benchmark + print('test_shutdown.........................................(pass)') + self.assertTrue( + self._stop_process(20), + '%s has not stopped in 20 sec' % ' '.join(self._process_cmd)) + + +# class TestProcess(TestProcessProto): +# """A test case for pybitmessage process""" +# def test_process_name(self): +# """Check PyBitmessage process name""" +# self.assertEqual(self.process.name(), 'PyBitmessage') + +# @unittest.skipIf(psutil.version_info < (4, 0), 'psutil is too old') +# def test_home(self): +# """Ensure BITMESSAGE_HOME is used by process""" +# print('test1......................', self.process.environ().get('BITMESSAGE_HOME')) +# print('test2......................', self.home) +# self.assertEqual( +# self.process.environ().get('BITMESSAGE_HOME'), self.home) + +# def test_listening(self): +# """Check that pybitmessage listens on port 8444""" +# for c in self.process.connections(): +# if c.status == 'LISTEN': +# self.assertEqual(c.laddr[1], 8444) +# break + +# def test_files(self): +# """Check existence of PyBitmessage files""" +# for pfile in self._files: +# if pfile.startswith('.'): +# continue +# self.assertIsNot( +# self._get_readline(pfile), None, +# 'Failed to read file %s' % pfile +# ) + +# def test_threads(self): +# """Testing PyBitmessage threads""" +# self._test_threads() diff --git a/src/bitmessagekivy/tests/test_trash_message.py b/src/bitmessagekivy/tests/test_trash_message.py new file mode 100644 index 00000000..0dacbd93 --- /dev/null +++ b/src/bitmessagekivy/tests/test_trash_message.py @@ -0,0 +1,29 @@ +import time +from bitmessagekivy.tests.telenium_process import TeleniumTestProcess + + +class TrashMessage(TeleniumTestProcess): + """Trash Screen Functionality Testing""" + + def test_delete_trash_message(self): + """Delete Message From List of Message Permanently Of Trash Screen/Window""" + print("=====================Test -Delete Messages Of Trash Screen=====================") + time.sleep(6) + self.cli.execute('app.clickNavDrawer()') + time.sleep(4) + self.cli.click_on('//NavigationItem[4]') + time.sleep(4) + self.cli.drag('//Trash/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]//TwoLineAvatarIconListItem[0]/BoxLayout[0]', + '//Trash/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]//TwoLineAvatarIconListItem[0]/BoxLayout[2]', 2) + time.sleep(4) + self.cli.click_on('//Trash/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/Carousel[0]//Button[0]') + time.sleep(2) + self.cli.click_on('//MDDialog/MDCard[0]/AnchorLayout[0]/MDBoxLayout[0]/MDFlatButton[0]') + time.sleep(4) + + +if __name__ == '__main__': + """Start Application""" + obj = TrashMessage() + obj.setUpClass() + obj.test_delete_trash_message() diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 08ca2d33..32b7a92b 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -152,7 +152,7 @@ class Main(object): # pylint: disable=too-many-statements,too-many-branches,too-many-locals # import tempfile # state.appdata = tempfile.gettempdir() - print('line..........................153(state.appdata)...', state.appdata) + # print('line BABAL..........................153(state.appdata)...', state.appdata) _fixSocket() adjustHalfOpenConnectionsLimit() @@ -261,7 +261,7 @@ class Main(object): # Start the SQL thread # import tempfile # state.appdata = tempfile.gettempdir() - print('state.appdata..........................(258)', state.appdata) + print('state.appdata (bitmessagemain)..........................(258)', state.appdata) sqlLookup = sqlThread() # DON'T close the main program even if there are threads left. # The closeEvent should command this thread to exit gracefully. diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index efbed11e..d553f60c 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -28,7 +28,9 @@ class sqlThread(threading.Thread): def run(self): # pylint: disable=too-many-locals, too-many-branches, too-many-statements """Process SQL queries from `.helper_sql.sqlSubmitQueue`""" - print('state.appdata..............................(31)', state.appdata) + # import tempfile + # state.appdata = tempfile.gettempdir() + print('state.appdata SQL..............................(31)', state.appdata) self.conn = sqlite3.connect(state.appdata + 'messages.dat') self.conn.text_factory = str self.cur = self.conn.cursor() diff --git a/src/helper_startup.py b/src/helper_startup.py index abe41874..21a80b0f 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -32,8 +32,9 @@ StoreConfigFilesInSameDirectoryAsProgramByDefault = False def loadConfig(): """Load the config""" config = BMConfigParser() - - print('state.appdata//////////////////////////////////................(36)', state.appdata) + # import tempfile + # state.appdata = tempfile.gettempdir() + print('state.appdata(helper_startup)......................(36)', state.appdata) if state.appdata: config.read(state.appdata + 'keys.dat') # state.appdata must have been specified as a startup option. @@ -44,13 +45,20 @@ def loadConfig(): 'Loading config files from directory specified' ' on startup: %s', state.appdata) else: + print('line...............................48', paths.lookupExeFolder()) config.read(paths.lookupExeFolder() + 'keys.dat') try: + print('inside try.................................51') config.get('bitmessagesettings', 'settingsversion') + print('inside try.................................53') logger.info('Loading config files from same directory as program.') + print('inside try..................................55') needToCreateKeysFile = False + print('inside try..................................57') state.appdata = paths.lookupExeFolder() + print('pass try.......................................59') except: + print('fail try.......................................', paths.lookupAppdataFolder()) # Could not load the keys.dat file in the program directory. # Perhaps it is in the appdata directory. state.appdata = paths.lookupAppdataFolder() @@ -61,6 +69,7 @@ def loadConfig(): logger.info( 'Loading existing config files from %s', state.appdata) + print('state.appdata(helper_startup)......................(64)', state.appdata) if needToCreateKeysFile: # This appears to be the first time running the program; there is diff --git a/src/paths.py b/src/paths.py index ac90da63..acde4e9a 100644 --- a/src/paths.py +++ b/src/paths.py @@ -37,10 +37,12 @@ def lookupAppdataFolder(): """Returns path of the folder where application data is stored""" APPNAME = "PyBitmessage" dataFolder = os.environ.get('BITMESSAGE_HOME') + print('path...........................40', dataFolder) if dataFolder: if dataFolder[-1] not in (os.path.sep, os.path.altsep): dataFolder += os.path.sep elif sys.platform == 'darwin': + print('path...........................45', os.environ['HOME']) try: dataFolder = os.path.join( os.environ['HOME'], @@ -61,8 +63,11 @@ def lookupAppdataFolder(): else: try: dataFolder = os.path.join(os.environ['XDG_CONFIG_HOME'], APPNAME) + print('path...........................66', os.environ['HOME']) except KeyError: dataFolder = os.path.join(os.environ['HOME'], '.config', APPNAME) + print('path...........................69', dataFolder) + print('path...........................70', os.environ['HOME']) # Migrate existing data to the proper location # if this is an existing install diff --git a/src/tests/common.py b/src/tests/common.py index 0b6451a2..ee796a7b 100644 --- a/src/tests/common.py +++ b/src/tests/common.py @@ -18,6 +18,7 @@ def cleanup(home=None, files=_files): for pfile in files: try: os.remove(os.path.join(home, pfile)) + print(__file__,'.........................................(clean)', pfile) except OSError: pass diff --git a/src/tests/test_process.py b/src/tests/test_process.py index e6fa7db3..7328eeab 100644 --- a/src/tests/test_process.py +++ b/src/tests/test_process.py @@ -54,13 +54,16 @@ class TestProcessProto(unittest.TestCase): def setUpClass(cls): """Setup environment and start pybitmessage""" print('setUpClass.........................................(pass)', state.appdata) + # print('os.environ["BITMESSAGE_HOME"](test_process file)57...........................', os.environ['BITMESSAGE_HOME']) # import pdb;pdb.set_trace() + print(__file__, 'cls.home..................................', cls.home) cls.flag = False if not cls.home: cls.home = tempfile.gettempdir() cls._cleanup_files() os.environ['BITMESSAGE_HOME'] = cls.home - print('os.environ["BITMESSAGE_HOME"]...........................', os.environ['BITMESSAGE_HOME']) + # print("blabla {}".format(__file__)) + print('os.environ["BITMESSAGE_HOME"](test_process file)65...........................', os.environ['BITMESSAGE_HOME']) put_signal_file(cls.home, 'unittest.lock') starttime = int(time.time()) - 0.5 cls.process = psutil.Popen(