pybitmessage kivy app test cases and test script

This commit is contained in:
cis 2021-06-11 22:44:57 +05:30
parent a9488fb120
commit eb85efe3e5
No known key found for this signature in database
GPG Key ID: 11DC6F36E8B65B24
22 changed files with 586 additions and 5 deletions

1
.gitignore vendored
View File

@ -1,5 +1,4 @@
**pyc **pyc
**dat
**.DS_Store **.DS_Store
src/build src/build
src/dist src/dist

18
.travis-kivy.yml Normal file
View File

@ -0,0 +1,18 @@
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
- python3 setup.py install
- export PYTHONWARNINGS=all
script:
- xvfb-run python3 tests-kivy.py

64
Dockerfile.kivy-travis Normal file
View File

@ -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"]

5
kivy-requirements.txt Normal file
View File

@ -0,0 +1,5 @@
kivy-garden.qrcode
-e git+https://github.com/kivymd/KivyMD#egg=kivymd
opencv-python
pyzbar
telenium

4
run-kivy-tests-in-docker.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
docker build -t pybm-kivy-travis-bionic -f Dockerfile.kivy-travis .
docker run pybm-kivy-travis-bionic

View File

@ -69,9 +69,12 @@ if __name__ == "__main__":
'pybitmessage.network', 'pybitmessage.network',
'pybitmessage.plugins', 'pybitmessage.plugins',
'pybitmessage.pyelliptic', 'pybitmessage.pyelliptic',
'pybitmessage.storage' 'pybitmessage.storage',
] ]
if sys.version_info[0] == 3:
packages.append('pybitmessage.bitmessagekivy')
# this will silently accept alternative providers of msgpack # this will silently accept alternative providers of msgpack
# if they are already installed # if they are already installed

View File

View File

