From f09d53952127c1b36a94033f7b573bbeb3b38550 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Sat, 22 Sep 2018 16:50:39 +1000 Subject: [PATCH 01/13] GUI unit tests in both share and receive mode --- .travis.yml | 3 +- unit_tests/__init__.py | 0 unit_tests/conftest.py | 160 ++++++++++ .../onionshare_receive_mode_upload_test.py | 258 ++++++++++++++++ ...re_receive_mode_upload_test_public_mode.py | 258 ++++++++++++++++ .../onionshare_share_mode_download_test.py | 287 ++++++++++++++++++ ...re_share_mode_download_test_public_mode.py | 287 ++++++++++++++++++ ...hare_share_mode_download_test_stay_open.py | 256 ++++++++++++++++ unit_tests/onionshare_timer_test.py | 142 +++++++++ unit_tests/run_unit_tests.sh | 5 + 10 files changed, 1655 insertions(+), 1 deletion(-) create mode 100644 unit_tests/__init__.py create mode 100644 unit_tests/conftest.py create mode 100644 unit_tests/onionshare_receive_mode_upload_test.py create mode 100644 unit_tests/onionshare_receive_mode_upload_test_public_mode.py create mode 100644 unit_tests/onionshare_share_mode_download_test.py create mode 100644 unit_tests/onionshare_share_mode_download_test_public_mode.py create mode 100644 unit_tests/onionshare_share_mode_download_test_stay_open.py create mode 100644 unit_tests/onionshare_timer_test.py create mode 100755 unit_tests/run_unit_tests.sh diff --git a/.travis.yml b/.travis.yml index afbaa887..71778af4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ python: # command to install dependencies install: - pip install -r install/requirements.txt - - pip install pytest-cov coveralls flake8 + - pip install pytest-cov coveralls flake8 pytest-faulthandler pytest-ordering before_script: # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics @@ -17,5 +17,6 @@ before_script: - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics # command to run tests script: pytest --cov=onionshare test/ +script: cd unit_tests && bash run_unit_tests.sh after_success: - coveralls diff --git a/unit_tests/__init__.py b/unit_tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/unit_tests/conftest.py b/unit_tests/conftest.py new file mode 100644 index 00000000..8ac7efb8 --- /dev/null +++ b/unit_tests/conftest.py @@ -0,0 +1,160 @@ +import sys +# Force tests to look for resources in the source code tree +sys.onionshare_dev_mode = True + +import os +import shutil +import tempfile + +import pytest + +from onionshare import common, web, settings + +@pytest.fixture +def temp_dir_1024(): + """ Create a temporary directory that has a single file of a + particular size (1024 bytes). + """ + + tmp_dir = tempfile.mkdtemp() + tmp_file, tmp_file_path = tempfile.mkstemp(dir=tmp_dir) + with open(tmp_file, 'wb') as f: + f.write(b'*' * 1024) + return tmp_dir + + +# pytest > 2.9 only needs @pytest.fixture +@pytest.yield_fixture +def temp_dir_1024_delete(): + """ Create a temporary directory that has a single file of a + particular size (1024 bytes). The temporary directory (including + the file inside) will be deleted after fixture usage. + """ + + with tempfile.TemporaryDirectory() as tmp_dir: + tmp_file, tmp_file_path = tempfile.mkstemp(dir=tmp_dir) + with open(tmp_file, 'wb') as f: + f.write(b'*' * 1024) + yield tmp_dir + + +@pytest.fixture +def temp_file_1024(): + """ Create a temporary file of a particular size (1024 bytes). """ + + with tempfile.NamedTemporaryFile(delete=False) as tmp_file: + tmp_file.write(b'*' * 1024) + return tmp_file.name + + +# pytest > 2.9 only needs @pytest.fixture +@pytest.yield_fixture +def temp_file_1024_delete(): + """ + Create a temporary file of a particular size (1024 bytes). + The temporary file will be deleted after fixture usage. + """ + + with tempfile.NamedTemporaryFile() as tmp_file: + tmp_file.write(b'*' * 1024) + tmp_file.flush() + yield tmp_file.name + + +# pytest > 2.9 only needs @pytest.fixture +@pytest.yield_fixture(scope='session') +def custom_zw(): + zw = web.share_mode.ZipWriter( + common.Common(), + zip_filename=common.Common.random_string(4, 6), + processed_size_callback=lambda _: 'custom_callback' + ) + yield zw + zw.close() + os.remove(zw.zip_filename) + + +# pytest > 2.9 only needs @pytest.fixture +@pytest.yield_fixture(scope='session') +def default_zw(): + zw = web.share_mode.ZipWriter(common.Common()) + yield zw + zw.close() + tmp_dir = os.path.dirname(zw.zip_filename) + shutil.rmtree(tmp_dir) + + +@pytest.fixture +def locale_en(monkeypatch): + monkeypatch.setattr('locale.getdefaultlocale', lambda: ('en_US', 'UTF-8')) + + +@pytest.fixture +def locale_fr(monkeypatch): + monkeypatch.setattr('locale.getdefaultlocale', lambda: ('fr_FR', 'UTF-8')) + + +@pytest.fixture +def locale_invalid(monkeypatch): + monkeypatch.setattr('locale.getdefaultlocale', lambda: ('xx_XX', 'UTF-8')) + + +@pytest.fixture +def locale_ru(monkeypatch): + monkeypatch.setattr('locale.getdefaultlocale', lambda: ('ru_RU', 'UTF-8')) + + +@pytest.fixture +def platform_darwin(monkeypatch): + monkeypatch.setattr('platform.system', lambda: 'Darwin') + + +@pytest.fixture # (scope="session") +def platform_linux(monkeypatch): + monkeypatch.setattr('platform.system', lambda: 'Linux') + + +@pytest.fixture +def platform_windows(monkeypatch): + monkeypatch.setattr('platform.system', lambda: 'Windows') + + +@pytest.fixture +def sys_argv_sys_prefix(monkeypatch): + monkeypatch.setattr('sys.argv', [sys.prefix]) + + +@pytest.fixture +def sys_frozen(monkeypatch): + monkeypatch.setattr('sys.frozen', True, raising=False) + + +@pytest.fixture +def sys_meipass(monkeypatch): + monkeypatch.setattr( + 'sys._MEIPASS', os.path.expanduser('~'), raising=False) + + +@pytest.fixture # (scope="session") +def sys_onionshare_dev_mode(monkeypatch): + monkeypatch.setattr('sys.onionshare_dev_mode', True, raising=False) + + +@pytest.fixture +def time_time_100(monkeypatch): + monkeypatch.setattr('time.time', lambda: 100) + + +@pytest.fixture +def time_strftime(monkeypatch): + monkeypatch.setattr('time.strftime', lambda _: 'Jun 06 2013 11:05:00') + +@pytest.fixture +def common_obj(): + return common.Common() + +@pytest.fixture +def settings_obj(sys_onionshare_dev_mode, platform_linux): + _common = common.Common() + _common.version = 'DUMMY_VERSION_1.2.3' + return settings.Settings(_common) diff --git a/unit_tests/onionshare_receive_mode_upload_test.py b/unit_tests/onionshare_receive_mode_upload_test.py new file mode 100644 index 00000000..b99faac0 --- /dev/null +++ b/unit_tests/onionshare_receive_mode_upload_test.py @@ -0,0 +1,258 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import socket +import pytest +import zipfile +import socks +import json +import requests + +from PyQt5 import QtCore, QtWidgets, QtTest + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, True, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": False, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + os.remove('/tmp/OnionShare/test.txt') + os.remove('/tmp/OnionShare/test-2.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded_and_tor_bootstrapped(self): + '''Test that the GUI actually is shown''' + self.assertTrue(self.gui.show) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + '''Test that the window title is OnionShare''' + self.assertEqual(self.gui.windowTitle(), 'OnionShare') + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + '''Test that the settings button is visible''' + self.assertTrue(self.gui.settings_button.isVisible()) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + '''Test that the status bar is visible''' + self.assertTrue(self.gui.status_bar.isVisible()) + + @pytest.mark.run(order=5) + def test_info_widget_is_not_visible(self): + '''Test that the info widget along top of screen is not shown because we have a file''' + self.assertFalse(self.gui.receive_mode.info_widget.isVisible()) + + @pytest.mark.run(order=6) + def test_click_receive_mode(self): + '''Test that we can switch to Receive Mode by clicking the button''' + QtTest.QTest.mouseClick(self.gui.receive_mode_button, QtCore.Qt.LeftButton) + self.assertTrue(self.gui.mode, self.gui.MODE_RECEIVE) + + @pytest.mark.run(order=7) + def test_uploads_section_is_visible(self): + '''Test that the Uploads section is visible and that the No Uploads Yet label is present''' + self.assertTrue(self.gui.receive_mode.uploads.isVisible()) + self.assertTrue(self.gui.receive_mode.uploads.no_uploads_label.isVisible()) + + @pytest.mark.run(order=8) + def test_server_working_on_start_button_pressed(self): + '''Test we can start the service''' + QtTest.QTest.mouseClick(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) + + # Should be in SERVER_WORKING state + self.assertEqual(self.gui.receive_mode.server_status.status, 1) + + @pytest.mark.run(order=9) + def test_server_status_indicator_says_starting(self): + '''Test that the Server Status indicator shows we are Starting''' + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + + @pytest.mark.run(order=10) + def test_settings_button_is_hidden(self): + '''Test that the settings button is hidden when the server starts''' + self.assertFalse(self.gui.settings_button.isVisible()) + + @pytest.mark.run(order=11) + def test_a_server_is_started(self): + '''Test that the server has started''' + QtTest.QTest.qWait(2000) + # Should now be in SERVER_STARTED state + self.assertEqual(self.gui.receive_mode.server_status.status, 2) + + @pytest.mark.run(order=12) + def test_a_web_server_is_running(self): + '''Test that the web server has started''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + # Running in local mode, so we have no .onion + #@pytest.mark.run(order=13) + #def test_have_an_onion_service(self): + # '''Test that we have a valid Onion URL''' + # self.assertRegex(self.gui.app.onion_host, r'[a-z2-7].onion') + # self.assertEqual(len(self.gui.app.onion_host), 62) + + @pytest.mark.run(order=14) + def test_have_a_slug(self): + '''Test that we have a valid slug''' + self.assertRegex(self.gui.receive_mode.server_status.web.slug, r'(\w+)-(\w+)') + + @pytest.mark.run(order=15) + def test_url_description_shown(self): + '''Test that the URL label is showing''' + self.assertTrue(self.gui.receive_mode.server_status.url_description.isVisible()) + + @pytest.mark.run(order=16) + def test_have_copy_url_button(self): + '''Test that the Copy URL button is shown''' + self.assertTrue(self.gui.receive_mode.server_status.copy_url_button.isVisible()) + + @pytest.mark.run(order=17) + def test_server_status_indicator_says_sharing(self): + '''Test that the Server Status indicator shows we are Receiving''' + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_started', True)) + + @pytest.mark.run(order=18) + def test_web_page(self): + '''Test that the web page contains the term Select the files you want to send, then click''' + s = socks.socksocket() + s.settimeout(60) + s.connect(('127.0.0.1', self.gui.app.port)) + + http_request = 'GET {} HTTP/1.0\r\n'.format(self.gui.receive_mode.server_status.web.slug) + http_request += 'Host: 127.0.0.1\r\n' + http_request += '\r\n' + s.sendall(http_request.encode('utf-8')) + + with open('/tmp/webpage', 'wb') as file_to_write: + while True: + data = s.recv(1024) + if not data: + break + file_to_write.write(data) + file_to_write.close() + + f = open('/tmp/webpage') + self.assertTrue('Select the files you want to send, then click "Send Files"' in f.read()) + f.close() + + @pytest.mark.run(order=19) + def test_upload_file(self): + '''Test that we can upload the file''' + files = {'file[]': open('/tmp/test.txt', 'rb')} + response = requests.post('http://127.0.0.1:{}/{}/upload'.format(self.gui.app.port, self.gui.receive_mode.web.slug), files=files) + QtTest.QTest.qWait(2000) + self.assertTrue(os.path.isfile('/tmp/OnionShare/test.txt')) + + @pytest.mark.run(order=20) + def test_uploads_widget_present(self): + '''Test that the No Uploads Yet label is hidden, that Clear History is present''' + self.assertFalse(self.gui.receive_mode.uploads.no_uploads_label.isVisible()) + self.assertTrue(self.gui.receive_mode.uploads.clear_history_button.isVisible()) + + @pytest.mark.run(order=21) + def test_upload_count_incremented(self): + '''Test that the Upload Count has incremented''' + self.assertEquals(self.gui.receive_mode.uploads_completed, 1) + + @pytest.mark.run(order=22) + def test_upload_same_file_is_renamed(self): + '''Test that we can upload the same file and that it gets renamed''' + files = {'file[]': open('/tmp/test.txt', 'rb')} + response = requests.post('http://127.0.0.1:{}/{}/upload'.format(self.gui.app.port, self.gui.receive_mode.web.slug), files=files) + QtTest.QTest.qWait(2000) + self.assertTrue(os.path.isfile('/tmp/OnionShare/test-2.txt')) + + @pytest.mark.run(order=23) + def test_upload_count_incremented_again(self): + '''Test that the Upload Count has incremented again''' + self.assertEquals(self.gui.receive_mode.uploads_completed, 2) + + @pytest.mark.run(order=24) + def test_server_is_stopped(self): + '''Test that the server stops when we click Stop''' + QtTest.QTest.mouseClick(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) + self.assertEquals(self.gui.receive_mode.server_status.status, 0) + + @pytest.mark.run(order=25) + def test_web_service_is_stopped(self): + '''Test that the web server also stopped''' + QtTest.QTest.qWait(2000) + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # We should be closed by now. Fail if not! + self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + @pytest.mark.run(order=26) + def test_server_status_indicator_says_closed(self): + '''Test that the Server Status indicator shows we closed''' + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_stopped', True)) + +if __name__ == "__main__": + unittest.main() diff --git a/unit_tests/onionshare_receive_mode_upload_test_public_mode.py b/unit_tests/onionshare_receive_mode_upload_test_public_mode.py new file mode 100644 index 00000000..d309e5b1 --- /dev/null +++ b/unit_tests/onionshare_receive_mode_upload_test_public_mode.py @@ -0,0 +1,258 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import socket +import pytest +import zipfile +import socks +import json +import requests + +from PyQt5 import QtCore, QtWidgets, QtTest + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, True, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": True, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + os.remove('/tmp/OnionShare/test.txt') + os.remove('/tmp/OnionShare/test-2.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded_and_tor_bootstrapped(self): + '''Test that the GUI actually is shown''' + self.assertTrue(self.gui.show) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + '''Test that the window title is OnionShare''' + self.assertEqual(self.gui.windowTitle(), 'OnionShare') + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + '''Test that the settings button is visible''' + self.assertTrue(self.gui.settings_button.isVisible()) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + '''Test that the status bar is visible''' + self.assertTrue(self.gui.status_bar.isVisible()) + + @pytest.mark.run(order=5) + def test_info_widget_is_not_visible(self): + '''Test that the info widget along top of screen is not shown because we have a file''' + self.assertFalse(self.gui.receive_mode.info_widget.isVisible()) + + @pytest.mark.run(order=6) + def test_click_receive_mode(self): + '''Test that we can switch to Receive Mode by clicking the button''' + QtTest.QTest.mouseClick(self.gui.receive_mode_button, QtCore.Qt.LeftButton) + self.assertTrue(self.gui.mode, self.gui.MODE_RECEIVE) + + @pytest.mark.run(order=7) + def test_uploads_section_is_visible(self): + '''Test that the Uploads section is visible and that the No Uploads Yet label is present''' + self.assertTrue(self.gui.receive_mode.uploads.isVisible()) + self.assertTrue(self.gui.receive_mode.uploads.no_uploads_label.isVisible()) + + @pytest.mark.run(order=8) + def test_server_working_on_start_button_pressed(self): + '''Test we can start the service''' + QtTest.QTest.mouseClick(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) + + # Should be in SERVER_WORKING state + self.assertEqual(self.gui.receive_mode.server_status.status, 1) + + @pytest.mark.run(order=9) + def test_server_status_indicator_says_starting(self): + '''Test that the Server Status indicator shows we are Starting''' + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + + @pytest.mark.run(order=10) + def test_settings_button_is_hidden(self): + '''Test that the settings button is hidden when the server starts''' + self.assertFalse(self.gui.settings_button.isVisible()) + + @pytest.mark.run(order=11) + def test_a_server_is_started(self): + '''Test that the server has started''' + QtTest.QTest.qWait(2000) + # Should now be in SERVER_STARTED state + self.assertEqual(self.gui.receive_mode.server_status.status, 2) + + @pytest.mark.run(order=12) + def test_a_web_server_is_running(self): + '''Test that the web server has started''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + # Running in local mode, so we have no .onion + #@pytest.mark.run(order=13) + #def test_have_an_onion_service(self): + # '''Test that we have a valid Onion URL''' + # self.assertRegex(self.gui.app.onion_host, r'[a-z2-7].onion') + # self.assertEqual(len(self.gui.app.onion_host), 62) + + @pytest.mark.run(order=14) + def test_have_no_slug(self): + '''Test that we have a valid slug''' + self.assertIsNone(self.gui.share_mode.server_status.web.slug) + + @pytest.mark.run(order=15) + def test_url_description_shown(self): + '''Test that the URL label is showing''' + self.assertTrue(self.gui.receive_mode.server_status.url_description.isVisible()) + + @pytest.mark.run(order=16) + def test_have_copy_url_button(self): + '''Test that the Copy URL button is shown''' + self.assertTrue(self.gui.receive_mode.server_status.copy_url_button.isVisible()) + + @pytest.mark.run(order=17) + def test_server_status_indicator_says_sharing(self): + '''Test that the Server Status indicator shows we are Receiving''' + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_started', True)) + + @pytest.mark.run(order=18) + def test_web_page(self): + '''Test that the web page contains the term Select the files you want to send, then click''' + s = socks.socksocket() + s.settimeout(60) + s.connect(('127.0.0.1', self.gui.app.port)) + + http_request = 'GET / HTTP/1.0\r\n' + http_request += 'Host: 127.0.0.1\r\n' + http_request += '\r\n' + s.sendall(http_request.encode('utf-8')) + + with open('/tmp/webpage', 'wb') as file_to_write: + while True: + data = s.recv(1024) + if not data: + break + file_to_write.write(data) + file_to_write.close() + + f = open('/tmp/webpage') + self.assertTrue('Select the files you want to send, then click "Send Files"' in f.read()) + f.close() + + @pytest.mark.run(order=19) + def test_upload_file(self): + '''Test that we can upload the file''' + files = {'file[]': open('/tmp/test.txt', 'rb')} + response = requests.post('http://127.0.0.1:{}/upload'.format(self.gui.app.port), files=files) + QtTest.QTest.qWait(2000) + self.assertTrue(os.path.isfile('/tmp/OnionShare/test.txt')) + + @pytest.mark.run(order=20) + def test_uploads_widget_present(self): + '''Test that the No Uploads Yet label is hidden, that Clear History is present''' + self.assertFalse(self.gui.receive_mode.uploads.no_uploads_label.isVisible()) + self.assertTrue(self.gui.receive_mode.uploads.clear_history_button.isVisible()) + + @pytest.mark.run(order=21) + def test_upload_count_incremented(self): + '''Test that the Upload Count has incremented''' + self.assertEquals(self.gui.receive_mode.uploads_completed, 1) + + @pytest.mark.run(order=22) + def test_upload_same_file_is_renamed(self): + '''Test that we can upload the same file and that it gets renamed''' + files = {'file[]': open('/tmp/test.txt', 'rb')} + response = requests.post('http://127.0.0.1:{}/upload'.format(self.gui.app.port), files=files) + QtTest.QTest.qWait(2000) + self.assertTrue(os.path.isfile('/tmp/OnionShare/test-2.txt')) + + @pytest.mark.run(order=23) + def test_upload_count_incremented_again(self): + '''Test that the Upload Count has incremented again''' + self.assertEquals(self.gui.receive_mode.uploads_completed, 2) + + @pytest.mark.run(order=24) + def test_server_is_stopped(self): + '''Test that the server stops when we click Stop''' + QtTest.QTest.mouseClick(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) + self.assertEquals(self.gui.receive_mode.server_status.status, 0) + + @pytest.mark.run(order=25) + def test_web_service_is_stopped(self): + '''Test that the web server also stopped''' + QtTest.QTest.qWait(2000) + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # We should be closed by now. Fail if not! + self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + @pytest.mark.run(order=26) + def test_server_status_indicator_says_closed(self): + '''Test that the Server Status indicator shows we closed''' + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_stopped', True)) + +if __name__ == "__main__": + unittest.main() diff --git a/unit_tests/onionshare_share_mode_download_test.py b/unit_tests/onionshare_share_mode_download_test.py new file mode 100644 index 00000000..aa8dcdaa --- /dev/null +++ b/unit_tests/onionshare_share_mode_download_test.py @@ -0,0 +1,287 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import socket +import pytest +import zipfile +import socks +import json + +from PyQt5 import QtCore, QtWidgets, QtTest + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, True, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": False, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded_and_tor_bootstrapped(self): + '''Test that the GUI actually is shown''' + self.assertTrue(self.gui.show) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + '''Test that the window title is OnionShare''' + self.assertEqual(self.gui.windowTitle(), 'OnionShare') + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + '''Test that the settings button is visible''' + self.assertTrue(self.gui.settings_button.isVisible()) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + '''Test that the status bar is visible''' + self.assertTrue(self.gui.status_bar.isVisible()) + + @pytest.mark.run(order=5) + def test_file_selection_widget_has_a_file(self): + '''Test that the number of files in the list is 1''' + self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 1) + + @pytest.mark.run(order=6) + def test_info_widget_is_visible(self): + '''Test that the info widget along top of screen is shown because we have a file''' + self.assertTrue(self.gui.share_mode.info_widget.isVisible()) + + @pytest.mark.run(order=7) + def test_downloads_section_is_visible(self): + '''Test that the Downloads section is visible and that the No Downloads Yet label is present''' + self.assertTrue(self.gui.share_mode.downloads.isVisible()) + self.assertTrue(self.gui.share_mode.downloads.no_downloads_label.isVisible()) + + @pytest.mark.run(order=8) + def test_deleting_only_file_hides_delete_button(self): + '''Test that clicking on the file item shows the delete button. Test that deleting the only item in the list hides the delete button''' + rect = self.gui.share_mode.server_status.file_selection.file_list.visualItemRect(self.gui.share_mode.server_status.file_selection.file_list.item(0)) + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.viewport(), QtCore.Qt.LeftButton, pos=rect.center()) + # Delete button should be visible + self.assertTrue(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + # Click delete, and since there's no more files, the delete button should be hidden + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.delete_button, QtCore.Qt.LeftButton) + self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + + @pytest.mark.run(order=9) + def test_add_a_file_and_delete_using_its_delete_widget(self): + '''Test that we can also delete a file by clicking on its [X] widget''' + self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.item(0).item_button, QtCore.Qt.LeftButton) + self.assertEquals(self.gui.share_mode.server_status.file_selection.get_num_files(), 0) + + @pytest.mark.run(order=10) + def test_file_selection_widget_readd_files(self): + '''Re-add some files to the list so we can share''' + self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') + self.gui.share_mode.server_status.file_selection.file_list.add_file('/tmp/test.txt') + self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 2) + + @pytest.mark.run(order=11) + def test_server_working_on_start_button_pressed(self): + '''Test we can start the service''' + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + + # Should be in SERVER_WORKING state + self.assertEqual(self.gui.share_mode.server_status.status, 1) + + @pytest.mark.run(order=12) + def test_server_status_indicator_says_starting(self): + '''Test that the Server Status indicator shows we are Starting''' + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + + @pytest.mark.run(order=13) + def test_add_delete_buttons_now_hidden(self): + '''Test that the add and delete buttons are hidden when the server starts''' + self.assertFalse(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) + self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + + @pytest.mark.run(order=14) + def test_settings_button_is_hidden(self): + '''Test that the settings button is hidden when the server starts''' + self.assertFalse(self.gui.settings_button.isVisible()) + + @pytest.mark.run(order=15) + def test_a_server_is_started(self): + '''Test that the server has started''' + QtTest.QTest.qWait(2000) + # Should now be in SERVER_STARTED state + self.assertEqual(self.gui.share_mode.server_status.status, 2) + + @pytest.mark.run(order=16) + def test_a_web_server_is_running(self): + '''Test that the web server has started''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + # Running in local mode, so we have no .onion + #@pytest.mark.run(order=17) + #def test_have_an_onion_service(self): + # '''Test that we have a valid Onion URL''' + # self.assertRegex(self.gui.app.onion_host, r'[a-z2-7].onion') + # self.assertEqual(len(self.gui.app.onion_host), 62) + + @pytest.mark.run(order=18) + def test_have_a_slug(self): + '''Test that we have a valid slug''' + self.assertRegex(self.gui.share_mode.server_status.web.slug, r'(\w+)-(\w+)') + + @pytest.mark.run(order=19) + def test_url_description_shown(self): + '''Test that the URL label is showing''' + self.assertTrue(self.gui.share_mode.server_status.url_description.isVisible()) + + @pytest.mark.run(order=20) + def test_have_copy_url_button(self): + '''Test that the Copy URL button is shown''' + self.assertTrue(self.gui.share_mode.server_status.copy_url_button.isVisible()) + + @pytest.mark.run(order=21) + def test_server_status_indicator_says_sharing(self): + '''Test that the Server Status indicator shows we are Sharing''' + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_started', True)) + + @pytest.mark.run(order=22) + def test_web_page(self): + '''Test that the web page contains the term Total size''' + s = socks.socksocket() + s.settimeout(60) + s.connect(('127.0.0.1', self.gui.app.port)) + + http_request = 'GET {} HTTP/1.0\r\n'.format(self.gui.share_mode.server_status.web.slug) + http_request += 'Host: 127.0.0.1\r\n' + http_request += '\r\n' + s.sendall(http_request.encode('utf-8')) + + with open('/tmp/webpage', 'wb') as file_to_write: + while True: + data = s.recv(1024) + if not data: + break + file_to_write.write(data) + file_to_write.close() + + f = open('/tmp/webpage') + self.assertTrue('Total size' in f.read()) + f.close() + + @pytest.mark.run(order=23) + def test_download_share(self): + '''Test that we can download the share''' + s = socks.socksocket() + s.settimeout(60) + s.connect(('127.0.0.1', self.gui.app.port)) + + http_request = 'GET {}/download HTTP/1.0\r\n'.format(self.gui.share_mode.server_status.web.slug) + http_request += 'Host: 127.0.0.1\r\n' + http_request += '\r\n' + s.sendall(http_request.encode('utf-8')) + + with open('/tmp/download.zip', 'wb') as file_to_write: + while True: + data = s.recv(1024) + if not data: + break + file_to_write.write(data) + file_to_write.close() + + zip = zipfile.ZipFile('/tmp/download.zip') + self.assertEquals('onionshare', zip.read('test.txt').decode('utf-8')) + + @pytest.mark.run(order=24) + def test_downloads_widget_present(self): + QtTest.QTest.qWait(1000) + '''Test that the No Downloads Yet label is hidden, that Clear History is present''' + self.assertFalse(self.gui.share_mode.downloads.no_downloads_label.isVisible()) + self.assertTrue(self.gui.share_mode.downloads.clear_history_button.isVisible()) + + @pytest.mark.run(order=25) + def test_server_is_stopped(self): + '''Test that the server stopped automatically when we downloaded the share''' + self.assertEquals(self.gui.share_mode.server_status.status, 0) + + @pytest.mark.run(order=26) + def test_web_service_is_stopped(self): + '''Test that the web server also stopped''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # We should be closed by now. Fail if not! + self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + @pytest.mark.run(order=27) + def test_server_status_indicator_says_closed(self): + '''Test that the Server Status indicator shows we closed because download occurred''' + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('closing_automatically', True)) + + @pytest.mark.run(order=28) + def test_add_button_visible_again(self): + '''Test that the add button should be visible again''' + self.assertTrue(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) + + +if __name__ == "__main__": + unittest.main() diff --git a/unit_tests/onionshare_share_mode_download_test_public_mode.py b/unit_tests/onionshare_share_mode_download_test_public_mode.py new file mode 100644 index 00000000..59905149 --- /dev/null +++ b/unit_tests/onionshare_share_mode_download_test_public_mode.py @@ -0,0 +1,287 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import socket +import pytest +import zipfile +import socks +import json + +from PyQt5 import QtCore, QtWidgets, QtTest + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, True, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": True, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded_and_tor_bootstrapped(self): + '''Test that the GUI actually is shown''' + self.assertTrue(self.gui.show) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + '''Test that the window title is OnionShare''' + self.assertEqual(self.gui.windowTitle(), 'OnionShare') + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + '''Test that the settings button is visible''' + self.assertTrue(self.gui.settings_button.isVisible()) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + '''Test that the status bar is visible''' + self.assertTrue(self.gui.status_bar.isVisible()) + + @pytest.mark.run(order=5) + def test_file_selection_widget_has_a_file(self): + '''Test that the number of files in the list is 1''' + self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 1) + + @pytest.mark.run(order=6) + def test_info_widget_is_visible(self): + '''Test that the info widget along top of screen is shown because we have a file''' + self.assertTrue(self.gui.share_mode.info_widget.isVisible()) + + @pytest.mark.run(order=7) + def test_downloads_section_is_visible(self): + '''Test that the Downloads section is visible and that the No Downloads Yet label is present''' + self.assertTrue(self.gui.share_mode.downloads.isVisible()) + self.assertTrue(self.gui.share_mode.downloads.no_downloads_label.isVisible()) + + @pytest.mark.run(order=8) + def test_deleting_only_file_hides_delete_button(self): + '''Test that clicking on the file item shows the delete button. Test that deleting the only item in the list hides the delete button''' + rect = self.gui.share_mode.server_status.file_selection.file_list.visualItemRect(self.gui.share_mode.server_status.file_selection.file_list.item(0)) + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.viewport(), QtCore.Qt.LeftButton, pos=rect.center()) + # Delete button should be visible + self.assertTrue(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + # Click delete, and since there's no more files, the delete button should be hidden + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.delete_button, QtCore.Qt.LeftButton) + self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + + @pytest.mark.run(order=9) + def test_add_a_file_and_delete_using_its_delete_widget(self): + '''Test that we can also delete a file by clicking on its [X] widget''' + self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.item(0).item_button, QtCore.Qt.LeftButton) + self.assertEquals(self.gui.share_mode.server_status.file_selection.get_num_files(), 0) + + @pytest.mark.run(order=10) + def test_file_selection_widget_readd_files(self): + '''Re-add some files to the list so we can share''' + self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') + self.gui.share_mode.server_status.file_selection.file_list.add_file('/tmp/test.txt') + self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 2) + + @pytest.mark.run(order=11) + def test_server_working_on_start_button_pressed(self): + '''Test we can start the service''' + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + + # Should be in SERVER_WORKING state + self.assertEqual(self.gui.share_mode.server_status.status, 1) + + @pytest.mark.run(order=12) + def test_server_status_indicator_says_starting(self): + '''Test that the Server Status indicator shows we are Starting''' + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + + @pytest.mark.run(order=13) + def test_add_delete_buttons_now_hidden(self): + '''Test that the add and delete buttons are hidden when the server starts''' + self.assertFalse(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) + self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + + @pytest.mark.run(order=14) + def test_settings_button_is_hidden(self): + '''Test that the settings button is hidden when the server starts''' + self.assertFalse(self.gui.settings_button.isVisible()) + + @pytest.mark.run(order=15) + def test_a_server_is_started(self): + '''Test that the server has started''' + QtTest.QTest.qWait(2000) + # Should now be in SERVER_STARTED state + self.assertEqual(self.gui.share_mode.server_status.status, 2) + + @pytest.mark.run(order=16) + def test_a_web_server_is_running(self): + '''Test that the web server has started''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + # Running in local mode, so we have no .onion + #@pytest.mark.run(order=17) + #def test_have_an_onion_service(self): + # '''Test that we have a valid Onion URL''' + # self.assertRegex(self.gui.app.onion_host, r'[a-z2-7].onion') + # self.assertEqual(len(self.gui.app.onion_host), 62) + + @pytest.mark.run(order=18) + def test_have_no_slug(self): + '''Test that we have a valid slug''' + self.assertIsNone(self.gui.share_mode.server_status.web.slug) + + @pytest.mark.run(order=19) + def test_url_description_shown(self): + '''Test that the URL label is showing''' + self.assertTrue(self.gui.share_mode.server_status.url_description.isVisible()) + + @pytest.mark.run(order=20) + def test_have_copy_url_button(self): + '''Test that the Copy URL button is shown''' + self.assertTrue(self.gui.share_mode.server_status.copy_url_button.isVisible()) + + @pytest.mark.run(order=21) + def test_server_status_indicator_says_sharing(self): + '''Test that the Server Status indicator shows we are Sharing''' + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_started', True)) + + @pytest.mark.run(order=22) + def test_web_page(self): + '''Test that the web page contains the term Total size''' + s = socks.socksocket() + s.settimeout(60) + s.connect(('127.0.0.1', self.gui.app.port)) + + http_request = 'GET / HTTP/1.0\r\n' + http_request += 'Host: 127.0.0.1\r\n' + http_request += '\r\n' + s.sendall(http_request.encode('utf-8')) + + with open('/tmp/webpage', 'wb') as file_to_write: + while True: + data = s.recv(1024) + if not data: + break + file_to_write.write(data) + file_to_write.close() + + f = open('/tmp/webpage') + self.assertTrue('Total size' in f.read()) + f.close() + + @pytest.mark.run(order=23) + def test_download_share(self): + '''Test that we can download the share''' + s = socks.socksocket() + s.settimeout(60) + s.connect(('127.0.0.1', self.gui.app.port)) + + http_request = 'GET /download HTTP/1.0\r\n' + http_request += 'Host: 127.0.0.1\r\n' + http_request += '\r\n' + s.sendall(http_request.encode('utf-8')) + + with open('/tmp/download.zip', 'wb') as file_to_write: + while True: + data = s.recv(1024) + if not data: + break + file_to_write.write(data) + file_to_write.close() + + zip = zipfile.ZipFile('/tmp/download.zip') + self.assertEquals('onionshare', zip.read('test.txt').decode('utf-8')) + + @pytest.mark.run(order=24) + def test_downloads_widget_present(self): + QtTest.QTest.qWait(1000) + '''Test that the No Downloads Yet label is hidden, that Clear History is present''' + self.assertFalse(self.gui.share_mode.downloads.no_downloads_label.isVisible()) + self.assertTrue(self.gui.share_mode.downloads.clear_history_button.isVisible()) + + @pytest.mark.run(order=25) + def test_server_is_stopped(self): + '''Test that the server stopped automatically when we downloaded the share''' + self.assertEquals(self.gui.share_mode.server_status.status, 0) + + @pytest.mark.run(order=26) + def test_web_service_is_stopped(self): + '''Test that the web server also stopped''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # We should be closed by now. Fail if not! + self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + @pytest.mark.run(order=27) + def test_server_status_indicator_says_closed(self): + '''Test that the Server Status indicator shows we closed because download occurred''' + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('closing_automatically', True)) + + @pytest.mark.run(order=28) + def test_add_button_visible_again(self): + '''Test that the add button should be visible again''' + self.assertTrue(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) + + +if __name__ == "__main__": + unittest.main() diff --git a/unit_tests/onionshare_share_mode_download_test_stay_open.py b/unit_tests/onionshare_share_mode_download_test_stay_open.py new file mode 100644 index 00000000..82a0ac87 --- /dev/null +++ b/unit_tests/onionshare_share_mode_download_test_stay_open.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import socket +import pytest +import zipfile +import socks +import json + +from PyQt5 import QtCore, QtWidgets, QtTest + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, True, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": False, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": False, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded_and_tor_bootstrapped(self): + '''Test that the GUI actually is shown''' + self.assertTrue(self.gui.show) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + '''Test that the window title is OnionShare''' + self.assertEqual(self.gui.windowTitle(), 'OnionShare') + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + '''Test that the settings button is visible''' + self.assertTrue(self.gui.settings_button.isVisible()) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + '''Test that the status bar is visible''' + self.assertTrue(self.gui.status_bar.isVisible()) + + @pytest.mark.run(order=5) + def test_file_selection_widget_has_a_file(self): + '''Test that the number of files in the list is 1''' + self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 1) + + @pytest.mark.run(order=6) + def test_info_widget_is_visible(self): + '''Test that the info widget along top of screen is shown because we have a file''' + self.assertTrue(self.gui.share_mode.info_widget.isVisible()) + + @pytest.mark.run(order=7) + def test_downloads_section_is_visible(self): + '''Test that the Downloads section is visible and that the No Downloads Yet label is present''' + self.assertTrue(self.gui.share_mode.downloads.isVisible()) + self.assertTrue(self.gui.share_mode.downloads.no_downloads_label.isVisible()) + + @pytest.mark.run(order=8) + def test_deleting_only_file_hides_delete_button(self): + '''Test that clicking on the file item shows the delete button. Test that deleting the only item in the list hides the delete button''' + rect = self.gui.share_mode.server_status.file_selection.file_list.visualItemRect(self.gui.share_mode.server_status.file_selection.file_list.item(0)) + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.viewport(), QtCore.Qt.LeftButton, pos=rect.center()) + # Delete button should be visible + self.assertTrue(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + # Click delete, and since there's no more files, the delete button should be hidden + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.delete_button, QtCore.Qt.LeftButton) + self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + + @pytest.mark.run(order=9) + def test_add_a_file_and_delete_using_its_delete_widget(self): + '''Test that we can also delete a file by clicking on its [X] widget''' + self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.item(0).item_button, QtCore.Qt.LeftButton) + self.assertEquals(self.gui.share_mode.server_status.file_selection.get_num_files(), 0) + + @pytest.mark.run(order=10) + def test_file_selection_widget_readd_files(self): + '''Re-add some files to the list so we can share''' + self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') + self.gui.share_mode.server_status.file_selection.file_list.add_file('/tmp/test.txt') + self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 2) + + @pytest.mark.run(order=11) + def test_server_working_on_start_button_pressed(self): + '''Test we can start the service''' + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + + # Should be in SERVER_WORKING state + self.assertEqual(self.gui.share_mode.server_status.status, 1) + + @pytest.mark.run(order=12) + def test_server_status_indicator_says_starting(self): + '''Test that the Server Status indicator shows we are Starting''' + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + + @pytest.mark.run(order=13) + def test_add_delete_buttons_now_hidden(self): + '''Test that the add and delete buttons are hidden when the server starts''' + self.assertFalse(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) + self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + + @pytest.mark.run(order=14) + def test_settings_button_is_hidden(self): + '''Test that the settings button is hidden when the server starts''' + self.assertFalse(self.gui.settings_button.isVisible()) + + @pytest.mark.run(order=15) + def test_a_server_is_started(self): + '''Test that the server has started''' + QtTest.QTest.qWait(2000) + # Should now be in SERVER_STARTED state + self.assertEqual(self.gui.share_mode.server_status.status, 2) + + @pytest.mark.run(order=16) + def test_a_web_server_is_running(self): + '''Test that the web server has started''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + # Running in local mode, so we have no .onion + #@pytest.mark.run(order=17) + #def test_have_an_onion_service(self): + # '''Test that we have a valid Onion URL''' + # self.assertRegex(self.gui.app.onion_host, r'[a-z2-7].onion') + # self.assertEqual(len(self.gui.app.onion_host), 62) + + @pytest.mark.run(order=18) + def test_have_a_slug(self): + '''Test that we have a valid slug''' + self.assertRegex(self.gui.share_mode.server_status.web.slug, r'(\w+)-(\w+)') + + @pytest.mark.run(order=19) + def test_url_description_shown(self): + '''Test that the URL label is showing''' + self.assertTrue(self.gui.share_mode.server_status.url_description.isVisible()) + + @pytest.mark.run(order=20) + def test_have_copy_url_button(self): + '''Test that the Copy URL button is shown''' + self.assertTrue(self.gui.share_mode.server_status.copy_url_button.isVisible()) + + @pytest.mark.run(order=21) + def test_server_status_indicator_says_sharing(self): + '''Test that the Server Status indicator shows we are Sharing''' + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_started', True)) + + @pytest.mark.run(order=22) + def test_download_share(self): + '''Test that we can download the share''' + s = socks.socksocket() + s.settimeout(60) + s.connect(('127.0.0.1', self.gui.app.port)) + + http_request = 'GET {}/download HTTP/1.0\r\n'.format(self.gui.share_mode.server_status.web.slug) + http_request += 'Host: 127.0.0.1\r\n' + http_request += '\r\n' + s.sendall(http_request.encode('utf-8')) + + with open('/tmp/download.zip', 'wb') as file_to_write: + while True: + data = s.recv(1024) + if not data: + break + file_to_write.write(data) + file_to_write.close() + + zip = zipfile.ZipFile('/tmp/download.zip') + self.assertEquals('onionshare', zip.read('test.txt').decode('utf-8')) + + @pytest.mark.run(order=23) + def test_downloads_widget_present(self): + QtTest.QTest.qWait(1000) + '''Test that the No Downloads Yet label is hidden, that Clear History is present''' + self.assertFalse(self.gui.share_mode.downloads.no_downloads_label.isVisible()) + self.assertTrue(self.gui.share_mode.downloads.clear_history_button.isVisible()) + + @pytest.mark.run(order=24) + def test_server_is_not_stopped(self): + '''Test that the server stayed open after we downloaded the share''' + self.assertEquals(self.gui.share_mode.server_status.status, 2) + + @pytest.mark.run(order=25) + def test_web_service_is_running(self): + '''Test that the web server is still running''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.assertEquals(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + @pytest.mark.run(order=26) + def test_download_count_incremented(self): + '''Test that the Download Count has incremented''' + self.assertEquals(self.gui.share_mode.downloads_completed, 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/unit_tests/onionshare_timer_test.py b/unit_tests/onionshare_timer_test.py new file mode 100644 index 00000000..ed20c1c0 --- /dev/null +++ b/unit_tests/onionshare_timer_test.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import socket +import pytest +import zipfile +import socks +import json + +from PyQt5 import QtCore, QtWidgets, QtTest + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, True, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": False, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": True, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded(self): + '''Test that the GUI actually is shown''' + self.assertTrue(self.gui.show) + + @pytest.mark.run(order=2) + def test_set_timeout(self): + '''Test that the timeout can be set''' + timer = QtCore.QDateTime.currentDateTime().addSecs(120) + self.gui.share_mode.server_status.shutdown_timeout.setDateTime(timer) + self.assertTrue(self.gui.share_mode.server_status.shutdown_timeout.dateTime(), timer) + + @pytest.mark.run(order=3) + def test_server_working_on_start_button_pressed(self): + '''Test we can start the service''' + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + + # Should be in SERVER_WORKING state + self.assertEqual(self.gui.share_mode.server_status.status, 1) + + @pytest.mark.run(order=4) + def test_server_status_indicator_says_starting(self): + '''Test that the Server Status indicator shows we are Starting''' + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + + @pytest.mark.run(order=5) + def test_a_server_is_started(self): + '''Test that the server has started''' + QtTest.QTest.qWait(2000) + # Should now be in SERVER_STARTED state + self.assertEqual(self.gui.share_mode.server_status.status, 2) + + @pytest.mark.run(order=6) + def test_a_web_server_is_running(self): + '''Test that the web server has started''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + @pytest.mark.run(order=7) + def test_timeout_widget_hidden(self): + '''Test that the timeout widget is hidden when share has started''' + self.assertFalse(self.gui.share_mode.server_status.shutdown_timeout_container.isVisible()) + + @pytest.mark.run(order=8) + def test_server_timed_out(self): + '''Test that the server has timed out after the timer ran out''' + QtTest.QTest.qWait(100000) + # We should have timed out now + self.assertEqual(self.gui.share_mode.server_status.status, 0) + + @pytest.mark.run(order=9) + def test_web_service_is_stopped(self): + '''Test that the web server also stopped''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # We should be closed by now. Fail if not! + self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + +if __name__ == "__main__": + unittest.main() diff --git a/unit_tests/run_unit_tests.sh b/unit_tests/run_unit_tests.sh new file mode 100755 index 00000000..d15f8a6e --- /dev/null +++ b/unit_tests/run_unit_tests.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +for test in `ls -1 | egrep ^onionshare_`; do + py.test-3 $test -vvv || exit 1 +done From 12838f8e9dc5824e99bc3249c99d68c0059944e2 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Sat, 22 Sep 2018 16:54:52 +1000 Subject: [PATCH 02/13] Try and make travis-friendly tests --- .travis.yml | 3 ++- unit_tests/run_unit_tests_travis.sh | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100755 unit_tests/run_unit_tests_travis.sh diff --git a/.travis.yml b/.travis.yml index 71778af4..03ae798a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ python: install: - pip install -r install/requirements.txt - pip install pytest-cov coveralls flake8 pytest-faulthandler pytest-ordering + - apt-get install xvfb before_script: # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics @@ -17,6 +18,6 @@ before_script: - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics # command to run tests script: pytest --cov=onionshare test/ -script: cd unit_tests && bash run_unit_tests.sh +script: cd unit_tests && bash run_unit_tests_travis.sh after_success: - coveralls diff --git a/unit_tests/run_unit_tests_travis.sh b/unit_tests/run_unit_tests_travis.sh new file mode 100755 index 00000000..236c48ff --- /dev/null +++ b/unit_tests/run_unit_tests_travis.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +for test in `ls -1 | egrep ^onionshare_`; do + xvfb-run pytest $test -vvv || exit 1 +done From 7c9cc76cce1c30be370e2b264b9488b5e14ca919 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Sat, 22 Sep 2018 16:57:26 +1000 Subject: [PATCH 03/13] xvfb might already be installed? --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 03ae798a..6771eca8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,6 @@ python: install: - pip install -r install/requirements.txt - pip install pytest-cov coveralls flake8 pytest-faulthandler pytest-ordering - - apt-get install xvfb before_script: # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics From 174cfbd3fb2e4c63d67be913fc0ff8ff0dc6bfce Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Sat, 22 Sep 2018 17:02:16 +1000 Subject: [PATCH 04/13] need pytest-qt --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6771eca8..c9c58e97 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ python: # command to install dependencies install: - pip install -r install/requirements.txt - - pip install pytest-cov coveralls flake8 pytest-faulthandler pytest-ordering + - pip install pytest-cov coveralls flake8 pytest-faulthandler pytest-ordering pytest-qt before_script: # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics From d48d780686efbaf449ff0ef9517607718a31baf1 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Sat, 22 Sep 2018 17:06:02 +1000 Subject: [PATCH 05/13] fighting with travis... --- .travis.yml | 1 + unit_tests/run_unit_tests_travis.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c9c58e97..7df1d4c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ python: install: - pip install -r install/requirements.txt - pip install pytest-cov coveralls flake8 pytest-faulthandler pytest-ordering pytest-qt + - sudo apt-get install python3-pytest before_script: # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics diff --git a/unit_tests/run_unit_tests_travis.sh b/unit_tests/run_unit_tests_travis.sh index 236c48ff..ba9b5b4e 100755 --- a/unit_tests/run_unit_tests_travis.sh +++ b/unit_tests/run_unit_tests_travis.sh @@ -1,5 +1,5 @@ #!/bin/bash for test in `ls -1 | egrep ^onionshare_`; do - xvfb-run pytest $test -vvv || exit 1 + xvfb-run pytest-3 $test -vvv || exit 1 done From 9a505af3bb977581c894b6b155f8e3ddeef9d7b2 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Sat, 22 Sep 2018 17:47:38 +1000 Subject: [PATCH 06/13] Add persistent slug test. Add test of clipboard contents in Share mode. Remove travis stuff that I couldn't get to work --- .travis.yml | 4 +- .../onionshare_share_mode_download_test.py | 7 +- unit_tests/onionshare_slug_persistent_test.py | 161 ++++++++++++++++++ unit_tests/run_unit_tests_travis.sh | 5 - 4 files changed, 167 insertions(+), 10 deletions(-) create mode 100644 unit_tests/onionshare_slug_persistent_test.py delete mode 100755 unit_tests/run_unit_tests_travis.sh diff --git a/.travis.yml b/.travis.yml index 7df1d4c4..afbaa887 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,7 @@ python: # command to install dependencies install: - pip install -r install/requirements.txt - - pip install pytest-cov coveralls flake8 pytest-faulthandler pytest-ordering pytest-qt - - sudo apt-get install python3-pytest + - pip install pytest-cov coveralls flake8 before_script: # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics @@ -18,6 +17,5 @@ before_script: - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics # command to run tests script: pytest --cov=onionshare test/ -script: cd unit_tests && bash run_unit_tests_travis.sh after_success: - coveralls diff --git a/unit_tests/onionshare_share_mode_download_test.py b/unit_tests/onionshare_share_mode_download_test.py index aa8dcdaa..c4c8bee7 100644 --- a/unit_tests/onionshare_share_mode_download_test.py +++ b/unit_tests/onionshare_share_mode_download_test.py @@ -8,7 +8,7 @@ import zipfile import socks import json -from PyQt5 import QtCore, QtWidgets, QtTest +from PyQt5 import QtCore, QtWidgets, QtTest, QtGui from onionshare.common import Common from onionshare.web import Web @@ -197,8 +197,11 @@ class OnionShareGuiTest(unittest.TestCase): @pytest.mark.run(order=20) def test_have_copy_url_button(self): - '''Test that the Copy URL button is shown''' + '''Test that the Copy URL button is shown and can be copied to clipboard''' self.assertTrue(self.gui.share_mode.server_status.copy_url_button.isVisible()) + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.copy_url_button, QtCore.Qt.LeftButton) + clipboard = self.gui.qtapp.clipboard() + self.assertEquals(clipboard.text(), 'http://127.0.0.1:{}/{}'.format(self.gui.app.port, self.gui.share_mode.server_status.web.slug)) @pytest.mark.run(order=21) def test_server_status_indicator_says_sharing(self): diff --git a/unit_tests/onionshare_slug_persistent_test.py b/unit_tests/onionshare_slug_persistent_test.py new file mode 100644 index 00000000..d0dcd08a --- /dev/null +++ b/unit_tests/onionshare_slug_persistent_test.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import socket +import pytest +import zipfile +import socks +import json + +from PyQt5 import QtCore, QtWidgets, QtTest + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + slug = '' + + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, True, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": False, + "receive_allow_receiver_shutdown": True, + "save_private_key": True, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded(self): + '''Test that the GUI actually is shown''' + self.assertTrue(self.gui.show) + + @pytest.mark.run(order=2) + def test_server_working_on_start_button_pressed(self): + '''Test we can start the service''' + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + + # Should be in SERVER_WORKING state + self.assertEqual(self.gui.share_mode.server_status.status, 1) + + @pytest.mark.run(order=3) + def test_server_status_indicator_says_starting(self): + '''Test that the Server Status indicator shows we are Starting''' + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + + @pytest.mark.run(order=4) + def test_a_server_is_started(self): + '''Test that the server has started''' + QtTest.QTest.qWait(2000) + # Should now be in SERVER_STARTED state + self.assertEqual(self.gui.share_mode.server_status.status, 2) + + @pytest.mark.run(order=5) + def test_a_web_server_is_running(self): + '''Test that the web server has started''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + @pytest.mark.run(order=6) + def test_have_a_slug(self): + '''Test that we have a valid slug''' + self.assertRegex(self.gui.share_mode.server_status.web.slug, r'(\w+)-(\w+)') + global slug + slug = self.gui.share_mode.server_status.web.slug + + @pytest.mark.run(order=7) + def test_server_can_be_stopped(self): + '''Test we can stop the service''' + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + + # Should be in SERVER_STOPPED state + self.assertEqual(self.gui.share_mode.server_status.status, 0) + + @pytest.mark.run(order=8) + def test_web_service_is_stopped(self): + '''Test that the web server also stopped''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + QtTest.QTest.qWait(4000) + + # We should be closed by now. Fail if not! + self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + @pytest.mark.run(order=9) + def test_server_started_again(self): + '''Test we can start the service again''' + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + QtTest.QTest.qWait(2000) + # Should now be in SERVER_STARTED state + self.assertEqual(self.gui.share_mode.server_status.status, 2) + + @pytest.mark.run(order=10) + def test_have_same_slug(self): + '''Test that we have the same slug''' + self.assertEqual(self.gui.share_mode.server_status.web.slug, slug) + + @pytest.mark.run(order=11) + def test_server_is_stopped_again(self): + '''Test that we can stop the server''' + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + QtTest.QTest.qWait(1000) + self.assertEqual(self.gui.share_mode.server_status.status, 0) + +if __name__ == "__main__": + unittest.main() diff --git a/unit_tests/run_unit_tests_travis.sh b/unit_tests/run_unit_tests_travis.sh deleted file mode 100755 index ba9b5b4e..00000000 --- a/unit_tests/run_unit_tests_travis.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -for test in `ls -1 | egrep ^onionshare_`; do - xvfb-run pytest-3 $test -vvv || exit 1 -done From cb3ed3eadde7c522faed15f9e9d8a5aa5f7f2bf2 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Sat, 22 Sep 2018 17:57:53 +1000 Subject: [PATCH 07/13] One more travis test --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index afbaa887..65eac2c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ python: # command to install dependencies install: - pip install -r install/requirements.txt - - pip install pytest-cov coveralls flake8 + - pip install pytest-cov coveralls flake8 pytest-faulthandler pytest-ordering pytest-qt pytest before_script: # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics @@ -17,5 +17,6 @@ before_script: - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics # command to run tests script: pytest --cov=onionshare test/ +script: xvfb-run py.test-3 unit_tests/onionshare_share_mode_download_test.py after_success: - coveralls From 157dde37e3253a0d5050b68dc07e914abb5aac56 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Sat, 22 Sep 2018 18:01:17 +1000 Subject: [PATCH 08/13] pytest --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 65eac2c5..9aece101 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,6 @@ before_script: - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics # command to run tests script: pytest --cov=onionshare test/ -script: xvfb-run py.test-3 unit_tests/onionshare_share_mode_download_test.py +script: xvfb-run pytest unit_tests/onionshare_share_mode_download_test.py after_success: - coveralls From 4e68c62b9c0607bbfc965b033997712090022c26 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Sat, 22 Sep 2018 18:07:14 +1000 Subject: [PATCH 09/13] Nope --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9aece101..afbaa887 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ python: # command to install dependencies install: - pip install -r install/requirements.txt - - pip install pytest-cov coveralls flake8 pytest-faulthandler pytest-ordering pytest-qt pytest + - pip install pytest-cov coveralls flake8 before_script: # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics @@ -17,6 +17,5 @@ before_script: - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics # command to run tests script: pytest --cov=onionshare test/ -script: xvfb-run pytest unit_tests/onionshare_share_mode_download_test.py after_success: - coveralls From de9bc975a4d1420a1bdfd52a90fc0b43fdc16975 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Mon, 24 Sep 2018 10:41:48 +1000 Subject: [PATCH 10/13] Refactor the unit tests to use common, abstracted tests --- unit_tests/commontests.py | 307 ++++++++++++++++++ .../onionshare_receive_mode_upload_test.py | 142 ++------ ...re_receive_mode_upload_test_public_mode.py | 144 ++------ .../onionshare_share_mode_download_test.py | 189 +++-------- ...re_share_mode_download_test_public_mode.py | 186 +++-------- ...hare_share_mode_download_test_stay_open.py | 171 ++++------ unit_tests/onionshare_slug_persistent_test.py | 108 +++--- unit_tests/onionshare_timer_test.py | 86 ++--- 8 files changed, 625 insertions(+), 708 deletions(-) create mode 100644 unit_tests/commontests.py diff --git a/unit_tests/commontests.py b/unit_tests/commontests.py new file mode 100644 index 00000000..1f6f5896 --- /dev/null +++ b/unit_tests/commontests.py @@ -0,0 +1,307 @@ +import os +import requests +import socket +import socks +import zipfile + +from PyQt5 import QtCore, QtTest +from onionshare import strings + +class CommonTests(object): + def test_gui_loaded(self): + '''Test that the GUI actually is shown''' + self.assertTrue(self.gui.show) + + def test_windowTitle_seen(self): + '''Test that the window title is OnionShare''' + self.assertEqual(self.gui.windowTitle(), 'OnionShare') + + def test_settings_button_is_visible(self): + '''Test that the settings button is visible''' + self.assertTrue(self.gui.settings_button.isVisible()) + + def test_server_status_bar_is_visible(self): + '''Test that the status bar is visible''' + self.assertTrue(self.gui.status_bar.isVisible()) + + def test_info_widget_is_not_visible(self, mode): + '''Test that the info widget along top of screen is not shown''' + if mode == 'receive': + self.assertFalse(self.gui.receive_mode.info_widget.isVisible()) + if mode == 'share': + self.assertFalse(self.gui.share_mode.info_widget.isVisible()) + + def test_info_widget_is_visible(self, mode): + '''Test that the info widget along top of screen is shown''' + if mode == 'receive': + self.assertTrue(self.gui.receive_mode.info_widget.isVisible()) + if mode == 'share': + self.assertTrue(self.gui.share_mode.info_widget.isVisible()) + + def test_click_mode(self, mode): + '''Test that we can switch Mode by clicking the button''' + if mode == 'receive': + QtTest.QTest.mouseClick(self.gui.receive_mode_button, QtCore.Qt.LeftButton) + self.assertTrue(self.gui.mode, self.gui.MODE_RECEIVE) + if mode == 'share': + QtTest.QTest.mouseClick(self.gui.share_mode_button, QtCore.Qt.LeftButton) + self.assertTrue(self.gui.mode, self.gui.MODE_SHARE) + + def test_history_is_visible(self, mode): + '''Test that the History section is visible and that the relevant widget is present''' + if mode == 'receive': + self.assertTrue(self.gui.receive_mode.uploads.isVisible()) + self.assertTrue(self.gui.receive_mode.uploads.no_uploads_label.isVisible()) + if mode == 'share': + self.assertTrue(self.gui.share_mode.downloads.isVisible()) + self.assertTrue(self.gui.share_mode.downloads.no_downloads_label.isVisible()) + + def test_server_working_on_start_button_pressed(self, mode): + '''Test we can start the service''' + # Should be in SERVER_WORKING state + if mode == 'receive': + QtTest.QTest.mouseClick(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) + self.assertEqual(self.gui.receive_mode.server_status.status, 1) + if mode == 'share': + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + self.assertEqual(self.gui.share_mode.server_status.status, 1) + + def test_server_status_indicator_says_starting(self, mode): + '''Test that the Server Status indicator shows we are Starting''' + if mode == 'receive': + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + if mode == 'share': + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + + def test_settings_button_is_hidden(self): + '''Test that the settings button is hidden when the server starts''' + self.assertFalse(self.gui.settings_button.isVisible()) + + def test_a_server_is_started(self, mode): + '''Test that the server has started''' + QtTest.QTest.qWait(2000) + # Should now be in SERVER_STARTED state + if mode == 'receive': + self.assertEqual(self.gui.receive_mode.server_status.status, 2) + if mode == 'share': + self.assertEqual(self.gui.share_mode.server_status.status, 2) + + def test_a_web_server_is_running(self): + '''Test that the web server has started''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + def test_have_a_slug(self, mode, public_mode): + '''Test that we have a valid slug''' + if mode == 'receive': + if not public_mode: + self.assertRegex(self.gui.receive_mode.server_status.web.slug, r'(\w+)-(\w+)') + else: + self.assertIsNone(self.gui.receive_mode.server_status.web.slug, r'(\w+)-(\w+)') + if mode == 'share': + if not public_mode: + self.assertRegex(self.gui.share_mode.server_status.web.slug, r'(\w+)-(\w+)') + else: + self.assertIsNone(self.gui.share_mode.server_status.web.slug, r'(\w+)-(\w+)') + + + def test_url_description_shown(self, mode): + '''Test that the URL label is showing''' + if mode == 'receive': + self.assertTrue(self.gui.receive_mode.server_status.url_description.isVisible()) + if mode == 'share': + self.assertTrue(self.gui.share_mode.server_status.url_description.isVisible()) + + def test_have_copy_url_button(self, mode): + '''Test that the Copy URL button is shown''' + if mode == 'receive': + self.assertTrue(self.gui.receive_mode.server_status.copy_url_button.isVisible()) + if mode == 'share': + self.assertTrue(self.gui.share_mode.server_status.copy_url_button.isVisible()) + + def test_server_status_indicator_says_started(self, mode): + '''Test that the Server Status indicator shows we are started''' + if mode == 'receive': + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_started', True)) + if mode == 'share': + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_share_started', True)) + + def test_web_page(self, mode, string, public_mode): + '''Test that the web page contains a string''' + s = socks.socksocket() + s.settimeout(60) + s.connect(('127.0.0.1', self.gui.app.port)) + + if not public_mode: + if mode == 'receive': + path = '/{}'.format(self.gui.receive_mode.server_status.web.slug) + if mode == 'share': + path = '/{}'.format(self.gui.share_mode.server_status.web.slug) + else: + path = '/' + + http_request = 'GET {} HTTP/1.0\r\n'.format(path) + http_request += 'Host: 127.0.0.1\r\n' + http_request += '\r\n' + s.sendall(http_request.encode('utf-8')) + + with open('/tmp/webpage', 'wb') as file_to_write: + while True: + data = s.recv(1024) + if not data: + break + file_to_write.write(data) + file_to_write.close() + + f = open('/tmp/webpage') + self.assertTrue(string in f.read()) + f.close() + + def test_history_widgets_present(self, mode): + '''Test that the relevant widgets are present in the history view after activity has taken place''' + if mode == 'receive': + self.assertFalse(self.gui.receive_mode.uploads.no_uploads_label.isVisible()) + self.assertTrue(self.gui.receive_mode.uploads.clear_history_button.isVisible()) + if mode == 'share': + self.assertFalse(self.gui.share_mode.downloads.no_downloads_label.isVisible()) + self.assertTrue(self.gui.share_mode.downloads.clear_history_button.isVisible()) + + def test_counter_incremented(self, mode, count): + '''Test that the counter has incremented''' + if mode == 'receive': + self.assertEquals(self.gui.receive_mode.uploads_completed, count) + if mode == 'share': + self.assertEquals(self.gui.share_mode.downloads_completed, count) + + def test_server_is_stopped(self, mode, stay_open): + '''Test that the server stops when we click Stop''' + if mode == 'receive': + QtTest.QTest.mouseClick(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) + self.assertEquals(self.gui.receive_mode.server_status.status, 0) + if mode == 'share': + if stay_open: + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + self.assertEquals(self.gui.share_mode.server_status.status, 0) + + def test_web_service_is_stopped(self): + '''Test that the web server also stopped''' + QtTest.QTest.qWait(2000) + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # We should be closed by now. Fail if not! + self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + def test_server_status_indicator_says_closed(self, mode, stay_open): + '''Test that the Server Status indicator shows we closed''' + if mode == 'receive': + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_stopped', True)) + if mode == 'share': + if stay_open: + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_stopped', True)) + else: + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('closing_automatically', True)) + + # Auto-stop timer tests + def test_set_timeout(self, mode): + '''Test that the timeout can be set''' + timer = QtCore.QDateTime.currentDateTime().addSecs(120) + if mode == 'receive': + self.gui.receive_mode.server_status.shutdown_timeout.setDateTime(timer) + self.assertTrue(self.gui.receive_mode.server_status.shutdown_timeout.dateTime(), timer) + if mode == 'share': + self.gui.share_mode.server_status.shutdown_timeout.setDateTime(timer) + self.assertTrue(self.gui.share_mode.server_status.shutdown_timeout.dateTime(), timer) + + def test_timeout_widget_hidden(self, mode): + '''Test that the timeout widget is hidden when share has started''' + if mode == 'receive': + self.assertFalse(self.gui.receive_mode.server_status.shutdown_timeout_container.isVisible()) + if mode == 'share': + self.assertFalse(self.gui.share_mode.server_status.shutdown_timeout_container.isVisible()) + + def test_server_timed_out(self, mode, wait): + '''Test that the server has timed out after the timer ran out''' + QtTest.QTest.qWait(wait) + # We should have timed out now + if mode == 'receive': + self.assertEqual(self.gui.receive_mode.server_status.status, 0) + if mode == 'share': + self.assertEqual(self.gui.share_mode.server_status.status, 0) + + # Receive-specific tests + def test_upload_file(self, public_mode, expected_file): + '''Test that we can upload the file''' + files = {'file[]': open('/tmp/test.txt', 'rb')} + if not public_mode: + path = 'http://127.0.0.1:{}/{}/upload'.format(self.gui.app.port, self.gui.receive_mode.web.slug) + else: + path = 'http://127.0.0.1:{}/upload'.format(self.gui.app.port) + response = requests.post(path, files=files) + QtTest.QTest.qWait(2000) + self.assertTrue(os.path.isfile(expected_file)) + + # Share-specific tests + def test_file_selection_widget_has_a_file(self): + '''Test that the number of files in the list is 1''' + self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 1) + + def test_deleting_only_file_hides_delete_button(self): + '''Test that clicking on the file item shows the delete button. Test that deleting the only item in the list hides the delete button''' + rect = self.gui.share_mode.server_status.file_selection.file_list.visualItemRect(self.gui.share_mode.server_status.file_selection.file_list.item(0)) + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.viewport(), QtCore.Qt.LeftButton, pos=rect.center()) + # Delete button should be visible + self.assertTrue(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + # Click delete, and since there's no more files, the delete button should be hidden + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.delete_button, QtCore.Qt.LeftButton) + self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + + def test_add_a_file_and_delete_using_its_delete_widget(self): + '''Test that we can also delete a file by clicking on its [X] widget''' + self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.item(0).item_button, QtCore.Qt.LeftButton) + self.assertEquals(self.gui.share_mode.server_status.file_selection.get_num_files(), 0) + + def test_file_selection_widget_readd_files(self): + '''Re-add some files to the list so we can share''' + self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') + self.gui.share_mode.server_status.file_selection.file_list.add_file('/tmp/test.txt') + self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 2) + + def test_add_delete_buttons_hidden(self): + '''Test that the add and delete buttons are hidden when the server starts''' + self.assertFalse(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) + self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + + def test_download_share(self, public_mode): + '''Test that we can download the share''' + s = socks.socksocket() + s.settimeout(60) + s.connect(('127.0.0.1', self.gui.app.port)) + + if public_mode: + path = '/download' + else: + path = '{}/download'.format(self.gui.share_mode.web.slug) + + http_request = 'GET {} HTTP/1.0\r\n'.format(path) + http_request += 'Host: 127.0.0.1\r\n' + http_request += '\r\n' + s.sendall(http_request.encode('utf-8')) + + with open('/tmp/download.zip', 'wb') as file_to_write: + while True: + data = s.recv(1024) + if not data: + break + file_to_write.write(data) + file_to_write.close() + + zip = zipfile.ZipFile('/tmp/download.zip') + QtTest.QTest.qWait(2000) + self.assertEquals('onionshare', zip.read('test.txt').decode('utf-8')) + + def test_add_button_visible(self): + '''Test that the add button should be visible''' + self.assertTrue(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) + diff --git a/unit_tests/onionshare_receive_mode_upload_test.py b/unit_tests/onionshare_receive_mode_upload_test.py index b99faac0..bac622fb 100644 --- a/unit_tests/onionshare_receive_mode_upload_test.py +++ b/unit_tests/onionshare_receive_mode_upload_test.py @@ -2,20 +2,18 @@ import os import sys import unittest -import socket import pytest -import zipfile -import socks import json -import requests -from PyQt5 import QtCore, QtWidgets, QtTest +from PyQt5 import QtWidgets from onionshare.common import Common from onionshare.web import Web from onionshare import onion, strings from onionshare_gui import * +from .commontests import CommonTests + app = QtWidgets.QApplication(sys.argv) class OnionShareGuiTest(unittest.TestCase): @@ -83,176 +81,104 @@ class OnionShareGuiTest(unittest.TestCase): os.remove('/tmp/OnionShare/test-2.txt') @pytest.mark.run(order=1) - def test_gui_loaded_and_tor_bootstrapped(self): - '''Test that the GUI actually is shown''' - self.assertTrue(self.gui.show) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) @pytest.mark.run(order=2) def test_windowTitle_seen(self): - '''Test that the window title is OnionShare''' - self.assertEqual(self.gui.windowTitle(), 'OnionShare') + CommonTests.test_windowTitle_seen(self) @pytest.mark.run(order=3) def test_settings_button_is_visible(self): - '''Test that the settings button is visible''' - self.assertTrue(self.gui.settings_button.isVisible()) + CommonTests.test_settings_button_is_visible(self) @pytest.mark.run(order=4) def test_server_status_bar_is_visible(self): - '''Test that the status bar is visible''' - self.assertTrue(self.gui.status_bar.isVisible()) + CommonTests.test_server_status_bar_is_visible(self) @pytest.mark.run(order=5) def test_info_widget_is_not_visible(self): - '''Test that the info widget along top of screen is not shown because we have a file''' - self.assertFalse(self.gui.receive_mode.info_widget.isVisible()) + CommonTests.test_info_widget_is_not_visible(self, 'receive') @pytest.mark.run(order=6) - def test_click_receive_mode(self): - '''Test that we can switch to Receive Mode by clicking the button''' - QtTest.QTest.mouseClick(self.gui.receive_mode_button, QtCore.Qt.LeftButton) - self.assertTrue(self.gui.mode, self.gui.MODE_RECEIVE) + def test_click_mode(self): + CommonTests.test_click_mode(self, 'receive') @pytest.mark.run(order=7) - def test_uploads_section_is_visible(self): - '''Test that the Uploads section is visible and that the No Uploads Yet label is present''' - self.assertTrue(self.gui.receive_mode.uploads.isVisible()) - self.assertTrue(self.gui.receive_mode.uploads.no_uploads_label.isVisible()) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'receive') @pytest.mark.run(order=8) def test_server_working_on_start_button_pressed(self): - '''Test we can start the service''' - QtTest.QTest.mouseClick(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) - - # Should be in SERVER_WORKING state - self.assertEqual(self.gui.receive_mode.server_status.status, 1) + CommonTests.test_server_working_on_start_button_pressed(self, 'receive') @pytest.mark.run(order=9) def test_server_status_indicator_says_starting(self): - '''Test that the Server Status indicator shows we are Starting''' - self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + CommonTests.test_server_status_indicator_says_starting(self, 'receive') @pytest.mark.run(order=10) def test_settings_button_is_hidden(self): - '''Test that the settings button is hidden when the server starts''' - self.assertFalse(self.gui.settings_button.isVisible()) + CommonTests.test_settings_button_is_hidden(self) @pytest.mark.run(order=11) def test_a_server_is_started(self): - '''Test that the server has started''' - QtTest.QTest.qWait(2000) - # Should now be in SERVER_STARTED state - self.assertEqual(self.gui.receive_mode.server_status.status, 2) + CommonTests.test_a_server_is_started(self, 'receive') @pytest.mark.run(order=12) def test_a_web_server_is_running(self): - '''Test that the web server has started''' - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) - - # Running in local mode, so we have no .onion - #@pytest.mark.run(order=13) - #def test_have_an_onion_service(self): - # '''Test that we have a valid Onion URL''' - # self.assertRegex(self.gui.app.onion_host, r'[a-z2-7].onion') - # self.assertEqual(len(self.gui.app.onion_host), 62) + CommonTests.test_a_web_server_is_running(self) @pytest.mark.run(order=14) def test_have_a_slug(self): - '''Test that we have a valid slug''' - self.assertRegex(self.gui.receive_mode.server_status.web.slug, r'(\w+)-(\w+)') + CommonTests.test_have_a_slug(self, 'receive', False) @pytest.mark.run(order=15) def test_url_description_shown(self): - '''Test that the URL label is showing''' - self.assertTrue(self.gui.receive_mode.server_status.url_description.isVisible()) + CommonTests.test_url_description_shown(self, 'receive') @pytest.mark.run(order=16) def test_have_copy_url_button(self): - '''Test that the Copy URL button is shown''' - self.assertTrue(self.gui.receive_mode.server_status.copy_url_button.isVisible()) + CommonTests.test_have_copy_url_button(self, 'receive') @pytest.mark.run(order=17) - def test_server_status_indicator_says_sharing(self): - '''Test that the Server Status indicator shows we are Receiving''' - self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_started', True)) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'receive') @pytest.mark.run(order=18) def test_web_page(self): - '''Test that the web page contains the term Select the files you want to send, then click''' - s = socks.socksocket() - s.settimeout(60) - s.connect(('127.0.0.1', self.gui.app.port)) - - http_request = 'GET {} HTTP/1.0\r\n'.format(self.gui.receive_mode.server_status.web.slug) - http_request += 'Host: 127.0.0.1\r\n' - http_request += '\r\n' - s.sendall(http_request.encode('utf-8')) - - with open('/tmp/webpage', 'wb') as file_to_write: - while True: - data = s.recv(1024) - if not data: - break - file_to_write.write(data) - file_to_write.close() - - f = open('/tmp/webpage') - self.assertTrue('Select the files you want to send, then click "Send Files"' in f.read()) - f.close() + CommonTests.test_web_page(self, 'receive', 'Select the files you want to send, then click', False) @pytest.mark.run(order=19) def test_upload_file(self): - '''Test that we can upload the file''' - files = {'file[]': open('/tmp/test.txt', 'rb')} - response = requests.post('http://127.0.0.1:{}/{}/upload'.format(self.gui.app.port, self.gui.receive_mode.web.slug), files=files) - QtTest.QTest.qWait(2000) - self.assertTrue(os.path.isfile('/tmp/OnionShare/test.txt')) + CommonTests.test_upload_file(self, False, '/tmp/OnionShare/test.txt') @pytest.mark.run(order=20) - def test_uploads_widget_present(self): - '''Test that the No Uploads Yet label is hidden, that Clear History is present''' - self.assertFalse(self.gui.receive_mode.uploads.no_uploads_label.isVisible()) - self.assertTrue(self.gui.receive_mode.uploads.clear_history_button.isVisible()) + def test_history_widgets_present(self): + CommonTests.test_history_widgets_present(self, 'receive') @pytest.mark.run(order=21) - def test_upload_count_incremented(self): - '''Test that the Upload Count has incremented''' - self.assertEquals(self.gui.receive_mode.uploads_completed, 1) + def test_counter_incremented(self): + CommonTests.test_counter_incremented(self, 'receive', 1) @pytest.mark.run(order=22) def test_upload_same_file_is_renamed(self): - '''Test that we can upload the same file and that it gets renamed''' - files = {'file[]': open('/tmp/test.txt', 'rb')} - response = requests.post('http://127.0.0.1:{}/{}/upload'.format(self.gui.app.port, self.gui.receive_mode.web.slug), files=files) - QtTest.QTest.qWait(2000) - self.assertTrue(os.path.isfile('/tmp/OnionShare/test-2.txt')) + CommonTests.test_upload_file(self, False, '/tmp/OnionShare/test-2.txt') @pytest.mark.run(order=23) def test_upload_count_incremented_again(self): - '''Test that the Upload Count has incremented again''' - self.assertEquals(self.gui.receive_mode.uploads_completed, 2) + CommonTests.test_counter_incremented(self, 'receive', 2) @pytest.mark.run(order=24) def test_server_is_stopped(self): - '''Test that the server stops when we click Stop''' - QtTest.QTest.mouseClick(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) - self.assertEquals(self.gui.receive_mode.server_status.status, 0) + CommonTests.test_server_is_stopped(self, 'receive', False) @pytest.mark.run(order=25) def test_web_service_is_stopped(self): - '''Test that the web server also stopped''' - QtTest.QTest.qWait(2000) - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - # We should be closed by now. Fail if not! - self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + CommonTests.test_web_service_is_stopped(self) @pytest.mark.run(order=26) def test_server_status_indicator_says_closed(self): - '''Test that the Server Status indicator shows we closed''' - self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_stopped', True)) + CommonTests.test_server_status_indicator_says_closed(self, 'receive', False) if __name__ == "__main__": unittest.main() diff --git a/unit_tests/onionshare_receive_mode_upload_test_public_mode.py b/unit_tests/onionshare_receive_mode_upload_test_public_mode.py index d309e5b1..8ed385f5 100644 --- a/unit_tests/onionshare_receive_mode_upload_test_public_mode.py +++ b/unit_tests/onionshare_receive_mode_upload_test_public_mode.py @@ -2,20 +2,18 @@ import os import sys import unittest -import socket import pytest -import zipfile -import socks import json -import requests -from PyQt5 import QtCore, QtWidgets, QtTest +from PyQt5 import QtWidgets from onionshare.common import Common from onionshare.web import Web from onionshare import onion, strings from onionshare_gui import * +from .commontests import CommonTests + app = QtWidgets.QApplication(sys.argv) class OnionShareGuiTest(unittest.TestCase): @@ -83,176 +81,104 @@ class OnionShareGuiTest(unittest.TestCase): os.remove('/tmp/OnionShare/test-2.txt') @pytest.mark.run(order=1) - def test_gui_loaded_and_tor_bootstrapped(self): - '''Test that the GUI actually is shown''' - self.assertTrue(self.gui.show) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) @pytest.mark.run(order=2) def test_windowTitle_seen(self): - '''Test that the window title is OnionShare''' - self.assertEqual(self.gui.windowTitle(), 'OnionShare') + CommonTests.test_windowTitle_seen(self) @pytest.mark.run(order=3) def test_settings_button_is_visible(self): - '''Test that the settings button is visible''' - self.assertTrue(self.gui.settings_button.isVisible()) + CommonTests.test_settings_button_is_visible(self) @pytest.mark.run(order=4) def test_server_status_bar_is_visible(self): - '''Test that the status bar is visible''' - self.assertTrue(self.gui.status_bar.isVisible()) + CommonTests.test_server_status_bar_is_visible(self) @pytest.mark.run(order=5) def test_info_widget_is_not_visible(self): - '''Test that the info widget along top of screen is not shown because we have a file''' - self.assertFalse(self.gui.receive_mode.info_widget.isVisible()) + CommonTests.test_info_widget_is_not_visible(self, 'receive') @pytest.mark.run(order=6) - def test_click_receive_mode(self): - '''Test that we can switch to Receive Mode by clicking the button''' - QtTest.QTest.mouseClick(self.gui.receive_mode_button, QtCore.Qt.LeftButton) - self.assertTrue(self.gui.mode, self.gui.MODE_RECEIVE) + def test_click_mode(self): + CommonTests.test_click_mode(self, 'receive') @pytest.mark.run(order=7) - def test_uploads_section_is_visible(self): - '''Test that the Uploads section is visible and that the No Uploads Yet label is present''' - self.assertTrue(self.gui.receive_mode.uploads.isVisible()) - self.assertTrue(self.gui.receive_mode.uploads.no_uploads_label.isVisible()) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'receive') @pytest.mark.run(order=8) def test_server_working_on_start_button_pressed(self): - '''Test we can start the service''' - QtTest.QTest.mouseClick(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) - - # Should be in SERVER_WORKING state - self.assertEqual(self.gui.receive_mode.server_status.status, 1) + CommonTests.test_server_working_on_start_button_pressed(self, 'receive') @pytest.mark.run(order=9) def test_server_status_indicator_says_starting(self): - '''Test that the Server Status indicator shows we are Starting''' - self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + CommonTests.test_server_status_indicator_says_starting(self, 'receive') @pytest.mark.run(order=10) def test_settings_button_is_hidden(self): - '''Test that the settings button is hidden when the server starts''' - self.assertFalse(self.gui.settings_button.isVisible()) + CommonTests.test_settings_button_is_hidden(self) @pytest.mark.run(order=11) def test_a_server_is_started(self): - '''Test that the server has started''' - QtTest.QTest.qWait(2000) - # Should now be in SERVER_STARTED state - self.assertEqual(self.gui.receive_mode.server_status.status, 2) + CommonTests.test_a_server_is_started(self, 'receive') @pytest.mark.run(order=12) def test_a_web_server_is_running(self): - '''Test that the web server has started''' - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) - - # Running in local mode, so we have no .onion - #@pytest.mark.run(order=13) - #def test_have_an_onion_service(self): - # '''Test that we have a valid Onion URL''' - # self.assertRegex(self.gui.app.onion_host, r'[a-z2-7].onion') - # self.assertEqual(len(self.gui.app.onion_host), 62) + CommonTests.test_a_web_server_is_running(self) @pytest.mark.run(order=14) - def test_have_no_slug(self): - '''Test that we have a valid slug''' - self.assertIsNone(self.gui.share_mode.server_status.web.slug) + def test_have_a_slug(self): + CommonTests.test_have_a_slug(self, 'receive', True) @pytest.mark.run(order=15) def test_url_description_shown(self): - '''Test that the URL label is showing''' - self.assertTrue(self.gui.receive_mode.server_status.url_description.isVisible()) + CommonTests.test_url_description_shown(self, 'receive') @pytest.mark.run(order=16) def test_have_copy_url_button(self): - '''Test that the Copy URL button is shown''' - self.assertTrue(self.gui.receive_mode.server_status.copy_url_button.isVisible()) + CommonTests.test_have_copy_url_button(self, 'receive') @pytest.mark.run(order=17) - def test_server_status_indicator_says_sharing(self): - '''Test that the Server Status indicator shows we are Receiving''' - self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_started', True)) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'receive') @pytest.mark.run(order=18) def test_web_page(self): - '''Test that the web page contains the term Select the files you want to send, then click''' - s = socks.socksocket() - s.settimeout(60) - s.connect(('127.0.0.1', self.gui.app.port)) - - http_request = 'GET / HTTP/1.0\r\n' - http_request += 'Host: 127.0.0.1\r\n' - http_request += '\r\n' - s.sendall(http_request.encode('utf-8')) - - with open('/tmp/webpage', 'wb') as file_to_write: - while True: - data = s.recv(1024) - if not data: - break - file_to_write.write(data) - file_to_write.close() - - f = open('/tmp/webpage') - self.assertTrue('Select the files you want to send, then click "Send Files"' in f.read()) - f.close() + CommonTests.test_web_page(self, 'receive', 'Select the files you want to send, then click', True) @pytest.mark.run(order=19) def test_upload_file(self): - '''Test that we can upload the file''' - files = {'file[]': open('/tmp/test.txt', 'rb')} - response = requests.post('http://127.0.0.1:{}/upload'.format(self.gui.app.port), files=files) - QtTest.QTest.qWait(2000) - self.assertTrue(os.path.isfile('/tmp/OnionShare/test.txt')) + CommonTests.test_upload_file(self, True, '/tmp/OnionShare/test.txt') @pytest.mark.run(order=20) - def test_uploads_widget_present(self): - '''Test that the No Uploads Yet label is hidden, that Clear History is present''' - self.assertFalse(self.gui.receive_mode.uploads.no_uploads_label.isVisible()) - self.assertTrue(self.gui.receive_mode.uploads.clear_history_button.isVisible()) + def test_history_widgets_present(self): + CommonTests.test_history_widgets_present(self, 'receive') @pytest.mark.run(order=21) - def test_upload_count_incremented(self): - '''Test that the Upload Count has incremented''' - self.assertEquals(self.gui.receive_mode.uploads_completed, 1) + def test_counter_incremented(self): + CommonTests.test_counter_incremented(self, 'receive', 1) @pytest.mark.run(order=22) def test_upload_same_file_is_renamed(self): - '''Test that we can upload the same file and that it gets renamed''' - files = {'file[]': open('/tmp/test.txt', 'rb')} - response = requests.post('http://127.0.0.1:{}/upload'.format(self.gui.app.port), files=files) - QtTest.QTest.qWait(2000) - self.assertTrue(os.path.isfile('/tmp/OnionShare/test-2.txt')) + CommonTests.test_upload_file(self, True, '/tmp/OnionShare/test-2.txt') @pytest.mark.run(order=23) def test_upload_count_incremented_again(self): - '''Test that the Upload Count has incremented again''' - self.assertEquals(self.gui.receive_mode.uploads_completed, 2) + CommonTests.test_counter_incremented(self, 'receive', 2) @pytest.mark.run(order=24) def test_server_is_stopped(self): - '''Test that the server stops when we click Stop''' - QtTest.QTest.mouseClick(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) - self.assertEquals(self.gui.receive_mode.server_status.status, 0) + CommonTests.test_server_is_stopped(self, 'receive', False) @pytest.mark.run(order=25) def test_web_service_is_stopped(self): - '''Test that the web server also stopped''' - QtTest.QTest.qWait(2000) - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - # We should be closed by now. Fail if not! - self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + CommonTests.test_web_service_is_stopped(self) @pytest.mark.run(order=26) def test_server_status_indicator_says_closed(self): - '''Test that the Server Status indicator shows we closed''' - self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_stopped', True)) + CommonTests.test_server_status_indicator_says_closed(self, 'receive', False) if __name__ == "__main__": unittest.main() diff --git a/unit_tests/onionshare_share_mode_download_test.py b/unit_tests/onionshare_share_mode_download_test.py index c4c8bee7..0ef03e97 100644 --- a/unit_tests/onionshare_share_mode_download_test.py +++ b/unit_tests/onionshare_share_mode_download_test.py @@ -2,19 +2,18 @@ import os import sys import unittest -import socket import pytest -import zipfile -import socks import json -from PyQt5 import QtCore, QtWidgets, QtTest, QtGui +from PyQt5 import QtWidgets from onionshare.common import Common from onionshare.web import Web from onionshare import onion, strings from onionshare_gui import * +from .commontests import CommonTests + app = QtWidgets.QApplication(sys.argv) class OnionShareGuiTest(unittest.TestCase): @@ -80,210 +79,112 @@ class OnionShareGuiTest(unittest.TestCase): os.remove('/tmp/test.txt') @pytest.mark.run(order=1) - def test_gui_loaded_and_tor_bootstrapped(self): - '''Test that the GUI actually is shown''' - self.assertTrue(self.gui.show) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) @pytest.mark.run(order=2) def test_windowTitle_seen(self): - '''Test that the window title is OnionShare''' - self.assertEqual(self.gui.windowTitle(), 'OnionShare') + CommonTests.test_windowTitle_seen(self) @pytest.mark.run(order=3) def test_settings_button_is_visible(self): - '''Test that the settings button is visible''' - self.assertTrue(self.gui.settings_button.isVisible()) + CommonTests.test_settings_button_is_visible(self) @pytest.mark.run(order=4) def test_server_status_bar_is_visible(self): - '''Test that the status bar is visible''' - self.assertTrue(self.gui.status_bar.isVisible()) + CommonTests.test_server_status_bar_is_visible(self) @pytest.mark.run(order=5) def test_file_selection_widget_has_a_file(self): - '''Test that the number of files in the list is 1''' - self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 1) + CommonTests.test_file_selection_widget_has_a_file(self) @pytest.mark.run(order=6) def test_info_widget_is_visible(self): - '''Test that the info widget along top of screen is shown because we have a file''' - self.assertTrue(self.gui.share_mode.info_widget.isVisible()) + CommonTests.test_info_widget_is_visible(self, 'share') @pytest.mark.run(order=7) - def test_downloads_section_is_visible(self): - '''Test that the Downloads section is visible and that the No Downloads Yet label is present''' - self.assertTrue(self.gui.share_mode.downloads.isVisible()) - self.assertTrue(self.gui.share_mode.downloads.no_downloads_label.isVisible()) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') @pytest.mark.run(order=8) def test_deleting_only_file_hides_delete_button(self): - '''Test that clicking on the file item shows the delete button. Test that deleting the only item in the list hides the delete button''' - rect = self.gui.share_mode.server_status.file_selection.file_list.visualItemRect(self.gui.share_mode.server_status.file_selection.file_list.item(0)) - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.viewport(), QtCore.Qt.LeftButton, pos=rect.center()) - # Delete button should be visible - self.assertTrue(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) - # Click delete, and since there's no more files, the delete button should be hidden - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.delete_button, QtCore.Qt.LeftButton) - self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + CommonTests.test_deleting_only_file_hides_delete_button(self) @pytest.mark.run(order=9) def test_add_a_file_and_delete_using_its_delete_widget(self): - '''Test that we can also delete a file by clicking on its [X] widget''' - self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.item(0).item_button, QtCore.Qt.LeftButton) - self.assertEquals(self.gui.share_mode.server_status.file_selection.get_num_files(), 0) + CommonTests.test_add_a_file_and_delete_using_its_delete_widget(self) @pytest.mark.run(order=10) def test_file_selection_widget_readd_files(self): - '''Re-add some files to the list so we can share''' - self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') - self.gui.share_mode.server_status.file_selection.file_list.add_file('/tmp/test.txt') - self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 2) + CommonTests.test_file_selection_widget_readd_files(self) @pytest.mark.run(order=11) def test_server_working_on_start_button_pressed(self): - '''Test we can start the service''' - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) - - # Should be in SERVER_WORKING state - self.assertEqual(self.gui.share_mode.server_status.status, 1) + CommonTests.test_server_working_on_start_button_pressed(self, 'share') @pytest.mark.run(order=12) def test_server_status_indicator_says_starting(self): - '''Test that the Server Status indicator shows we are Starting''' - self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + CommonTests.test_server_status_indicator_says_starting(self, 'share') @pytest.mark.run(order=13) - def test_add_delete_buttons_now_hidden(self): - '''Test that the add and delete buttons are hidden when the server starts''' - self.assertFalse(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) - self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + def test_add_delete_buttons_hidden(self): + CommonTests.test_add_delete_buttons_hidden(self) @pytest.mark.run(order=14) def test_settings_button_is_hidden(self): - '''Test that the settings button is hidden when the server starts''' - self.assertFalse(self.gui.settings_button.isVisible()) + CommonTests.test_settings_button_is_hidden(self) @pytest.mark.run(order=15) def test_a_server_is_started(self): - '''Test that the server has started''' - QtTest.QTest.qWait(2000) - # Should now be in SERVER_STARTED state - self.assertEqual(self.gui.share_mode.server_status.status, 2) + CommonTests.test_a_server_is_started(self, 'share') @pytest.mark.run(order=16) def test_a_web_server_is_running(self): - '''Test that the web server has started''' - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + CommonTests.test_a_web_server_is_running(self) - self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) - - # Running in local mode, so we have no .onion - #@pytest.mark.run(order=17) - #def test_have_an_onion_service(self): - # '''Test that we have a valid Onion URL''' - # self.assertRegex(self.gui.app.onion_host, r'[a-z2-7].onion') - # self.assertEqual(len(self.gui.app.onion_host), 62) + @pytest.mark.run(order=17) + def test_have_a_slug(self): + CommonTests.test_have_a_slug(self, 'share', False) @pytest.mark.run(order=18) - def test_have_a_slug(self): - '''Test that we have a valid slug''' - self.assertRegex(self.gui.share_mode.server_status.web.slug, r'(\w+)-(\w+)') + def test_url_description_shown(self): + CommonTests.test_url_description_shown(self, 'share') @pytest.mark.run(order=19) - def test_url_description_shown(self): - '''Test that the URL label is showing''' - self.assertTrue(self.gui.share_mode.server_status.url_description.isVisible()) + def test_have_copy_url_button(self): + CommonTests.test_have_copy_url_button(self, 'share') @pytest.mark.run(order=20) - def test_have_copy_url_button(self): - '''Test that the Copy URL button is shown and can be copied to clipboard''' - self.assertTrue(self.gui.share_mode.server_status.copy_url_button.isVisible()) - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.copy_url_button, QtCore.Qt.LeftButton) - clipboard = self.gui.qtapp.clipboard() - self.assertEquals(clipboard.text(), 'http://127.0.0.1:{}/{}'.format(self.gui.app.port, self.gui.share_mode.server_status.web.slug)) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'share') @pytest.mark.run(order=21) - def test_server_status_indicator_says_sharing(self): - '''Test that the Server Status indicator shows we are Sharing''' - self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_started', True)) + def test_web_page(self): + CommonTests.test_web_page(self, 'share', 'Total size', False) @pytest.mark.run(order=22) - def test_web_page(self): - '''Test that the web page contains the term Total size''' - s = socks.socksocket() - s.settimeout(60) - s.connect(('127.0.0.1', self.gui.app.port)) - - http_request = 'GET {} HTTP/1.0\r\n'.format(self.gui.share_mode.server_status.web.slug) - http_request += 'Host: 127.0.0.1\r\n' - http_request += '\r\n' - s.sendall(http_request.encode('utf-8')) - - with open('/tmp/webpage', 'wb') as file_to_write: - while True: - data = s.recv(1024) - if not data: - break - file_to_write.write(data) - file_to_write.close() - - f = open('/tmp/webpage') - self.assertTrue('Total size' in f.read()) - f.close() + def test_download_share(self): + CommonTests.test_download_share(self, False) @pytest.mark.run(order=23) - def test_download_share(self): - '''Test that we can download the share''' - s = socks.socksocket() - s.settimeout(60) - s.connect(('127.0.0.1', self.gui.app.port)) - - http_request = 'GET {}/download HTTP/1.0\r\n'.format(self.gui.share_mode.server_status.web.slug) - http_request += 'Host: 127.0.0.1\r\n' - http_request += '\r\n' - s.sendall(http_request.encode('utf-8')) - - with open('/tmp/download.zip', 'wb') as file_to_write: - while True: - data = s.recv(1024) - if not data: - break - file_to_write.write(data) - file_to_write.close() - - zip = zipfile.ZipFile('/tmp/download.zip') - self.assertEquals('onionshare', zip.read('test.txt').decode('utf-8')) + def test_history_widgets_present(self): + CommonTests.test_history_widgets_present(self, 'share') @pytest.mark.run(order=24) - def test_downloads_widget_present(self): - QtTest.QTest.qWait(1000) - '''Test that the No Downloads Yet label is hidden, that Clear History is present''' - self.assertFalse(self.gui.share_mode.downloads.no_downloads_label.isVisible()) - self.assertTrue(self.gui.share_mode.downloads.clear_history_button.isVisible()) + def test_server_is_stopped(self): + CommonTests.test_server_is_stopped(self, 'share', False) @pytest.mark.run(order=25) - def test_server_is_stopped(self): - '''Test that the server stopped automatically when we downloaded the share''' - self.assertEquals(self.gui.share_mode.server_status.status, 0) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) @pytest.mark.run(order=26) - def test_web_service_is_stopped(self): - '''Test that the web server also stopped''' - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - # We should be closed by now. Fail if not! - self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + def test_server_status_indicator_says_closed(self): + CommonTests.test_server_status_indicator_says_closed(self, 'share', False) @pytest.mark.run(order=27) - def test_server_status_indicator_says_closed(self): - '''Test that the Server Status indicator shows we closed because download occurred''' - self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('closing_automatically', True)) - - @pytest.mark.run(order=28) - def test_add_button_visible_again(self): - '''Test that the add button should be visible again''' - self.assertTrue(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) + def test_add_button_visible(self): + CommonTests.test_add_button_visible(self) if __name__ == "__main__": diff --git a/unit_tests/onionshare_share_mode_download_test_public_mode.py b/unit_tests/onionshare_share_mode_download_test_public_mode.py index 59905149..417eb8b9 100644 --- a/unit_tests/onionshare_share_mode_download_test_public_mode.py +++ b/unit_tests/onionshare_share_mode_download_test_public_mode.py @@ -2,19 +2,18 @@ import os import sys import unittest -import socket import pytest -import zipfile -import socks import json -from PyQt5 import QtCore, QtWidgets, QtTest +from PyQt5 import QtWidgets from onionshare.common import Common from onionshare.web import Web from onionshare import onion, strings from onionshare_gui import * +from .commontests import CommonTests + app = QtWidgets.QApplication(sys.argv) class OnionShareGuiTest(unittest.TestCase): @@ -80,207 +79,112 @@ class OnionShareGuiTest(unittest.TestCase): os.remove('/tmp/test.txt') @pytest.mark.run(order=1) - def test_gui_loaded_and_tor_bootstrapped(self): - '''Test that the GUI actually is shown''' - self.assertTrue(self.gui.show) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) @pytest.mark.run(order=2) def test_windowTitle_seen(self): - '''Test that the window title is OnionShare''' - self.assertEqual(self.gui.windowTitle(), 'OnionShare') + CommonTests.test_windowTitle_seen(self) @pytest.mark.run(order=3) def test_settings_button_is_visible(self): - '''Test that the settings button is visible''' - self.assertTrue(self.gui.settings_button.isVisible()) + CommonTests.test_settings_button_is_visible(self) @pytest.mark.run(order=4) def test_server_status_bar_is_visible(self): - '''Test that the status bar is visible''' - self.assertTrue(self.gui.status_bar.isVisible()) + CommonTests.test_server_status_bar_is_visible(self) @pytest.mark.run(order=5) def test_file_selection_widget_has_a_file(self): - '''Test that the number of files in the list is 1''' - self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 1) + CommonTests.test_file_selection_widget_has_a_file(self) @pytest.mark.run(order=6) def test_info_widget_is_visible(self): - '''Test that the info widget along top of screen is shown because we have a file''' - self.assertTrue(self.gui.share_mode.info_widget.isVisible()) + CommonTests.test_info_widget_is_visible(self, 'share') @pytest.mark.run(order=7) - def test_downloads_section_is_visible(self): - '''Test that the Downloads section is visible and that the No Downloads Yet label is present''' - self.assertTrue(self.gui.share_mode.downloads.isVisible()) - self.assertTrue(self.gui.share_mode.downloads.no_downloads_label.isVisible()) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') @pytest.mark.run(order=8) def test_deleting_only_file_hides_delete_button(self): - '''Test that clicking on the file item shows the delete button. Test that deleting the only item in the list hides the delete button''' - rect = self.gui.share_mode.server_status.file_selection.file_list.visualItemRect(self.gui.share_mode.server_status.file_selection.file_list.item(0)) - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.viewport(), QtCore.Qt.LeftButton, pos=rect.center()) - # Delete button should be visible - self.assertTrue(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) - # Click delete, and since there's no more files, the delete button should be hidden - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.delete_button, QtCore.Qt.LeftButton) - self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + CommonTests.test_deleting_only_file_hides_delete_button(self) @pytest.mark.run(order=9) def test_add_a_file_and_delete_using_its_delete_widget(self): - '''Test that we can also delete a file by clicking on its [X] widget''' - self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.item(0).item_button, QtCore.Qt.LeftButton) - self.assertEquals(self.gui.share_mode.server_status.file_selection.get_num_files(), 0) + CommonTests.test_add_a_file_and_delete_using_its_delete_widget(self) @pytest.mark.run(order=10) def test_file_selection_widget_readd_files(self): - '''Re-add some files to the list so we can share''' - self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') - self.gui.share_mode.server_status.file_selection.file_list.add_file('/tmp/test.txt') - self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 2) + CommonTests.test_file_selection_widget_readd_files(self) @pytest.mark.run(order=11) def test_server_working_on_start_button_pressed(self): - '''Test we can start the service''' - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) - - # Should be in SERVER_WORKING state - self.assertEqual(self.gui.share_mode.server_status.status, 1) + CommonTests.test_server_working_on_start_button_pressed(self, 'share') @pytest.mark.run(order=12) def test_server_status_indicator_says_starting(self): - '''Test that the Server Status indicator shows we are Starting''' - self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + CommonTests.test_server_status_indicator_says_starting(self, 'share') @pytest.mark.run(order=13) - def test_add_delete_buttons_now_hidden(self): - '''Test that the add and delete buttons are hidden when the server starts''' - self.assertFalse(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) - self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + def test_add_delete_buttons_hidden(self): + CommonTests.test_add_delete_buttons_hidden(self) @pytest.mark.run(order=14) def test_settings_button_is_hidden(self): - '''Test that the settings button is hidden when the server starts''' - self.assertFalse(self.gui.settings_button.isVisible()) + CommonTests.test_settings_button_is_hidden(self) @pytest.mark.run(order=15) def test_a_server_is_started(self): - '''Test that the server has started''' - QtTest.QTest.qWait(2000) - # Should now be in SERVER_STARTED state - self.assertEqual(self.gui.share_mode.server_status.status, 2) + CommonTests.test_a_server_is_started(self, 'share') @pytest.mark.run(order=16) def test_a_web_server_is_running(self): - '''Test that the web server has started''' - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + CommonTests.test_a_web_server_is_running(self) - self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) - - # Running in local mode, so we have no .onion - #@pytest.mark.run(order=17) - #def test_have_an_onion_service(self): - # '''Test that we have a valid Onion URL''' - # self.assertRegex(self.gui.app.onion_host, r'[a-z2-7].onion') - # self.assertEqual(len(self.gui.app.onion_host), 62) + @pytest.mark.run(order=17) + def test_have_a_slug(self): + CommonTests.test_have_a_slug(self, 'share', True) @pytest.mark.run(order=18) - def test_have_no_slug(self): - '''Test that we have a valid slug''' - self.assertIsNone(self.gui.share_mode.server_status.web.slug) + def test_url_description_shown(self): + CommonTests.test_url_description_shown(self, 'share') @pytest.mark.run(order=19) - def test_url_description_shown(self): - '''Test that the URL label is showing''' - self.assertTrue(self.gui.share_mode.server_status.url_description.isVisible()) + def test_have_copy_url_button(self): + CommonTests.test_have_copy_url_button(self, 'share') @pytest.mark.run(order=20) - def test_have_copy_url_button(self): - '''Test that the Copy URL button is shown''' - self.assertTrue(self.gui.share_mode.server_status.copy_url_button.isVisible()) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'share') @pytest.mark.run(order=21) - def test_server_status_indicator_says_sharing(self): - '''Test that the Server Status indicator shows we are Sharing''' - self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_started', True)) + def test_web_page(self): + CommonTests.test_web_page(self, 'share', 'Total size', True) @pytest.mark.run(order=22) - def test_web_page(self): - '''Test that the web page contains the term Total size''' - s = socks.socksocket() - s.settimeout(60) - s.connect(('127.0.0.1', self.gui.app.port)) - - http_request = 'GET / HTTP/1.0\r\n' - http_request += 'Host: 127.0.0.1\r\n' - http_request += '\r\n' - s.sendall(http_request.encode('utf-8')) - - with open('/tmp/webpage', 'wb') as file_to_write: - while True: - data = s.recv(1024) - if not data: - break - file_to_write.write(data) - file_to_write.close() - - f = open('/tmp/webpage') - self.assertTrue('Total size' in f.read()) - f.close() + def test_download_share(self): + CommonTests.test_download_share(self, True) @pytest.mark.run(order=23) - def test_download_share(self): - '''Test that we can download the share''' - s = socks.socksocket() - s.settimeout(60) - s.connect(('127.0.0.1', self.gui.app.port)) - - http_request = 'GET /download HTTP/1.0\r\n' - http_request += 'Host: 127.0.0.1\r\n' - http_request += '\r\n' - s.sendall(http_request.encode('utf-8')) - - with open('/tmp/download.zip', 'wb') as file_to_write: - while True: - data = s.recv(1024) - if not data: - break - file_to_write.write(data) - file_to_write.close() - - zip = zipfile.ZipFile('/tmp/download.zip') - self.assertEquals('onionshare', zip.read('test.txt').decode('utf-8')) + def test_history_widgets_present(self): + CommonTests.test_history_widgets_present(self, 'share') @pytest.mark.run(order=24) - def test_downloads_widget_present(self): - QtTest.QTest.qWait(1000) - '''Test that the No Downloads Yet label is hidden, that Clear History is present''' - self.assertFalse(self.gui.share_mode.downloads.no_downloads_label.isVisible()) - self.assertTrue(self.gui.share_mode.downloads.clear_history_button.isVisible()) + def test_server_is_stopped(self): + CommonTests.test_server_is_stopped(self, 'share', False) @pytest.mark.run(order=25) - def test_server_is_stopped(self): - '''Test that the server stopped automatically when we downloaded the share''' - self.assertEquals(self.gui.share_mode.server_status.status, 0) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) @pytest.mark.run(order=26) - def test_web_service_is_stopped(self): - '''Test that the web server also stopped''' - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - # We should be closed by now. Fail if not! - self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + def test_server_status_indicator_says_closed(self): + CommonTests.test_server_status_indicator_says_closed(self, 'share', False) @pytest.mark.run(order=27) - def test_server_status_indicator_says_closed(self): - '''Test that the Server Status indicator shows we closed because download occurred''' - self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('closing_automatically', True)) - - @pytest.mark.run(order=28) - def test_add_button_visible_again(self): - '''Test that the add button should be visible again''' - self.assertTrue(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) + def test_add_button_visible(self): + CommonTests.test_add_button_visible(self) if __name__ == "__main__": diff --git a/unit_tests/onionshare_share_mode_download_test_stay_open.py b/unit_tests/onionshare_share_mode_download_test_stay_open.py index 82a0ac87..c3177a38 100644 --- a/unit_tests/onionshare_share_mode_download_test_stay_open.py +++ b/unit_tests/onionshare_share_mode_download_test_stay_open.py @@ -2,19 +2,18 @@ import os import sys import unittest -import socket import pytest -import zipfile -import socks import json -from PyQt5 import QtCore, QtWidgets, QtTest +from PyQt5 import QtWidgets from onionshare.common import Common from onionshare.web import Web from onionshare import onion, strings from onionshare_gui import * +from .commontests import CommonTests + app = QtWidgets.QApplication(sys.argv) class OnionShareGuiTest(unittest.TestCase): @@ -51,7 +50,7 @@ class OnionShareGuiTest(unittest.TestCase): "hidservauth_string": "", "no_bridges": True, "private_key": "", - "public_mode": False, + "public_mode": True, "receive_allow_receiver_shutdown": True, "save_private_key": False, "shutdown_timeout": False, @@ -80,176 +79,124 @@ class OnionShareGuiTest(unittest.TestCase): os.remove('/tmp/test.txt') @pytest.mark.run(order=1) - def test_gui_loaded_and_tor_bootstrapped(self): - '''Test that the GUI actually is shown''' - self.assertTrue(self.gui.show) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) @pytest.mark.run(order=2) def test_windowTitle_seen(self): - '''Test that the window title is OnionShare''' - self.assertEqual(self.gui.windowTitle(), 'OnionShare') + CommonTests.test_windowTitle_seen(self) @pytest.mark.run(order=3) def test_settings_button_is_visible(self): - '''Test that the settings button is visible''' - self.assertTrue(self.gui.settings_button.isVisible()) + CommonTests.test_settings_button_is_visible(self) @pytest.mark.run(order=4) def test_server_status_bar_is_visible(self): - '''Test that the status bar is visible''' - self.assertTrue(self.gui.status_bar.isVisible()) + CommonTests.test_server_status_bar_is_visible(self) @pytest.mark.run(order=5) def test_file_selection_widget_has_a_file(self): - '''Test that the number of files in the list is 1''' - self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 1) + CommonTests.test_file_selection_widget_has_a_file(self) @pytest.mark.run(order=6) def test_info_widget_is_visible(self): - '''Test that the info widget along top of screen is shown because we have a file''' - self.assertTrue(self.gui.share_mode.info_widget.isVisible()) + CommonTests.test_info_widget_is_visible(self, 'share') @pytest.mark.run(order=7) - def test_downloads_section_is_visible(self): - '''Test that the Downloads section is visible and that the No Downloads Yet label is present''' - self.assertTrue(self.gui.share_mode.downloads.isVisible()) - self.assertTrue(self.gui.share_mode.downloads.no_downloads_label.isVisible()) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') @pytest.mark.run(order=8) def test_deleting_only_file_hides_delete_button(self): - '''Test that clicking on the file item shows the delete button. Test that deleting the only item in the list hides the delete button''' - rect = self.gui.share_mode.server_status.file_selection.file_list.visualItemRect(self.gui.share_mode.server_status.file_selection.file_list.item(0)) - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.viewport(), QtCore.Qt.LeftButton, pos=rect.center()) - # Delete button should be visible - self.assertTrue(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) - # Click delete, and since there's no more files, the delete button should be hidden - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.delete_button, QtCore.Qt.LeftButton) - self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + CommonTests.test_deleting_only_file_hides_delete_button(self) @pytest.mark.run(order=9) def test_add_a_file_and_delete_using_its_delete_widget(self): - '''Test that we can also delete a file by clicking on its [X] widget''' - self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.item(0).item_button, QtCore.Qt.LeftButton) - self.assertEquals(self.gui.share_mode.server_status.file_selection.get_num_files(), 0) + CommonTests.test_add_a_file_and_delete_using_its_delete_widget(self) @pytest.mark.run(order=10) def test_file_selection_widget_readd_files(self): - '''Re-add some files to the list so we can share''' - self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') - self.gui.share_mode.server_status.file_selection.file_list.add_file('/tmp/test.txt') - self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 2) + CommonTests.test_file_selection_widget_readd_files(self) @pytest.mark.run(order=11) def test_server_working_on_start_button_pressed(self): - '''Test we can start the service''' - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) - - # Should be in SERVER_WORKING state - self.assertEqual(self.gui.share_mode.server_status.status, 1) + CommonTests.test_server_working_on_start_button_pressed(self, 'share') @pytest.mark.run(order=12) def test_server_status_indicator_says_starting(self): - '''Test that the Server Status indicator shows we are Starting''' - self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + CommonTests.test_server_status_indicator_says_starting(self, 'share') @pytest.mark.run(order=13) - def test_add_delete_buttons_now_hidden(self): - '''Test that the add and delete buttons are hidden when the server starts''' - self.assertFalse(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) - self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + def test_add_delete_buttons_hidden(self): + CommonTests.test_add_delete_buttons_hidden(self) @pytest.mark.run(order=14) def test_settings_button_is_hidden(self): - '''Test that the settings button is hidden when the server starts''' - self.assertFalse(self.gui.settings_button.isVisible()) + CommonTests.test_settings_button_is_hidden(self) @pytest.mark.run(order=15) def test_a_server_is_started(self): - '''Test that the server has started''' - QtTest.QTest.qWait(2000) - # Should now be in SERVER_STARTED state - self.assertEqual(self.gui.share_mode.server_status.status, 2) + CommonTests.test_a_server_is_started(self, 'share') @pytest.mark.run(order=16) def test_a_web_server_is_running(self): - '''Test that the web server has started''' - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + CommonTests.test_a_web_server_is_running(self) - self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) - - # Running in local mode, so we have no .onion - #@pytest.mark.run(order=17) - #def test_have_an_onion_service(self): - # '''Test that we have a valid Onion URL''' - # self.assertRegex(self.gui.app.onion_host, r'[a-z2-7].onion') - # self.assertEqual(len(self.gui.app.onion_host), 62) + @pytest.mark.run(order=17) + def test_have_a_slug(self): + CommonTests.test_have_a_slug(self, 'share', True) @pytest.mark.run(order=18) - def test_have_a_slug(self): - '''Test that we have a valid slug''' - self.assertRegex(self.gui.share_mode.server_status.web.slug, r'(\w+)-(\w+)') + def test_url_description_shown(self): + CommonTests.test_url_description_shown(self, 'share') @pytest.mark.run(order=19) - def test_url_description_shown(self): - '''Test that the URL label is showing''' - self.assertTrue(self.gui.share_mode.server_status.url_description.isVisible()) + def test_have_copy_url_button(self): + CommonTests.test_have_copy_url_button(self, 'share') @pytest.mark.run(order=20) - def test_have_copy_url_button(self): - '''Test that the Copy URL button is shown''' - self.assertTrue(self.gui.share_mode.server_status.copy_url_button.isVisible()) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'share') @pytest.mark.run(order=21) - def test_server_status_indicator_says_sharing(self): - '''Test that the Server Status indicator shows we are Sharing''' - self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_started', True)) + def test_web_page(self): + CommonTests.test_web_page(self, 'share', 'Total size', True) @pytest.mark.run(order=22) def test_download_share(self): - '''Test that we can download the share''' - s = socks.socksocket() - s.settimeout(60) - s.connect(('127.0.0.1', self.gui.app.port)) - - http_request = 'GET {}/download HTTP/1.0\r\n'.format(self.gui.share_mode.server_status.web.slug) - http_request += 'Host: 127.0.0.1\r\n' - http_request += '\r\n' - s.sendall(http_request.encode('utf-8')) - - with open('/tmp/download.zip', 'wb') as file_to_write: - while True: - data = s.recv(1024) - if not data: - break - file_to_write.write(data) - file_to_write.close() - - zip = zipfile.ZipFile('/tmp/download.zip') - self.assertEquals('onionshare', zip.read('test.txt').decode('utf-8')) + CommonTests.test_download_share(self, True) @pytest.mark.run(order=23) - def test_downloads_widget_present(self): - QtTest.QTest.qWait(1000) - '''Test that the No Downloads Yet label is hidden, that Clear History is present''' - self.assertFalse(self.gui.share_mode.downloads.no_downloads_label.isVisible()) - self.assertTrue(self.gui.share_mode.downloads.clear_history_button.isVisible()) + def test_history_widgets_present(self): + CommonTests.test_history_widgets_present(self, 'share') @pytest.mark.run(order=24) - def test_server_is_not_stopped(self): - '''Test that the server stayed open after we downloaded the share''' - self.assertEquals(self.gui.share_mode.server_status.status, 2) + def test_counter_incremented(self): + CommonTests.test_counter_incremented(self, 'share', 1) @pytest.mark.run(order=25) - def test_web_service_is_running(self): - '''Test that the web server is still running''' - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.assertEquals(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + def test_download_share_again(self): + CommonTests.test_download_share(self, True) @pytest.mark.run(order=26) - def test_download_count_incremented(self): - '''Test that the Download Count has incremented''' - self.assertEquals(self.gui.share_mode.downloads_completed, 1) + def test_counter_incremented_again(self): + CommonTests.test_counter_incremented(self, 'share', 2) + + @pytest.mark.run(order=27) + def test_server_is_stopped(self): + CommonTests.test_server_is_stopped(self, 'share', True) + + @pytest.mark.run(order=28) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) + + @pytest.mark.run(order=29) + def test_server_status_indicator_says_closed(self): + CommonTests.test_server_status_indicator_says_closed(self, 'share', True) + + @pytest.mark.run(order=30) + def test_add_button_visible(self): + CommonTests.test_add_button_visible(self) if __name__ == "__main__": diff --git a/unit_tests/onionshare_slug_persistent_test.py b/unit_tests/onionshare_slug_persistent_test.py index d0dcd08a..05c9719a 100644 --- a/unit_tests/onionshare_slug_persistent_test.py +++ b/unit_tests/onionshare_slug_persistent_test.py @@ -2,19 +2,18 @@ import os import sys import unittest -import socket import pytest -import zipfile -import socks import json -from PyQt5 import QtCore, QtWidgets, QtTest +from PyQt5 import QtWidgets from onionshare.common import Common from onionshare.web import Web from onionshare import onion, strings from onionshare_gui import * +from .commontests import CommonTests + app = QtWidgets.QApplication(sys.argv) class OnionShareGuiTest(unittest.TestCase): @@ -83,79 +82,86 @@ class OnionShareGuiTest(unittest.TestCase): @pytest.mark.run(order=1) def test_gui_loaded(self): - '''Test that the GUI actually is shown''' - self.assertTrue(self.gui.show) + CommonTests.test_gui_loaded(self) @pytest.mark.run(order=2) - def test_server_working_on_start_button_pressed(self): - '''Test we can start the service''' - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) - - # Should be in SERVER_WORKING state - self.assertEqual(self.gui.share_mode.server_status.status, 1) + def test_windowTitle_seen(self): + CommonTests.test_windowTitle_seen(self) @pytest.mark.run(order=3) - def test_server_status_indicator_says_starting(self): - '''Test that the Server Status indicator shows we are Starting''' - self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + def test_settings_button_is_visible(self): + CommonTests.test_settings_button_is_visible(self) @pytest.mark.run(order=4) - def test_a_server_is_started(self): - '''Test that the server has started''' - QtTest.QTest.qWait(2000) - # Should now be in SERVER_STARTED state - self.assertEqual(self.gui.share_mode.server_status.status, 2) + def test_server_status_bar_is_visible(self): + CommonTests.test_server_status_bar_is_visible(self) @pytest.mark.run(order=5) - def test_a_web_server_is_running(self): - '''Test that the web server has started''' - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + def test_info_widget_is_visible(self): + CommonTests.test_info_widget_is_visible(self, 'share') @pytest.mark.run(order=6) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') + + @pytest.mark.run(order=7) + def test_server_working_on_start_button_pressed(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'share') + + @pytest.mark.run(order=8) + def test_server_status_indicator_says_starting(self): + CommonTests.test_server_status_indicator_says_starting(self, 'share') + + @pytest.mark.run(order=9) + def test_settings_button_is_hidden(self): + CommonTests.test_settings_button_is_hidden(self) + + @pytest.mark.run(order=10) + def test_a_server_is_started(self): + CommonTests.test_a_server_is_started(self, 'share') + + @pytest.mark.run(order=11) + def test_a_web_server_is_running(self): + CommonTests.test_a_web_server_is_running(self) + + @pytest.mark.run(order=12) def test_have_a_slug(self): - '''Test that we have a valid slug''' - self.assertRegex(self.gui.share_mode.server_status.web.slug, r'(\w+)-(\w+)') + CommonTests.test_have_a_slug(self, 'share', False) global slug slug = self.gui.share_mode.server_status.web.slug - @pytest.mark.run(order=7) - def test_server_can_be_stopped(self): - '''Test we can stop the service''' - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + @pytest.mark.run(order=13) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'share') - # Should be in SERVER_STOPPED state - self.assertEqual(self.gui.share_mode.server_status.status, 0) + @pytest.mark.run(order=14) + def test_server_is_stopped(self): + CommonTests.test_server_is_stopped(self, 'share', True) - @pytest.mark.run(order=8) + @pytest.mark.run(order=15) def test_web_service_is_stopped(self): - '''Test that the web server also stopped''' - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - QtTest.QTest.qWait(4000) + CommonTests.test_web_service_is_stopped(self) - # We should be closed by now. Fail if not! - self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + @pytest.mark.run(order=16) + def test_server_status_indicator_says_closed(self): + CommonTests.test_server_status_indicator_says_closed(self, 'share', True) - @pytest.mark.run(order=9) + @pytest.mark.run(order=17) def test_server_started_again(self): - '''Test we can start the service again''' - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) - QtTest.QTest.qWait(2000) - # Should now be in SERVER_STARTED state - self.assertEqual(self.gui.share_mode.server_status.status, 2) + CommonTests.test_server_working_on_start_button_pressed(self, 'share') + CommonTests.test_server_status_indicator_says_starting(self, 'share') + CommonTests.test_a_server_is_started(self, 'share') - @pytest.mark.run(order=10) + @pytest.mark.run(order=18) def test_have_same_slug(self): '''Test that we have the same slug''' self.assertEqual(self.gui.share_mode.server_status.web.slug, slug) - @pytest.mark.run(order=11) + @pytest.mark.run(order=19) def test_server_is_stopped_again(self): - '''Test that we can stop the server''' - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) - QtTest.QTest.qWait(1000) - self.assertEqual(self.gui.share_mode.server_status.status, 0) + CommonTests.test_server_is_stopped(self, 'share', True) + CommonTests.test_web_service_is_stopped(self) + if __name__ == "__main__": unittest.main() diff --git a/unit_tests/onionshare_timer_test.py b/unit_tests/onionshare_timer_test.py index ed20c1c0..34c77f12 100644 --- a/unit_tests/onionshare_timer_test.py +++ b/unit_tests/onionshare_timer_test.py @@ -2,19 +2,18 @@ import os import sys import unittest -import socket import pytest -import zipfile -import socks import json -from PyQt5 import QtCore, QtWidgets, QtTest +from PyQt5 import QtWidgets from onionshare.common import Common from onionshare.web import Web from onionshare import onion, strings from onionshare_gui import * +from .commontests import CommonTests + app = QtWidgets.QApplication(sys.argv) class OnionShareGuiTest(unittest.TestCase): @@ -81,62 +80,63 @@ class OnionShareGuiTest(unittest.TestCase): @pytest.mark.run(order=1) def test_gui_loaded(self): - '''Test that the GUI actually is shown''' - self.assertTrue(self.gui.show) + CommonTests.test_gui_loaded(self) @pytest.mark.run(order=2) - def test_set_timeout(self): - '''Test that the timeout can be set''' - timer = QtCore.QDateTime.currentDateTime().addSecs(120) - self.gui.share_mode.server_status.shutdown_timeout.setDateTime(timer) - self.assertTrue(self.gui.share_mode.server_status.shutdown_timeout.dateTime(), timer) + def test_windowTitle_seen(self): + CommonTests.test_windowTitle_seen(self) @pytest.mark.run(order=3) - def test_server_working_on_start_button_pressed(self): - '''Test we can start the service''' - QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) - - # Should be in SERVER_WORKING state - self.assertEqual(self.gui.share_mode.server_status.status, 1) + def test_settings_button_is_visible(self): + CommonTests.test_settings_button_is_visible(self) @pytest.mark.run(order=4) - def test_server_status_indicator_says_starting(self): - '''Test that the Server Status indicator shows we are Starting''' - self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + def test_server_status_bar_is_visible(self): + CommonTests.test_server_status_bar_is_visible(self) @pytest.mark.run(order=5) - def test_a_server_is_started(self): - '''Test that the server has started''' - QtTest.QTest.qWait(2000) - # Should now be in SERVER_STARTED state - self.assertEqual(self.gui.share_mode.server_status.status, 2) + def test_file_selection_widget_has_a_file(self): + CommonTests.test_file_selection_widget_has_a_file(self) @pytest.mark.run(order=6) - def test_a_web_server_is_running(self): - '''Test that the web server has started''' - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + def test_info_widget_is_visible(self): + CommonTests.test_info_widget_is_visible(self, 'share') @pytest.mark.run(order=7) - def test_timeout_widget_hidden(self): - '''Test that the timeout widget is hidden when share has started''' - self.assertFalse(self.gui.share_mode.server_status.shutdown_timeout_container.isVisible()) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') @pytest.mark.run(order=8) - def test_server_timed_out(self): - '''Test that the server has timed out after the timer ran out''' - QtTest.QTest.qWait(100000) - # We should have timed out now - self.assertEqual(self.gui.share_mode.server_status.status, 0) + def test_set_timeout(self): + CommonTests.test_set_timeout(self, 'share') @pytest.mark.run(order=9) - def test_web_service_is_stopped(self): - '''Test that the web server also stopped''' - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + def test_server_working_on_start_button_pressed(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'share') - # We should be closed by now. Fail if not! - self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + @pytest.mark.run(order=10) + def test_server_status_indicator_says_starting(self): + CommonTests.test_server_status_indicator_says_starting(self, 'share') + + @pytest.mark.run(order=11) + def test_a_server_is_started(self): + CommonTests.test_a_server_is_started(self, 'share') + + @pytest.mark.run(order=12) + def test_a_web_server_is_running(self): + CommonTests.test_a_web_server_is_running(self) + + @pytest.mark.run(order=13) + def test_timeout_widget_hidden(self): + CommonTests.test_timeout_widget_hidden(self, 'share') + + @pytest.mark.run(order=14) + def test_timeout(self): + CommonTests.test_server_timed_out(self, 'share', 120000) + + @pytest.mark.run(order=15) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) if __name__ == "__main__": unittest.main() From 201f351279ee58166458717415045cfe62c2ac69 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Thu, 27 Sep 2018 15:43:59 +1000 Subject: [PATCH 11/13] Pass --local-only down to the ServerStatus and Mode so that we can set shorter timeouts for local GUI tests. Update the tests to use a very short timeout --- onionshare_gui/mode.py | 7 +++++-- onionshare_gui/onionshare_gui.py | 4 ++-- onionshare_gui/server_status.py | 26 ++++++++++++++++++-------- unit_tests/commontests.py | 4 ++-- unit_tests/onionshare_timer_test.py | 4 ++-- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/onionshare_gui/mode.py b/onionshare_gui/mode.py index 4c21de76..6b156f7e 100644 --- a/onionshare_gui/mode.py +++ b/onionshare_gui/mode.py @@ -37,7 +37,7 @@ class Mode(QtWidgets.QWidget): starting_server_error = QtCore.pyqtSignal(str) set_server_active = QtCore.pyqtSignal(bool) - def __init__(self, common, qtapp, app, status_bar, server_status_label, system_tray, filenames=None): + def __init__(self, common, qtapp, app, status_bar, server_status_label, system_tray, filenames=None, local_only=False): super(Mode, self).__init__() self.common = common self.qtapp = qtapp @@ -54,12 +54,15 @@ class Mode(QtWidgets.QWidget): # The web object gets created in init() self.web = None + # Local mode is passed from OnionShareGui + self.local_only = local_only + # Threads start out as None self.onion_thread = None self.web_thread = None # Server status - self.server_status = ServerStatus(self.common, self.qtapp, self.app) + self.server_status = ServerStatus(self.common, self.qtapp, self.app, None, self.local_only) self.server_status.server_started.connect(self.start_server) self.server_status.server_stopped.connect(self.stop_server) self.server_status.server_canceled.connect(self.cancel_server) diff --git a/onionshare_gui/onionshare_gui.py b/onionshare_gui/onionshare_gui.py index 8b61a18e..83f3a7e0 100644 --- a/onionshare_gui/onionshare_gui.py +++ b/onionshare_gui/onionshare_gui.py @@ -121,7 +121,7 @@ class OnionShareGui(QtWidgets.QMainWindow): self.setStatusBar(self.status_bar) # Share mode - self.share_mode = ShareMode(self.common, qtapp, app, self.status_bar, self.server_status_label, self.system_tray, filenames) + self.share_mode = ShareMode(self.common, qtapp, app, self.status_bar, self.server_status_label, self.system_tray, filenames, self.local_only) self.share_mode.init() self.share_mode.server_status.server_started.connect(self.update_server_status_indicator) self.share_mode.server_status.server_stopped.connect(self.update_server_status_indicator) @@ -135,7 +135,7 @@ class OnionShareGui(QtWidgets.QMainWindow): self.share_mode.set_server_active.connect(self.set_server_active) # Receive mode - self.receive_mode = ReceiveMode(self.common, qtapp, app, self.status_bar, self.server_status_label, self.system_tray) + self.receive_mode = ReceiveMode(self.common, qtapp, app, self.status_bar, self.server_status_label, self.system_tray, None, self.local_only) self.receive_mode.init() self.receive_mode.server_status.server_started.connect(self.update_server_status_indicator) self.receive_mode.server_status.server_stopped.connect(self.update_server_status_indicator) diff --git a/onionshare_gui/server_status.py b/onionshare_gui/server_status.py index 9afceb38..32135ca4 100644 --- a/onionshare_gui/server_status.py +++ b/onionshare_gui/server_status.py @@ -44,7 +44,7 @@ class ServerStatus(QtWidgets.QWidget): STATUS_WORKING = 1 STATUS_STARTED = 2 - def __init__(self, common, qtapp, app, file_selection=None): + def __init__(self, common, qtapp, app, file_selection=None, local_only=False): super(ServerStatus, self).__init__() self.common = common @@ -56,17 +56,23 @@ class ServerStatus(QtWidgets.QWidget): self.app = app self.web = None + self.local_only = local_only self.resizeEvent(None) # Shutdown timeout layout self.shutdown_timeout_label = QtWidgets.QLabel(strings._('gui_settings_shutdown_timeout', True)) self.shutdown_timeout = QtWidgets.QDateTimeEdit() - # Set proposed timeout to be 5 minutes into the future self.shutdown_timeout.setDisplayFormat("hh:mm A MMM d, yy") - self.shutdown_timeout.setDateTime(QtCore.QDateTime.currentDateTime().addSecs(300)) - # Onion services can take a little while to start, so reduce the risk of it expiring too soon by setting the minimum to 2 min from now - self.shutdown_timeout.setMinimumDateTime(QtCore.QDateTime.currentDateTime().addSecs(120)) + if self.local_only: + # For testing + self.shutdown_timeout.setDateTime(QtCore.QDateTime.currentDateTime().addSecs(15)) + self.shutdown_timeout.setMinimumDateTime(QtCore.QDateTime.currentDateTime()) + else: + # Set proposed timeout to be 5 minutes into the future + self.shutdown_timeout.setDateTime(QtCore.QDateTime.currentDateTime().addSecs(300)) + # Onion services can take a little while to start, so reduce the risk of it expiring too soon by setting the minimum to 60s from now + self.shutdown_timeout.setMinimumDateTime(QtCore.QDateTime.currentDateTime().addSecs(60)) self.shutdown_timeout.setCurrentSection(QtWidgets.QDateTimeEdit.MinuteSection) shutdown_timeout_layout = QtWidgets.QHBoxLayout() shutdown_timeout_layout.addWidget(self.shutdown_timeout_label) @@ -154,7 +160,8 @@ class ServerStatus(QtWidgets.QWidget): Reset the timeout in the UI after stopping a share """ self.shutdown_timeout.setDateTime(QtCore.QDateTime.currentDateTime().addSecs(300)) - self.shutdown_timeout.setMinimumDateTime(QtCore.QDateTime.currentDateTime().addSecs(120)) + if not self.local_only: + self.shutdown_timeout.setMinimumDateTime(QtCore.QDateTime.currentDateTime().addSecs(60)) def update(self): """ @@ -255,8 +262,11 @@ class ServerStatus(QtWidgets.QWidget): """ if self.status == self.STATUS_STOPPED: if self.common.settings.get('shutdown_timeout'): - # Get the timeout chosen, stripped of its seconds. This prevents confusion if the share stops at (say) 37 seconds past the minute chosen - self.timeout = self.shutdown_timeout.dateTime().toPyDateTime().replace(second=0, microsecond=0) + if self.local_only: + self.timeout = self.shutdown_timeout.dateTime().toPyDateTime() + else: + # Get the timeout chosen, stripped of its seconds. This prevents confusion if the share stops at (say) 37 seconds past the minute chosen + self.timeout = self.shutdown_timeout.dateTime().toPyDateTime().replace(second=0, microsecond=0) # If the timeout has actually passed already before the user hit Start, refuse to start the server. if QtCore.QDateTime.currentDateTime().toPyDateTime() > self.timeout: Alert(self.common, strings._('gui_server_timeout_expired', QtWidgets.QMessageBox.Warning)) diff --git a/unit_tests/commontests.py b/unit_tests/commontests.py index 1f6f5896..de1ad9ab 100644 --- a/unit_tests/commontests.py +++ b/unit_tests/commontests.py @@ -203,9 +203,9 @@ class CommonTests(object): self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('closing_automatically', True)) # Auto-stop timer tests - def test_set_timeout(self, mode): + def test_set_timeout(self, mode, timeout): '''Test that the timeout can be set''' - timer = QtCore.QDateTime.currentDateTime().addSecs(120) + timer = QtCore.QDateTime.currentDateTime().addSecs(timeout) if mode == 'receive': self.gui.receive_mode.server_status.shutdown_timeout.setDateTime(timer) self.assertTrue(self.gui.receive_mode.server_status.shutdown_timeout.dateTime(), timer) diff --git a/unit_tests/onionshare_timer_test.py b/unit_tests/onionshare_timer_test.py index 34c77f12..f36331b8 100644 --- a/unit_tests/onionshare_timer_test.py +++ b/unit_tests/onionshare_timer_test.py @@ -108,7 +108,7 @@ class OnionShareGuiTest(unittest.TestCase): @pytest.mark.run(order=8) def test_set_timeout(self): - CommonTests.test_set_timeout(self, 'share') + CommonTests.test_set_timeout(self, 'share', 5) @pytest.mark.run(order=9) def test_server_working_on_start_button_pressed(self): @@ -132,7 +132,7 @@ class OnionShareGuiTest(unittest.TestCase): @pytest.mark.run(order=14) def test_timeout(self): - CommonTests.test_server_timed_out(self, 'share', 120000) + CommonTests.test_server_timed_out(self, 'share', 10000) @pytest.mark.run(order=15) def test_web_service_is_stopped(self): From 8fc8e0765c73530136b9cd203bc059be09bd8475 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Thu, 27 Sep 2018 15:54:46 +1000 Subject: [PATCH 12/13] Rename test dir to tests. Rename unit_tests to tests_gui_local. Add test dependencies. Update various paths. Add GUI unit tests docs to BUILD.md --- .travis.yml | 2 +- BUILD.md | 17 +++++++++++++++-- MANIFEST.in | 2 +- install/check_lacked_trans.py | 2 +- install/requirements-tests.txt | 11 +++++++++++ {test => tests}/__init__.py | 0 {test => tests}/conftest.py | 0 {test => tests}/test_helpers.py | 0 {test => tests}/test_onionshare.py | 0 {test => tests}/test_onionshare_common.py | 0 {test => tests}/test_onionshare_settings.py | 0 {test => tests}/test_onionshare_strings.py | 0 {test => tests}/test_onionshare_web.py | 0 {unit_tests => tests_gui_local}/__init__.py | 0 {unit_tests => tests_gui_local}/commontests.py | 0 {unit_tests => tests_gui_local}/conftest.py | 0 .../onionshare_receive_mode_upload_test.py | 0 ...hare_receive_mode_upload_test_public_mode.py | 0 .../onionshare_share_mode_download_test.py | 0 ...hare_share_mode_download_test_public_mode.py | 0 ...nshare_share_mode_download_test_stay_open.py | 0 .../onionshare_slug_persistent_test.py | 0 .../onionshare_timer_test.py | 0 .../run_unit_tests.sh | 0 24 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 install/requirements-tests.txt rename {test => tests}/__init__.py (100%) rename {test => tests}/conftest.py (100%) rename {test => tests}/test_helpers.py (100%) rename {test => tests}/test_onionshare.py (100%) rename {test => tests}/test_onionshare_common.py (100%) rename {test => tests}/test_onionshare_settings.py (100%) rename {test => tests}/test_onionshare_strings.py (100%) rename {test => tests}/test_onionshare_web.py (100%) rename {unit_tests => tests_gui_local}/__init__.py (100%) rename {unit_tests => tests_gui_local}/commontests.py (100%) rename {unit_tests => tests_gui_local}/conftest.py (100%) rename {unit_tests => tests_gui_local}/onionshare_receive_mode_upload_test.py (100%) rename {unit_tests => tests_gui_local}/onionshare_receive_mode_upload_test_public_mode.py (100%) rename {unit_tests => tests_gui_local}/onionshare_share_mode_download_test.py (100%) rename {unit_tests => tests_gui_local}/onionshare_share_mode_download_test_public_mode.py (100%) rename {unit_tests => tests_gui_local}/onionshare_share_mode_download_test_stay_open.py (100%) rename {unit_tests => tests_gui_local}/onionshare_slug_persistent_test.py (100%) rename {unit_tests => tests_gui_local}/onionshare_timer_test.py (100%) rename {unit_tests => tests_gui_local}/run_unit_tests.sh (100%) diff --git a/.travis.yml b/.travis.yml index afbaa887..a41339cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,6 @@ before_script: # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics # command to run tests -script: pytest --cov=onionshare test/ +script: pytest --cov=onionshare tests/ after_success: - coveralls diff --git a/BUILD.md b/BUILD.md index 1feedf49..308a186c 100644 --- a/BUILD.md +++ b/BUILD.md @@ -137,8 +137,21 @@ This will prompt you to codesign three binaries and execute one unsigned binary. ## Tests -OnionShare includes PyTest unit tests. To run the tests: +OnionShare includes PyTest unit tests. To run the tests, first install some dependencies: ```sh -pytest test/ +pip3 install -r install/requirements-tests.txt +``` + +If you'd like to run the CLI-based tests that Travis runs: + +```sh +pytest tests/ +``` + +If you would like to run the GUI unit tests in 'local only mode': + +```sh +cd tests_gui_local/ +./run_unit_tests.sh ``` diff --git a/MANIFEST.in b/MANIFEST.in index c8a4d87c..71af3740 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -10,4 +10,4 @@ include install/onionshare.desktop include install/onionshare.appdata.xml include install/onionshare80.xpm include install/scripts/onionshare-nautilus.py -include test/*.py +include tests/*.py diff --git a/install/check_lacked_trans.py b/install/check_lacked_trans.py index 027edab1..1caa6b27 100644 --- a/install/check_lacked_trans.py +++ b/install/check_lacked_trans.py @@ -59,7 +59,7 @@ def main(): files_in(dir, 'onionshare_gui/share_mode') + \ files_in(dir, 'onionshare_gui/receive_mode') + \ files_in(dir, 'install/scripts') + \ - files_in(dir, 'test') + files_in(dir, 'tests') pysrc = [p for p in src if p.endswith('.py')] lang_code = args.lang_code diff --git a/install/requirements-tests.txt b/install/requirements-tests.txt new file mode 100644 index 00000000..0d9c1581 --- /dev/null +++ b/install/requirements-tests.txt @@ -0,0 +1,11 @@ +atomicwrites==1.2.1 +attrs==18.2.0 +more-itertools==4.3.0 +pluggy==0.6.0 +py==1.6.0 +pytest==3.4.2 +pytest-faulthandler==1.5.0 +pytest-ordering==0.5 +pytest-qt==3.1.0 +six==1.11.0 +urllib3==1.23 diff --git a/test/__init__.py b/tests/__init__.py similarity index 100% rename from test/__init__.py rename to tests/__init__.py diff --git a/test/conftest.py b/tests/conftest.py similarity index 100% rename from test/conftest.py rename to tests/conftest.py diff --git a/test/test_helpers.py b/tests/test_helpers.py similarity index 100% rename from test/test_helpers.py rename to tests/test_helpers.py diff --git a/test/test_onionshare.py b/tests/test_onionshare.py similarity index 100% rename from test/test_onionshare.py rename to tests/test_onionshare.py diff --git a/test/test_onionshare_common.py b/tests/test_onionshare_common.py similarity index 100% rename from test/test_onionshare_common.py rename to tests/test_onionshare_common.py diff --git a/test/test_onionshare_settings.py b/tests/test_onionshare_settings.py similarity index 100% rename from test/test_onionshare_settings.py rename to tests/test_onionshare_settings.py diff --git a/test/test_onionshare_strings.py b/tests/test_onionshare_strings.py similarity index 100% rename from test/test_onionshare_strings.py rename to tests/test_onionshare_strings.py diff --git a/test/test_onionshare_web.py b/tests/test_onionshare_web.py similarity index 100% rename from test/test_onionshare_web.py rename to tests/test_onionshare_web.py diff --git a/unit_tests/__init__.py b/tests_gui_local/__init__.py similarity index 100% rename from unit_tests/__init__.py rename to tests_gui_local/__init__.py diff --git a/unit_tests/commontests.py b/tests_gui_local/commontests.py similarity index 100% rename from unit_tests/commontests.py rename to tests_gui_local/commontests.py diff --git a/unit_tests/conftest.py b/tests_gui_local/conftest.py similarity index 100% rename from unit_tests/conftest.py rename to tests_gui_local/conftest.py diff --git a/unit_tests/onionshare_receive_mode_upload_test.py b/tests_gui_local/onionshare_receive_mode_upload_test.py similarity index 100% rename from unit_tests/onionshare_receive_mode_upload_test.py rename to tests_gui_local/onionshare_receive_mode_upload_test.py diff --git a/unit_tests/onionshare_receive_mode_upload_test_public_mode.py b/tests_gui_local/onionshare_receive_mode_upload_test_public_mode.py similarity index 100% rename from unit_tests/onionshare_receive_mode_upload_test_public_mode.py rename to tests_gui_local/onionshare_receive_mode_upload_test_public_mode.py diff --git a/unit_tests/onionshare_share_mode_download_test.py b/tests_gui_local/onionshare_share_mode_download_test.py similarity index 100% rename from unit_tests/onionshare_share_mode_download_test.py rename to tests_gui_local/onionshare_share_mode_download_test.py diff --git a/unit_tests/onionshare_share_mode_download_test_public_mode.py b/tests_gui_local/onionshare_share_mode_download_test_public_mode.py similarity index 100% rename from unit_tests/onionshare_share_mode_download_test_public_mode.py rename to tests_gui_local/onionshare_share_mode_download_test_public_mode.py diff --git a/unit_tests/onionshare_share_mode_download_test_stay_open.py b/tests_gui_local/onionshare_share_mode_download_test_stay_open.py similarity index 100% rename from unit_tests/onionshare_share_mode_download_test_stay_open.py rename to tests_gui_local/onionshare_share_mode_download_test_stay_open.py diff --git a/unit_tests/onionshare_slug_persistent_test.py b/tests_gui_local/onionshare_slug_persistent_test.py similarity index 100% rename from unit_tests/onionshare_slug_persistent_test.py rename to tests_gui_local/onionshare_slug_persistent_test.py diff --git a/unit_tests/onionshare_timer_test.py b/tests_gui_local/onionshare_timer_test.py similarity index 100% rename from unit_tests/onionshare_timer_test.py rename to tests_gui_local/onionshare_timer_test.py diff --git a/unit_tests/run_unit_tests.sh b/tests_gui_local/run_unit_tests.sh similarity index 100% rename from unit_tests/run_unit_tests.sh rename to tests_gui_local/run_unit_tests.sh From 8212da2d3df36c17162225f83be12a9db09cbccb Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Thu, 27 Sep 2018 17:33:15 +1000 Subject: [PATCH 13/13] Add Tor GUI unit tests --- BUILD.md | 9 + tests_gui_tor/__init__.py | 0 tests_gui_tor/commontests.py | 359 ++++++++++++++++++ tests_gui_tor/conftest.py | 160 ++++++++ .../onionshare_receive_mode_upload_test.py | 188 +++++++++ ...re_receive_mode_upload_test_public_mode.py | 188 +++++++++ ...onionshare_share_mode_cancel_share_test.py | 159 ++++++++ .../onionshare_share_mode_download_test.py | 195 ++++++++++ ...re_share_mode_download_test_public_mode.py | 195 ++++++++++ ...hare_share_mode_download_test_stay_open.py | 207 ++++++++++ .../onionshare_share_mode_persistent_test.py | 179 +++++++++ .../onionshare_share_mode_stealth_test.py | 174 +++++++++ ...e_share_mode_tor_connection_killed_test.py | 179 +++++++++ tests_gui_tor/onionshare_timer_test.py | 142 +++++++ .../onionshare_tor_connection_killed_test.py | 179 +++++++++ tests_gui_tor/run_unit_tests.sh | 5 + 16 files changed, 2518 insertions(+) create mode 100644 tests_gui_tor/__init__.py create mode 100644 tests_gui_tor/commontests.py create mode 100644 tests_gui_tor/conftest.py create mode 100644 tests_gui_tor/onionshare_receive_mode_upload_test.py create mode 100644 tests_gui_tor/onionshare_receive_mode_upload_test_public_mode.py create mode 100644 tests_gui_tor/onionshare_share_mode_cancel_share_test.py create mode 100644 tests_gui_tor/onionshare_share_mode_download_test.py create mode 100644 tests_gui_tor/onionshare_share_mode_download_test_public_mode.py create mode 100644 tests_gui_tor/onionshare_share_mode_download_test_stay_open.py create mode 100644 tests_gui_tor/onionshare_share_mode_persistent_test.py create mode 100644 tests_gui_tor/onionshare_share_mode_stealth_test.py create mode 100644 tests_gui_tor/onionshare_share_mode_tor_connection_killed_test.py create mode 100644 tests_gui_tor/onionshare_timer_test.py create mode 100644 tests_gui_tor/onionshare_tor_connection_killed_test.py create mode 100755 tests_gui_tor/run_unit_tests.sh diff --git a/BUILD.md b/BUILD.md index 308a186c..00d24cd2 100644 --- a/BUILD.md +++ b/BUILD.md @@ -155,3 +155,12 @@ If you would like to run the GUI unit tests in 'local only mode': cd tests_gui_local/ ./run_unit_tests.sh ``` + +If you would like to run the GUI unit tests in 'tor' (bundled) mode: + +```sh +cd tests_gui_tor/ +./run_unit_tests.sh +``` + +Keep in mind that the Tor tests take a lot longer to run than local mode, but they are also more comprehensive. diff --git a/tests_gui_tor/__init__.py b/tests_gui_tor/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests_gui_tor/commontests.py b/tests_gui_tor/commontests.py new file mode 100644 index 00000000..a0d9bf5f --- /dev/null +++ b/tests_gui_tor/commontests.py @@ -0,0 +1,359 @@ +import os +import requests +import socket +import socks +import zipfile + +from PyQt5 import QtCore, QtTest +from onionshare import strings + +class CommonTests(object): + def test_gui_loaded(self): + '''Test that the GUI actually is shown''' + self.assertTrue(self.gui.show) + + def test_windowTitle_seen(self): + '''Test that the window title is OnionShare''' + self.assertEqual(self.gui.windowTitle(), 'OnionShare') + + def test_settings_button_is_visible(self): + '''Test that the settings button is visible''' + self.assertTrue(self.gui.settings_button.isVisible()) + + def test_server_status_bar_is_visible(self): + '''Test that the status bar is visible''' + self.assertTrue(self.gui.status_bar.isVisible()) + + def test_info_widget_is_not_visible(self, mode): + '''Test that the info widget along top of screen is not shown''' + if mode == 'receive': + self.assertFalse(self.gui.receive_mode.info_widget.isVisible()) + if mode == 'share': + self.assertFalse(self.gui.share_mode.info_widget.isVisible()) + + def test_info_widget_is_visible(self, mode): + '''Test that the info widget along top of screen is shown''' + if mode == 'receive': + self.assertTrue(self.gui.receive_mode.info_widget.isVisible()) + if mode == 'share': + self.assertTrue(self.gui.share_mode.info_widget.isVisible()) + + def test_click_mode(self, mode): + '''Test that we can switch Mode by clicking the button''' + if mode == 'receive': + QtTest.QTest.mouseClick(self.gui.receive_mode_button, QtCore.Qt.LeftButton) + self.assertTrue(self.gui.mode, self.gui.MODE_RECEIVE) + if mode == 'share': + QtTest.QTest.mouseClick(self.gui.share_mode_button, QtCore.Qt.LeftButton) + self.assertTrue(self.gui.mode, self.gui.MODE_SHARE) + + def test_history_is_visible(self, mode): + '''Test that the History section is visible and that the relevant widget is present''' + if mode == 'receive': + self.assertTrue(self.gui.receive_mode.uploads.isVisible()) + self.assertTrue(self.gui.receive_mode.uploads.no_uploads_label.isVisible()) + if mode == 'share': + self.assertTrue(self.gui.share_mode.downloads.isVisible()) + self.assertTrue(self.gui.share_mode.downloads.no_downloads_label.isVisible()) + + def test_server_working_on_start_button_pressed(self, mode): + '''Test we can start the service''' + # Should be in SERVER_WORKING state + if mode == 'receive': + QtTest.QTest.mouseClick(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) + self.assertEqual(self.gui.receive_mode.server_status.status, 1) + if mode == 'share': + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + self.assertEqual(self.gui.share_mode.server_status.status, 1) + + def test_server_status_indicator_says_starting(self, mode): + '''Test that the Server Status indicator shows we are Starting''' + if mode == 'receive': + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + if mode == 'share': + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_working', True)) + + def test_settings_button_is_hidden(self): + '''Test that the settings button is hidden when the server starts''' + self.assertFalse(self.gui.settings_button.isVisible()) + + def test_a_server_is_started(self, mode): + '''Test that the server has started''' + QtTest.QTest.qWait(45000) + # Should now be in SERVER_STARTED state + if mode == 'receive': + self.assertEqual(self.gui.receive_mode.server_status.status, 2) + if mode == 'share': + self.assertEqual(self.gui.share_mode.server_status.status, 2) + + def test_a_web_server_is_running(self): + '''Test that the web server has started''' + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + self.assertEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + def test_have_a_slug(self, mode, public_mode): + '''Test that we have a valid slug''' + if mode == 'receive': + if not public_mode: + self.assertRegex(self.gui.receive_mode.server_status.web.slug, r'(\w+)-(\w+)') + else: + self.assertIsNone(self.gui.receive_mode.server_status.web.slug, r'(\w+)-(\w+)') + if mode == 'share': + if not public_mode: + self.assertRegex(self.gui.share_mode.server_status.web.slug, r'(\w+)-(\w+)') + else: + self.assertIsNone(self.gui.share_mode.server_status.web.slug, r'(\w+)-(\w+)') + + def test_have_an_onion_service(self): + '''Test that we have a valid Onion URL''' + self.assertRegex(self.gui.app.onion_host, r'[a-z2-7].onion') + + def test_url_description_shown(self, mode): + '''Test that the URL label is showing''' + if mode == 'receive': + self.assertTrue(self.gui.receive_mode.server_status.url_description.isVisible()) + if mode == 'share': + self.assertTrue(self.gui.share_mode.server_status.url_description.isVisible()) + + def test_have_copy_url_button(self, mode): + '''Test that the Copy URL button is shown''' + if mode == 'receive': + self.assertTrue(self.gui.receive_mode.server_status.copy_url_button.isVisible()) + if mode == 'share': + self.assertTrue(self.gui.share_mode.server_status.copy_url_button.isVisible()) + + def test_server_status_indicator_says_started(self, mode): + '''Test that the Server Status indicator shows we are started''' + if mode == 'receive': + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_started', True)) + if mode == 'share': + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_share_started', True)) + + def test_web_page(self, mode, string, public_mode): + '''Test that the web page contains a string''' + (socks_address, socks_port) = self.gui.app.onion.get_tor_socks_port() + socks.set_default_proxy(socks.SOCKS5, socks_address, socks_port) + + s = socks.socksocket() + s.settimeout(60) + s.connect((self.gui.app.onion_host, 80)) + + if not public_mode: + if mode == 'receive': + path = '/{}'.format(self.gui.receive_mode.server_status.web.slug) + if mode == 'share': + path = '/{}'.format(self.gui.share_mode.server_status.web.slug) + else: + path = '/' + + http_request = 'GET {} HTTP/1.0\r\n'.format(path) + http_request += 'Host: {}\r\n'.format(self.gui.app.onion_host) + http_request += '\r\n' + s.sendall(http_request.encode('utf-8')) + + with open('/tmp/webpage', 'wb') as file_to_write: + while True: + data = s.recv(1024) + if not data: + break + file_to_write.write(data) + file_to_write.close() + + f = open('/tmp/webpage') + self.assertTrue(string in f.read()) + f.close() + + def test_history_widgets_present(self, mode): + '''Test that the relevant widgets are present in the history view after activity has taken place''' + if mode == 'receive': + self.assertFalse(self.gui.receive_mode.uploads.no_uploads_label.isVisible()) + self.assertTrue(self.gui.receive_mode.uploads.clear_history_button.isVisible()) + if mode == 'share': + self.assertFalse(self.gui.share_mode.downloads.no_downloads_label.isVisible()) + self.assertTrue(self.gui.share_mode.downloads.clear_history_button.isVisible()) + + def test_counter_incremented(self, mode, count): + '''Test that the counter has incremented''' + if mode == 'receive': + self.assertEquals(self.gui.receive_mode.uploads_completed, count) + if mode == 'share': + self.assertEquals(self.gui.share_mode.downloads_completed, count) + + def test_server_is_stopped(self, mode, stay_open): + '''Test that the server stops when we click Stop''' + if mode == 'receive': + QtTest.QTest.mouseClick(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) + self.assertEquals(self.gui.receive_mode.server_status.status, 0) + if mode == 'share': + if stay_open: + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + self.assertEquals(self.gui.share_mode.server_status.status, 0) + + def test_web_service_is_stopped(self): + '''Test that the web server also stopped''' + QtTest.QTest.qWait(2000) + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # We should be closed by now. Fail if not! + self.assertNotEqual(sock.connect_ex(('127.0.0.1',self.gui.app.port)), 0) + + def test_server_status_indicator_says_closed(self, mode, stay_open): + '''Test that the Server Status indicator shows we closed''' + if mode == 'receive': + self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_stopped', True)) + if mode == 'share': + if stay_open: + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_stopped', True)) + else: + self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('closing_automatically', True)) + + def test_cancel_the_share(self, mode): + '''Test that we can cancel this share before it's started up ''' + if mode == 'share': + QtTest.QTest.mousePress(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + QtTest.QTest.qWait(1000) + QtTest.QTest.mouseRelease(self.gui.share_mode.server_status.server_button, QtCore.Qt.LeftButton) + self.assertEqual(self.gui.share_mode.server_status.status, 0) + + if mode == 'receive': + QtTest.QTest.mousePress(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) + QtTest.QTest.qWait(1000) + QtTest.QTest.mouseRelease(self.gui.receive_mode.server_status.server_button, QtCore.Qt.LeftButton) + self.assertEqual(self.gui.receive_mode.server_status.status, 0) + + + # Auto-stop timer tests + def test_set_timeout(self, mode, timeout): + '''Test that the timeout can be set''' + timer = QtCore.QDateTime.currentDateTime().addSecs(timeout) + if mode == 'receive': + self.gui.receive_mode.server_status.shutdown_timeout.setDateTime(timer) + self.assertTrue(self.gui.receive_mode.server_status.shutdown_timeout.dateTime(), timer) + if mode == 'share': + self.gui.share_mode.server_status.shutdown_timeout.setDateTime(timer) + self.assertTrue(self.gui.share_mode.server_status.shutdown_timeout.dateTime(), timer) + + def test_timeout_widget_hidden(self, mode): + '''Test that the timeout widget is hidden when share has started''' + if mode == 'receive': + self.assertFalse(self.gui.receive_mode.server_status.shutdown_timeout_container.isVisible()) + if mode == 'share': + self.assertFalse(self.gui.share_mode.server_status.shutdown_timeout_container.isVisible()) + + def test_server_timed_out(self, mode, wait): + '''Test that the server has timed out after the timer ran out''' + QtTest.QTest.qWait(wait) + # We should have timed out now + if mode == 'receive': + self.assertEqual(self.gui.receive_mode.server_status.status, 0) + if mode == 'share': + self.assertEqual(self.gui.share_mode.server_status.status, 0) + + # Receive-specific tests + def test_upload_file(self, public_mode, expected_file): + '''Test that we can upload the file''' + (socks_address, socks_port) = self.gui.app.onion.get_tor_socks_port() + session = requests.session() + session.proxies = {} + session.proxies['http'] = 'socks5h://{}:{}'.format(socks_address, socks_port) + + files = {'file[]': open('/tmp/test.txt', 'rb')} + if not public_mode: + path = 'http://{}/{}/upload'.format(self.gui.app.onion_host, self.gui.receive_mode.web.slug) + else: + path = 'http://{}/upload'.format(self.gui.app.onion_host) + response = session.post(path, files=files) + QtTest.QTest.qWait(4000) + self.assertTrue(os.path.isfile(expected_file)) + + # Share-specific tests + def test_file_selection_widget_has_a_file(self): + '''Test that the number of files in the list is 1''' + self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 1) + + def test_deleting_only_file_hides_delete_button(self): + '''Test that clicking on the file item shows the delete button. Test that deleting the only item in the list hides the delete button''' + rect = self.gui.share_mode.server_status.file_selection.file_list.visualItemRect(self.gui.share_mode.server_status.file_selection.file_list.item(0)) + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.viewport(), QtCore.Qt.LeftButton, pos=rect.center()) + # Delete button should be visible + self.assertTrue(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + # Click delete, and since there's no more files, the delete button should be hidden + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.delete_button, QtCore.Qt.LeftButton) + self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + + def test_add_a_file_and_delete_using_its_delete_widget(self): + '''Test that we can also delete a file by clicking on its [X] widget''' + self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') + QtTest.QTest.mouseClick(self.gui.share_mode.server_status.file_selection.file_list.item(0).item_button, QtCore.Qt.LeftButton) + self.assertEquals(self.gui.share_mode.server_status.file_selection.get_num_files(), 0) + + def test_file_selection_widget_readd_files(self): + '''Re-add some files to the list so we can share''' + self.gui.share_mode.server_status.file_selection.file_list.add_file('/etc/hosts') + self.gui.share_mode.server_status.file_selection.file_list.add_file('/tmp/test.txt') + self.assertEqual(self.gui.share_mode.server_status.file_selection.get_num_files(), 2) + + def test_add_delete_buttons_hidden(self): + '''Test that the add and delete buttons are hidden when the server starts''' + self.assertFalse(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) + self.assertFalse(self.gui.share_mode.server_status.file_selection.delete_button.isVisible()) + + def test_download_share(self, public_mode): + '''Test that we can download the share''' + (socks_address, socks_port) = self.gui.app.onion.get_tor_socks_port() + socks.set_default_proxy(socks.SOCKS5, socks_address, socks_port) + + s = socks.socksocket() + s.settimeout(60) + s.connect((self.gui.app.onion_host, 80)) + + if public_mode: + path = '/download' + else: + path = '{}/download'.format(self.gui.share_mode.web.slug) + + http_request = 'GET {} HTTP/1.0\r\n'.format(path) + http_request += 'Host: {}\r\n'.format(self.gui.app.onion_host) + http_request += '\r\n' + s.sendall(http_request.encode('utf-8')) + + with open('/tmp/download.zip', 'wb') as file_to_write: + while True: + data = s.recv(1024) + if not data: + break + file_to_write.write(data) + file_to_write.close() + + zip = zipfile.ZipFile('/tmp/download.zip') + QtTest.QTest.qWait(4000) + self.assertEquals('onionshare', zip.read('test.txt').decode('utf-8')) + + def test_add_button_visible(self): + '''Test that the add button should be visible''' + self.assertTrue(self.gui.share_mode.server_status.file_selection.add_button.isVisible()) + + + # Stealth tests + def test_copy_have_hidserv_auth_button(self, mode): + '''Test that the Copy HidservAuth button is shown''' + if mode == 'share': + self.assertTrue(self.gui.share_mode.server_status.copy_hidservauth_button.isVisible()) + if mode == 'receive': + self.assertTrue(self.gui.receive_mode.server_status.copy_hidservauth_button.isVisible()) + + def test_hidserv_auth_string(self): + '''Test the validity of the HidservAuth string''' + self.assertRegex(self.gui.app.auth_string, r'HidServAuth %s [a-zA-Z1-9]' % self.gui.app.onion_host) + + + # Miscellaneous tests + def test_tor_killed_statusbar_message_shown(self, mode): + '''Test that the status bar message shows Tor was disconnected''' + self.gui.app.onion.cleanup(stop_tor=True) + QtTest.QTest.qWait(2500) + if mode == 'share': + self.assertTrue(self.gui.share_mode.status_bar.currentMessage(), strings._('gui_tor_connection_lost', True)) + if mode == 'receive': + self.assertTrue(self.gui.receive_mode.status_bar.currentMessage(), strings._('gui_tor_connection_lost', True)) diff --git a/tests_gui_tor/conftest.py b/tests_gui_tor/conftest.py new file mode 100644 index 00000000..8ac7efb8 --- /dev/null +++ b/tests_gui_tor/conftest.py @@ -0,0 +1,160 @@ +import sys +# Force tests to look for resources in the source code tree +sys.onionshare_dev_mode = True + +import os +import shutil +import tempfile + +import pytest + +from onionshare import common, web, settings + +@pytest.fixture +def temp_dir_1024(): + """ Create a temporary directory that has a single file of a + particular size (1024 bytes). + """ + + tmp_dir = tempfile.mkdtemp() + tmp_file, tmp_file_path = tempfile.mkstemp(dir=tmp_dir) + with open(tmp_file, 'wb') as f: + f.write(b'*' * 1024) + return tmp_dir + + +# pytest > 2.9 only needs @pytest.fixture +@pytest.yield_fixture +def temp_dir_1024_delete(): + """ Create a temporary directory that has a single file of a + particular size (1024 bytes). The temporary directory (including + the file inside) will be deleted after fixture usage. + """ + + with tempfile.TemporaryDirectory() as tmp_dir: + tmp_file, tmp_file_path = tempfile.mkstemp(dir=tmp_dir) + with open(tmp_file, 'wb') as f: + f.write(b'*' * 1024) + yield tmp_dir + + +@pytest.fixture +def temp_file_1024(): + """ Create a temporary file of a particular size (1024 bytes). """ + + with tempfile.NamedTemporaryFile(delete=False) as tmp_file: + tmp_file.write(b'*' * 1024) + return tmp_file.name + + +# pytest > 2.9 only needs @pytest.fixture +@pytest.yield_fixture +def temp_file_1024_delete(): + """ + Create a temporary file of a particular size (1024 bytes). + The temporary file will be deleted after fixture usage. + """ + + with tempfile.NamedTemporaryFile() as tmp_file: + tmp_file.write(b'*' * 1024) + tmp_file.flush() + yield tmp_file.name + + +# pytest > 2.9 only needs @pytest.fixture +@pytest.yield_fixture(scope='session') +def custom_zw(): + zw = web.share_mode.ZipWriter( + common.Common(), + zip_filename=common.Common.random_string(4, 6), + processed_size_callback=lambda _: 'custom_callback' + ) + yield zw + zw.close() + os.remove(zw.zip_filename) + + +# pytest > 2.9 only needs @pytest.fixture +@pytest.yield_fixture(scope='session') +def default_zw(): + zw = web.share_mode.ZipWriter(common.Common()) + yield zw + zw.close() + tmp_dir = os.path.dirname(zw.zip_filename) + shutil.rmtree(tmp_dir) + + +@pytest.fixture +def locale_en(monkeypatch): + monkeypatch.setattr('locale.getdefaultlocale', lambda: ('en_US', 'UTF-8')) + + +@pytest.fixture +def locale_fr(monkeypatch): + monkeypatch.setattr('locale.getdefaultlocale', lambda: ('fr_FR', 'UTF-8')) + + +@pytest.fixture +def locale_invalid(monkeypatch): + monkeypatch.setattr('locale.getdefaultlocale', lambda: ('xx_XX', 'UTF-8')) + + +@pytest.fixture +def locale_ru(monkeypatch): + monkeypatch.setattr('locale.getdefaultlocale', lambda: ('ru_RU', 'UTF-8')) + + +@pytest.fixture +def platform_darwin(monkeypatch): + monkeypatch.setattr('platform.system', lambda: 'Darwin') + + +@pytest.fixture # (scope="session") +def platform_linux(monkeypatch): + monkeypatch.setattr('platform.system', lambda: 'Linux') + + +@pytest.fixture +def platform_windows(monkeypatch): + monkeypatch.setattr('platform.system', lambda: 'Windows') + + +@pytest.fixture +def sys_argv_sys_prefix(monkeypatch): + monkeypatch.setattr('sys.argv', [sys.prefix]) + + +@pytest.fixture +def sys_frozen(monkeypatch): + monkeypatch.setattr('sys.frozen', True, raising=False) + + +@pytest.fixture +def sys_meipass(monkeypatch): + monkeypatch.setattr( + 'sys._MEIPASS', os.path.expanduser('~'), raising=False) + + +@pytest.fixture # (scope="session") +def sys_onionshare_dev_mode(monkeypatch): + monkeypatch.setattr('sys.onionshare_dev_mode', True, raising=False) + + +@pytest.fixture +def time_time_100(monkeypatch): + monkeypatch.setattr('time.time', lambda: 100) + + +@pytest.fixture +def time_strftime(monkeypatch): + monkeypatch.setattr('time.strftime', lambda _: 'Jun 06 2013 11:05:00') + +@pytest.fixture +def common_obj(): + return common.Common() + +@pytest.fixture +def settings_obj(sys_onionshare_dev_mode, platform_linux): + _common = common.Common() + _common.version = 'DUMMY_VERSION_1.2.3' + return settings.Settings(_common) diff --git a/tests_gui_tor/onionshare_receive_mode_upload_test.py b/tests_gui_tor/onionshare_receive_mode_upload_test.py new file mode 100644 index 00000000..5c2945f1 --- /dev/null +++ b/tests_gui_tor/onionshare_receive_mode_upload_test.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import pytest +import json + +from PyQt5 import QtWidgets + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +from .commontests import CommonTests + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, False, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": False, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, False) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + os.remove('/tmp/OnionShare/test.txt') + os.remove('/tmp/OnionShare/test-2.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + CommonTests.test_windowTitle_seen(self) + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + CommonTests.test_settings_button_is_visible(self) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + CommonTests.test_server_status_bar_is_visible(self) + + @pytest.mark.run(order=5) + def test_info_widget_is_not_visible(self): + CommonTests.test_info_widget_is_not_visible(self, 'receive') + + @pytest.mark.run(order=6) + def test_click_mode(self): + CommonTests.test_click_mode(self, 'receive') + + @pytest.mark.run(order=7) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'receive') + + @pytest.mark.run(order=8) + def test_server_working_on_start_button_pressed(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'receive') + + @pytest.mark.run(order=9) + def test_server_status_indicator_says_starting(self): + CommonTests.test_server_status_indicator_says_starting(self, 'receive') + + @pytest.mark.run(order=10) + def test_settings_button_is_hidden(self): + CommonTests.test_settings_button_is_hidden(self) + + @pytest.mark.run(order=11) + def test_a_server_is_started(self): + CommonTests.test_a_server_is_started(self, 'receive') + + @pytest.mark.run(order=12) + def test_a_web_server_is_running(self): + CommonTests.test_a_web_server_is_running(self) + + @pytest.mark.run(order=14) + def test_have_a_slug(self): + CommonTests.test_have_a_slug(self, 'receive', False) + + @pytest.mark.run(order=15) + def test_have_an_onion(self): + CommonTests.test_have_an_onion_service(self) + + @pytest.mark.run(order=16) + def test_url_description_shown(self): + CommonTests.test_url_description_shown(self, 'receive') + + @pytest.mark.run(order=17) + def test_have_copy_url_button(self): + CommonTests.test_have_copy_url_button(self, 'receive') + + @pytest.mark.run(order=18) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'receive') + + @pytest.mark.run(order=19) + def test_web_page(self): + CommonTests.test_web_page(self, 'receive', 'Select the files you want to send, then click', False) + + @pytest.mark.run(order=20) + def test_upload_file(self): + CommonTests.test_upload_file(self, False, '/tmp/OnionShare/test.txt') + + @pytest.mark.run(order=21) + def test_history_widgets_present(self): + CommonTests.test_history_widgets_present(self, 'receive') + + @pytest.mark.run(order=22) + def test_counter_incremented(self): + CommonTests.test_counter_incremented(self, 'receive', 1) + + @pytest.mark.run(order=23) + def test_upload_same_file_is_renamed(self): + CommonTests.test_upload_file(self, False, '/tmp/OnionShare/test-2.txt') + + @pytest.mark.run(order=24) + def test_upload_count_incremented_again(self): + CommonTests.test_counter_incremented(self, 'receive', 2) + + @pytest.mark.run(order=25) + def test_server_is_stopped(self): + CommonTests.test_server_is_stopped(self, 'receive', False) + + @pytest.mark.run(order=26) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) + + @pytest.mark.run(order=27) + def test_server_status_indicator_says_closed(self): + CommonTests.test_server_status_indicator_says_closed(self, 'receive', False) + +if __name__ == "__main__": + unittest.main() diff --git a/tests_gui_tor/onionshare_receive_mode_upload_test_public_mode.py b/tests_gui_tor/onionshare_receive_mode_upload_test_public_mode.py new file mode 100644 index 00000000..86cde0d9 --- /dev/null +++ b/tests_gui_tor/onionshare_receive_mode_upload_test_public_mode.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import pytest +import json + +from PyQt5 import QtWidgets + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +from .commontests import CommonTests + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, False, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": True, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, False) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + os.remove('/tmp/OnionShare/test.txt') + os.remove('/tmp/OnionShare/test-2.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + CommonTests.test_windowTitle_seen(self) + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + CommonTests.test_settings_button_is_visible(self) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + CommonTests.test_server_status_bar_is_visible(self) + + @pytest.mark.run(order=5) + def test_info_widget_is_not_visible(self): + CommonTests.test_info_widget_is_not_visible(self, 'receive') + + @pytest.mark.run(order=6) + def test_click_mode(self): + CommonTests.test_click_mode(self, 'receive') + + @pytest.mark.run(order=7) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'receive') + + @pytest.mark.run(order=8) + def test_server_working_on_start_button_pressed(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'receive') + + @pytest.mark.run(order=9) + def test_server_status_indicator_says_starting(self): + CommonTests.test_server_status_indicator_says_starting(self, 'receive') + + @pytest.mark.run(order=10) + def test_settings_button_is_hidden(self): + CommonTests.test_settings_button_is_hidden(self) + + @pytest.mark.run(order=11) + def test_a_server_is_started(self): + CommonTests.test_a_server_is_started(self, 'receive') + + @pytest.mark.run(order=12) + def test_a_web_server_is_running(self): + CommonTests.test_a_web_server_is_running(self) + + @pytest.mark.run(order=14) + def test_have_a_slug(self): + CommonTests.test_have_a_slug(self, 'receive', True) + + @pytest.mark.run(order=15) + def test_have_an_onion(self): + CommonTests.test_have_an_onion_service(self) + + @pytest.mark.run(order=16) + def test_url_description_shown(self): + CommonTests.test_url_description_shown(self, 'receive') + + @pytest.mark.run(order=17) + def test_have_copy_url_button(self): + CommonTests.test_have_copy_url_button(self, 'receive') + + @pytest.mark.run(order=18) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'receive') + + @pytest.mark.run(order=19) + def test_web_page(self): + CommonTests.test_web_page(self, 'receive', 'Select the files you want to send, then click', True) + + @pytest.mark.run(order=20) + def test_upload_file(self): + CommonTests.test_upload_file(self, True, '/tmp/OnionShare/test.txt') + + @pytest.mark.run(order=21) + def test_history_widgets_present(self): + CommonTests.test_history_widgets_present(self, 'receive') + + @pytest.mark.run(order=22) + def test_counter_incremented(self): + CommonTests.test_counter_incremented(self, 'receive', 1) + + @pytest.mark.run(order=23) + def test_upload_same_file_is_renamed(self): + CommonTests.test_upload_file(self, True, '/tmp/OnionShare/test-2.txt') + + @pytest.mark.run(order=24) + def test_upload_count_incremented_again(self): + CommonTests.test_counter_incremented(self, 'receive', 2) + + @pytest.mark.run(order=25) + def test_server_is_stopped(self): + CommonTests.test_server_is_stopped(self, 'receive', False) + + @pytest.mark.run(order=26) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) + + @pytest.mark.run(order=27) + def test_server_status_indicator_says_closed(self): + CommonTests.test_server_status_indicator_says_closed(self, 'receive', False) + +if __name__ == "__main__": + unittest.main() diff --git a/tests_gui_tor/onionshare_share_mode_cancel_share_test.py b/tests_gui_tor/onionshare_share_mode_cancel_share_test.py new file mode 100644 index 00000000..a2d1a06a --- /dev/null +++ b/tests_gui_tor/onionshare_share_mode_cancel_share_test.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import pytest +import json + +from PyQt5 import QtWidgets + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +from .commontests import CommonTests + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, False, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": False, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, False) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + CommonTests.test_windowTitle_seen(self) + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + CommonTests.test_settings_button_is_visible(self) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + CommonTests.test_server_status_bar_is_visible(self) + + @pytest.mark.run(order=5) + def test_file_selection_widget_has_a_file(self): + CommonTests.test_file_selection_widget_has_a_file(self) + + @pytest.mark.run(order=6) + def test_info_widget_is_visible(self): + CommonTests.test_info_widget_is_visible(self, 'share') + + @pytest.mark.run(order=7) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') + + @pytest.mark.run(order=8) + def test_deleting_only_file_hides_delete_button(self): + CommonTests.test_deleting_only_file_hides_delete_button(self) + + @pytest.mark.run(order=9) + def test_add_a_file_and_delete_using_its_delete_widget(self): + CommonTests.test_add_a_file_and_delete_using_its_delete_widget(self) + + @pytest.mark.run(order=10) + def test_file_selection_widget_readd_files(self): + CommonTests.test_file_selection_widget_readd_files(self) + + @pytest.mark.run(order=11) + def test_server_working_on_start_button_pressed(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'share') + + @pytest.mark.run(order=12) + def test_server_status_indicator_says_starting(self): + CommonTests.test_server_status_indicator_says_starting(self, 'share') + + @pytest.mark.run(order=13) + def test_add_delete_buttons_hidden(self): + CommonTests.test_add_delete_buttons_hidden(self) + + @pytest.mark.run(order=14) + def test_settings_button_is_hidden(self): + CommonTests.test_settings_button_is_hidden(self) + + @pytest.mark.run(order=16) + def test_a_web_server_is_running(self): + CommonTests.test_a_web_server_is_running(self) + + @pytest.mark.run(order=17) + def test_cancel_the_share(self): + CommonTests.test_cancel_the_share(self, 'share') + + @pytest.mark.run(order=18) + def test_server_is_stopped(self): + CommonTests.test_server_is_stopped(self, 'share', False) + + @pytest.mark.run(order=19) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) + + @pytest.mark.run(order=20) + def test_add_button_visible(self): + CommonTests.test_add_button_visible(self) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests_gui_tor/onionshare_share_mode_download_test.py b/tests_gui_tor/onionshare_share_mode_download_test.py new file mode 100644 index 00000000..d1eb5b54 --- /dev/null +++ b/tests_gui_tor/onionshare_share_mode_download_test.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import pytest +import json + +from PyQt5 import QtWidgets + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +from .commontests import CommonTests + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, False, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": False, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, False) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + CommonTests.test_windowTitle_seen(self) + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + CommonTests.test_settings_button_is_visible(self) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + CommonTests.test_server_status_bar_is_visible(self) + + @pytest.mark.run(order=5) + def test_file_selection_widget_has_a_file(self): + CommonTests.test_file_selection_widget_has_a_file(self) + + @pytest.mark.run(order=6) + def test_info_widget_is_visible(self): + CommonTests.test_info_widget_is_visible(self, 'share') + + @pytest.mark.run(order=7) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') + + @pytest.mark.run(order=8) + def test_deleting_only_file_hides_delete_button(self): + CommonTests.test_deleting_only_file_hides_delete_button(self) + + @pytest.mark.run(order=9) + def test_add_a_file_and_delete_using_its_delete_widget(self): + CommonTests.test_add_a_file_and_delete_using_its_delete_widget(self) + + @pytest.mark.run(order=10) + def test_file_selection_widget_readd_files(self): + CommonTests.test_file_selection_widget_readd_files(self) + + @pytest.mark.run(order=11) + def test_server_working_on_start_button_pressed(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'share') + + @pytest.mark.run(order=12) + def test_server_status_indicator_says_starting(self): + CommonTests.test_server_status_indicator_says_starting(self, 'share') + + @pytest.mark.run(order=13) + def test_add_delete_buttons_hidden(self): + CommonTests.test_add_delete_buttons_hidden(self) + + @pytest.mark.run(order=14) + def test_settings_button_is_hidden(self): + CommonTests.test_settings_button_is_hidden(self) + + @pytest.mark.run(order=15) + def test_a_server_is_started(self): + CommonTests.test_a_server_is_started(self, 'share') + + @pytest.mark.run(order=16) + def test_a_web_server_is_running(self): + CommonTests.test_a_web_server_is_running(self) + + @pytest.mark.run(order=17) + def test_have_a_slug(self): + CommonTests.test_have_a_slug(self, 'share', False) + + @pytest.mark.run(order=18) + def test_have_an_onion(self): + CommonTests.test_have_an_onion_service(self) + + @pytest.mark.run(order=19) + def test_url_description_shown(self): + CommonTests.test_url_description_shown(self, 'share') + + @pytest.mark.run(order=20) + def test_have_copy_url_button(self): + CommonTests.test_have_copy_url_button(self, 'share') + + @pytest.mark.run(order=21) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'share') + + @pytest.mark.run(order=22) + def test_web_page(self): + CommonTests.test_web_page(self, 'share', 'Total size', False) + + @pytest.mark.run(order=23) + def test_download_share(self): + CommonTests.test_download_share(self, False) + + @pytest.mark.run(order=24) + def test_history_widgets_present(self): + CommonTests.test_history_widgets_present(self, 'share') + + @pytest.mark.run(order=25) + def test_server_is_stopped(self): + CommonTests.test_server_is_stopped(self, 'share', False) + + @pytest.mark.run(order=26) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) + + @pytest.mark.run(order=27) + def test_server_status_indicator_says_closed(self): + CommonTests.test_server_status_indicator_says_closed(self, 'share', False) + + @pytest.mark.run(order=28) + def test_add_button_visible(self): + CommonTests.test_add_button_visible(self) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests_gui_tor/onionshare_share_mode_download_test_public_mode.py b/tests_gui_tor/onionshare_share_mode_download_test_public_mode.py new file mode 100644 index 00000000..4e5f1114 --- /dev/null +++ b/tests_gui_tor/onionshare_share_mode_download_test_public_mode.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import pytest +import json + +from PyQt5 import QtWidgets + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +from .commontests import CommonTests + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, False, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": True, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, False) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + CommonTests.test_windowTitle_seen(self) + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + CommonTests.test_settings_button_is_visible(self) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + CommonTests.test_server_status_bar_is_visible(self) + + @pytest.mark.run(order=5) + def test_file_selection_widget_has_a_file(self): + CommonTests.test_file_selection_widget_has_a_file(self) + + @pytest.mark.run(order=6) + def test_info_widget_is_visible(self): + CommonTests.test_info_widget_is_visible(self, 'share') + + @pytest.mark.run(order=7) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') + + @pytest.mark.run(order=8) + def test_deleting_only_file_hides_delete_button(self): + CommonTests.test_deleting_only_file_hides_delete_button(self) + + @pytest.mark.run(order=9) + def test_add_a_file_and_delete_using_its_delete_widget(self): + CommonTests.test_add_a_file_and_delete_using_its_delete_widget(self) + + @pytest.mark.run(order=10) + def test_file_selection_widget_readd_files(self): + CommonTests.test_file_selection_widget_readd_files(self) + + @pytest.mark.run(order=11) + def test_server_working_on_start_button_pressed(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'share') + + @pytest.mark.run(order=12) + def test_server_status_indicator_says_starting(self): + CommonTests.test_server_status_indicator_says_starting(self, 'share') + + @pytest.mark.run(order=13) + def test_add_delete_buttons_hidden(self): + CommonTests.test_add_delete_buttons_hidden(self) + + @pytest.mark.run(order=14) + def test_settings_button_is_hidden(self): + CommonTests.test_settings_button_is_hidden(self) + + @pytest.mark.run(order=15) + def test_a_server_is_started(self): + CommonTests.test_a_server_is_started(self, 'share') + + @pytest.mark.run(order=16) + def test_a_web_server_is_running(self): + CommonTests.test_a_web_server_is_running(self) + + @pytest.mark.run(order=17) + def test_have_a_slug(self): + CommonTests.test_have_a_slug(self, 'share', True) + + @pytest.mark.run(order=18) + def test_have_an_onion(self): + CommonTests.test_have_an_onion_service(self) + + @pytest.mark.run(order=19) + def test_url_description_shown(self): + CommonTests.test_url_description_shown(self, 'share') + + @pytest.mark.run(order=20) + def test_have_copy_url_button(self): + CommonTests.test_have_copy_url_button(self, 'share') + + @pytest.mark.run(order=21) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'share') + + @pytest.mark.run(order=22) + def test_web_page(self): + CommonTests.test_web_page(self, 'share', 'Total size', True) + + @pytest.mark.run(order=23) + def test_download_share(self): + CommonTests.test_download_share(self, True) + + @pytest.mark.run(order=24) + def test_history_widgets_present(self): + CommonTests.test_history_widgets_present(self, 'share') + + @pytest.mark.run(order=25) + def test_server_is_stopped(self): + CommonTests.test_server_is_stopped(self, 'share', False) + + @pytest.mark.run(order=26) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) + + @pytest.mark.run(order=27) + def test_server_status_indicator_says_closed(self): + CommonTests.test_server_status_indicator_says_closed(self, 'share', False) + + @pytest.mark.run(order=28) + def test_add_button_visible(self): + CommonTests.test_add_button_visible(self) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests_gui_tor/onionshare_share_mode_download_test_stay_open.py b/tests_gui_tor/onionshare_share_mode_download_test_stay_open.py new file mode 100644 index 00000000..78cd1578 --- /dev/null +++ b/tests_gui_tor/onionshare_share_mode_download_test_stay_open.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import pytest +import json + +from PyQt5 import QtWidgets + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +from .commontests import CommonTests + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, False, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": False, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": True, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, False) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + CommonTests.test_windowTitle_seen(self) + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + CommonTests.test_settings_button_is_visible(self) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + CommonTests.test_server_status_bar_is_visible(self) + + @pytest.mark.run(order=5) + def test_file_selection_widget_has_a_file(self): + CommonTests.test_file_selection_widget_has_a_file(self) + + @pytest.mark.run(order=6) + def test_info_widget_is_visible(self): + CommonTests.test_info_widget_is_visible(self, 'share') + + @pytest.mark.run(order=7) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') + + @pytest.mark.run(order=8) + def test_deleting_only_file_hides_delete_button(self): + CommonTests.test_deleting_only_file_hides_delete_button(self) + + @pytest.mark.run(order=9) + def test_add_a_file_and_delete_using_its_delete_widget(self): + CommonTests.test_add_a_file_and_delete_using_its_delete_widget(self) + + @pytest.mark.run(order=10) + def test_file_selection_widget_readd_files(self): + CommonTests.test_file_selection_widget_readd_files(self) + + @pytest.mark.run(order=11) + def test_server_working_on_start_button_pressed(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'share') + + @pytest.mark.run(order=12) + def test_server_status_indicator_says_starting(self): + CommonTests.test_server_status_indicator_says_starting(self, 'share') + + @pytest.mark.run(order=13) + def test_add_delete_buttons_hidden(self): + CommonTests.test_add_delete_buttons_hidden(self) + + @pytest.mark.run(order=14) + def test_settings_button_is_hidden(self): + CommonTests.test_settings_button_is_hidden(self) + + @pytest.mark.run(order=15) + def test_a_server_is_started(self): + CommonTests.test_a_server_is_started(self, 'share') + + @pytest.mark.run(order=16) + def test_a_web_server_is_running(self): + CommonTests.test_a_web_server_is_running(self) + + @pytest.mark.run(order=17) + def test_have_a_slug(self): + CommonTests.test_have_a_slug(self, 'share', True) + + @pytest.mark.run(order=18) + def test_have_an_onion(self): + CommonTests.test_have_an_onion_service(self) + + @pytest.mark.run(order=19) + def test_url_description_shown(self): + CommonTests.test_url_description_shown(self, 'share') + + @pytest.mark.run(order=20) + def test_have_copy_url_button(self): + CommonTests.test_have_copy_url_button(self, 'share') + + @pytest.mark.run(order=21) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'share') + + @pytest.mark.run(order=22) + def test_web_page(self): + CommonTests.test_web_page(self, 'share', 'Total size', True) + + @pytest.mark.run(order=23) + def test_download_share(self): + CommonTests.test_download_share(self, True) + + @pytest.mark.run(order=24) + def test_history_widgets_present(self): + CommonTests.test_history_widgets_present(self, 'share') + + @pytest.mark.run(order=25) + def test_counter_incremented(self): + CommonTests.test_counter_incremented(self, 'share', 1) + + @pytest.mark.run(order=26) + def test_download_share_again(self): + CommonTests.test_download_share(self, True) + + @pytest.mark.run(order=27) + def test_counter_incremented_again(self): + CommonTests.test_counter_incremented(self, 'share', 2) + + @pytest.mark.run(order=28) + def test_server_is_stopped(self): + CommonTests.test_server_is_stopped(self, 'share', True) + + @pytest.mark.run(order=29) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) + + @pytest.mark.run(order=30) + def test_server_status_indicator_says_closed(self): + CommonTests.test_server_status_indicator_says_closed(self, 'share', True) + + @pytest.mark.run(order=31) + def test_add_button_visible(self): + CommonTests.test_add_button_visible(self) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests_gui_tor/onionshare_share_mode_persistent_test.py b/tests_gui_tor/onionshare_share_mode_persistent_test.py new file mode 100644 index 00000000..a2d429b2 --- /dev/null +++ b/tests_gui_tor/onionshare_share_mode_persistent_test.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import pytest +import json + +from PyQt5 import QtWidgets + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +from .commontests import CommonTests + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + slug = '' + onion_host = '' + + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, False, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": False, + "receive_allow_receiver_shutdown": True, + "save_private_key": True, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, False) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + CommonTests.test_windowTitle_seen(self) + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + CommonTests.test_settings_button_is_visible(self) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + CommonTests.test_server_status_bar_is_visible(self) + + @pytest.mark.run(order=5) + def test_info_widget_is_visible(self): + CommonTests.test_info_widget_is_visible(self, 'share') + + @pytest.mark.run(order=6) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') + + @pytest.mark.run(order=7) + def test_server_working_on_start_button_pressed(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'share') + + @pytest.mark.run(order=8) + def test_server_status_indicator_says_starting(self): + CommonTests.test_server_status_indicator_says_starting(self, 'share') + + @pytest.mark.run(order=9) + def test_settings_button_is_hidden(self): + CommonTests.test_settings_button_is_hidden(self) + + @pytest.mark.run(order=10) + def test_a_server_is_started(self): + CommonTests.test_a_server_is_started(self, 'share') + + @pytest.mark.run(order=11) + def test_a_web_server_is_running(self): + CommonTests.test_a_web_server_is_running(self) + + @pytest.mark.run(order=12) + def test_have_a_slug(self): + CommonTests.test_have_a_slug(self, 'share', False) + global slug + slug = self.gui.share_mode.server_status.web.slug + + @pytest.mark.run(order=13) + def test_have_an_onion(self): + CommonTests.test_have_an_onion_service(self) + global onion_host + onion_host = self.gui.app.onion_host + + @pytest.mark.run(order=14) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'share') + + @pytest.mark.run(order=15) + def test_server_is_stopped(self): + CommonTests.test_server_is_stopped(self, 'share', True) + + @pytest.mark.run(order=16) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) + + @pytest.mark.run(order=17) + def test_server_status_indicator_says_closed(self): + CommonTests.test_server_status_indicator_says_closed(self, 'share', True) + + @pytest.mark.run(order=18) + def test_server_started_again(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'share') + CommonTests.test_server_status_indicator_says_starting(self, 'share') + CommonTests.test_a_server_is_started(self, 'share') + + @pytest.mark.run(order=19) + def test_have_same_slug(self): + '''Test that we have the same slug''' + self.assertEqual(self.gui.share_mode.server_status.web.slug, slug) + + @pytest.mark.run(order=20) + def test_have_same_onion(self): + '''Test that we have the same onion''' + self.assertEqual(self.gui.app.onion_host, onion_host) + + @pytest.mark.run(order=21) + def test_server_is_stopped_again(self): + CommonTests.test_server_is_stopped(self, 'share', True) + CommonTests.test_web_service_is_stopped(self) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests_gui_tor/onionshare_share_mode_stealth_test.py b/tests_gui_tor/onionshare_share_mode_stealth_test.py new file mode 100644 index 00000000..948e834a --- /dev/null +++ b/tests_gui_tor/onionshare_share_mode_stealth_test.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import pytest +import json + +from PyQt5 import QtWidgets + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +from .commontests import CommonTests + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, False, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": False, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": True, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, False) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + CommonTests.test_windowTitle_seen(self) + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + CommonTests.test_settings_button_is_visible(self) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + CommonTests.test_server_status_bar_is_visible(self) + + @pytest.mark.run(order=5) + def test_file_selection_widget_has_a_file(self): + CommonTests.test_file_selection_widget_has_a_file(self) + + @pytest.mark.run(order=6) + def test_info_widget_is_visible(self): + CommonTests.test_info_widget_is_visible(self, 'share') + + @pytest.mark.run(order=7) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') + + @pytest.mark.run(order=8) + def test_deleting_only_file_hides_delete_button(self): + CommonTests.test_deleting_only_file_hides_delete_button(self) + + @pytest.mark.run(order=9) + def test_add_a_file_and_delete_using_its_delete_widget(self): + CommonTests.test_add_a_file_and_delete_using_its_delete_widget(self) + + @pytest.mark.run(order=10) + def test_file_selection_widget_readd_files(self): + CommonTests.test_file_selection_widget_readd_files(self) + + @pytest.mark.run(order=11) + def test_server_working_on_start_button_pressed(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'share') + + @pytest.mark.run(order=12) + def test_server_status_indicator_says_starting(self): + CommonTests.test_server_status_indicator_says_starting(self, 'share') + + @pytest.mark.run(order=13) + def test_add_delete_buttons_hidden(self): + CommonTests.test_add_delete_buttons_hidden(self) + + @pytest.mark.run(order=14) + def test_settings_button_is_hidden(self): + CommonTests.test_settings_button_is_hidden(self) + + @pytest.mark.run(order=15) + def test_a_server_is_started(self): + CommonTests.test_a_server_is_started(self, 'share') + + @pytest.mark.run(order=16) + def test_a_web_server_is_running(self): + CommonTests.test_a_web_server_is_running(self) + + @pytest.mark.run(order=17) + def test_have_a_slug(self): + CommonTests.test_have_a_slug(self, 'share', False) + + @pytest.mark.run(order=18) + def test_have_an_onion(self): + CommonTests.test_have_an_onion_service(self) + + @pytest.mark.run(order=19) + def test_url_description_shown(self): + CommonTests.test_url_description_shown(self, 'share') + + @pytest.mark.run(order=20) + def test_have_copy_url_button(self): + CommonTests.test_have_copy_url_button(self, 'share') + + @pytest.mark.run(order=21) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'share') + + @pytest.mark.run(order=22) + def test_copy_have_hidserv_auth_button(self): + CommonTests.test_copy_have_hidserv_auth_button(self, 'share') + + @pytest.mark.run(order=23) + def test_hidserv_auth_string(self): + CommonTests.test_hidserv_auth_string(self) + +if __name__ == "__main__": + unittest.main() diff --git a/tests_gui_tor/onionshare_share_mode_tor_connection_killed_test.py b/tests_gui_tor/onionshare_share_mode_tor_connection_killed_test.py new file mode 100644 index 00000000..3eeea9bc --- /dev/null +++ b/tests_gui_tor/onionshare_share_mode_tor_connection_killed_test.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import pytest +import json + +from PyQt5 import QtWidgets + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +from .commontests import CommonTests + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, False, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": False, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, False) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + CommonTests.test_windowTitle_seen(self) + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + CommonTests.test_settings_button_is_visible(self) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + CommonTests.test_server_status_bar_is_visible(self) + + @pytest.mark.run(order=5) + def test_file_selection_widget_has_a_file(self): + CommonTests.test_file_selection_widget_has_a_file(self) + + @pytest.mark.run(order=6) + def test_info_widget_is_visible(self): + CommonTests.test_info_widget_is_visible(self, 'share') + + @pytest.mark.run(order=7) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') + + @pytest.mark.run(order=8) + def test_deleting_only_file_hides_delete_button(self): + CommonTests.test_deleting_only_file_hides_delete_button(self) + + @pytest.mark.run(order=9) + def test_add_a_file_and_delete_using_its_delete_widget(self): + CommonTests.test_add_a_file_and_delete_using_its_delete_widget(self) + + @pytest.mark.run(order=10) + def test_file_selection_widget_readd_files(self): + CommonTests.test_file_selection_widget_readd_files(self) + + @pytest.mark.run(order=11) + def test_server_working_on_start_button_pressed(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'share') + + @pytest.mark.run(order=12) + def test_server_status_indicator_says_starting(self): + CommonTests.test_server_status_indicator_says_starting(self, 'share') + + @pytest.mark.run(order=13) + def test_add_delete_buttons_hidden(self): + CommonTests.test_add_delete_buttons_hidden(self) + + @pytest.mark.run(order=14) + def test_settings_button_is_hidden(self): + CommonTests.test_settings_button_is_hidden(self) + + @pytest.mark.run(order=15) + def test_a_server_is_started(self): + CommonTests.test_a_server_is_started(self, 'share') + + @pytest.mark.run(order=16) + def test_a_web_server_is_running(self): + CommonTests.test_a_web_server_is_running(self) + + @pytest.mark.run(order=17) + def test_have_a_slug(self): + CommonTests.test_have_a_slug(self, 'share', False) + + @pytest.mark.run(order=18) + def test_have_an_onion(self): + CommonTests.test_have_an_onion_service(self) + + @pytest.mark.run(order=19) + def test_url_description_shown(self): + CommonTests.test_url_description_shown(self, 'share') + + @pytest.mark.run(order=20) + def test_have_copy_url_button(self): + CommonTests.test_have_copy_url_button(self, 'share') + + @pytest.mark.run(order=21) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'share') + + @pytest.mark.run(order=22) + def test_tor_killed_statusbar_message_shown(self): + CommonTests.test_tor_killed_statusbar_message_shown(self, 'share') + + @pytest.mark.run(order=23) + def test_server_is_stopped(self): + CommonTests.test_server_is_stopped(self, 'share', False) + + @pytest.mark.run(order=24) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests_gui_tor/onionshare_timer_test.py b/tests_gui_tor/onionshare_timer_test.py new file mode 100644 index 00000000..865b3a8b --- /dev/null +++ b/tests_gui_tor/onionshare_timer_test.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import pytest +import json + +from PyQt5 import QtWidgets + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +from .commontests import CommonTests + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, False, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": False, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": True, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, False) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + CommonTests.test_windowTitle_seen(self) + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + CommonTests.test_settings_button_is_visible(self) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + CommonTests.test_server_status_bar_is_visible(self) + + @pytest.mark.run(order=5) + def test_file_selection_widget_has_a_file(self): + CommonTests.test_file_selection_widget_has_a_file(self) + + @pytest.mark.run(order=6) + def test_info_widget_is_visible(self): + CommonTests.test_info_widget_is_visible(self, 'share') + + @pytest.mark.run(order=7) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') + + @pytest.mark.run(order=8) + def test_set_timeout(self): + CommonTests.test_set_timeout(self, 'share', 120) + + @pytest.mark.run(order=9) + def test_server_working_on_start_button_pressed(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'share') + + @pytest.mark.run(order=10) + def test_server_status_indicator_says_starting(self): + CommonTests.test_server_status_indicator_says_starting(self, 'share') + + @pytest.mark.run(order=11) + def test_a_server_is_started(self): + CommonTests.test_a_server_is_started(self, 'share') + + @pytest.mark.run(order=12) + def test_a_web_server_is_running(self): + CommonTests.test_a_web_server_is_running(self) + + @pytest.mark.run(order=13) + def test_timeout_widget_hidden(self): + CommonTests.test_timeout_widget_hidden(self, 'share') + + @pytest.mark.run(order=14) + def test_timeout(self): + CommonTests.test_server_timed_out(self, 'share', 125000) + + @pytest.mark.run(order=15) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) + +if __name__ == "__main__": + unittest.main() diff --git a/tests_gui_tor/onionshare_tor_connection_killed_test.py b/tests_gui_tor/onionshare_tor_connection_killed_test.py new file mode 100644 index 00000000..3eeea9bc --- /dev/null +++ b/tests_gui_tor/onionshare_tor_connection_killed_test.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 +import os +import sys +import unittest +import pytest +import json + +from PyQt5 import QtWidgets + +from onionshare.common import Common +from onionshare.web import Web +from onionshare import onion, strings +from onionshare_gui import * + +from .commontests import CommonTests + +app = QtWidgets.QApplication(sys.argv) + +class OnionShareGuiTest(unittest.TestCase): + '''Test the OnionShare GUI''' + @classmethod + def setUpClass(cls): + '''Create the GUI''' + # Create our test file + testfile = open('/tmp/test.txt', 'w') + testfile.write('onionshare') + testfile.close() + common = Common() + common.define_css() + + # Start the Onion + strings.load_strings(common) + + testonion = onion.Onion(common) + global qtapp + qtapp = Application(common) + app = OnionShare(common, testonion, False, 0) + + web = Web(common, False, True) + + test_settings = { + "auth_password": "", + "auth_type": "no_auth", + "autoupdate_timestamp": "", + "close_after_first_download": True, + "connection_type": "bundled", + "control_port_address": "127.0.0.1", + "control_port_port": 9051, + "downloads_dir": "/tmp/OnionShare", + "hidservauth_string": "", + "no_bridges": True, + "private_key": "", + "public_mode": False, + "receive_allow_receiver_shutdown": True, + "save_private_key": False, + "shutdown_timeout": False, + "slug": "", + "socks_address": "127.0.0.1", + "socks_port": 9050, + "socket_file_path": "/var/run/tor/control", + "systray_notifications": True, + "tor_bridges_use_meek_lite_azure": False, + "tor_bridges_use_meek_lite_amazon": False, + "tor_bridges_use_custom_bridges": "", + "tor_bridges_use_obfs4": False, + "use_stealth": False, + "use_legacy_v2_onions": False, + "use_autoupdate": True, + "version": "1.3.1" + } + testsettings = '/tmp/testsettings.json' + open(testsettings, 'w').write(json.dumps(test_settings)) + + cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, False) + + @classmethod + def tearDownClass(cls): + '''Clean up after tests''' + os.remove('/tmp/test.txt') + + @pytest.mark.run(order=1) + def test_gui_loaded(self): + CommonTests.test_gui_loaded(self) + + @pytest.mark.run(order=2) + def test_windowTitle_seen(self): + CommonTests.test_windowTitle_seen(self) + + @pytest.mark.run(order=3) + def test_settings_button_is_visible(self): + CommonTests.test_settings_button_is_visible(self) + + @pytest.mark.run(order=4) + def test_server_status_bar_is_visible(self): + CommonTests.test_server_status_bar_is_visible(self) + + @pytest.mark.run(order=5) + def test_file_selection_widget_has_a_file(self): + CommonTests.test_file_selection_widget_has_a_file(self) + + @pytest.mark.run(order=6) + def test_info_widget_is_visible(self): + CommonTests.test_info_widget_is_visible(self, 'share') + + @pytest.mark.run(order=7) + def test_history_is_visible(self): + CommonTests.test_history_is_visible(self, 'share') + + @pytest.mark.run(order=8) + def test_deleting_only_file_hides_delete_button(self): + CommonTests.test_deleting_only_file_hides_delete_button(self) + + @pytest.mark.run(order=9) + def test_add_a_file_and_delete_using_its_delete_widget(self): + CommonTests.test_add_a_file_and_delete_using_its_delete_widget(self) + + @pytest.mark.run(order=10) + def test_file_selection_widget_readd_files(self): + CommonTests.test_file_selection_widget_readd_files(self) + + @pytest.mark.run(order=11) + def test_server_working_on_start_button_pressed(self): + CommonTests.test_server_working_on_start_button_pressed(self, 'share') + + @pytest.mark.run(order=12) + def test_server_status_indicator_says_starting(self): + CommonTests.test_server_status_indicator_says_starting(self, 'share') + + @pytest.mark.run(order=13) + def test_add_delete_buttons_hidden(self): + CommonTests.test_add_delete_buttons_hidden(self) + + @pytest.mark.run(order=14) + def test_settings_button_is_hidden(self): + CommonTests.test_settings_button_is_hidden(self) + + @pytest.mark.run(order=15) + def test_a_server_is_started(self): + CommonTests.test_a_server_is_started(self, 'share') + + @pytest.mark.run(order=16) + def test_a_web_server_is_running(self): + CommonTests.test_a_web_server_is_running(self) + + @pytest.mark.run(order=17) + def test_have_a_slug(self): + CommonTests.test_have_a_slug(self, 'share', False) + + @pytest.mark.run(order=18) + def test_have_an_onion(self): + CommonTests.test_have_an_onion_service(self) + + @pytest.mark.run(order=19) + def test_url_description_shown(self): + CommonTests.test_url_description_shown(self, 'share') + + @pytest.mark.run(order=20) + def test_have_copy_url_button(self): + CommonTests.test_have_copy_url_button(self, 'share') + + @pytest.mark.run(order=21) + def test_server_status_indicator_says_started(self): + CommonTests.test_server_status_indicator_says_started(self, 'share') + + @pytest.mark.run(order=22) + def test_tor_killed_statusbar_message_shown(self): + CommonTests.test_tor_killed_statusbar_message_shown(self, 'share') + + @pytest.mark.run(order=23) + def test_server_is_stopped(self): + CommonTests.test_server_is_stopped(self, 'share', False) + + @pytest.mark.run(order=24) + def test_web_service_is_stopped(self): + CommonTests.test_web_service_is_stopped(self) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests_gui_tor/run_unit_tests.sh b/tests_gui_tor/run_unit_tests.sh new file mode 100755 index 00000000..d15f8a6e --- /dev/null +++ b/tests_gui_tor/run_unit_tests.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +for test in `ls -1 | egrep ^onionshare_`; do + py.test-3 $test -vvv || exit 1 +done