diff --git a/.gitignore b/.gitignore index 8153e385..d3da7bf8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ **pyc -**dat **.DS_Store src/build src/dist diff --git a/.travis-kivy.yml b/.travis-kivy.yml new file mode 100644 index 00000000..87c196a3 --- /dev/null +++ b/.travis-kivy.yml @@ -0,0 +1,17 @@ +language: python3.7 +cache: pip3 +dist: bionic +python: + - "3.7" +addons: + apt: + packages: + - build-essential + - libcap-dev + - libmtdev-dev + - xvfb +install: + - pip3 install -r kivy-requirements.txt + - python setup.py install +script: + - xvfb-run python3 tests-kivy.py diff --git a/Dockerfile.kivy-travis b/Dockerfile.kivy-travis new file mode 100644 index 00000000..4dcdf60b --- /dev/null +++ b/Dockerfile.kivy-travis @@ -0,0 +1,64 @@ +FROM ubuntu:bionic AS pybm-kivy-travis-bionic + +ENV DEBIAN_FRONTEND noninteractive +ENV TRAVIS_SKIP_APT_UPDATE 1 + +RUN apt-get update + +RUN apt-get install -yq --no-install-suggests --no-install-recommends \ + software-properties-common + +RUN dpkg --add-architecture i386 + +RUN add-apt-repository ppa:deadsnakes/ppa + +RUN apt-get -y install sudo + +RUN apt-get -y install git + +RUN apt-get install -yq --no-install-suggests --no-install-recommends \ + # travis xenial bionic + python-setuptools libssl-dev libpq-dev python-prctl python-dev \ + python-dev python-virtualenv python-pip virtualenv \ + # Code quality + pylint python-pycodestyle python3-pycodestyle pycodestyle python-flake8 \ + python3-flake8 flake8 python-pyflakes python3-pyflakes pyflakes pyflakes3 \ + curl \ + # Wine + python python-pip wget wine-stable winetricks mingw-w64 wine32 wine64 xvfb \ + # Buildbot + python3-dev libffi-dev python3-setuptools \ + python3-pip \ + # python 3.7 + python3.7 python3.7-dev \ + # .travis-kivy.yml + build-essential libcap-dev tor \ + language-pack-en \ + xclip xsel \ + libzbar-dev + +# cleanup +RUN rm -rf /var/lib/apt/lists/* + +RUN useradd -m -U builder + +RUN echo 'builder ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers + +# travis2bash +RUN wget -O /usr/local/bin/travis2bash.sh https://git.bitmessage.org/Bitmessage/buildbot-scripts/raw/branch/master/travis2bash.sh +RUN chmod +x /usr/local/bin/travis2bash.sh + +# copy sources +COPY . /home/builder/src +RUN chown -R builder.builder /home/builder/src + +USER builder + +ENV LANG en_US.UTF-8 +ENV LANGUAGE en_US:en +ENV LC_ALL en_US.UTF-8 + +WORKDIR /home/builder/src + + +ENTRYPOINT ["/usr/local/bin/travis2bash.sh", ".travis-kivy.yml"] diff --git a/kivy-requirements.txt b/kivy-requirements.txt new file mode 100644 index 00000000..632404a5 --- /dev/null +++ b/kivy-requirements.txt @@ -0,0 +1,34 @@ +certifi==2020.12.5 +chardet==4.0.0 +cheroot==8.5.2 +CherryPy==18.6.0 +docutils==0.16 +idna==2.10 +jaraco.classes==3.2.1 +jaraco.collections==3.2.0 +jaraco.functools==3.2.1 +jaraco.text==3.5.0 +json-rpc==1.13.0 +Kivy==2.0.0 +Kivy-Garden==0.1.4 +kivy-garden.qrcode==2021.314 +-e git+https://github.com/kivymd/KivyMD#egg=kivymd +Mako==1.1.4 +MarkupSafe==1.1.1 +more-itertools==8.7.0 +numpy==1.20.1 +opencv-python==4.5.1.48 +Pillow==8.1.2 +portend==2.7.1 +Pygments==2.8.1 +pytz==2021.1 +pyzbar==0.1.8 +qrcode==6.1 +requests==2.25.1 +six==1.15.0 +telenium==0.5.0 +tempora==4.0.1 +urllib3==1.26.4 +Werkzeug==1.0.1 +ws4py==0.5.1 +zc.lockfile==2.0 diff --git a/run-kivy-tests-in-docker.sh b/run-kivy-tests-in-docker.sh new file mode 100755 index 00000000..1308aac2 --- /dev/null +++ b/run-kivy-tests-in-docker.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +docker build -t pybm-kivy-travis-bionic -f Dockerfile.kivy-travis . +docker run pybm-kivy-travis-bionic diff --git a/setup.py b/setup.py index 0de2eb8c..2bf2aa2d 100644 --- a/setup.py +++ b/setup.py @@ -69,7 +69,8 @@ if __name__ == "__main__": 'pybitmessage.network', 'pybitmessage.plugins', 'pybitmessage.pyelliptic', - 'pybitmessage.storage' + 'pybitmessage.storage', + 'pybitmessage.bitmessagekivy', ] # this will silently accept alternative providers of msgpack diff --git a/src/bitmessagekivy/mpybit.py b/src/bitmessagekivy/mpybit.py new file mode 100644 index 00000000..4f85e806 --- /dev/null +++ b/src/bitmessagekivy/mpybit.py @@ -0,0 +1,29 @@ +""" + Bitmessage Desktop and android(mobile) interface +""" +# pylint: disable=too-few-public-methods + +from kivy.app import App +from kivy.uix.label import Label + + +class NavigateApp(App): + """Navigation Layout of class""" + + def build(self): + """Method builds the widget""" + # pylint: disable=no-self-use + + return Label(text="Hello World !") + + def clickNavDrawer(self): + """method for clicking navigation drawer""" + pass + + def addingtoaddressbook(self): + """method for clicking address book popup""" + pass + + +if __name__ == '__main__': + NavigateApp().run() diff --git a/src/bitmessagekivy/tests/__init__.py b/src/bitmessagekivy/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/bitmessagekivy/tests/common.py b/src/bitmessagekivy/tests/common.py new file mode 100644 index 00000000..18f3bb00 --- /dev/null +++ b/src/bitmessagekivy/tests/common.py @@ -0,0 +1,24 @@ +""" +This module is used for running test cases ui order. +""" +import unittest + + +def make_ordered_test(): + """this method is for compairing and arranging in order""" + order = {} + + def ordered_method(f): + """method for ordering""" + order[f.__name__] = len(order) + return f + + def compare_method(a, b): + """method for compairing order of methods""" + return [1, -1][order[a] < order[b]] + + return ordered_method, compare_method + + +ordered, compare = make_ordered_test() +unittest.defaultTestLoader.sortTestMethodsUsing = compare diff --git a/src/bitmessagekivy/tests/sampleData/keys.dat b/src/bitmessagekivy/tests/sampleData/keys.dat new file mode 100644 index 00000000..940b3e14 --- /dev/null +++ b/src/bitmessagekivy/tests/sampleData/keys.dat @@ -0,0 +1,59 @@ +[bitmessagesettings] +settingsversion = 0 +port = 8444 +timeformat = %%c +blackwhitelist = black +startonlogon = false +minimizetotray = false +showtraynotifications = true +startintray = false +socksproxytype = none +sockshostname = localhost +socksport = 9050 +socksauthentication = false +socksusername = +sockspassword = +keysencrypted = false +messagesencrypted = false +defaultnoncetrialsperbyte = 1000 +defaultpayloadlengthextrabytes = 1000 +minimizeonclose = false +replybelow = False +maxdownloadrate = 0 +maxuploadrate = 0 +stopresendingafterxdays = +stopresendingafterxmonths = +sockslisten = false +userlocale = system +sendoutgoingconnections = True +useidenticons = True +identiconsuffix = qcqQGW6sQtZK +maxacceptablenoncetrialsperbyte = 20000000000 +maxacceptablepayloadlengthextrabytes = 20000000000 +onionhostname = +onionport = 8444 +onionbindip = 127.0.0.1 +smtpdeliver = +hidetrayconnectionnotifications = false +ttl = 367200 + +[BM-2cTpgCn57rYUgqm5BrgmykuV9gK1Ak1THF] +label = test1 +enabled = true +decoy = false +noncetrialsperbyte = 1000 +payloadlengthextrabytes = 1000 +privsigningkey = 5KYCPJ4Vp31UD6k5NWmDKtHhfapW25UJ7V2MjctYxcgL3BpWGA3 +privencryptionkey = 5JLER8q2zyj3KDEgGMv682en2SRUkkWWhUrNuqVYfGNNhHJmdkJ +lastpubkeysendtime = 1623160189 + +[BM-2cVrdzQjCQRqUuET6dc3byVyRTjZcgcJXj] +label = test2 +enabled = true +decoy = false +noncetrialsperbyte = 1000 +payloadlengthextrabytes = 1000 +privsigningkey = 5KhryWvNowFWWA9JRjQnLVStYKwhpKpAG4RtWwzyaQqmK2fTMue +privencryptionkey = 5JKQ9NqX2LRzHBCgyxc1GAL3rDvyDTHPifpL22a6UNN7K6y9BmL +lastpubkeysendtime = 1623160221 + diff --git a/src/bitmessagekivy/tests/sampleData/knownnodes.dat b/src/bitmessagekivy/tests/sampleData/knownnodes.dat new file mode 100644 index 00000000..41ba8a28 --- /dev/null +++ b/src/bitmessagekivy/tests/sampleData/knownnodes.dat @@ -0,0 +1,110 @@ +[ + { + "stream": 1, + "peer": { + "host": "5.45.99.75", + "port": 8444 + }, + "info": { + "lastseen": 1620741290.255359, + "rating": 0, + "self": false + } + }, + { + "stream": 1, + "peer": { + "host": "75.167.159.54", + "port": 8444 + }, + "info": { + "lastseen": 1620741290.255359, + "rating": 0, + "self": false + } + }, + { + "stream": 1, + "peer": { + "host": "95.165.168.168", + "port": 8444 + }, + "info": { + "lastseen": 1620741290.255359, + "rating": 0, + "self": false + } + }, + { + "stream": 1, + "peer": { + "host": "85.180.139.241", + "port": 8444 + }, + "info": { + "lastseen": 1620741290.255359, + "rating": 0, + "self": false + } + }, + { + "stream": 1, + "peer": { + "host": "158.222.217.190", + "port": 8080 + }, + "info": { + "lastseen": 1620741290.255359, + "rating": 0, + "self": false + } + }, + { + "stream": 1, + "peer": { + "host": "178.62.12.187", + "port": 8448 + }, + "info": { + "lastseen": 1620741290.255359, + "rating": 0, + "self": false + } + }, + { + "stream": 1, + "peer": { + "host": "24.188.198.204", + "port": 8111 + }, + "info": { + "lastseen": 1620741290.255359, + "rating": 0, + "self": false + } + }, + { + "stream": 1, + "peer": { + "host": "109.147.204.113", + "port": 1195 + }, + "info": { + "lastseen": 1620741290.255359, + "rating": 0, + "self": false + } + }, + { + "stream": 1, + "peer": { + "host": "178.11.46.221", + "port": 8444 + }, + "info": { + "lastseen": 1620741290.255359, + "rating": 0, + "self": false + } + } +] \ No newline at end of file diff --git a/src/bitmessagekivy/tests/sampleData/messages.dat b/src/bitmessagekivy/tests/sampleData/messages.dat new file mode 100644 index 00000000..ad9aae5f Binary files /dev/null and b/src/bitmessagekivy/tests/sampleData/messages.dat differ diff --git a/src/bitmessagekivy/tests/telenium_process.py b/src/bitmessagekivy/tests/telenium_process.py new file mode 100644 index 00000000..e5ba24a3 --- /dev/null +++ b/src/bitmessagekivy/tests/telenium_process.py @@ -0,0 +1,61 @@ +import os +import shutil +import tempfile + +from telenium.tests import TeleniumTestCase + +_files = ( + 'keys.dat', 'debug.log', 'messages.dat', 'knownnodes.dat', + '.api_started', 'unittest.lock' +) + +tmp_db_file = ( + 'keys.dat', 'messages.dat' +) + + +def cleanup(home=None, files=_files): + """Cleanup application files""" + if not home: + home = tempfile.gettempdir() + for pfile in files: + try: + os.remove(os.path.join(home, pfile)) + except OSError: + pass + + +def set_temp_data(): + """Set temp data in tmp directory""" + for file_name in tmp_db_file: + old_source_file = os.path.join( + os.path.abspath(os.path.dirname(__file__)), 'sampleData', file_name) + new_destination_file = os.path.join(os.environ['BITMESSAGE_HOME'], file_name) + shutil.copyfile(old_source_file, new_destination_file) + + +class TeleniumTestProcess(TeleniumTestCase): + """Setting Screen Functionality Testing""" + cmd_entrypoint = [os.path.join(os.path.abspath(os.getcwd()), 'src', 'mock', 'main.py')] + + @classmethod + def setUpClass(cls): + """Setupclass is for setting temp environment""" + os.environ["BITMESSAGE_HOME"] = tempfile.gettempdir() + set_temp_data() + super(TeleniumTestProcess, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + """Ensures that pybitmessage stopped and removes files""" + # pylint: disable=no-member + cleanup() + try: + cls.cli.app_quit() + except: + pass + + try: + cls.process.kill() + except: + pass diff --git a/src/bitmessagekivy/tests/test_addressbook.py b/src/bitmessagekivy/tests/test_addressbook.py new file mode 100644 index 00000000..20be1c0a --- /dev/null +++ b/src/bitmessagekivy/tests/test_addressbook.py @@ -0,0 +1,111 @@ +from .telenium_process import TeleniumTestProcess +from .common import ordered + +data = [ + 'BM-2cWmjntZ47WKEUtocrdvs19y5CivpKoi1h', + 'BM-2cVpswZo8rWLXDVtZEUNcDQvnvHJ6TLRYr' +] + + +class AddressBook(TeleniumTestProcess): + """AddressBook Screen Functionality Testing""" + + @ordered + def test_save_address(self): + """Save Address On Address Book Screen/Window""" + print("=====================Test -Save Address In Address Book=====================") + self.cli.sleep(6) + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(4) + self.cli.drag("//NavigationItem[@text=\"Sent\"]", "//NavigationItem[@text=\"Inbox\"]", 1) + self.cli.sleep(3) + self.cli.click_on('//NavigationItem[6]') + self.cli.sleep(4) + self.cli.execute('app.addingtoaddressbook()') + self.cli.sleep(3) + self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[0]') + self.cli.sleep(4) + self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[1]') + self.cli.sleep(4) + self.cli.click_on('//MDRaisedButton[0]') + self.cli.sleep(4) + self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[0]') + self.cli.sleep(3) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[0]', 'text', 'test1') + self.cli.sleep(3) + self.cli.click_on('//MDRaisedButton[0]') + self.cli.sleep(4) + self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[1]') + self.cli.sleep(3) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]', 'text', 'sectorAppartment') + self.cli.sleep(3) + self.cli.click_on('//MDRaisedButton[0]') + self.cli.sleep(5) + self.cli.click_on('//GrashofPopup/BoxLayout[0]/MDTextField[1]') + self.cli.sleep(3) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]', 'text', data[0]) + self.cli.sleep(3) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]', 'text', '') + self.cli.sleep(3) + self.cli.click_on('//MDRaisedButton[0]') + self.cli.sleep(4) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]', 'text', 'BM-2cX78L9CZpb6GGC3rRVizYiUBwHELMLybd') + self.cli.sleep(3) + self.cli.click_on('//MDRaisedButton[0]') + self.cli.sleep(4) + + @ordered + def test_cancel_addressbook_popup(self): + """Cancel Address""" + print("=====================Test -Cancel Address Add Popup=====================") + self.cli.sleep(3) + self.cli.execute('app.addingtoaddressbook()') + self.cli.sleep(3) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[0]', 'text', 'test2') + self.cli.sleep(3) + self.cli.setattr('//GrashofPopup/BoxLayout[0]/MDTextField[1]', 'text', data[0]) + self.cli.sleep(3) + self.cli.click_on('//MDRaisedButton[1]') + + @ordered + def test_send_message_to_addressbook(self): + """Directly Send Message To The User""" + print("=====================Test -Directly Send Message To The User=====================") + self.cli.sleep(4) + self.cli.click_on( + '//AddressBook/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/SwipeToDeleteItem[0]') + self.cli.sleep(3) + self.cli.click_on('//MDRaisedButton[0]') + self.cli.sleep(3) + self.cli.click_on( + '//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[0]/BoxLayout[0]/CustomSpinner[0]/ArrowImg[0]') + self.cli.sleep(2) + self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]') + self.cli.sleep(3) + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]', 'text', 'Second') + self.cli.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) + self.cli.sleep(0.2) + self.cli.click_on('//MDActionTopAppBarButton[2]') + self.cli.sleep(2) + + @ordered + def test_delete_address_from_address_contact(self): + """Delete Address From Address Book""" + print("=====================Test -Delete Address From Address Book=====================") + self.cli.sleep(3) + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(3) + self.cli.click_on('//NavigationItem[6]') + self.cli.sleep(3) + self.cli.drag( + '//MDList[0]/SwipeToDeleteItem[0]//TwoLineAvatarIconListItem[0]/BoxLayout[1]', + '//MDList[0]/SwipeToDeleteItem[0]//TwoLineAvatarIconListItem[0]/BoxLayout[2]', 1) + self.cli.click_on('//MDList[0]/SwipeToDeleteItem[0]') + self.cli.sleep(2) + self.cli.click_on('//MDList[0]/SwipeToDeleteItem[0]//MDIconButton[0]') + self.cli.sleep(2) diff --git a/src/bitmessagekivy/tests/test_allmail_message.py b/src/bitmessagekivy/tests/test_allmail_message.py new file mode 100644 index 00000000..0c34e474 --- /dev/null +++ b/src/bitmessagekivy/tests/test_allmail_message.py @@ -0,0 +1,27 @@ +from .telenium_process import TeleniumTestProcess +from .common import ordered + + +class AllMailMessage(TeleniumTestProcess): + """AllMail Screen Functionality Testing""" + + @ordered + def test_show_allmail_list(self): + """Show All Messages on Mail Screen/Window""" + print("=====================Test -Show Messages Of Mail Screen=====================") + self.cli.sleep(5) + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(4) + self.cli.click_on('//NavigationItem[5]') + self.cli.sleep(4) + + @ordered + def test_delete_message_from_allmail_list(self): + """Delete Message From Message body of Mail Screen/Window""" + print("=====================Test -Delete Messages Of Mail Screen=====================") + self.cli.sleep(4) + self.cli.click_on( + '//Allmails[0]/BoxLayout[0]/BoxLayout[0]/ScrollView[0]/MDList[0]/CutsomSwipeToDeleteItem[0]') + self.cli.sleep(5) + self.cli.click_on('//MDToolbar/BoxLayout[2]/MDActionTopAppBarButton[1]') + self.cli.sleep(5) diff --git a/src/bitmessagekivy/tests/test_create_random_address.py b/src/bitmessagekivy/tests/test_create_random_address.py new file mode 100644 index 00000000..54e20f87 --- /dev/null +++ b/src/bitmessagekivy/tests/test_create_random_address.py @@ -0,0 +1,78 @@ +import os +import tempfile + +from .telenium_process import TeleniumTestProcess, cleanup +from .common import ordered +from random import choice +from string import ascii_lowercase + + +class CreateRandomAddress(TeleniumTestProcess): + """This is for testing randrom address creation""" + + @classmethod + def setUpClass(cls): + """overriding setupclass for cleaning temp storage.""" + # pylint: disable=bad-super-call + os.environ["BITMESSAGE_HOME"] = tempfile.gettempdir() + cleanup() + super(TeleniumTestProcess, cls).setUpClass() + + @ordered + def test_login_screen(self): + """Clicking on Proceed Button to Proceed to Next Screen.""" + print("=====================Test - Login Screen=====================") + self.cli.sleep(3) + self.cli.wait_click( + '//ScreenManager[0]/Screen[0]/BoxLayout[0]/AnchorLayout[3]/MDFillRoundFlatIconButton[0]') + self.cli.sleep(3) + + @ordered + def test_random_screen(self): + """Creating New Adress For New User.""" + print("=====================Test - Create New Address=====================") + self.cli.click_on('//RandomBoxlayout/BoxLayout[0]/AnchorLayout[1]/MDTextField[0]') + self.cli.sleep(3) + self.cli.wait_click('//RandomBoxlayout/BoxLayout[0]/AnchorLayout[2]/MDFillRoundFlatIconButton[0]') + self.cli.sleep(3) + self.cli.click_on('//RandomBoxlayout/BoxLayout[0]/AnchorLayout[1]/MDTextField[0]') + self.cli.sleep(3) + random_label = "" + for _ in range(10): + random_label += choice(ascii_lowercase) + self.cli.setattr('//RandomBoxlayout/BoxLayout[0]/AnchorLayout[1]/MDTextField[0]', "text", random_label) + self.cli.sleep(0.2) + self.cli.sleep(1) + self.cli.wait_click('//RandomBoxlayout/BoxLayout[0]/AnchorLayout[2]/MDFillRoundFlatIconButton[0]') + self.cli.sleep(5) + + @ordered + def test_create_new_address(self): + """Clicking on Navigation Drawer To Open New Address""" + print("=====================Test - Create New Address=====================") + self.cli.sleep(5) + self.cli.execute('app.root.ids.nav_drawer.set_state("toggle")') + self.cli.sleep(2) + self.cli.drag("//NavigationItem[@text=\"Sent\"]", "//NavigationItem[@text=\"Inbox\"]", 1) + self.cli.sleep(3) + self.cli.click_on('//NavigationItem[9]') + self.cli.sleep(4) + self.cli.wait_click( + '''//Login/BoxLayout[0]/BoxLayout[0]/ScreenManager[0]/Screen[0]/BoxLayout[0]/AnchorLayout[3]''' + '''/MDFillRoundFlatIconButton[0]''') + self.test_random_screen() + + @ordered + def test_select_address(self): + """Select First Address From Drawer-Box""" + print("=====================Test - Select First Address From Drawer-Box=======================") + self.cli.sleep(3) + # self.cli.execute('app.root.ids.nav_drawer.set_state("toggle")') + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(2) + self.cli.drag("//NavigationItem[@text=\"Address Book\"]", "//NavigationItem[@text=\"Settings\"]", 1) + self.cli.sleep(2) + self.cli.click_on('//NavigationItem[0]') + self.cli.sleep(2) + self.cli.click_on('//MySpinnerOption[0]') + self.cli.sleep(3) diff --git a/src/bitmessagekivy/tests/test_draft_message.py b/src/bitmessagekivy/tests/test_draft_message.py new file mode 100644 index 00000000..4e4467e9 --- /dev/null +++ b/src/bitmessagekivy/tests/test_draft_message.py @@ -0,0 +1,99 @@ +from .telenium_process import TeleniumTestProcess +from .common import ordered + + +class DraftMessage(TeleniumTestProcess): + """Draft Screen Functionality Testing""" + + @ordered + def test_save_draft_message(self): + """Select A Draft Screen From Navigaion-Drawer-Box Then + Send a drafted message """ + print("=====================Test - Select A Draft Screen From Navigaion-Drawer-Box=====================") + # OPEN NAVIGATION-DRAWER + self.cli.sleep(4) + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(2) + # OPEN INBOX SCREEN + self.cli.click_on('//NavigationItem[1]') + self.cli.sleep(2) + # CLICK ON PLUS ICON BUTTON + self.cli.click_on('//Inbox/ComposerButton[0]/MDFloatingActionButton[0]') + self.cli.sleep(3) + # SELECT - TO ADDRESS + self.cli.click_on( + '//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[0]/BoxLayout[0]/CustomSpinner[0]/ArrowImg[0]') + self.cli.sleep(2) + self.cli.click_on('//MyTextInput[0]') + self.cli.sleep(3) + # ADD FROM MESSAGE + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]', + "text", 'BM-2cSsuH1bUWBski8bvdqnK2DivMqQCeQA1J') + self.cli.sleep(3) + # CLICK BACK-BUTTON + self.cli.click_on('//MDToolbar/BoxLayout[0]/MDActionTopAppBarButton[0]') + self.cli.sleep(5) + self.cli.click_on('//Inbox/ComposerButton[0]/MDFloatingActionButton[0]') + self.cli.sleep(3) + # SELECT - TO ADDRESS + self.cli.click_on( + '//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[0]/BoxLayout[0]/CustomSpinner[0]/ArrowImg[0]') + self.cli.sleep(1) + self.cli.click_on('//MyTextInput[0]') + self.cli.sleep(3) + # ADD FROM MESSAGE + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]', + "text", 'BM-2cSsuH1bUWBski8bvdqnK2DivMqQCeQA1J') + self.cli.sleep(4) + random_label = "" + for char in "Another Draft message": + random_label += char + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]', 'text', random_label) + self.cli.sleep(0.2) + # CLICK BACK-BUTTON + self.cli.click_on('//MDToolbar/BoxLayout[0]/MDActionTopAppBarButton[0]') + self.cli.sleep(4) + + @ordered + def test_edit_and_resend_draft_messgae(self): + """Select A Message From List of Messages Then + make changes and send it.""" + print("=====================Test - Edit A Message From Draft Screen=====================") + # OPEN NAVIGATION-DRAWER + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(4) + # OPEN DRAFT SCREEN + self.cli.click_on('//NavigationItem[3]') + self.cli.sleep(4) + # SHOW DRAFT MESSAGE AND SELECT FIRST MESSAGE + # self.cli.click_on('//Carousel[0]//TwoLineAvatarIconListItem[0]') + self.cli.click_on('//SwipeToDeleteItem[0]//TwoLineAvatarIconListItem[0]') + self.cli.sleep(3) + # CLICK EDIT BUTTON + self.cli.click_on('//MDToolbar/BoxLayout[2]/MDActionTopAppBarButton[0]') + self.cli.sleep(5) + random_label = "" + for char in "Hey,This is draft Message Body": + random_label += char + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]', + 'text', random_label) + self.cli.sleep(0.2) + self.cli.sleep(3) + self.cli.click_on('//MDActionTopAppBarButton[2]') + self.cli.sleep(5) + + @ordered + def test_delete_draft_message(self): + """Delete A Message From List of Messages""" + print("=====================Test - Delete A Message From List of Messages=====================") + self.cli.sleep(5) + # self.cli.execute('app.root.ids.nav_drawer.set_state("toggle")') + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(4) + self.cli.click_on('//NavigationItem[3]') + self.cli.sleep(5) + self.cli.click_on('//SwipeToDeleteItem[0]//TwoLineAvatarIconListItem[0]') + # self.cli.click_on('//Carousel[0]//TwoLineAvatarIconListItem[0]') + self.cli.sleep(5) + self.cli.click_on('//MDToolbar/BoxLayout[2]/MDActionTopAppBarButton[1]') + self.cli.sleep(5) diff --git a/src/bitmessagekivy/tests/test_myaddress_screen.py b/src/bitmessagekivy/tests/test_myaddress_screen.py new file mode 100644 index 00000000..c017b763 --- /dev/null +++ b/src/bitmessagekivy/tests/test_myaddress_screen.py @@ -0,0 +1,63 @@ +from .telenium_process import TeleniumTestProcess +from .common import ordered + +data = [ + 'BM-2cWmjntZ47WKEUtocrdvs19y5CivpKoi1h', + 'BM-2cVpswZo8rWLXDVtZEUNcDQvnvHJ6TLRYr' +] + + +class MyAddressScreen(TeleniumTestProcess): + """MyAddress Screen Functionality Testing""" + + @ordered + def test_select_myaddress_list(self): + """Select Address From List of Address""" + print("=====================Test -Select Address From List of Address=====================") + self.cli.sleep(4) + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(3) + self.cli.drag("//NavigationItem[@text=\"Sent\"]", "//NavigationItem[@text=\"Inbox\"]", 1) + self.cli.sleep(3) + self.cli.click_on('//NavigationItem[11]') + self.cli.sleep(4) + + @ordered + def test_show_Qrcode(self): + """Show the Qr code of selected address""" + print("=====================Test -Show QR code of selected address=====================") + self.cli.sleep(4) + self.cli.click_on( + '''//MyAddress/BoxLayout[0]/FloatLayout[0]/MDScrollViewRefreshLayout[0]/MDList[0]/''' + '''CustomTwoLineAvatarIconListItem[0]''') + self.cli.sleep(3) + self.cli.click_on('//MyaddDetailPopup/BoxLayout[1]/MDRaisedButton[1]/MDLabel[0]') + self.cli.sleep(3) + self.cli.click_on('//MDToolbar/BoxLayout[0]/MDActionTopAppBarButton[0]') + self.cli.sleep(3) + + @ordered + def test_send_message_from(self): + """Send Message From Send Message From Button""" + print("=====================Test -Send Message From Send Message From Button=====================") + self.cli.sleep(4) + self.cli.click_on( + '''//MyAddress/BoxLayout[0]/FloatLayout[0]/MDScrollViewRefreshLayout[0]/MDList[0]/''' + '''CustomTwoLineAvatarIconListItem[0]''') + self.cli.sleep(4) + self.cli.click_on('//MyaddDetailPopup/BoxLayout[1]/MDRaisedButton[0]/MDLabel[0]') + self.cli.sleep(3) + self.cli.setattr( + '//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput', "text", data[1]) + self.cli.sleep(3) + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]', 'text', 'Hey') + self.cli.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) + self.cli.sleep(0.2) + self.cli.sleep(2) + self.cli.click_on('//MDActionTopAppBarButton[2]') + self.cli.sleep(4) diff --git a/src/bitmessagekivy/tests/test_network_screen.py b/src/bitmessagekivy/tests/test_network_screen.py new file mode 100644 index 00000000..d0ab7ce5 --- /dev/null +++ b/src/bitmessagekivy/tests/test_network_screen.py @@ -0,0 +1,19 @@ +from .telenium_process import TeleniumTestProcess + + +class NetwrokStatusScreen(TeleniumTestProcess): + """NetwrokStatus Screen Functionality Testing""" + # pylint: disable=too-few-public-methods + + def test_network_status(self): + """Show NetwrokStatus""" + print("=====================Test -Show NetwrokStatus=====================") + self.cli.sleep(4) + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(3) + self.cli.drag("//NavigationItem[@text=\"Sent\"]", "//NavigationItem[@text=\"Inbox\"]", 1) + self.cli.sleep(3) + self.cli.click_on('//NavigationItem[10]') + self.cli.sleep(4) + self.cli.click_on('//NetworkStat/MDTabs[0]/MDTabsBar[0]/MDTabsScrollView[0]/MDGridLayout[0]/MDTabsLabel[1]') + self.cli.sleep(4) diff --git a/src/bitmessagekivy/tests/test_payment_subscription.py b/src/bitmessagekivy/tests/test_payment_subscription.py new file mode 100644 index 00000000..23589a68 --- /dev/null +++ b/src/bitmessagekivy/tests/test_payment_subscription.py @@ -0,0 +1,27 @@ +from .telenium_process import TeleniumTestProcess + + +class PaymentScreen(TeleniumTestProcess): + """SubscriptionPayment Screen Functionality Testing""" + # pylint: disable=too-few-public-methods + + def test_select_subscripton(self): + """Select Subscripton From List of Subscriptons""" + print("=====================Test -Select Subscripton From List of Subscriptons=====================") + self.cli.sleep(4) + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(3) + self.cli.drag("//NavigationItem[@text=\"Sent\"]", "//NavigationItem[@text=\"Inbox\"]", 1) + self.cli.sleep(3) + self.cli.click_on('//NavigationItem[8]') + self.cli.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) + self.cli.sleep(2) + self.cli.click_on('//MDRaisedButton[3]') + self.cli.sleep(2) + self.cli.click_on('//ListItemWithLabel[0]') + self.cli.sleep(2) + self.cli.click_on('//MDRaisedButton[3]') + self.cli.sleep(2) diff --git a/src/bitmessagekivy/tests/test_sent_message.py b/src/bitmessagekivy/tests/test_sent_message.py new file mode 100644 index 00000000..d15c1809 --- /dev/null +++ b/src/bitmessagekivy/tests/test_sent_message.py @@ -0,0 +1,108 @@ +from .telenium_process import TeleniumTestProcess +from .common import ordered + +data = [ + 'BM-2cWmjntZ47WKEUtocrdvs19y5CivpKoi1h', + 'BM-2cVpswZo8rWLXDVtZEUNcDQvnvHJ6TLRYr' +] + + +class SendMessage(TeleniumTestProcess): + """Sent Screen Functionality Testing""" + + @ordered + def test_send_message_and_validation(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 with validation Checks=======") + self.cli.sleep(3) + # self.cli.execute('app.root.ids.nav_drawer.set_state("toggle")') + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(2) + self.cli.click_on('//NavigationItem[1]') + self.cli.sleep(2) + self.cli.click_on('//Inbox/ComposerButton[0]/MDFloatingActionButton[0]') + self.cli.sleep(3) + self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[0]/MyMDTextField[0]') + self.cli.sleep(3) + self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/MyTextInput[0]') + self.cli.sleep(3) + self.cli.setattr( + '//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/MyTextInput[0]', "text", "second add") + self.cli.sleep(3) + self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]') + self.cli.sleep(4) + self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]') + self.cli.sleep(4) + self.cli.click_on('//MDActionTopAppBarButton[2]') + self.cli.sleep(3) + self.cli.click_on('//MDFlatButton[0]') + self.cli.sleep(5) + self.cli.click_on( + '//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[0]/BoxLayout[0]/CustomSpinner[0]/ArrowImg[0]') + self.cli.sleep(2) + self.cli.click_on('//MyTextInput[0]') + self.cli.sleep(3) + self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]') + self.cli.sleep(2) + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]', 'text', 'heyyyyyy') + self.cli.sleep(3) + self.cli.click_on('//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]') + self.cli.sleep(4) + random_label = "" + for char in "how are you this is message body": + random_label += char + self.cli.setattr( + '//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]', 'text', random_label) + self.cli.sleep(0.2) + self.cli.sleep(3) + self.cli.click_on('//MDActionTopAppBarButton[2]') + self.cli.sleep(3) + self.cli.click_on('//MDFlatButton[0]') + self.cli.sleep(6) + self.cli.setattr( + '//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]', "text", data[0]) + self.cli.sleep(3) + self.cli.click_on('//MDActionTopAppBarButton[2]') + self.cli.sleep(3) + + @ordered + def test_sent_multiple_messages(self): + """ + Sending Second Message From Inbox Screen + for testing the search and delete functionality for two messages on the screen + """ + print("=====================Test - Sending Message From Inbox Screen=====================") + self.cli.sleep(3) + # self.cli.execute('app.root.ids.nav_drawer.set_state("toggle")') + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(5) + self.cli.click_on('//NavigationItem[1]') + self.cli.sleep(3) + self.cli.click_on('//Inbox/ComposerButton[0]/MDFloatingActionButton[0]') + self.cli.sleep(3) + self.cli.click_on( + '//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[0]/BoxLayout[0]/CustomSpinner[0]/ArrowImg[0]') + self.cli.sleep(2) + self.cli.click_on('//MyTextInput[0]') + self.cli.sleep(3) + self.cli.setattr( + '//DropDownWidget/ScrollView[0]/BoxLayout[0]/BoxLayout[1]/BoxLayout[0]/MyTextInput[0]', "text", data[0]) + self.cli.sleep(3) + self.cli.setattr('//DropDownWidget/ScrollView[0]/BoxLayout[0]/MyMDTextField[0]', 'text', 'Second') + self.cli.sleep(3) + random_label = "" + for char in "Hey This Is Second Message Body": + random_label += char + self.cli.setattr( + '//DropDownWidget/ScrollView[0]/BoxLayout[0]/ScrollView[0]/TextInput[0]', "text", random_label) + self.cli.sleep(0.2) + self.cli.sleep(2) + self.cli.click_on('//MDActionTopAppBarButton[2]') + self.cli.sleep(5) + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(3) + self.cli.click_on('//NavigationItem[2]') + self.cli.sleep(3) diff --git a/src/bitmessagekivy/tests/test_setting_screen.py b/src/bitmessagekivy/tests/test_setting_screen.py new file mode 100644 index 00000000..af99139e --- /dev/null +++ b/src/bitmessagekivy/tests/test_setting_screen.py @@ -0,0 +1,17 @@ +from .telenium_process import TeleniumTestProcess + + +class SettingScreen(TeleniumTestProcess): + """Setting Screen Functionality Testing""" + # pylint: disable=too-few-public-methods + + def test_setting_screen(self): + """Show Setting Screen""" + print("=====================Test -Show Setting Screen=====================") + self.cli.sleep(3) + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(3) + self.cli.drag("//NavigationItem[@text=\"Sent\"]", "//NavigationItem[@text=\"Inbox\"]", 1) + self.cli.sleep(3) + self.cli.click_on('//NavigationItem[7]') + self.cli.sleep(4) diff --git a/src/bitmessagekivy/tests/test_trash_message.py b/src/bitmessagekivy/tests/test_trash_message.py new file mode 100644 index 00000000..e30362ec --- /dev/null +++ b/src/bitmessagekivy/tests/test_trash_message.py @@ -0,0 +1,25 @@ +from .telenium_process import TeleniumTestProcess + + +class TrashMessage(TeleniumTestProcess): + """Trash Screen Functionality Testing""" + # pylint: disable=too-few-public-methods + + def test_delete_trash_message(self): + """Delete Trash message permanently from trash message listing""" + print("=====================Test -Delete Message From Trash Message Listing=====================") + self.cli.sleep(4) + self.cli.execute('app.clickNavDrawer()') + self.cli.sleep(4) + self.cli.click_on('//NavigationItem[4]') + self.cli.sleep(4) + self.cli.drag( + '//MDList[0]/CutsomSwipeToDeleteItem[0]//TwoLineAvatarIconListItem[0]/BoxLayout[1]', + '//MDList[0]/CutsomSwipeToDeleteItem[0]//TwoLineAvatarIconListItem[0]/BoxLayout[2]', 1) + self.cli.click_on('//MDList[0]/CutsomSwipeToDeleteItem[0]') + self.cli.sleep(4) + self.cli.click_on('//MDList[0]/CutsomSwipeToDeleteItem[0]//MDIconButton[0]') + self.cli.sleep(2) + self.cli.click_on('//MDDialog/MDCard[0]/AnchorLayout[0]/MDBoxLayout[0]/MDFlatButton[0]') + # self.cli.click_on('//MDDialog/DialogFakeCard[0]/AnchorLayout[0]/MDBoxLayout[0]/MDFlatButton[0]') + self.cli.sleep(4) diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index 1f5d4fce..c969d8fb 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -10,8 +10,8 @@ from datetime import datetime from six import string_types from six.moves import configparser -import state -from singleton import Singleton +from pybitmessage import state +from pybitmessage.singleton import Singleton SafeConfigParser = configparser.SafeConfigParser diff --git a/src/mock/__init__.py b/src/mock/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/mock/class_addressGenerator.py b/src/mock/class_addressGenerator.py new file mode 100644 index 00000000..5d6b0351 --- /dev/null +++ b/src/mock/class_addressGenerator.py @@ -0,0 +1,93 @@ +""" +A thread for creating addresses +""" +# import queues +try: + import queue as Queue +except ImportError: + import Queue + +import logging +import random +from pybitmessage import state +import threading + +from pybitmessage.bmconfigparser import BMConfigParser + +# from network.threads import StoppableThread + + +fake_addresses = [ + 'BM-2cXDconV3bk6nPwWgBwN7wXaqZoT1bEzGv', + 'BM-2cTWjUVedYftZJbnZfs7MWts92v1R35Try', + 'BM-2cV1UN3er2YVQBcmJaaeYMXvpwBVokJNTo', + 'BM-2cWVkWk3TyKUscdcn9E7s9hrwpv2ZsBBog', + 'BM-2cW2a5R1KidMGNByqPKn6nJDDnHtazoere' +] + +UISignalQueue = Queue.Queue() +addressGeneratorQueue = Queue.Queue() + + +class StoppableThread(threading.Thread): + """Base class for application threads with stopThread method""" + name = None + logger = logging.getLogger('default') + + def __init__(self, name=None): + if name: + self.name = name + super(StoppableThread, self).__init__(name=self.name) + self.stop = threading.Event() + self._stopped = False + random.seed() + self.logger.info('Init thread %s', self.name) + + def stopThread(self): + """Stop the thread""" + self._stopped = True + self.stop.set() + + +class FakeAddressGenerator(StoppableThread): + """A thread for creating fake addresses""" + name = "addressGenerator" + + def stopThread(self): + try: + addressGeneratorQueue.put(("stopThread", "data")) + except: + pass + super(FakeAddressGenerator, self).stopThread() + + def run(self): + """ + Process the requests for addresses generation + from `.queues.addressGeneratorQueue` + """ + while state.shutdown == 0: + queueValue = addressGeneratorQueue.get() + streamNumber = 1 + try: + if len(BMConfigParser().addresses()) > 0: + address = fake_addresses[len(BMConfigParser().addresses())] + else: + address = fake_addresses[0] + + label = queueValue[3] + BMConfigParser().add_section(address) + BMConfigParser().set(address, 'label', label) + BMConfigParser().set(address, 'enabled', 'true') + BMConfigParser().set( + address, 'privencryptionkey', '5KUayt1aPSsNWsxMJnk27kv79wfRE3cWVPYLazyLQc752bXfQP3') + BMConfigParser().save() + + UISignalQueue.put(( + 'updateStatusBar', "" + )) + UISignalQueue.put(('writeNewAddressToTable', ( + label, address, streamNumber))) + addressGeneratorQueue.task_done() + except IndexError: + self.logger.error( + 'Program error: you can only create 5 fake addresses') diff --git a/src/mock/main.py b/src/mock/main.py new file mode 100644 index 00000000..0a5fbb84 --- /dev/null +++ b/src/mock/main.py @@ -0,0 +1,29 @@ +"""This module is for thread start.""" + +from pybitmessage import state +from pybitmessage.bitmessagekivy.mpybit import NavigateApp +from class_addressGenerator import FakeAddressGenerator +# from class_sqlThread import sqlThread + + +def main(): + """main method for starting threads""" + if state.enableObjProc: + # Start the address generation thread + addressGeneratorThread = FakeAddressGenerator() + # close the main program even if there are threads left + addressGeneratorThread.daemon = True + addressGeneratorThread.start() + + # sqlLookup = sqlThread() + # DON'T close the main program even if there are threads left. + # The closeEvent should command this thread to exit gracefully. + # sqlLookup.daemon = False + # sqlLookup.start() + + state.kivyapp = NavigateApp() + state.kivyapp.run() + + +if __name__ == '__main__': + main() diff --git a/tests-kivy.py b/tests-kivy.py new file mode 100644 index 00000000..92b10b86 --- /dev/null +++ b/tests-kivy.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +"""Custom tests runner script for tox and python3""" +import random # noseq +import sys +import unittest + + +def unittest_discover(): + """Explicit test suite creation""" + loader = unittest.defaultTestLoader + loader.sortTestMethodsUsing = lambda a, b: random.randint(-1, 1) + return loader.discover('src.bitmessagekivy.tests') + + +if __name__ == "__main__": + result = unittest.TextTestRunner(verbosity=2).run(unittest_discover()) + sys.exit(not result.wasSuccessful())