@ -0,0 +1,28 @@
"""
Dummy implementation for kivy 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()

View File

View File

@ -0,0 +1,37 @@
"""
This module is used for running test cases ui order.
"""
import unittest
from pybitmessage import state
def make_ordered_test():
"""this method is for comparing 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 comparing order of methods"""
return [1, -1][order[a] < order[b]]
return ordered_method, compare_method
ordered, compare = make_ordered_test()
unittest.defaultTestLoader.sortTestMethodsUsing = compare
def skip_screen_checks(x):
"""This methos is skipping current screen checks"""
def inner(y):
"""Inner function"""
if not state.enableKivy:
return unittest.skip('Kivy not enabled')
else:
x(y)
return inner

View File

@ -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

View File

@ -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
}
}
]

Binary file not shown.

View File

@ -0,0 +1,83 @@
"""
Base class for telenium test cases which run kivy app as background process
"""
import os
import shutil
import tempfile
from time import time, sleep
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(files=_files):
"""Cleanup application files"""
for pfile in files:
try:
os.remove(os.path.join(tempfile.gettempdir(), pfile))
except OSError:
pass
def populate_test_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', 'kivy_main.py')]
@classmethod
def setUpClass(cls):
"""Setupclass is for setting temp environment"""
os.environ["BITMESSAGE_HOME"] = tempfile.gettempdir()
populate_test_data()
super(TeleniumTestProcess, cls).setUpClass()
@classmethod
def tearDownClass(cls):
"""Ensures that pybitmessage stopped and removes files"""
# pylint: disable=no-member
try:
cls.cli.app_quit()
except:
pass
try:
cls.process.kill()
except:
pass
cleanup()
def drag(self, xpath1, xpath2):
"""this method is for dragging"""
self.cli.drag(xpath1, xpath2, 1)
self.cli.sleep(0.3)
def assertCheckScrollDown(self, selector, timeout=-1):
"""this method is for checking scroll"""
start = time()
while True:
scroll_distance = self.cli.getattr(selector, 'scroll_y')
if scroll_distance > 0.0:
self.assertGreaterEqual(scroll_distance, 0.0)
return True
if timeout == -1:
return False
if timeout > 0 and time() - start > timeout:
raise Exception("Timeout")
sleep(0.1)

View File

@ -0,0 +1,28 @@
# pylint: disable=too-few-public-methods
from .telenium_process import TeleniumTestProcess
from .common import skip_screen_checks
class SettingScreen(TeleniumTestProcess):
"""Setting Screen Functionality Testing"""
@skip_screen_checks
def test_setting_screen(self):
"""Show Setting Screen"""
print("=====================Test -Show Setting Screen=====================")
self.cli.sleep(3)
# this is for checking current screen
self.assertExists("//Inbox[@name~=\"inbox\"]", timeout=2)
# this is for opening Nav drawer
self.cli.wait_click('//MDActionTopAppBarButton[@icon=\"menu\"]', timeout=2)
# checking state of Nav drawer
self.assertExists("//MDNavigationDrawer[@state~=\"open\"]", timeout=2)
# this is for scrolling Nav drawer
self.drag("//NavigationItem[@text=\"Sent\"]", "//NavigationItem[@text=\"Inbox\"]")
# assert for checking scroll funcation
self.assertCheckScrollDown('//ContentNavigationDrawer//ScrollView[0]', timeout=3)
# this is for opening setting screen
self.cli.wait_click('//NavigationItem[@text=\"Settings\"]', timeout=1)
# Checking current screen
self.assertExists("//Setting[@name~=\"set\"]", timeout=2)

View File

@ -10,8 +10,12 @@ from datetime import datetime
from six import string_types from six import string_types
from six.moves import configparser from six.moves import configparser
try:
import state import state
from singleton import Singleton from singleton import Singleton
except ImportError:
from pybitmessage import state
from pybitmessage.singleton import Singleton
SafeConfigParser = configparser.SafeConfigParser SafeConfigParser = configparser.SafeConfigParser

View File

@ -3,7 +3,10 @@
import os import os
import random import random
try:
from pyelliptic.openssl import OpenSSL from pyelliptic.openssl import OpenSSL
except ImportError:
from .pyelliptic.openssl import OpenSSL
NoneType = type(None) NoneType = type(None)

0
src/mock/__init__.py Normal file
View File

View File

@ -0,0 +1,96 @@
"""
A thread for creating addresses
"""
import logging
import random
import threading
from pybitmessage import state
from pybitmessage import queues
from pybitmessage.bmconfigparser import BMConfigParser
# from network.threads import StoppableThread
fake_addresses = {
'BM-2cUgQGcTLWAkC6dNsv2Bc8XB3Y1GEesVLV': {
'privsigningkey': '5KWXwYq1oJMzghUSJaJoWPn8VdeBbhDN8zFot1cBd6ezKKReqBd',
'privencryptionkey': '5JaeFJs8iPcQT3N8676r3gHKvJ5mTWXy1VLhGCEDqRs4vpvpxV8'
},
'BM-2cUd2dm8MVMokruMTcGhhteTpyRZCAMhnA': {
'privsigningkey': '5JnJ79nkcwjo4Aj7iG8sFMkzYoQqWfpUjTcitTuFJZ1YKHZz98J',
'privencryptionkey': '5JXgNzTRouFLqSRFJvuHMDHCYPBvTeMPBiHt4Jeb6smNjhUNTYq'
},
'BM-2cWyvL54WytfALrJHZqbsDHca5QkrtByAW': {
'privsigningkey': '5KVE4gLmcfYVicLdgyD4GmnbBTFSnY7Yj2UCuytQqgBBsfwDhpi',
'privencryptionkey': '5JTw48CGm5CP8fyJUJQMq8HQANQMHDHp2ETUe1dgm6EFpT1egD7'
},
'BM-2cTE65PK9Y4AQEkCZbazV86pcQACocnRXd': {
'privsigningkey': '5KCuyReHx9MB4m5hhEyCWcLEXqc8rxhD1T2VWk8CicPFc8B6LaZ',
'privencryptionkey': '5KBRpwXdX3n2tP7f583SbFgfzgs6Jemx7qfYqhdH7B1Vhe2jqY6'
},
'BM-2cX5z1EgmJ87f2oKAwXdv4VQtEVwr2V3BG': {
'privsigningkey': '5K5UK7qED7F1uWCVsehudQrszLyMZxFVnP6vN2VDQAjtn5qnyRK',
'privencryptionkey': '5J5coocoJBX6hy5DFTWKtyEgPmADpSwfQTazMpU7QPeART6oMAu'
}
}
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"
address_list = list(fake_addresses.keys())
def stopThread(self):
try:
queues.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 = queues.addressGeneratorQueue.get()
try:
address = self.address_list.pop(0)
label = queueValue[3]
BMConfigParser().add_section(address)
BMConfigParser().set(address, 'label', label)
BMConfigParser().set(address, 'enabled', 'true')
BMConfigParser().set(
address, 'privsigningkey', fake_addresses[address]['privsigningkey'])
BMConfigParser().set(
address, 'privencryptionkey', fake_addresses[address]['privencryptionkey'])
BMConfigParser().save()
queues.addressGeneratorQueue.task_done()
except IndexError:
self.logger.error(
'Program error: you can only create 5 fake addresses')

21
src/mock/kivy_main.py Normal file
View File

@ -0,0 +1,21 @@
"""Mock kivy app with mock threads."""
from pybitmessage import state
from pybitmessage.bitmessagekivy.mpybit import NavigateApp
from class_addressGenerator import FakeAddressGenerator
def main():
"""main method for starting threads"""
# Start the address generation thread
addressGeneratorThread = FakeAddressGenerator()
# close the main program even if there are threads left
addressGeneratorThread.daemon = True
addressGeneratorThread.start()
state.kivyapp = NavigateApp()
state.kivyapp.run()
if __name__ == '__main__':
main()

View File

@ -32,6 +32,8 @@ enableGUI = True
"""enable GUI (QT or ncurses)""" """enable GUI (QT or ncurses)"""
enableSTDIO = False enableSTDIO = False
"""enable STDIO threads""" """enable STDIO threads"""
enableKivy = False
"""enable kivy app and test cases"""
curses = False curses = False
maximumNumberOfHalfOpenConnections = 0 maximumNumberOfHalfOpenConnections = 0

17
tests-kivy.py Normal file
View File

@ -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())