From d4414bd1504b12d80552d889f36b9bdbb3050128 Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Fri, 31 May 2019 22:06:54 -0400 Subject: [PATCH 1/9] Reworking tests Reworking tests with pytest --- .gitignore | 1 + Pipfile | 4 +- Pipfile.lock | 185 ++++++++++- bumper/confserver.py | 7 +- tests/test_bumper.py | 126 ++++---- tests/test_confserver.py | 664 ++++++++++++++++++--------------------- tests/tests.md | 8 +- 7 files changed, 556 insertions(+), 439 deletions(-) diff --git a/.gitignore b/.gitignore index ebef324..e470b09 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ __pycache__ .vscode/ .coverage .noseids +.pytest_cache nosetests.xml tests/report tests/tmp.db diff --git a/Pipfile b/Pipfile index b7df90c..aafbc10 100644 --- a/Pipfile +++ b/Pipfile @@ -11,11 +11,13 @@ pyyaml = ">=4.2b1" [dev-packages] black = "*" -nose = "*" coverage = "*" mock = "*" pylint = "*" pbr = "*" +pytest-asyncio = "*" +pytest-aiohttp = "*" +pytest-cov = "*" [pipenv] allow_prereleases = true diff --git a/Pipfile.lock b/Pipfile.lock index 1f64b3a..b7c6c8b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "6e5b4ccc879dfdf82f53f7966eac54af90f9b9a2ffd1da6f1ce126d0ca125fc9" + "sha256": "89b1dc5fde60f217d24d1b66c94fa5640ca23925420992a2c14718f61866dc61" }, "pipfile-spec": 6, "requires": {}, @@ -208,6 +208,34 @@ } }, "develop": { + "aiohttp": { + "hashes": [ + "sha256:02396865118790ebb0bd14d6935e9e4fa80d87683240618894e585048a8b83ec", + "sha256:0f448b5d5cd45e642b9fcf4798e48cca4149ae479022f59bd67a47caed44657e", + "sha256:1af72f53ccead6d161296e576aa2b5d0c6c7403a389601dd7aa7a7a30a9f41c3", + "sha256:32eeef64a5bcf6dc652f19e020b16f36ec66d291957f62ffad18ecfc58695966", + "sha256:36c4e234a85a81e325d8b1d7fdeb696a3d51bb8eb09a8c8e69c7532b421e8a29", + "sha256:371a5f1bb604fc262ba32893931f5aad3bb3e797dbebcf2b5b2c36f97603e4c7", + "sha256:3f5a30f67e4152d4075063ae9f2286313af2e39b950869edba76232569e08793", + "sha256:48c65d65d0de79f1a4391bc29c8c8ec7655671a03ad7902d5e66fd735531893e", + "sha256:4ede22808195126d55879f1a14aaa3d1004f188c341f92ec3b9ca5ea13e695b9", + "sha256:53228028648b40f59fc941c0cd67b7899bce52f35eb66aeb9e33b75bac0aac0a", + "sha256:67cb8e71c043686f806cfdb4189774c57ef929d32890024c3775d72b54381797", + "sha256:6b1e99dc838c28f14e45bffef6fb77bf5b54bd2bfb1a475c776da5ba8a9fec2d", + "sha256:6c30eca95e7d60fbf13e6ebcaf62b7c0f3f93ec5de8862919aa5ede3720b1c86", + "sha256:6f2c905ab82aa0ee8a06210d5a6c1359c79f3f2088cc1b53c8758cae1dbc0d55", + "sha256:746b73eff86a1618025093b9c86ff4d642cff71a7ac7244f7fd8a186967cee22", + "sha256:9ebf518c7bc08e65b5396f80e8155c7bb1380b921b84b510570e62196c9fca56", + "sha256:9efc80ced0936f3fb2774e1bc981006324c74d1e58fc7f7164ecd98ede727c7d", + "sha256:abc43651f2c6d70b812cb874fc8caa00eb69fac11930cd2640d32a11ee7beef0", + "sha256:b4c6e1f5a591511537d4ccd4c807f6c8bb8d1b8a5043395950ba339086380904", + "sha256:bee80820a8ef5f6bddd58d762fc9f981ef1041a464d382d7d9a992bb94cd23c6", + "sha256:f0c304dcc1494dbc3fc492ebc2e61d0db323be9756a1bb14f407097d8adf82ec", + "sha256:fb9c2f27d2db6d709a02421733bb6ad22e16104beb2cf403e1120c24f3cc8668" + ], + "index": "pypi", + "version": "==4.0.0a0" + }, "appdirs": { "hashes": [ "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", @@ -222,6 +250,20 @@ ], "version": "==2.2.5" }, + "async-timeout": { + "hashes": [ + "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", + "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3" + ], + "version": "==3.0.1" + }, + "atomicwrites": { + "hashes": [ + "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", + "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6" + ], + "version": "==1.3.0" + }, "attrs": { "hashes": [ "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", @@ -237,6 +279,13 @@ "index": "pypi", "version": "==19.3b0" }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, "click": { "hashes": [ "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", @@ -277,6 +326,20 @@ "index": "pypi", "version": "==5.0a5" }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "importlib-metadata": { + "hashes": [ + "sha256:a9f185022cfa69e9ca5f7eabfd5a58b689894cb78a11e3c8c89398a8ccbb8e7f", + "sha256:df1403cd3aebeb2b1dcd3515ca062eecb5bd3ea7611f18cba81130c68707e879" + ], + "version": "==0.17" + }, "isort": { "hashes": [ "sha256:c40744b6bc5162bbb39c1257fe298b7a393861d50978b565f3ccd9cb9de0182a", @@ -322,14 +385,47 @@ "index": "pypi", "version": "==3.0.5" }, - "nose": { + "more-itertools": { "hashes": [ - "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac", - "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a", - "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98" + "sha256:2112d2ca570bb7c3e53ea1a35cd5df42bb0fd10c45f0fb97178679c3c03d64c7", + "sha256:c3e4748ba1aad8dba30a4886b0b1a2004f9a863837b8654e7059eebf727afa5a" ], - "index": "pypi", - "version": "==1.3.7" + "markers": "python_version > '2.7'", + "version": "==7.0.0" + }, + "multidict": { + "hashes": [ + "sha256:024b8129695a952ebd93373e45b5d341dbb87c17ce49637b34000093f243dd4f", + "sha256:041e9442b11409be5e4fc8b6a97e4bcead758ab1e11768d1e69160bdde18acc3", + "sha256:045b4dd0e5f6121e6f314d81759abd2c257db4634260abcfe0d3f7083c4908ef", + "sha256:047c0a04e382ef8bd74b0de01407e8d8632d7d1b4db6f2561106af812a68741b", + "sha256:068167c2d7bbeebd359665ac4fff756be5ffac9cda02375b5c5a7c4777038e73", + "sha256:148ff60e0fffa2f5fad2eb25aae7bef23d8f3b8bdaf947a65cdbe84a978092bc", + "sha256:1d1c77013a259971a72ddaa83b9f42c80a93ff12df6a4723be99d858fa30bee3", + "sha256:1d48bc124a6b7a55006d97917f695effa9725d05abe8ee78fd60d6588b8344cd", + "sha256:31dfa2fc323097f8ad7acd41aa38d7c614dd1960ac6681745b6da124093dc351", + "sha256:34f82db7f80c49f38b032c5abb605c458bac997a6c3142e0d6c130be6fb2b941", + "sha256:3d5dd8e5998fb4ace04789d1d008e2bb532de501218519d70bb672c4c5a2fc5d", + "sha256:4a6ae52bd3ee41ee0f3acf4c60ceb3f44e0e3bc52ab7da1c2b2aa6703363a3d1", + "sha256:4b02a3b2a2f01d0490dd39321c74273fed0568568ea0e7ea23e02bd1fb10a10b", + "sha256:4b843f8e1dd6a3195679d9838eb4670222e8b8d01bc36c9894d6c3538316fa0a", + "sha256:5de53a28f40ef3c4fd57aeab6b590c2c663de87a5af76136ced519923d3efbb3", + "sha256:61b2b33ede821b94fa99ce0b09c9ece049c7067a33b279f343adfe35108a4ea7", + "sha256:6a3a9b0f45fd75dc05d8e93dc21b18fc1670135ec9544d1ad4acbcf6b86781d0", + "sha256:76ad8e4c69dadbb31bad17c16baee61c0d1a4a73bed2590b741b2e1a46d3edd0", + "sha256:7ba19b777dc00194d1b473180d4ca89a054dd18de27d0ee2e42a103ec9b7d014", + "sha256:7c1b7eab7a49aa96f3db1f716f0113a8a2e93c7375dd3d5d21c4941f1405c9c5", + "sha256:7fc0eee3046041387cbace9314926aa48b681202f8897f8bff3809967a049036", + "sha256:8ccd1c5fff1aa1427100ce188557fc31f1e0a383ad8ec42c559aabd4ff08802d", + "sha256:8e08dd76de80539d613654915a2f5196dbccc67448df291e69a88712ea21e24a", + "sha256:c18498c50c59263841862ea0501da9f2b3659c00db54abfbf823a80787fde8ce", + "sha256:c49db89d602c24928e68c0d510f4fcf8989d77defd01c973d6cbe27e684833b1", + "sha256:ce20044d0317649ddbb4e54dab3c1bcc7483c78c27d3f58ab3d0c7e6bc60d26a", + "sha256:d1071414dd06ca2eafa90c85a079169bfeb0e5f57fd0b45d44c092546fcd6fd9", + "sha256:d3be11ac43ab1a3e979dac80843b42226d5d3cccd3986f2e03152720a4297cd7", + "sha256:db603a1c235d110c860d5f39988ebc8218ee028f07a7cbc056ba6424372ca31b" + ], + "version": "==4.5.2" }, "pbr": { "hashes": [ @@ -339,6 +435,20 @@ "index": "pypi", "version": "==5.2.1" }, + "pluggy": { + "hashes": [ + "sha256:0825a152ac059776623854c1543d65a4ad408eb3d33ee114dff91e57ec6ae6fc", + "sha256:b9817417e95936bf75d85d3f8767f7df6cdde751fc40aed3bb3074cbcb77757c" + ], + "version": "==0.12.0" + }, + "py": { + "hashes": [ + "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", + "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53" + ], + "version": "==1.8.0" + }, "pylint": { "hashes": [ "sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09", @@ -347,6 +457,37 @@ "index": "pypi", "version": "==2.3.1" }, + "pytest": { + "hashes": [ + "sha256:1a8aa4fa958f8f451ac5441f3ac130d9fc86ea38780dd2715e6d5c5882700b24", + "sha256:b8bf138592384bd4e87338cb0f256bf5f615398a649d4bd83915f0e4047a5ca6" + ], + "version": "==4.5.0" + }, + "pytest-aiohttp": { + "hashes": [ + "sha256:0b9b660b146a65e1313e2083d0d2e1f63047797354af9a28d6b7c9f0726fa33d", + "sha256:c929854339637977375838703b62fef63528598bc0a9d451639eba95f4aaa44f" + ], + "index": "pypi", + "version": "==0.3.0" + }, + "pytest-asyncio": { + "hashes": [ + "sha256:9fac5100fd716cbecf6ef89233e8590a4ad61d729d1732e0a96b84182df1daaf", + "sha256:d734718e25cfc32d2bf78d346e99d33724deeba774cc4afdf491530c6184b63b" + ], + "index": "pypi", + "version": "==0.10.0" + }, + "pytest-cov": { + "hashes": [ + "sha256:2b097cde81a302e1047331b48cadacf23577e431b61e9c6f49a1170bbe3d3da6", + "sha256:e00ea4fdde970725482f1f35630d12f074e121a23801aabf2ae154ec6bdd343a" + ], + "index": "pypi", + "version": "==2.7.1" + }, "six": { "hashes": [ "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", @@ -386,11 +527,41 @@ "markers": "implementation_name == 'cpython'", "version": "==1.3.5" }, + "wcwidth": { + "hashes": [ + "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", + "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" + ], + "version": "==0.1.7" + }, "wrapt": { "hashes": [ "sha256:4aea003270831cceb8a90ff27c4031da6ead7ec1886023b80ce0dfe0adf61533" ], "version": "==1.11.1" + }, + "yarl": { + "hashes": [ + "sha256:024ecdc12bc02b321bc66b41327f930d1c2c543fa9a561b39861da9388ba7aa9", + "sha256:2f3010703295fbe1aec51023740871e64bb9664c789cba5a6bdf404e93f7568f", + "sha256:3890ab952d508523ef4881457c4099056546593fa05e93da84c7250516e632eb", + "sha256:3e2724eb9af5dc41648e5bb304fcf4891adc33258c6e14e2a7414ea32541e320", + "sha256:5badb97dd0abf26623a9982cd448ff12cb39b8e4c94032ccdedf22ce01a64842", + "sha256:73f447d11b530d860ca1e6b582f947688286ad16ca42256413083d13f260b7a0", + "sha256:7ab825726f2940c16d92aaec7d204cfc34ac26c0040da727cf8ba87255a33829", + "sha256:b25de84a8c20540531526dfbb0e2d2b648c13fd5dd126728c496d7c3fea33310", + "sha256:c6e341f5a6562af74ba55205dbd56d248daf1b5748ec48a0200ba227bb9e33f4", + "sha256:c9bb7c249c4432cd47e75af3864bc02d26c9594f49c82e2a28624417f0ae63b8", + "sha256:e060906c0c585565c718d1c3841747b61c5439af2211e185f6739a9412dfbde1" + ], + "version": "==1.3.0" + }, + "zipp": { + "hashes": [ + "sha256:8c1019c6aad13642199fbe458275ad6a84907634cc9f0989877ccc4a2840139d", + "sha256:ca943a7e809cc12257001ccfb99e3563da9af99d52f261725e96dfe0f9275bc3" + ], + "version": "==0.5.1" } } } diff --git a/bumper/confserver.py b/bumper/confserver.py index 91895aa..dc99543 100644 --- a/bumper/confserver.py +++ b/bumper/confserver.py @@ -64,8 +64,11 @@ class ConfServer: self.run_async = False self.app = None - def confserver_app(self): - self.app = web.Application() + def confserver_app(self, loop=None): + if loop: + self.app = web.Application(loop=loop) + else: + self.app = web.Application() self.app.add_routes( [ diff --git a/tests/test_bumper.py b/tests/test_bumper.py index 2e43d51..d1e9060 100644 --- a/tests/test_bumper.py +++ b/tests/test_bumper.py @@ -1,6 +1,5 @@ -from nose.tools import * -import nose import mock +import pytest from tinydb.storages import MemoryStorage from tinydb import TinyDB, Query import bumper @@ -10,13 +9,13 @@ import platform def test_get_milli_time(): - assert_equals( + assert ( bumper.get_milli_time( datetime.datetime( 2018, 1, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc ).timestamp() - ), - 1514768400000, + ) + == 1514768400000 ) @@ -27,80 +26,73 @@ def test_user_db(): # Test os_db_path platform.system = mock.MagicMock(return_value="Windows") p = platform.system() - os.getenv = mock.MagicMock(return_value="C:\AppData") + os.getenv = mock.MagicMock(return_value="C:\\AppData") o = os.getenv("APPDATA") - assert_equals(bumper.os_db_path(createdir=False), os.path.join(os.getenv("APPDATA"), "bumper.db")) + assert bumper.os_db_path(createdir=False) == os.path.join( + os.getenv("APPDATA"), "bumper.db" + ) platform.system = mock.MagicMock(return_value="Linux") - assert_equals(bumper.os_db_path(createdir=False), os.path.expanduser("~/.config/bumper.db")) + assert bumper.os_db_path(createdir=False) == os.path.expanduser( + "~/.config/bumper.db" + ) bumper.db = "tests/tmp.db" # Set db location for testing bumper.user_add("testuser") # Add testuser - assert_equals( - bumper.user_get("testuser")["userid"], "testuser" + assert ( + bumper.user_get("testuser")["userid"] == "testuser" ) # Test that testuser was created and returned bumper.user_add_device("testuser", "dev_1234") # Add device to testuser - assert_equals( - bumper.user_by_deviceid("dev_1234")["userid"], "testuser" + assert ( + bumper.user_by_deviceid("dev_1234")["userid"] == "testuser" ) # Test that testuser was found by deviceid bumper.user_remove_device("testuser", "dev_1234") # Remove device from testuser - assert_true( - "dev_1234" not in bumper.user_get("testuser")["devices"] - ) # Test that dev_1234 was not found in testuser devices + assert "dev_1234" not in bumper.user_get("testuser")["devices"] + # Test that dev_1234 was not found in testuser devices bumper.user_add_bot("testuser", "bot_1234") # Add bot did to testuser - assert_true( - "bot_1234" in bumper.user_get("testuser")["bots"] - ) # Test that bot was found in testuser's bot list + assert "bot_1234" in bumper.user_get("testuser")["bots"] + # Test that bot was found in testuser's bot list bumper.user_remove_bot("testuser", "bot_1234") # Remove bot did from testuser - assert_true( - "bot_1234" not in bumper.user_get("testuser")["bots"] - ) # Test that bot was not found in testuser's bot list + assert "bot_1234" not in bumper.user_get("testuser")["bots"] + # Test that bot was not found in testuser's bot list bumper.user_add_token("testuser", "token_1234") # Add token to testuser - assert_true( - bumper.check_token("testuser", "token_1234") - ) # Test that token was found for testuser + assert bumper.check_token("testuser", "token_1234") + # Test that token was found for testuser - assert_true( - bumper.user_get_token("testuser", "token_1234") - ) # Test that token was returned for testuser + assert bumper.user_get_token("testuser", "token_1234") + # Test that token was returned for testuser bumper.user_add_authcode( "testuser", "token_1234", "auth_1234" ) # Add authcode to token_1234 for testuser - assert_true( - bumper.check_authcode("testuser", "auth_1234") - ) # Test that authcode was found for testuser + assert bumper.check_authcode("testuser", "auth_1234") + # Test that authcode was found for testuser bumper.user_revoke_authcode( "testuser", "token_1234", "auth_1234" ) # Remove authcode from testuser - assert_false( - bumper.check_authcode("testuser", "auth_1234") - ) # Test that authcode was not found for testuser + assert bumper.check_authcode("testuser", "auth_1234") == False + # Test that authcode was not found for testuser bumper.user_revoke_token("testuser", "token_1234") # Remove token from testuser - assert_false( - bumper.check_token("testuser", "token_1234") + assert ( + bumper.check_token("testuser", "token_1234") == False ) # Test that token was not found for testuser bumper.user_add_token("testuser", "token_1234") # Add token_1234 bumper.user_add_token("testuser", "token_4321") # Add token_4321 - assert_equals( - len(bumper.user_get_tokens("testuser")), 2 - ) # Test 2 tokens are available + assert len(bumper.user_get_tokens("testuser")) == 2 # Test 2 tokens are available bumper.user_revoke_all_tokens("testuser") # Revoke all tokens - assert_equals( - len(bumper.user_get_tokens("testuser")), 0 - ) # Test 0 tokens are available + assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available db = TinyDB("tests/tmp.db") tokens = db.table("tokens") @@ -114,13 +106,9 @@ def test_user_db(): } ) # Add expired token db.close() - assert_equals( - len(bumper.user_get_tokens("testuser")), 1 - ) # Test 1 tokens are available + assert len(bumper.user_get_tokens("testuser")) == 1 # Test 1 tokens are available bumper.user_revoke_expired_tokens("testuser") # Revoke expired tokens - assert_equals( - len(bumper.user_get_tokens("testuser")), 0 - ) # Test 0 tokens are available + assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available db = TinyDB("tests/tmp.db") tokens = db.table("tokens") @@ -134,53 +122,49 @@ def test_user_db(): } ) # Add expired token db.close() - assert_equals( - len(bumper.user_get_tokens("testuser")), 1 - ) # Test 1 tokens are available + assert len(bumper.user_get_tokens("testuser")) == 1 # Test 1 tokens are available bumper.revoke_expired_tokens() # Revoke expired tokens - assert_equals( - len(bumper.user_get_tokens("testuser")), 0 - ) # Test 0 tokens are available + assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available def test_bot_db(): bumper.db = "tests/tmp.db" # Set db location for testing bumper.bot_add("sn_123", "did_123", "dev_123", "res_123", "co_123") - assert_true(bumper.bot_get("did_123")) # Test that bot was added to db + assert bumper.bot_get("did_123") # Test that bot was added to db bumper.bot_set_nick("did_123", "nick_123") - assert_equals( - bumper.bot_get("did_123")["nick"], "nick_123" + assert ( + bumper.bot_get("did_123")["nick"] == "nick_123" ) # Test that nick was added to bot bumper.bot_set_mqtt("did_123", True) - assert_true( - bumper.bot_get("did_123")["mqtt_connection"] - ) # Test that mqtt was set True for bot + assert bumper.bot_get("did_123")[ + "mqtt_connection" + ] # Test that mqtt was set True for bot bumper.bot_set_xmpp("did_123", True) - assert_true( - bumper.bot_get("did_123")["xmpp_connection"] - ) # Test that xmpp was set True for bot + assert bumper.bot_get("did_123")[ + "xmpp_connection" + ] # Test that xmpp was set True for bot bumper.bot_remove("did_123") - assert_false(bumper.bot_get("did_123")) # Test that bot is no longer in db + assert bumper.bot_get("did_123") == None # Test that bot is no longer in db def test_client_db(): bumper.db = "tests/tmp.db" # Set db location for testing bumper.client_add("user_123", "realm_123", "resource_123") - assert_true(bumper.client_get("resource_123")) # Test client was added + assert bumper.client_get("resource_123") # Test client was added bumper.client_set_mqtt("resource_123", True) - assert_true( - bumper.client_get("resource_123")["mqtt_connection"] - ) # Test that mqtt was set True for client + assert bumper.client_get("resource_123")[ + "mqtt_connection" + ] # Test that mqtt was set True for client bumper.client_set_xmpp("resource_123", False) - assert_false( - bumper.client_get("resource_123")["xmpp_connection"] + assert ( + bumper.client_get("resource_123")["xmpp_connection"] == False ) # Test that xmpp was set False for client - assert_equals( - len(bumper.get_disconnected_xmpp_clients()), 1 + assert ( + len(bumper.get_disconnected_xmpp_clients()) == 1 ) # Test len of connected xmpp clients is 1 diff --git a/tests/test_confserver.py b/tests/test_confserver.py index 4fd9a2a..eae8cb1 100644 --- a/tests/test_confserver.py +++ b/tests/test_confserver.py @@ -1,16 +1,22 @@ -from nose.tools import * import mock import bumper import asyncio +import pytest import os import json import tinydb -from aiohttp.test_utils import TestClient, TestServer, loop_context -from aiohttp import request +import pytest_aiohttp +from aiohttp import web -confserver = bumper.ConfServer("127.0.0.1:11111", False, mock.MagicMock) -confserver.confserver_app() -app = confserver.app + +def create_confserver(): + return bumper.ConfServer("127.0.0.1:11111", False, mock.MagicMock) + + +def create_app(loop): + confserver = bumper.ConfServer("127.0.0.1:11111", False, mock.MagicMock) + confserver.confserver_app(loop=loop) + return confserver.app def async_return(result): @@ -19,151 +25,115 @@ def async_return(result): return f -def test_disconnect(): - async def test_disconnect_async(): - await confserver.disconnect() - - loop = asyncio.get_event_loop() - # Test - loop.run_until_complete(test_disconnect_async()) - - -def test_base(): +async def test_base(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db bumper.db = "tests/tmp.db" # Set db location for testing - loop = asyncio.get_event_loop() - client = TestClient(TestServer(app), loop=loop) - loop.run_until_complete(client.start_server()) - root = "http://{}".format(confserver.address) + client = await aiohttp_client(create_app) - async def test_handle_base(): - resp = await client.get("/") - assert resp.status == 200 - text = await resp.text() - assert "Bumper!" in text - - # Test - loop.run_until_complete(test_handle_base()) - - loop.run_until_complete( - client.close() - ) # Close test server after all tests are done + resp = await client.get("/") + assert resp.status == 200 + text = await resp.text() + assert "Bumper!" in text -def test_login(): +async def test_login(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db bumper.db = "tests/tmp.db" # Set db location for testing - loop = asyncio.get_event_loop() - client = TestClient(TestServer(app), loop=loop) - loop.run_until_complete(client.start_server()) - root = "http://{}".format(confserver.address) + client = await aiohttp_client(create_app) - async def test_handle_login(): - resp = await client.get("/1/private/us/en/dev_1234/ios/1/0/0/user/login") - assert resp.status == 200 - text = await resp.text() - jsonresp = json.loads(text) - if jsonresp: - assert jsonresp["code"] == bumper.RETURN_API_SUCCESS - assert "accessToken" in jsonresp["data"] - assert "uid" in jsonresp["data"] - assert "username" in jsonresp["data"] - else: - assert jsonresp - - # Test - loop.run_until_complete(test_handle_login()) + # Test without user + resp = await client.get("/1/private/us/en/dev_1234/ios/1/0/0/user/login") + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + assert "accessToken" in jsonresp["data"] + assert "uid" in jsonresp["data"] + assert "username" in jsonresp["data"] # Add a user to db and test with existing users bumper.user_add("testuser") - # Test - loop.run_until_complete(test_handle_login()) + resp = await client.get("/1/private/us/en/dev_1234/ios/1/0/0/user/login") + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + assert "accessToken" in jsonresp["data"] + assert "uid" in jsonresp["data"] + assert "username" in jsonresp["data"] # Add a bot to db that will be added to user bumper.bot_add("sn_123", "did_123", "dev_123", "res_123", "com_123") - # Test - loop.run_until_complete(test_handle_login()) - - loop.run_until_complete( - client.close() - ) # Close test server after all tests are done + resp = await client.get("/1/private/us/en/dev_1234/ios/1/0/0/user/login") + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + assert "accessToken" in jsonresp["data"] + assert "uid" in jsonresp["data"] + assert "username" in jsonresp["data"] -def test_logout(): +async def test_logout(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db bumper.db = "tests/tmp.db" # Set db location for testing - loop = asyncio.get_event_loop() - client = TestClient(TestServer(app), loop=loop) - loop.run_until_complete(client.start_server()) - root = "http://{}".format(confserver.address) - - async def test_handle_logout(token=None): - resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/user/logout?accessToken={}".format( - token - ) - ) - assert resp.status == 200 - text = await resp.text() - jsonresp = json.loads(text) - if jsonresp: - assert jsonresp["code"] == bumper.RETURN_API_SUCCESS - else: - assert jsonresp + client = await aiohttp_client(create_app) # Add a token to user and test bumper.user_add("testuser") bumper.user_add_device("testuser", "dev_1234") bumper.user_add_token("testuser", "token_1234") - # Test - loop.run_until_complete(test_handle_logout(token="token_1234")) + resp = await client.get( + "/1/private/us/en/dev_1234/ios/1/0/0/user/logout?accessToken={}".format( + "token_1234" + ) + ) - loop.run_until_complete( - client.close() - ) # Close test server after all tests are done + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS -def test_checkLogin(): +async def test_checkLogin(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db bumper.db = "tests/tmp.db" # Set db location for testing - loop = asyncio.get_event_loop() - client = TestClient(TestServer(app), loop=loop) - loop.run_until_complete(client.start_server()) - root = "http://{}".format(confserver.address) + client = await aiohttp_client(create_app) - async def test_handle_checkLogin(token=None): - resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/user/checkLogin?accessToken={}".format( - token - ) + # Test without token + resp = await client.get( + "/1/private/us/en/dev_1234/ios/1/0/0/user/checkLogin?accessToken={}".format( + None ) - assert resp.status == 200 - text = await resp.text() - jsonresp = json.loads(text) - if jsonresp: - assert jsonresp["code"] == bumper.RETURN_API_SUCCESS - assert "accessToken" in jsonresp["data"] - if not token: - assert jsonresp["data"]["accessToken"] != "token_1234" - else: - assert jsonresp["data"]["accessToken"] == "token_1234" - - assert "uid" in jsonresp["data"] - assert "username" in jsonresp["data"] - else: - assert jsonresp - - # Test - loop.run_until_complete(test_handle_checkLogin()) + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + assert "accessToken" in jsonresp["data"] + assert jsonresp["data"]["accessToken"] != "token_1234" + assert "uid" in jsonresp["data"] + assert "username" in jsonresp["data"] # Add a user to db and test with existing users bumper.user_add("testuser") - # Test - loop.run_until_complete(test_handle_checkLogin()) + resp = await client.get( + "/1/private/us/en/dev_1234/ios/1/0/0/user/checkLogin?accessToken={}".format( + None + ) + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + assert "accessToken" in jsonresp["data"] + assert jsonresp["data"]["accessToken"] != "token_1234" + assert "uid" in jsonresp["data"] + assert "username" in jsonresp["data"] # Remove dev from tmpuser bumper.user_remove_device("tmpuser", "dev_1234") @@ -172,231 +142,156 @@ def test_checkLogin(): bumper.user_add("testuser") bumper.user_add_device("testuser", "dev_1234") bumper.user_add_token("testuser", "token_1234") - # Test - loop.run_until_complete(test_handle_checkLogin(token="token_1234")) - - loop.run_until_complete( - client.close() - ) # Close test server after all tests are done + resp = await client.get( + "/1/private/us/en/dev_1234/ios/1/0/0/user/checkLogin?accessToken={}".format( + "token_1234" + ) + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + assert "accessToken" in jsonresp["data"] + assert jsonresp["data"]["accessToken"] == "token_1234" + assert "uid" in jsonresp["data"] + assert "username" in jsonresp["data"] -def test_getAuthCode(): +async def test_getAuthCode(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db bumper.db = "tests/tmp.db" # Set db location for testing - loop = asyncio.get_event_loop() - client = TestClient(TestServer(app), loop=loop) - loop.run_until_complete(client.start_server()) - root = "http://{}".format(confserver.address) - - async def test_handle_getAuthCode(uid=None, token=None): - resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/user/getAuthCode?uid={}&accessToken={}".format( - uid, token - ) - ) - assert resp.status == 200 - text = await resp.text() - jsonresp = json.loads(text) - if jsonresp: - if token: - assert jsonresp["code"] == bumper.RETURN_API_SUCCESS - assert "authCode" in jsonresp["data"] - assert "ecovacsUid" in jsonresp["data"] - else: - assert jsonresp["code"] == bumper.ERR_TOKEN_INVALID - else: - assert jsonresp + client = await aiohttp_client(create_app) # Test without user or token - loop.run_until_complete(test_handle_getAuthCode()) + resp = await client.get( + "/1/private/us/en/dev_1234/ios/1/0/0/user/getAuthCode?uid={}&accessToken={}".format( + None, None + ) + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.ERR_TOKEN_INVALID # Add a token to user and test bumper.user_add("testuser") bumper.user_add_device("testuser", "dev_1234") bumper.user_add_token("testuser", "token_1234") - # Test - loop.run_until_complete(test_handle_getAuthCode(uid="testuser", token="token_1234")) + resp = await client.get( + "/1/private/us/en/dev_1234/ios/1/0/0/user/getAuthCode?uid={}&accessToken={}".format( + "testuser", "token_1234" + ) + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + assert "authCode" in jsonresp["data"] + assert "ecovacsUid" in jsonresp["data"] # The above should have added an authcode to token, try again to test with existing authcode - # Test - loop.run_until_complete(test_handle_getAuthCode(uid="testuser", token="token_1234")) - - loop.run_until_complete( - client.close() - ) # Close test server after all tests are done - - -def test_checkAgreement(): - if os.path.exists("tests/tmp.db"): - os.remove("tests/tmp.db") # Remove existing db - bumper.db = "tests/tmp.db" # Set db location for testing - loop = asyncio.get_event_loop() - client = TestClient(TestServer(app), loop=loop) - loop.run_until_complete(client.start_server()) - root = "http://{}".format(confserver.address) - - async def test_handle_checkAgreement(): - resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/user/checkAgreement" + resp = await client.get( + "/1/private/us/en/dev_1234/ios/1/0/0/user/getAuthCode?uid={}&accessToken={}".format( + "testuser", "token_1234" ) - assert resp.status == 200 - text = await resp.text() - jsonresp = json.loads(text) - if jsonresp: - assert jsonresp["code"] == bumper.RETURN_API_SUCCESS - else: - assert jsonresp - - # Test - loop.run_until_complete(test_handle_checkAgreement()) - - loop.run_until_complete( - client.close() - ) # Close test server after all tests are done + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + assert "authCode" in jsonresp["data"] + assert "ecovacsUid" in jsonresp["data"] -def test_homePageAlert(): +async def test_checkAgreement(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db bumper.db = "tests/tmp.db" # Set db location for testing - loop = asyncio.get_event_loop() - client = TestClient(TestServer(app), loop=loop) - loop.run_until_complete(client.start_server()) - root = "http://{}".format(confserver.address) + client = await aiohttp_client(create_app) - async def test_handle_homePageAlert(): - resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/campaign/homePageAlert" - ) - assert resp.status == 200 - text = await resp.text() - jsonresp = json.loads(text) - if jsonresp: - assert jsonresp["code"] == bumper.RETURN_API_SUCCESS - else: - assert jsonresp - - # Test - loop.run_until_complete(test_handle_homePageAlert()) - - loop.run_until_complete( - client.close() - ) # Close test server after all tests are done + resp = await client.get("/1/private/us/en/dev_1234/ios/1/0/0/user/checkAgreement") + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS -def test_checkVersion(): +async def test_homePageAlert(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db bumper.db = "tests/tmp.db" # Set db location for testing - loop = asyncio.get_event_loop() - client = TestClient(TestServer(app), loop=loop) - loop.run_until_complete(client.start_server()) - root = "http://{}".format(confserver.address) + client = await aiohttp_client(create_app) - async def test_handle_checkVersion(): - resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/common/checkVersion" - ) - assert resp.status == 200 - text = await resp.text() - jsonresp = json.loads(text) - if jsonresp: - assert jsonresp["code"] == bumper.RETURN_API_SUCCESS - else: - assert jsonresp - - # Test - loop.run_until_complete(test_handle_checkVersion()) - - loop.run_until_complete( - client.close() - ) # Close test server after all tests are done + resp = await client.get( + "/1/private/us/en/dev_1234/ios/1/0/0/campaign/homePageAlert" + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS -def test_getProductIotMap(): +async def test_checkVersion(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db bumper.db = "tests/tmp.db" # Set db location for testing - loop = asyncio.get_event_loop() - client = TestClient(TestServer(app), loop=loop) - loop.run_until_complete(client.start_server()) - root = "http://{}".format(confserver.address) + client = await aiohttp_client(create_app) - async def test_handle_getProductIotMap(): - resp = await client.post("/api/pim/product/getProductIotMap") - assert resp.status == 200 - text = await resp.text() - jsonresp = json.loads(text) - if jsonresp: - assert jsonresp["code"] == bumper.RETURN_API_SUCCESS - else: - assert jsonresp - - # Test - loop.run_until_complete(test_handle_getProductIotMap()) - - loop.run_until_complete( - client.close() - ) # Close test server after all tests are done + resp = await client.get("/1/private/us/en/dev_1234/ios/1/0/0/common/checkVersion") + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS -def test_getUsersAPI(): +async def test_getProductIotMap(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db bumper.db = "tests/tmp.db" # Set db location for testing - loop = asyncio.get_event_loop() - client = TestClient(TestServer(app), loop=loop) - loop.run_until_complete(client.start_server()) - root = "http://{}".format(confserver.address) + client = await aiohttp_client(create_app) - async def test_handle_getUsersApi(): - resp = await client.get("/api/users/user.do") - assert resp.status == 200 - text = await resp.text() - jsonresp = json.loads(text) - if jsonresp: - assert jsonresp["result"] == "fail" - else: - assert jsonresp - - # Test - loop.run_until_complete(test_handle_getUsersApi()) - - loop.run_until_complete( - client.close() - ) # Close test server after all tests are done + resp = await client.post("/api/pim/product/getProductIotMap") + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS -def test_postUsersAPI(): +async def test_getUsersAPI(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db bumper.db = "tests/tmp.db" # Set db location for testing - loop = asyncio.get_event_loop() - client = TestClient(TestServer(app), loop=loop) - loop.run_until_complete(client.start_server()) - root = "http://{}".format(confserver.address) + client = await aiohttp_client(create_app) - async def test_handle_postUsersApi(postbody=None): - resp = await client.post("/api/users/user.do", json=postbody) + resp = await client.get("/api/users/user.do") + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["result"] == "fail" - assert resp.status == 200 - text = await resp.text() - jsonresp = json.loads(text) - if jsonresp: - assert jsonresp["result"] == "ok" - else: - assert jsonresp + +async def test_postUsersAPI(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + client = await aiohttp_client(create_app) # Test FindBest postbody = {"todo": "FindBest", "service": "EcoMsgNew"} - # Test - loop.run_until_complete(test_handle_postUsersApi(postbody)) + resp = await client.post("/api/users/user.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["result"] == "ok" # Test EcoUpdate postbody = {"todo": "FindBest", "service": "EcoUpdate"} - # Test - loop.run_until_complete(test_handle_postUsersApi(postbody)) + resp = await client.post("/api/users/user.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["result"] == "ok" # Test loginByItToken - Uses the authcode bumper.user_add("testuser") @@ -415,7 +310,11 @@ def test_postUsersAPI(): "token": "auth_1234", "userId": "testuser", } - loop.run_until_complete(test_handle_postUsersApi(postbody)) + resp = await client.post("/api/users/user.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["result"] == "ok" # Test GetDeviceList postbody = { @@ -429,7 +328,11 @@ def test_postUsersAPI(): "todo": "GetDeviceList", "userid": "testuser", } - loop.run_until_complete(test_handle_postUsersApi(postbody)) + resp = await client.post("/api/users/user.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["result"] == "ok" # Test SetDeviceNick postbody = { @@ -444,7 +347,11 @@ def test_postUsersAPI(): "nick": "botnick", "did": "did_1234", } - loop.run_until_complete(test_handle_postUsersApi(postbody)) + resp = await client.post("/api/users/user.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["result"] == "ok" # Test AddOneDevice - Same as set nick for some bots postbody = { @@ -459,7 +366,11 @@ def test_postUsersAPI(): "nick": "botnick", "did": "did_1234", } - loop.run_until_complete(test_handle_postUsersApi(postbody)) + resp = await client.post("/api/users/user.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["result"] == "ok" # Test DeleteOneDevice - remove bot postbody = { @@ -473,79 +384,50 @@ def test_postUsersAPI(): "todo": "DeleteOneDevice", "did": "did_1234", } - loop.run_until_complete(test_handle_postUsersApi(postbody)) - - loop.run_until_complete( - client.close() - ) # Close test server after all tests are done + resp = await client.post("/api/users/user.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["result"] == "ok" -def test_postLookup(): +async def test_postLookup(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db bumper.db = "tests/tmp.db" # Set db location for testing - loop = asyncio.get_event_loop() - client = TestClient(TestServer(app), loop=loop) - loop.run_until_complete(client.start_server()) - root = "http://{}".format(confserver.address) - - async def test_handle_lookup(postbody=None): - resp = await client.post("/lookup.do", json=postbody) - - assert resp.status == 200 - text = await resp.text() - jsonresp = json.loads(text) - if jsonresp: - assert jsonresp["result"] == "ok" - else: - assert jsonresp + client = await aiohttp_client(create_app) # Test FindBest postbody = {"todo": "FindBest", "service": "EcoMsgNew"} - # Test - loop.run_until_complete(test_handle_lookup(postbody)) + resp = await client.post("/lookup.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + test_resp = json.loads(text) + assert test_resp["result"] == "ok" # Test EcoUpdate postbody = {"todo": "FindBest", "service": "EcoUpdate"} - # Test - loop.run_until_complete(test_handle_lookup(postbody)) - - loop.run_until_complete( - client.close() - ) # Close test server after all tests are done + resp = await client.post("/lookup.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + test_resp = json.loads(text) + assert test_resp["result"] == "ok" -def test_devmgr(): +async def test_devmgr(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db bumper.db = "tests/tmp.db" # Set db location for testing - loop = asyncio.get_event_loop() - client = TestClient(TestServer(app), loop=loop) - loop.run_until_complete(client.start_server()) - root = "http://{}".format(confserver.address) - - async def test_devmanager(postbody=None, command=False): - resp = await client.post("/api/iot/devmanager.do", json=postbody) - - assert resp.status == 200 - text = await resp.text() - jsonresp = json.loads(text) - if jsonresp: - if not command: - assert jsonresp["ret"] == "ok" - else: - if "ret" in jsonresp: - if jsonresp["ret"] == "ok": - assert jsonresp["resp"] - else: - assert jsonresp["errno"] - else: - assert jsonresp + confserver = create_confserver() + client = await aiohttp_client(create_app) # Test PollSCResult postbody = {"td": "PollSCResult"} - # Test - loop.run_until_complete(test_devmanager(postbody, command=False)) + resp = await client.post("/api/dim/devmanager.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + test_resp = json.loads(text) + assert test_resp["ret"] == "ok" # Test BotCommand bumper.bot_add("sn_1234", "did_1234", "dev_1234", "res_1234", "eco-ng") @@ -561,25 +443,99 @@ def test_devmgr(): confserver.helperbot.send_command = mock.MagicMock( return_value=async_return(command_getstatus_resp) ) - # Test - loop.run_until_complete(test_devmanager(postbody, command=True)) + resp = await client.post("/api/dim/devmanager.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + test_resp = json.loads(text) + assert test_resp["ret"] == "ok" # Test return fail timeout command_timeout_resp = {"id": "resp_1234", "errno": "timeout", "ret": "fail"} confserver.helperbot.send_command = mock.MagicMock( return_value=async_return(command_timeout_resp) ) - # Test - loop.run_until_complete(test_devmanager(postbody, command=True)) + resp = await client.post("/api/dim/devmanager.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + test_resp = json.loads(text) + assert test_resp["ret"] == "fail" # Set bot not on mqtt bumper.bot_set_mqtt("did_1234", False) confserver.helperbot.send_command = mock.MagicMock( return_value=async_return(command_getstatus_resp) ) - # Test - loop.run_until_complete(test_devmanager(postbody, command=True)) + resp = await client.post("/api/dim/devmanager.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + test_resp = json.loads(text) + assert test_resp["ret"] == "fail" + + +async def test_dim_devmanager(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + confserver = create_confserver() + client = await aiohttp_client(create_app) + + # Test PollSCResult + postbody = {"td": "PollSCResult"} + resp = await client.post("/api/dim/devmanager.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + test_resp = json.loads(text) + assert test_resp["ret"] == "ok" + + # Test HasUnreadMsg + postbody = {"td": "HasUnreadMsg"} + resp = await client.post("/api/dim/devmanager.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + test_resp = json.loads(text) + assert test_resp["ret"] == "ok" + assert test_resp["unRead"] == False + + # Test BotCommand + bumper.bot_add("sn_1234", "did_1234", "dev_1234", "res_1234", "eco-ng") + bumper.bot_set_mqtt("did_1234", True) + postbody = {"toId": "did_1234"} + + # Test return get status + command_getstatus_resp = { + "id": "resp_1234", + "resp": "", + "ret": "ok", + } + confserver.helperbot.send_command = mock.MagicMock( + return_value=async_return(command_getstatus_resp) + ) + resp = await client.post("/api/dim/devmanager.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + test_resp = json.loads(text) + assert test_resp["ret"] == "ok" + + # Test return fail timeout + command_timeout_resp = {"id": "resp_1234", "errno": "timeout", "ret": "fail"} + confserver.helperbot.send_command = mock.MagicMock( + return_value=async_return(command_timeout_resp) + ) + resp = await client.post("/api/dim/devmanager.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + test_resp = json.loads(text) + assert test_resp["ret"] == "fail" + assert test_resp["errno"] == "timeout" + + # Set bot not on mqtt + bumper.bot_set_mqtt("did_1234", False) + confserver.helperbot.send_command = mock.MagicMock( + return_value=async_return(command_getstatus_resp) + ) + resp = await client.post("/api/dim/devmanager.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + test_resp = json.loads(text) + assert test_resp["ret"] == "fail" - loop.run_until_complete( - client.close() - ) # Close test server after all tests are done diff --git a/tests/tests.md b/tests/tests.md index d4756ce..c485135 100644 --- a/tests/tests.md +++ b/tests/tests.md @@ -1,16 +1,16 @@ # Bumper tests -Bumper uses nosetests for the majority of test cases. Install requirements using `pipenv install --dev` +Bumper uses pytest for the majority of test cases. Install requirements using `pipenv install --dev` ## Testing Enter pipenv shell `pipenv shell` ### Run tests -`nosetests` +`python -m pytest` ### Run tests with coverage -`nosetests --cover-package bumper --with-coverage` +`python -m pytest --cov=bumper tests/` ### Run tests with coverage html report -`nosetests --cover-package bumper --with-coverage --cover-html-dir="tests/report" --cover-html` +`python -m pytest --cov=bumper tests/ --cov-report html:tests/report` The report will be output into tests/report/index.html for further analysis. \ No newline at end of file From 615c6011eda075c5da3e2ccf29bb10e80ee7134e Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Mon, 3 Jun 2019 09:04:16 -0400 Subject: [PATCH 2/9] add test_xmppserver.py Add new test_xmppserver.py - first connect test --- start_bumper.py | 2 +- tests/test_xmppserver.py | 48 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 tests/test_xmppserver.py diff --git a/start_bumper.py b/start_bumper.py index 4ec5414..3fc4fc1 100644 --- a/start_bumper.py +++ b/start_bumper.py @@ -48,7 +48,7 @@ async def main(): xmpp_address = (listen_host, 5223) mqtt_address = (listen_host, 8883) - xmpp_server = bumper.XMPPServer(xmpp_address) + mqtt_server = bumper.MQTTServer(mqtt_address) mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) conf_server = bumper.ConfServer( diff --git a/tests/test_xmppserver.py b/tests/test_xmppserver.py new file mode 100644 index 0000000..3de9298 --- /dev/null +++ b/tests/test_xmppserver.py @@ -0,0 +1,48 @@ +import mock +import bumper +import asyncio +import pytest +import os +import json +import tinydb +import pytest_asyncio + + +def return_send_data(data, *args, **kwargs): + return data + + +def mock_transport_extra_info(*args, **kwargs): + return ("127.0.0.1", 1234) + + +async def test_client(*args, **kwargs): + test_transport = asyncio.Transport() + test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) + test_transport.write = mock.Mock(return_value=return_send_data) + xmppclient = bumper.xmppserver.XMPPAsyncClient(test_transport) + xmppclient.state = xmppclient.INIT # Set client state to INIT + mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data) + + # Send init connect stream from "client" + test_data = "".encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + # Expect 2 calls to send + assert mock_send.call_count == 2 + # Server opens stream + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) + # Server tells client available features + assert ( + mock_send.mock_calls[1].args[0] + == '' + ) + + # Reset mock calls + mock_send.reset_mock() + From bcafa83c650061909fa29878ef19ad6a18c2f0ee Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Mon, 3 Jun 2019 09:55:22 -0400 Subject: [PATCH 3/9] update travis and appveyor configs update travis and appveyor configs to run pytest instead of nosetests --- .travis.yml | 2 +- appveyor.yml | 2 +- start_bumper.py | 1 - tests/test_xmppserver.py | 33 ++++++++++++++++++++++++++++++++- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ccfe3d7..3d268f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,4 +9,4 @@ install: - pip install pipenv - pipenv install --dev -script: nosetests +script: pipenv run python -m pytest diff --git a/appveyor.yml b/appveyor.yml index 26f3592..ebd43a2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,4 +19,4 @@ test_script: # Note that you must use the environment variable %PYTHON% to refer to # the interpreter you're using - Appveyor does not do anything special # to put the Python version you want to use on PATH. -- "pipenv run nosetests" +- "pipenv run python -m pytest" diff --git a/start_bumper.py b/start_bumper.py index 3fc4fc1..677e219 100644 --- a/start_bumper.py +++ b/start_bumper.py @@ -48,7 +48,6 @@ async def main(): xmpp_address = (listen_host, 5223) mqtt_address = (listen_host, 8883) - mqtt_server = bumper.MQTTServer(mqtt_address) mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) conf_server = bumper.ConfServer( diff --git a/tests/test_xmppserver.py b/tests/test_xmppserver.py index 3de9298..8bdf6cd 100644 --- a/tests/test_xmppserver.py +++ b/tests/test_xmppserver.py @@ -16,7 +16,7 @@ def mock_transport_extra_info(*args, **kwargs): return ("127.0.0.1", 1234) -async def test_client(*args, **kwargs): +async def test_client_init(*args, **kwargs): test_transport = asyncio.Transport() test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) test_transport.write = mock.Mock(return_value=return_send_data) @@ -46,3 +46,34 @@ async def test_client(*args, **kwargs): # Reset mock calls mock_send.reset_mock() + +async def test_bot_init(*args, **kwargs): + test_transport = asyncio.Transport() + test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) + test_transport.write = mock.Mock(return_value=return_send_data) + xmppclient = bumper.xmppserver.XMPPAsyncClient(test_transport) + xmppclient.state = xmppclient.INIT # Set client state to INIT + mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data) + + # Send init connect stream from "client" + test_data = "".encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + # Expect 2 calls to send + assert mock_send.call_count == 2 + # Server opens stream + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) + # Server tells client available features + assert ( + mock_send.mock_calls[1].args[0] + == '' + ) + + # Reset mock calls + mock_send.reset_mock() + From 9d95cbd60637f5e17d5eac3bfd8fd19be3ad2b8e Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Mon, 3 Jun 2019 15:48:24 -0400 Subject: [PATCH 4/9] rename test_bumper to test_init - rename test_bumper to test_init - added more xmppserver tests --- tests/{test_bumper.py => test_init.py} | 0 tests/test_xmppserver.py | 310 ++++++++++++++++++++++++- 2 files changed, 303 insertions(+), 7 deletions(-) rename tests/{test_bumper.py => test_init.py} (100%) diff --git a/tests/test_bumper.py b/tests/test_init.py similarity index 100% rename from tests/test_bumper.py rename to tests/test_init.py diff --git a/tests/test_xmppserver.py b/tests/test_xmppserver.py index 8bdf6cd..95fa8e1 100644 --- a/tests/test_xmppserver.py +++ b/tests/test_xmppserver.py @@ -6,6 +6,7 @@ import os import json import tinydb import pytest_asyncio +import xml.etree.ElementTree as ET def return_send_data(data, *args, **kwargs): @@ -16,15 +17,15 @@ def mock_transport_extra_info(*args, **kwargs): return ("127.0.0.1", 1234) -async def test_client_init(*args, **kwargs): +async def test_client_connect_no_starttls(*args, **kwargs): test_transport = asyncio.Transport() test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) test_transport.write = mock.Mock(return_value=return_send_data) xmppclient = bumper.xmppserver.XMPPAsyncClient(test_transport) - xmppclient.state = xmppclient.INIT # Set client state to INIT + xmppclient.state = xmppclient.CONNECT # Set client state to CONNECT mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data) - # Send init connect stream from "client" + # Send connect stream from "client" test_data = "".encode( "utf-8" ) @@ -40,22 +41,109 @@ async def test_client_init(*args, **kwargs): # Server tells client available features assert ( mock_send.mock_calls[1].args[0] - == '' + == 'PLAIN' ) # Reset mock calls mock_send.reset_mock() + # Client sendss auth - Ignoring the starttls, we don't force this with bumper + test_data = 'AGZ1aWRfdG1wdXNlcgAwL0lPU0Y1M0QwN0JBL3VzXzg5ODgwMmZkYmM0NDQxYjBiYzgxNWIxZDFjNjgzMDJl'.encode( + "utf-8" + ) + xmppclient._parse_data(test_data) -async def test_bot_init(*args, **kwargs): + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) # Client successfully authenticated + assert xmppclient.state == xmppclient.INIT # Client moved to INIT state + + +async def test_client_connect_starttls_called(*args, **kwargs): test_transport = asyncio.Transport() test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) test_transport.write = mock.Mock(return_value=return_send_data) xmppclient = bumper.xmppserver.XMPPAsyncClient(test_transport) - xmppclient.state = xmppclient.INIT # Set client state to INIT + xmppclient.state = xmppclient.CONNECT # Set client state to CONNECT mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data) - # Send init connect stream from "client" + # Send connect stream from "client" + test_data = "".encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + # Expect 2 calls to send + assert mock_send.call_count == 2 + # Server opens stream + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) + # Server tells client available features + assert ( + mock_send.mock_calls[1].args[0] + == 'PLAIN' + ) + + # Reset mock calls + mock_send.reset_mock() + + mock_tls = xmppclient._handle_starttls = mock.Mock() + + # Send start tls from "client" + test_data = "".encode("utf-8") + xmppclient._parse_data(test_data) + + # After upgrading connection, server tells client to proceed with auth again + assert mock_tls.called + xmppclient.TLSUpgraded = True + + # After TLS is upgraded, Client establishes session again and will auth this time + # Send connect stream from "client" + test_data = "".encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + # Expect 2 calls to send + assert mock_send.call_count == 2 + # Server opens stream + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) + # Server tells client available features (without STARTTLS) + assert ( + mock_send.mock_calls[1].args[0] + == 'PLAIN' + ) + # Reset mock calls + mock_send.reset_mock() + + # Client sends auth + test_data = 'AGZ1aWRfdG1wdXNlcgAwL0lPU0Y1M0QwN0JBL3VzXzg5ODgwMmZkYmM0NDQxYjBiYzgxNWIxZDFjNjgzMDJl'.encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) # Client successfully authenticated + assert xmppclient.state == xmppclient.INIT # Client moved to INIT state + + +async def test_bot_connect(*args, **kwargs): + test_transport = asyncio.Transport() + test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) + test_transport.write = mock.Mock(return_value=return_send_data) + xmppclient = bumper.xmppserver.XMPPAsyncClient(test_transport) + xmppclient.state = xmppclient.CONNECT # Set client state to CONNECT + mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data) + + # Send connect stream from "bot" test_data = "".encode( "utf-8" ) @@ -69,6 +157,52 @@ async def test_bot_init(*args, **kwargs): == '' ) # Server tells client available features + assert ( + mock_send.mock_calls[1].args[0] + == 'PLAIN' + ) + + # Reset mock calls + mock_send.reset_mock() + + # Send auth from "bot" + test_data = "AEUwMDAwMDAwMDAwMDAwMDAxMjM0AGVuY3J5cHRlZF9wYXNz".encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) # Bot successfully authenticated + assert xmppclient.state == xmppclient.INIT # Bot moved to INIT state + assert xmppclient.type == xmppclient.BOT # Client type is now bot + + +async def test_bot_init(*args, **kwargs): + test_transport = asyncio.Transport() + test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) + test_transport.write = mock.Mock(return_value=return_send_data) + xmppclient = bumper.xmppserver.XMPPAsyncClient(test_transport) + xmppclient.state = xmppclient.INIT # Set client state to INIT + xmppclient.uid = "E0000000000000001234" + xmppclient.devclass = "159" + mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data) + + # Send connect stream from "bot" + test_data = "".encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + # Expect 2 calls to send + assert mock_send.call_count == 2 + # Server opens stream + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) + # Server tells client binds assert ( mock_send.mock_calls[1].args[0] == '' @@ -77,3 +211,165 @@ async def test_bot_init(*args, **kwargs): # Reset mock calls mock_send.reset_mock() + # Send bind from "bot" + test_data = "atom".encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + assert ( + mock_send.mock_calls[0].args[0] + == 'E0000000000000001234@159.ecorobot.net/atom' + ) # Bot successfully binded + assert xmppclient.state == xmppclient.BIND # Bot moved to BIND state + + # Reset mock calls + mock_send.reset_mock() + + # Send set session from bot + test_data = "".encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + assert xmppclient.state == xmppclient.READY # Bot moved to READY state + assert ( + mock_send.mock_calls[0].args[0] == '' + ) # Bot ready + + # Reset mock calls + mock_send.reset_mock() + + # Send presense from bot + test_data = "hello world".encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + assert ( + mock_send.mock_calls[0].args[0] + == ' dummy ' + ) # bot presence - dummy response + + +async def test_ping_server(*args, **kwargs): + test_transport = asyncio.Transport() + test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) + test_transport.write = mock.Mock(return_value=return_send_data) + xmppclient = bumper.xmppserver.XMPPAsyncClient(test_transport) + xmppclient.state = xmppclient.READY # Set client state to READY + xmppclient.uid = "E0000000000000001234" + xmppclient.devclass = "159" + mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data) + + # Ping from bot + test_data = ''.encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) # ping response + + +async def test_ping_client_to_client(*args, **kwargs): + + test_transport = asyncio.Transport() + test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) + test_transport.write = mock.Mock(return_value=return_send_data) + xmppclient = bumper.xmppserver.XMPPAsyncClient(test_transport) + xmppclient.state = xmppclient.READY # Set client state to READY + xmppclient.uid = "E0000000000000001234" + xmppclient.devclass = "159" + xmppclient.bumper_jid = "E0000000000000001234@159.ecorobot.net/atom" + mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data) + + xmppclient2 = bumper.xmppserver.XMPPAsyncClient(test_transport) + xmppclient2.state = xmppclient.READY # Set client state to READY + xmppclient2.uid = "fuid_tmpuser" + xmppclient2.resource = "IOSF53D07BA" + xmppclient2.bumper_jid = "fuid_tmpuser@ecouser.net/IOSF53D07BA" + mock_send2 = xmppclient2.send = mock.Mock(side_effect=return_send_data) + + bumper.xmppserver.XMPPServer.clients.append(xmppclient) + bumper.xmppserver.XMPPServer.clients.append(xmppclient2) + + # Ping from user to bot + test_data = ''.encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + # Ping response from bot to user + test_data = "".encode( + "utf-8" + ) + xmppclient2._parse_data(test_data) + + +async def test_client_send_iq(*args, **kwargs): + test_transport = asyncio.Transport() + test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) + test_transport.write = mock.Mock(return_value=return_send_data) + xmppclient = bumper.xmppserver.XMPPAsyncClient(test_transport) + xmppclient.state = xmppclient.READY # Set client state to READY + xmppclient.uid = "fuid_tmpuser" + xmppclient.resource = "IOSF53D07BA" + xmppclient.bumper_jid = "fuid_tmpuser@ecouser.net/IOSF53D07BA" + xmppclient.type - xmppclient.CONTROLLER + mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data) + bumper.xmppserver.XMPPServer.clients.append(xmppclient) + + xmppclient2 = bumper.xmppserver.XMPPAsyncClient(test_transport) + xmppclient2.state = xmppclient.READY # Set client state to READY + xmppclient2.uid = "E0000000000000001234" + xmppclient2.devclass = "159" + xmppclient2.bumper_jid = "E0000000000000001234@159.ecorobot.net/atom" + xmppclient2.type = xmppclient2.BOT + mock_send2 = xmppclient2.send = mock.Mock(side_effect=return_send_data) + + bumper.xmppserver.XMPPServer.clients.append(xmppclient2) + + # Roster IQ - Only seen from Android app so far + test_data = ''.encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) # ping response + + # Reset mock calls + mock_send.reset_mock() + + # Bot Command + test_data = ''.encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + assert ( + mock_send2.mock_calls[0].args[0] + == '' + ) # command was sent to bot + + # Reset mock calls + mock_send.reset_mock() + + # Bot response to query + test_data = ''.encode( + "utf-8" + ) + xmppclient2._parse_data(test_data) + + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) # result sent to client + + # Reset mock calls + mock_send.reset_mock() From 3060e7db20b6b453b9013834e5e185c1e9404311 Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Mon, 3 Jun 2019 16:41:52 -0400 Subject: [PATCH 5/9] remove iq auth Remove old iq auth that is replaced by sasl --- bumper/xmppserver.py | 102 +------------------------ tests/test_xmppserver.py | 156 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 155 insertions(+), 103 deletions(-) diff --git a/bumper/xmppserver.py b/bumper/xmppserver.py index f012f6f..0dabdc9 100644 --- a/bumper/xmppserver.py +++ b/bumper/xmppserver.py @@ -402,22 +402,20 @@ class XMPPAsyncClient: if self.TLSUpgraded == False: # With STARTTLS #https://xmpp.org/rfcs/rfc3920.html self.send( - 'PLAIN' + 'PLAIN' ) else: - # Already using TLS send authentication support for iq-auth (fallback) and SASL + # Already using TLS send authentication support for SASL self.send( - 'PLAIN' + 'PLAIN' ) else: self.send("") else: - if "jabber:iq:auth" in xml.tag: # Handle iq-auth - self._handle_iq_auth(xml) - elif ( + if ( "urn:ietf:params:xml:ns:xmpp-sasl" in xml.tag ): # Handle SASL Auth self._handle_sasl_auth(xml) @@ -486,98 +484,6 @@ class XMPPAsyncClient: except Exception as e: xmppserverlog.exception("{}".format(e)) - def _handle_iq_auth(self, data): - try: - xml = ET.fromstring(data.decode("utf-8")) - ctl = xml[0][0] - xmppserverlog.info("IQ AUTH XML: {}".format(xml)) - # Received username and auth tag, send username/password requirement - if ( - xml.get("type") == "get" - and "auth}username" in ctl.tag - and self.type == self.UNKNOWN - ): - self.send( - ''.format( - xml.get("id") - ) - ) - - # Received username, password, resource - Handle auth here and return pass or fail - if ( - xml.get("type") == "set" - and "auth}username" in ctl.tag - and self.type == self.UNKNOWN - ): - xmlauth = xml[0].getchildren() - # uid = "" - password = "" - authcode = "" - resource = "" - for aitem in xmlauth: - if "username" in aitem.tag: - self.uid = aitem.text - - elif "password" in aitem.tag: - password = aitem.text.split("/")[2] - authcode = password - - elif "resource" in aitem.tag: - self.clientresource = aitem.text - resource = self.clientresource - - if self.devclass: # if there is a devclass it is a bot - bumper.bot_add("", self.uid, "", resource, "eco-legacy") - xmppserverlog.debug("bot authenticated {}".format(self.uid)) - - # Client authenticated, move to next state - self._set_state("INIT") - - # Successful auth - self.send(''.format(xml.get("id"))) - - else: - auth = False - if bumper.check_authcode(self.uid, authcode): - auth = True - elif bumper.use_auth == False: - auth = True - - if auth: - bumper.client_add(self.uid, "bumper", self.clientresource) - xmppserverlog.debug("client authenticated {}".format(self.uid)) - - # Client authenticated, move to next state - self._set_state("INIT") - - # Successful auth - self.send(''.format(xml.get("id"))) - - else: - # Failed auth - self.send( - ''.format( - xml.get("id") - ) - ) - - except ET.ParseError as e: - if "no element found" in e.msg: - xmppserverlog.debug( - "xml parse error - {} - {}".format(data.decode("utf-8"), e) - ) - elif "not well-formed (invalid token)" in e.msg: - xmppserverlog.debug( - "xml parse error - {} - {}".format(data.decode("utf-8"), e) - ) - else: - xmppserverlog.debug( - "xml parse error - {} - {}".format(data.decode("utf-8"), e) - ) - - except Exception as e: - xmppserverlog.exception("{}".format(e)) - def _handle_sasl_auth(self, xml): try: diff --git a/tests/test_xmppserver.py b/tests/test_xmppserver.py index 95fa8e1..e56fdcf 100644 --- a/tests/test_xmppserver.py +++ b/tests/test_xmppserver.py @@ -41,7 +41,7 @@ async def test_client_connect_no_starttls(*args, **kwargs): # Server tells client available features assert ( mock_send.mock_calls[1].args[0] - == 'PLAIN' + == 'PLAIN' ) # Reset mock calls @@ -60,6 +60,38 @@ async def test_client_connect_no_starttls(*args, **kwargs): assert xmppclient.state == xmppclient.INIT # Client moved to INIT state +async def test_client_end_stream(*args, **kwargs): + test_transport = asyncio.Transport() + test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) + test_transport.write = mock.Mock(return_value=return_send_data) + xmppclient = bumper.xmppserver.XMPPAsyncClient(test_transport) + xmppclient.state = xmppclient.CONNECT # Set client state to CONNECT + mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data) + + # Send end stream from "client" + test_data = "".encode("utf-8") + xmppclient._parse_data(test_data) + + # Expect 2 calls to send + assert mock_send.call_count == 1 + # Server opens stream + assert mock_send.mock_calls[0].args[0] == "" + + # Reset mock calls + mock_send.reset_mock() + + # Send abnormal stream from "client" + test_data = "".encode("utf-8") + xmppclient._parse_data(test_data) + + # Reset mock calls + mock_send.reset_mock() + + # Send blank from "client" + test_data = "".encode("utf-8") + xmppclient._parse_data(test_data) + + async def test_client_connect_starttls_called(*args, **kwargs): test_transport = asyncio.Transport() test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) @@ -84,7 +116,7 @@ async def test_client_connect_starttls_called(*args, **kwargs): # Server tells client available features assert ( mock_send.mock_calls[1].args[0] - == 'PLAIN' + == 'PLAIN' ) # Reset mock calls @@ -117,7 +149,7 @@ async def test_client_connect_starttls_called(*args, **kwargs): # Server tells client available features (without STARTTLS) assert ( mock_send.mock_calls[1].args[0] - == 'PLAIN' + == 'PLAIN' ) # Reset mock calls mock_send.reset_mock() @@ -135,6 +167,80 @@ async def test_client_connect_starttls_called(*args, **kwargs): assert xmppclient.state == xmppclient.INIT # Client moved to INIT state +async def test_client_init(*args, **kwargs): + test_transport = asyncio.Transport() + test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) + test_transport.write = mock.Mock(return_value=return_send_data) + xmppclient = bumper.xmppserver.XMPPAsyncClient(test_transport) + xmppclient.state = xmppclient.INIT # Set client state to INIT + xmppclient.uid = "fuid_tmpuser" + xmppclient.resource = "IOSF53D07BA" + xmppclient.bumper_jid = "fuid_tmpuser@ecouser.net/IOSF53D07BA" + xmppclient.type = xmppclient.CONTROLLER + mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data) + + # Send connect stream from "client" + test_data = "".encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + # Expect 2 calls to send + assert mock_send.call_count == 2 + # Server opens stream + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) + # Server tells client binds + assert ( + mock_send.mock_calls[1].args[0] + == '' + ) + + # Reset mock calls + mock_send.reset_mock() + + # Send bind from "client" + test_data = 'IOSF53D07BA'.encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + assert ( + mock_send.mock_calls[0].args[0] + == 'fuid_tmpuser@ecouser.net/IOSF53D07BA' + ) # client successfully binded + assert xmppclient.state == xmppclient.BIND # client moved to BIND state + + # Reset mock calls + mock_send.reset_mock() + + # Send set session from client + test_data = ''.encode( + "utf-8" + ) + xmppclient._parse_data(test_data) + + assert xmppclient.state == xmppclient.READY # client moved to READY state + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) # client ready + + # Reset mock calls + mock_send.reset_mock() + + # Send presense from client + test_data = ''.encode("utf-8") + xmppclient._parse_data(test_data) + + assert ( + mock_send.mock_calls[0].args[0] + == ' dummy ' + ) # client presence - dummy response + + async def test_bot_connect(*args, **kwargs): test_transport = asyncio.Transport() test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) @@ -159,7 +265,7 @@ async def test_bot_connect(*args, **kwargs): # Server tells client available features assert ( mock_send.mock_calls[1].args[0] - == 'PLAIN' + == 'PLAIN' ) # Reset mock calls @@ -187,6 +293,7 @@ async def test_bot_init(*args, **kwargs): xmppclient.state = xmppclient.INIT # Set client state to INIT xmppclient.uid = "E0000000000000001234" xmppclient.devclass = "159" + xmppclient.type = xmppclient.BOT mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data) # Send connect stream from "bot" @@ -302,12 +409,22 @@ async def test_ping_client_to_client(*args, **kwargs): ) xmppclient._parse_data(test_data) + assert ( + mock_send2.mock_calls[0].args[0] + == '' + ) # ping response + # Ping response from bot to user test_data = "".encode( "utf-8" ) xmppclient2._parse_data(test_data) + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) # ping response + async def test_client_send_iq(*args, **kwargs): test_transport = asyncio.Transport() @@ -341,7 +458,7 @@ async def test_client_send_iq(*args, **kwargs): assert ( mock_send.mock_calls[0].args[0] == '' - ) # ping response + ) # feature not implemented response # Reset mock calls mock_send.reset_mock() @@ -373,3 +490,32 @@ async def test_client_send_iq(*args, **kwargs): # Reset mock calls mock_send.reset_mock() + + # Bot result + test_data = "".encode( + "utf-8" + ) + xmppclient2._parse_data(test_data) + + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) # result sent to ecouser.net + + # Reset mock calls + mock_send.reset_mock() + + # Bot iq set + test_data = "".encode( + "utf-8" + ) + xmppclient2._parse_data(test_data) + + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) # result sent to ecouser.net + + # Reset mock calls + mock_send.reset_mock() + From 0cb5c0b4f32436858e4fb0b97aacf311f084dd59 Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Tue, 4 Jun 2019 09:57:45 -0400 Subject: [PATCH 6/9] add test_mqttserver.py add test_mqttserver.py --- Pipfile | 1 + Pipfile.lock | 30 +++++++-- tests/test_mqttserver.py | 129 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 tests/test_mqttserver.py diff --git a/Pipfile b/Pipfile index aafbc10..9489286 100644 --- a/Pipfile +++ b/Pipfile @@ -18,6 +18,7 @@ pbr = "*" pytest-asyncio = "*" pytest-aiohttp = "*" pytest-cov = "*" +testfixtures = "*" [pipenv] allow_prereleases = true diff --git a/Pipfile.lock b/Pipfile.lock index b7c6c8b..44933a8 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "89b1dc5fde60f217d24d1b66c94fa5640ca23925420992a2c14718f61866dc61" + "sha256": "ce534b7ec3bc05783e99636abeb05165298c96698d1c6e1288595a1d3174168b" }, "pipfile-spec": 6, "requires": {}, @@ -427,6 +427,13 @@ ], "version": "==4.5.2" }, + "packaging": { + "hashes": [ + "sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af", + "sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3" + ], + "version": "==19.0" + }, "pbr": { "hashes": [ "sha256:0ce920b865091450bbcd452b35cf6d6eb8a6d9ce13ad2210d6e77557f85cf32b", @@ -457,12 +464,19 @@ "index": "pypi", "version": "==2.3.1" }, + "pyparsing": { + "hashes": [ + "sha256:1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a", + "sha256:9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03" + ], + "version": "==2.4.0" + }, "pytest": { "hashes": [ - "sha256:1a8aa4fa958f8f451ac5441f3ac130d9fc86ea38780dd2715e6d5c5882700b24", - "sha256:b8bf138592384bd4e87338cb0f256bf5f615398a649d4bd83915f0e4047a5ca6" + "sha256:6032845e68a17a96e8da3088037f899b56357769a724122056265ca2ea1890ee", + "sha256:bea27a646a3d74cbbcf8d3d4a06b2dfc336baf3dc2cc85cf70ad0157e73e8322" ], - "version": "==4.5.0" + "version": "==4.6.2" }, "pytest-aiohttp": { "hashes": [ @@ -495,6 +509,14 @@ ], "version": "==1.12.0" }, + "testfixtures": { + "hashes": [ + "sha256:819e9090bf3cce5dfaf56817f55ede76b3ae490ad0e9ffe3060a6618d11894c3", + "sha256:a6e95634a80bd6e5adc7e861729f4abd84433e91b4215d48a2098a096c0261b7" + ], + "index": "pypi", + "version": "==6.8.2" + }, "toml": { "hashes": [ "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", diff --git a/tests/test_mqttserver.py b/tests/test_mqttserver.py new file mode 100644 index 0000000..d4e5f55 --- /dev/null +++ b/tests/test_mqttserver.py @@ -0,0 +1,129 @@ +import mock +import bumper +import asyncio +import pytest +import os +import json +import tinydb +import pytest_asyncio +import xml.etree.ElementTree as ET +import hbmqtt +import logging +from testfixtures import LogCapture + + +async def test_helperbot_message(): + with LogCapture("helperbot") as l: + mqtt_address = ("127.0.0.1", 8883) + mqtt_server = bumper.MQTTServer(mqtt_address) + broker = hbmqtt.broker.Broker( + mqtt_server.default_config, plugin_namespace="hbmqtt.test.plugins" + ) + await broker.start() + + # Test broadcast message + mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) + await mqtt_helperbot.start_helper_bot() + assert ( + mqtt_helperbot.Client._connected_state._value == True + ) # Check helperbot is connected + msg_payload = "" + msg_topic_name = "iot/atr/DustCaseST/bot_serial/ls1ok3/wC3g/x" + await mqtt_helperbot.Client.publish( + msg_topic_name, msg_payload.encode(), hbmqtt.client.QOS_0 + ) + try: + await asyncio.wait_for(mqtt_helperbot.Client.deliver_message(), timeout=0.1) + except asyncio.TimeoutError: + pass + l.check_present( + ( + "helperbot", + "DEBUG", + "Received Broadcast - Topic: iot/atr/DustCaseST/bot_serial/ls1ok3/wC3g/x - Message: ", + ) + ) # Check broadcast message was logged + l.clear() + mqtt_helperbot.Client.disconnect() + + # Send command to bot + mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) + await mqtt_helperbot.start_helper_bot() + assert ( + mqtt_helperbot.Client._connected_state._value == True + ) # Check helperbot is connected + msg_payload = "{}" + msg_topic_name = ( + "iot/p2p/GetWKVer/helper1/bumper/helper1/bot_serial/ls1ok3/wC3g/q/iCmuqp/j" + ) + await mqtt_helperbot.Client.publish( + msg_topic_name, msg_payload.encode(), hbmqtt.client.QOS_0 + ) + try: + await asyncio.wait_for(mqtt_helperbot.Client.deliver_message(), timeout=0.1) + except asyncio.TimeoutError: + pass + l.check_present( + ( + "helperbot", + "DEBUG", + "Send Command - Topic: iot/p2p/GetWKVer/helper1/bumper/helper1/bot_serial/ls1ok3/wC3g/q/iCmuqp/j - Message: {}", + ) + ) # Check send command message was logged + l.clear() + mqtt_helperbot.Client.disconnect() + + # Received response to command + mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) + await mqtt_helperbot.start_helper_bot() + assert ( + mqtt_helperbot.Client._connected_state._value == True + ) # Check helperbot is connected + msg_payload = '{"ret":"ok","ver":"0.13.5"}' + msg_topic_name = ( + "iot/p2p/GetWKVer/bot_serial/ls1ok3/wC3g/helper1/bumper/helper1/p/iCmuqp/j" + ) + await mqtt_helperbot.Client.publish( + msg_topic_name, msg_payload.encode(), hbmqtt.client.QOS_0 + ) + try: + await asyncio.wait_for(mqtt_helperbot.Client.deliver_message(), timeout=0.1) + except asyncio.TimeoutError: + pass + l.check_present( + ( + "helperbot", + "DEBUG", + 'Received Response - Topic: iot/p2p/GetWKVer/bot_serial/ls1ok3/wC3g/helper1/bumper/helper1/p/iCmuqp/j - Message: {"ret":"ok","ver":"0.13.5"}', + ) + ) # Check received response message was logged + l.clear() + mqtt_helperbot.Client.disconnect() + + # Received unknown message + mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) + await mqtt_helperbot.start_helper_bot() + assert ( + mqtt_helperbot.Client._connected_state._value == True + ) # Check helperbot is connected + msg_payload = 'test' + msg_topic_name = ( + "iot/p2p/GetWKVer/bot_serial/ls1ok3/wC3g/TESTBAD/bumper/helper1/p/iCmuqp/j" + ) + await mqtt_helperbot.Client.publish( + msg_topic_name, msg_payload.encode(), hbmqtt.client.QOS_0 + ) + try: + await asyncio.wait_for(mqtt_helperbot.Client.deliver_message(), timeout=0.1) + except asyncio.TimeoutError: + pass + l.check_present( + ( + "helperbot", + "DEBUG", + 'Received Message - Topic: iot/p2p/GetWKVer/bot_serial/ls1ok3/wC3g/TESTBAD/bumper/helper1/p/iCmuqp/j - Message: test', + ) + ) # Check received message was logged + l.clear() + mqtt_helperbot.Client.disconnect() + await broker.shutdown() \ No newline at end of file From 105f0ad63232b322bf169a573449daac116b667c Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Tue, 4 Jun 2019 17:29:39 -0400 Subject: [PATCH 7/9] more mqtt tests more mqtt tests --- bumper/mqttserver.py | 20 ++- tests/test_mqttserver.py | 257 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 264 insertions(+), 13 deletions(-) diff --git a/bumper/mqttserver.py b/bumper/mqttserver.py index 83c3c9e..4edaca7 100644 --- a/bumper/mqttserver.py +++ b/bumper/mqttserver.py @@ -33,6 +33,8 @@ logging.getLogger("hbmqtt.client").setLevel(logging.CRITICAL + 1) # Ignore this class MQTTHelperBot: Client = MQTTClient() + wait_resp_timeout_seconds = 10 + expire_msg_seconds = 10 def __init__(self, address): self.address = address @@ -105,12 +107,13 @@ class MQTTHelperBot: # Cleanup "expired messages" > 60 seconds from time for msg in self.command_responses: expire_time = ( - datetime.fromtimestamp(msg["time"]) + timedelta(seconds=10) + datetime.fromtimestamp(msg["time"]) + + timedelta(seconds=self.expire_msg_seconds) ).timestamp() if time.time() > expire_time: helperbotlog.debug( - "Pruning Message Time: {}, MsgTime: {}, MsgTime+60: {}".format( - time.time(), msg["time"], expire_time + "Pruning Message Due To Expiration - Message Topic: {}".format( + msg["topic"] ) ) self.command_responses.remove(msg) @@ -118,7 +121,9 @@ class MQTTHelperBot: async def wait_for_resp(self, requestid): try: - t_end = (datetime.now() + timedelta(seconds=10)).timestamp() + t_end = ( + datetime.now() + timedelta(seconds=self.wait_resp_timeout_seconds) + ).timestamp() while time.time() < t_end: await asyncio.sleep(0.1) @@ -186,14 +191,15 @@ class MQTTHelperBot: class MQTTServer: default_config = {} + broker = None async def broker_coro(self): try: mqttserverlog.info( "Starting MQTT Server at {}:{}".format(self.address[0], self.address[1]) ) - broker = hbmqtt.broker.Broker(config=self.default_config) - await broker.start() + self.broker = hbmqtt.broker.Broker(config=self.default_config) + await self.broker.start() except PermissionError as e: if "bind" in e.strerror: @@ -360,12 +366,14 @@ class BumperMQTTServer_Plugin: bot = bumper.bot_get(didsplit[0]) if bot: bumper.bot_set_mqtt(bot["did"], False) + return # clientuserid = didsplit[0] clientresource = didsplit[1].split("/")[1] client = bumper.client_get(clientresource) if client: bumper.client_set_mqtt(client["resource"], False) + return except Exception as e: mqttserverlog.exception("{}".format(e)) diff --git a/tests/test_mqttserver.py b/tests/test_mqttserver.py index d4e5f55..848ed09 100644 --- a/tests/test_mqttserver.py +++ b/tests/test_mqttserver.py @@ -10,16 +10,21 @@ import xml.etree.ElementTree as ET import hbmqtt import logging from testfixtures import LogCapture +import time async def test_helperbot_message(): with LogCapture("helperbot") as l: mqtt_address = ("127.0.0.1", 8883) mqtt_server = bumper.MQTTServer(mqtt_address) - broker = hbmqtt.broker.Broker( - mqtt_server.default_config, plugin_namespace="hbmqtt.test.plugins" - ) - await broker.start() + await mqtt_server.broker_coro() + #broker = mqtt_server.broker + #mqtt_address = ("127.0.0.1", 8883) + #mqtt_server = bumper.MQTTServer(mqtt_address) + #broker = hbmqtt.broker.Broker( + # mqtt_server.default_config, plugin_namespace="hbmqtt.test.plugins" + #) + #await broker.start() # Test broadcast message mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) @@ -106,7 +111,7 @@ async def test_helperbot_message(): assert ( mqtt_helperbot.Client._connected_state._value == True ) # Check helperbot is connected - msg_payload = 'test' + msg_payload = "test" msg_topic_name = ( "iot/p2p/GetWKVer/bot_serial/ls1ok3/wC3g/TESTBAD/bumper/helper1/p/iCmuqp/j" ) @@ -117,13 +122,251 @@ async def test_helperbot_message(): await asyncio.wait_for(mqtt_helperbot.Client.deliver_message(), timeout=0.1) except asyncio.TimeoutError: pass + l.check_present( ( "helperbot", "DEBUG", - 'Received Message - Topic: iot/p2p/GetWKVer/bot_serial/ls1ok3/wC3g/TESTBAD/bumper/helper1/p/iCmuqp/j - Message: test', + "Received Message - Topic: iot/p2p/GetWKVer/bot_serial/ls1ok3/wC3g/TESTBAD/bumper/helper1/p/iCmuqp/j - Message: test", ) ) # Check received message was logged l.clear() mqtt_helperbot.Client.disconnect() - await broker.shutdown() \ No newline at end of file + await mqtt_server.broker.shutdown() + + +async def test_helperbot_expire_message(): + with LogCapture("helperbot") as l: + mqtt_address = ("127.0.0.1", 8883) + mqtt_server = bumper.MQTTServer(mqtt_address) + await mqtt_server.broker_coro() + #mqtt_address = ("127.0.0.1", 8883) + #mqtt_server = bumper.MQTTServer(mqtt_address) + #broker = hbmqtt.broker.Broker( + # mqtt_server.default_config, plugin_namespace="hbmqtt.test.plugins" + #) + #await broker.start() + + # Test broadcast message + mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) + await mqtt_helperbot.start_helper_bot() + assert ( + mqtt_helperbot.Client._connected_state._value == True + ) # Check helperbot is connected + + expire_msg_payload = '{"ret":"ok","ver":"0.13.5"}' + expire_msg_topic_name = "iot/p2p/GetWKVer/bot_serial/ls1ok3/wC3g/helper1/bumper/helper1/p/testgood/j" + currenttime = time.time() + mqtt_helperbot.command_responses.append( + { + "time": currenttime, + "topic": expire_msg_topic_name, + "payload": expire_msg_payload, + } + ) + + assert { + "time": currenttime, + "topic": expire_msg_topic_name, + "payload": expire_msg_payload, + } in mqtt_helperbot.command_responses # check message is in command_responses + + await asyncio.sleep(0.2) + mqtt_helperbot.expire_msg_seconds = ( + 0.1 + ) # Set expire message seconds to 0.1 so we don't wait 10 seconds + msg_payload = "" + msg_topic_name = "iot/atr/DustCaseST/bot_serial/ls1ok3/wC3g/x" + await mqtt_helperbot.Client.publish( + msg_topic_name, msg_payload.encode(), hbmqtt.client.QOS_0 + ) # Send another message to force get_msg + + try: + await asyncio.wait_for(mqtt_helperbot.Client.deliver_message(), timeout=0.1) + except asyncio.TimeoutError: + pass + + assert { + "time": currenttime, + "topic": expire_msg_topic_name, + "payload": expire_msg_payload, + } not in mqtt_helperbot.command_responses # check message was expired and removed from command_responses + + l.check_present( + ( + "helperbot", + "DEBUG", + "Pruning Message Due To Expiration - Message Topic: {}".format( + expire_msg_topic_name + ), + ) + ) # Check received message was logged + mqtt_helperbot.Client.disconnect() + await mqtt_server.broker.shutdown() + + +async def test_helperbot_sendcommand(): + mqtt_address = ("127.0.0.1", 8883) + mqtt_server = bumper.MQTTServer(mqtt_address) + await mqtt_server.broker_coro() + #mqtt_address = ("127.0.0.1", 8883) + #mqtt_server = bumper.MQTTServer(mqtt_address) + #broker = hbmqtt.broker.Broker( + # mqtt_server.default_config, plugin_namespace="hbmqtt.test.plugins" + #) + #await broker.start() + + mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) + await mqtt_helperbot.start_helper_bot() + assert ( + mqtt_helperbot.Client._connected_state._value == True + ) # Check helperbot is connected + + cmdjson = { + "toType": "ls1ok3", + "payloadType": "j", + "toRes": "wC3g", + "payload": {}, + "td": "q", + "toId": "bot_serial", + "cmdName": "GetWKVer", + "auth": { + "token": "us_52cb21fef8e547f38f4ec9a699a5d77e", + "resource": "IOSF53D07BA", + "userid": "fuid_tmpuser", + "with": "users", + "realm": "ecouser.net", + }, + } + mqtt_helperbot.wait_resp_timeout_seconds = ( + 0.1 + ) # Override wait_resp_timeout (so we don't wait 10 seconds for timeout) + commandresult = await mqtt_helperbot.send_command(cmdjson, "testfail") + # Don't send a response, ensure timeout + assert commandresult == { + "debug": "wait for response timed out", + "errno": 500, + "id": "testfail", + "ret": "fail", + } # Check timeout + + mqtt_helperbot.wait_resp_timeout_seconds = ( + 0.2 + ) # Override wait_resp_timeout (so we don't wait 10 seconds for timeout) + # Send response beforehand + msg_payload = '{"ret":"ok","ver":"0.13.5"}' + msg_topic_name = ( + "iot/p2p/GetWKVer/bot_serial/ls1ok3/wC3g/helper1/bumper/helper1/p/testgood/j" + ) + await mqtt_helperbot.Client.publish( + msg_topic_name, msg_payload.encode(), hbmqtt.client.QOS_0 + ) + + commandresult = await mqtt_helperbot.send_command(cmdjson, "testgood") + assert commandresult == { + "id": "testgood", + "resp": {"ret": "ok", "ver": "0.13.5"}, + "ret": "ok", + } + + mqtt_helperbot.Client.disconnect() + + cmdjson = { + "toType": "ls1ok3", + "payloadType": "x", + "toRes": "wC3g", + "payload": '', + "td": "q", + "toId": "bot_serial", + "cmdName": "GetLifeSpan", + "auth": { + "token": "us_52cb21fef8e547f38f4ec9a699a5d77e", + "resource": "IOSF53D07BA", + "userid": "fuid_tmpuser", + "with": "users", + "realm": "ecouser.net", + }, + } + + mqtt_helperbot.wait_resp_timeout_seconds = ( + 0.2 + ) # Override wait_resp_timeout (so we don't wait 10 seconds for timeout) + # Send response beforehand + msg_payload = ( + "{'id': 'testx', 'ret': 'ok', 'resp': " + "" + "}" + ) + msg_topic_name = ( + "iot/p2p/GetLifeSpan/bot_serial/ls1ok3/wC3g/helper1/bumper/helper1/p/testx/q" + ) + await mqtt_helperbot.Client.publish( + msg_topic_name, msg_payload.encode(), hbmqtt.client.QOS_0 + ) + + commandresult = await mqtt_helperbot.send_command(cmdjson, "testx") + assert commandresult == { + "id": "testx", + "resp": "{'id': 'testx', 'ret': 'ok', 'resp': }", + "ret": "ok", + } + + mqtt_helperbot.Client.disconnect() + + await mqtt_server.broker.shutdown() + + +async def test_mqttserver(): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + + bumper.db = "tests/tmp.db" # Set db location for testing + + mqtt_address = ("127.0.0.1", 8883) + + mqtt_server = bumper.MQTTServer(mqtt_address) + await mqtt_server.broker_coro() + + # Test helperbot connect + mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) + await mqtt_helperbot.start_helper_bot() + assert ( + mqtt_helperbot.Client._connected_state._value == True + ) # Check helperbot is connected + await mqtt_helperbot.Client.disconnect() + + # Test client connect + bumper.user_add("user_123") # Add user to db + bumper.client_add("user_123", "ecouser.net", "resource_123") # Add client to db + test_client = bumper.MQTTHelperBot(mqtt_address) + test_client.client_id = "user_123@ecouser.net/resource_123" + # await test_client.start_helper_bot() + test_client.Client = hbmqtt.client.MQTTClient( + client_id=test_client.client_id, config={"check_hostname": False} + ) + + await test_client.Client.connect( + "mqtts://{}:{}/".format(test_client.address[0], test_client.address[1]), + cafile=bumper.ca_cert, + ) + assert ( + test_client.Client._connected_state._value == True + ) # Check client is connected + await test_client.Client.disconnect() + assert ( + test_client.Client._connected_state._value == False + ) # Check client is disconnected + + # Test fake_bot connect + fake_bot = bumper.MQTTHelperBot(mqtt_address) + fake_bot.client_id = "bot_serial@ls1ok3/wC3g" + await fake_bot.start_helper_bot() + assert ( + fake_bot.Client._connected_state._value == True + ) # Check fake_bot is connected + await fake_bot.Client.disconnect() + + await mqtt_helperbot.Client.reconnect() # This forces the above disconnect + + + await mqtt_server.broker.shutdown() \ No newline at end of file From 2a4c369d58d7c066a0fcdad01783656c3618662e Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Tue, 4 Jun 2019 22:20:11 -0400 Subject: [PATCH 8/9] add more xmpp tests - test xmpp server - test starttls upgrade --- bumper/xmppserver.py | 7 +-- tests/test_mqttserver.py | 3 +- tests/test_xmppserver.py | 103 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 107 insertions(+), 6 deletions(-) diff --git a/bumper/xmppserver.py b/bumper/xmppserver.py index 0dabdc9..453de22 100644 --- a/bumper/xmppserver.py +++ b/bumper/xmppserver.py @@ -14,6 +14,7 @@ class XMPPServer: server_id = "ecouser.net" clients = [] exit_flag = False + server = None def __init__(self, address): # Initialize bot server @@ -27,12 +28,11 @@ class XMPPServer: loop = asyncio.get_running_loop() - server = await loop.create_server( + self.server = await loop.create_server( self.xmpp_protocol, host=self.address[0], port=self.address[1] ) - async with server: - await server.serve_forever() + self.server_coro = loop.create_task(self.server.serve_forever()) def disconnect(self): try: @@ -42,6 +42,7 @@ class XMPPServer: self.exit_flag = True xmppserverlog.debug("shutting down") + self.server_coro.cancel() except Exception as e: xmppserverlog.error("{}".format(e)) diff --git a/tests/test_mqttserver.py b/tests/test_mqttserver.py index 848ed09..24ef16f 100644 --- a/tests/test_mqttserver.py +++ b/tests/test_mqttserver.py @@ -365,8 +365,7 @@ async def test_mqttserver(): fake_bot.Client._connected_state._value == True ) # Check fake_bot is connected await fake_bot.Client.disconnect() - - await mqtt_helperbot.Client.reconnect() # This forces the above disconnect + await asyncio.sleep(0.1) await mqtt_server.broker.shutdown() \ No newline at end of file diff --git a/tests/test_xmppserver.py b/tests/test_xmppserver.py index e56fdcf..6ed558a 100644 --- a/tests/test_xmppserver.py +++ b/tests/test_xmppserver.py @@ -7,6 +7,9 @@ import json import tinydb import pytest_asyncio import xml.etree.ElementTree as ET +import socket +from testfixtures import LogCapture +import ssl def return_send_data(data, *args, **kwargs): @@ -14,7 +17,45 @@ def return_send_data(data, *args, **kwargs): def mock_transport_extra_info(*args, **kwargs): - return ("127.0.0.1", 1234) + return ("127.0.0.1", 5223) + + +async def test_xmpp_server(): + with LogCapture("xmppserver") as l: + xmpp_address = ("127.0.0.1", 5223) + xmpp_server = bumper.XMPPServer(xmpp_address) + await xmpp_server.start_async_server() + + reader, writer = await asyncio.open_connection("127.0.0.1", 5223) + + writer.write(b"") # Start stream + await writer.drain() + + await asyncio.sleep(0.1) + + assert len(xmpp_server.clients) == 1 # Client count increased + assert ( + xmpp_server.clients[0].address[1] + == writer.transport.get_extra_info("sockname")[1] + ) + + writer.close() # Close connection + await writer.wait_closed() + + await asyncio.sleep(0.1) + + assert len(xmpp_server.clients) == 0 # Client count decreased + + reader, writer = await asyncio.open_connection("127.0.0.1", 5223) + + writer.write(b"") # Start stream + await writer.drain() + + await asyncio.sleep(0.1) + xmpp_server.disconnect() + await asyncio.sleep(0.1) + assert len(xmpp_server.clients) == 0 # Client count decreased + print(l) async def test_client_connect_no_starttls(*args, **kwargs): @@ -167,6 +208,66 @@ async def test_client_connect_starttls_called(*args, **kwargs): assert xmppclient.state == xmppclient.INIT # Client moved to INIT state +async def test_xmpp_server_client_tls(): + with LogCapture("xmppserver") as l: + + async def do_stuff_after_start_tls( + ssl_reader, ssl_writer + ): # Used after starttls + + writer.write( + b"" + ) # New Stream + + await writer.drain() + + await asyncio.sleep(0.1) + + writer.write( + b'AGZ1aWRfdG1wdXNlcgAwL0lPU0Y1M0QwN0JBL3VzXzg5ODgwMmZkYmM0NDQxYjBiYzgxNWIxZDFjNjgzMDJl' + ) # Send Auth + + await writer.drain() + + await asyncio.sleep(0.1) + + xmpp_address = ("127.0.0.1", 5223) + xmpp_server = bumper.XMPPServer(xmpp_address) + await xmpp_server.start_async_server() + + reader, writer = await asyncio.open_connection("127.0.0.1", 5223) + + writer.write( + b"" + ) # Start stream + await writer.drain() + + await asyncio.sleep(0.1) + + writer.write( + b"" + ) # Send StartTLS + await writer.drain() + + await asyncio.sleep(0.1) + + # Below will upgrade connection to TLS then callback to "do_stuff_after_start_tls" + ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) + ssl_context.check_hostname = False + ssl_context.load_verify_locations(cafile=bumper.ca_cert) + loop = asyncio.get_event_loop() + transport = writer.transport + protocol = writer.transport.get_protocol() + new_transport = await loop.start_tls( + transport, protocol, ssl_context, server_side=False + ) + protocol._stream_reader = asyncio.StreamReader(loop=loop) + protocol._client_connected_cb = do_stuff_after_start_tls + protocol.connection_made(new_transport) + + print(l) + + async def test_client_init(*args, **kwargs): test_transport = asyncio.Transport() test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info()) From 29356c984938a1d2572be1ebcc7a20b52055aeee Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Tue, 4 Jun 2019 23:46:28 -0400 Subject: [PATCH 9/9] add confserver tests add confserver tests --- bumper/confserver.py | 9 +- tests/test_confserver.py | 409 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 394 insertions(+), 24 deletions(-) diff --git a/bumper/confserver.py b/bumper/confserver.py index dc99543..5180769 100644 --- a/bumper/confserver.py +++ b/bumper/confserver.py @@ -64,11 +64,8 @@ class ConfServer: self.run_async = False self.app = None - def confserver_app(self, loop=None): - if loop: - self.app = web.Application(loop=loop) - else: - self.app = web.Application() + def confserver_app(self): + self.app = web.Application(loop=asyncio.get_event_loop()) self.app.add_routes( [ @@ -128,7 +125,7 @@ class ConfServer: "/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/message/hasUnreadMsg", self.handle_hasUnreadMessage, ), - web.get( # EcoVacs Home neng message hasUnreadMsg + web.post( # EcoVacs Home neng message hasUnreadMsg "/api/neng/message/hasUnreadMsg", self.handle_neng_hasUnreadMessage ), web.get( # EcoVacs Home message getMsgList diff --git a/tests/test_confserver.py b/tests/test_confserver.py index eae8cb1..3c85115 100644 --- a/tests/test_confserver.py +++ b/tests/test_confserver.py @@ -6,6 +6,7 @@ import os import json import tinydb import pytest_aiohttp +import pytest_asyncio from aiohttp import web @@ -15,7 +16,7 @@ def create_confserver(): def create_app(loop): confserver = bumper.ConfServer("127.0.0.1:11111", False, mock.MagicMock) - confserver.confserver_app(loop=loop) + confserver.confserver_app() return confserver.app @@ -25,6 +26,18 @@ def async_return(result): return f +async def test_confserver_ssl(): + conf_server = bumper.ConfServer(("127.0.0.1", 111111), usessl=True, helperbot=None) + conf_server.confserver_app() + asyncio.create_task(conf_server.start_server()) + + +async def test_confserver_no_ssl(): + conf_server = bumper.ConfServer(("127.0.0.1", 111111), usessl=False, helperbot=None) + conf_server.confserver_app() + asyncio.create_task(conf_server.start_server()) + + async def test_base(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db @@ -44,7 +57,21 @@ async def test_login(aiohttp_client): client = await aiohttp_client(create_app) # Test without user - resp = await client.get("/1/private/us/en/dev_1234/ios/1/0/0/user/login") + resp = await client.get("/v1/private/us/en/dev_1234/ios/1/0/0/user/login") + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + assert "accessToken" in jsonresp["data"] + assert "uid" in jsonresp["data"] + assert "username" in jsonresp["data"] + + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + + # Test global_e without user + resp = await client.get("/v1/private/us/en/dev_1234/global_e/1/0/0/user/login") assert resp.status == 200 text = await resp.text() jsonresp = json.loads(text) @@ -55,7 +82,7 @@ async def test_login(aiohttp_client): # Add a user to db and test with existing users bumper.user_add("testuser") - resp = await client.get("/1/private/us/en/dev_1234/ios/1/0/0/user/login") + resp = await client.get("/v1/private/us/en/dev_1234/ios/1/0/0/user/login") assert resp.status == 200 text = await resp.text() jsonresp = json.loads(text) @@ -66,7 +93,7 @@ async def test_login(aiohttp_client): # Add a bot to db that will be added to user bumper.bot_add("sn_123", "did_123", "dev_123", "res_123", "com_123") - resp = await client.get("/1/private/us/en/dev_1234/ios/1/0/0/user/login") + resp = await client.get("/v1/private/us/en/dev_1234/ios/1/0/0/user/login") assert resp.status == 200 text = await resp.text() jsonresp = json.loads(text) @@ -87,7 +114,7 @@ async def test_logout(aiohttp_client): bumper.user_add_device("testuser", "dev_1234") bumper.user_add_token("testuser", "token_1234") resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/user/logout?accessToken={}".format( + "/v1/private/us/en/dev_1234/ios/1/0/0/user/logout?accessToken={}".format( "token_1234" ) ) @@ -106,7 +133,7 @@ async def test_checkLogin(aiohttp_client): # Test without token resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/user/checkLogin?accessToken={}".format( + "/v1/private/us/en/dev_1234/ios/1/0/0/user/checkLogin?accessToken={}".format( None ) ) @@ -122,7 +149,23 @@ async def test_checkLogin(aiohttp_client): # Add a user to db and test with existing users bumper.user_add("testuser") resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/user/checkLogin?accessToken={}".format( + "/v1/private/us/en/dev_1234/ios/1/0/0/user/checkLogin?accessToken={}".format( + None + ) + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + assert "accessToken" in jsonresp["data"] + assert jsonresp["data"]["accessToken"] != "token_1234" + assert "uid" in jsonresp["data"] + assert "username" in jsonresp["data"] + + # Test again using global_e app + bumper.user_add("testuser") + resp = await client.get( + "/v1/private/us/en/dev_1234/global_e/1/0/0/user/checkLogin?accessToken={}".format( None ) ) @@ -143,7 +186,23 @@ async def test_checkLogin(aiohttp_client): bumper.user_add_device("testuser", "dev_1234") bumper.user_add_token("testuser", "token_1234") resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/user/checkLogin?accessToken={}".format( + "/v1/private/us/en/dev_1234/ios/1/0/0/user/checkLogin?accessToken={}".format( + "token_1234" + ) + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + assert "accessToken" in jsonresp["data"] + assert jsonresp["data"]["accessToken"] == "token_1234" + assert "uid" in jsonresp["data"] + assert "username" in jsonresp["data"] + + # Test again using global_e app + bumper.user_add("testuser") + resp = await client.get( + "/v1/private/us/en/dev_1234/global_e/1/0/0/user/checkLogin?accessToken={}".format( "token_1234" ) ) @@ -165,7 +224,7 @@ async def test_getAuthCode(aiohttp_client): # Test without user or token resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/user/getAuthCode?uid={}&accessToken={}".format( + "/v1/private/us/en/dev_1234/ios/1/0/0/user/getAuthCode?uid={}&accessToken={}".format( None, None ) ) @@ -174,12 +233,21 @@ async def test_getAuthCode(aiohttp_client): jsonresp = json.loads(text) assert jsonresp["code"] == bumper.ERR_TOKEN_INVALID + # Test as global_e + resp = await client.get( + "/v1/global/auth/getAuthCode?uid={}&deviceId={}".format(None, "dev_1234") + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.ERR_TOKEN_INVALID + # Add a token to user and test bumper.user_add("testuser") bumper.user_add_device("testuser", "dev_1234") bumper.user_add_token("testuser", "token_1234") resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/user/getAuthCode?uid={}&accessToken={}".format( + "/v1/private/us/en/dev_1234/ios/1/0/0/user/getAuthCode?uid={}&accessToken={}".format( "testuser", "token_1234" ) ) @@ -192,7 +260,7 @@ async def test_getAuthCode(aiohttp_client): # The above should have added an authcode to token, try again to test with existing authcode resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/user/getAuthCode?uid={}&accessToken={}".format( + "/v1/private/us/en/dev_1234/ios/1/0/0/user/getAuthCode?uid={}&accessToken={}".format( "testuser", "token_1234" ) ) @@ -210,7 +278,16 @@ async def test_checkAgreement(aiohttp_client): bumper.db = "tests/tmp.db" # Set db location for testing client = await aiohttp_client(create_app) - resp = await client.get("/1/private/us/en/dev_1234/ios/1/0/0/user/checkAgreement") + resp = await client.get("/v1/private/us/en/dev_1234/ios/1/0/0/user/checkAgreement") + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + + # Test as global_e + resp = await client.get( + "/v1/private/us/en/dev_1234/global_e/1/0/0/user/checkAgreement" + ) assert resp.status == 200 text = await resp.text() jsonresp = json.loads(text) @@ -224,7 +301,7 @@ async def test_homePageAlert(aiohttp_client): client = await aiohttp_client(create_app) resp = await client.get( - "/1/private/us/en/dev_1234/ios/1/0/0/campaign/homePageAlert" + "/v1/private/us/en/dev_1234/ios/1/0/0/campaign/homePageAlert" ) assert resp.status == 200 text = await resp.text() @@ -238,13 +315,156 @@ async def test_checkVersion(aiohttp_client): bumper.db = "tests/tmp.db" # Set db location for testing client = await aiohttp_client(create_app) - resp = await client.get("/1/private/us/en/dev_1234/ios/1/0/0/common/checkVersion") + resp = await client.get("/v1/private/us/en/dev_1234/ios/1/0/0/common/checkVersion") assert resp.status == 200 text = await resp.text() jsonresp = json.loads(text) assert jsonresp["code"] == bumper.RETURN_API_SUCCESS +async def test_checkAppVersion(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + client = await aiohttp_client(create_app) + + resp = await client.get( + "/v1/private/us/en/dev_1234/global_e/1/0/0/common/checkAPPVersion" + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + + +async def test_uploadDeviceInfo(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + client = await aiohttp_client(create_app) + + resp = await client.get( + "/v1/private/us/en/dev_1234/global_e/1/0/0/common/uploadDeviceInfo" + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + + +async def test_getAdByPositionType(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + client = await aiohttp_client(create_app) + + resp = await client.get( + "/v1/private/us/en/dev_1234/global_e/1/0/0/ad/getAdByPositionType" + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + + +async def test_getBootScreen(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + client = await aiohttp_client(create_app) + + resp = await client.get( + "/v1/private/us/en/dev_1234/global_e/1/0/0/ad/getBootScreen" + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + + +async def test_hasUnreadMsg(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + client = await aiohttp_client(create_app) + + resp = await client.get( + "/v1/private/us/en/dev_1234/global_e/1/0/0/message/hasUnreadMsg" + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + + +async def test_getMsgList(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + client = await aiohttp_client(create_app) + + resp = await client.get( + "/v1/private/us/en/dev_1234/global_e/1/0/0/message/getMsgList" + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + + +async def test_getSystemReminder(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + client = await aiohttp_client(create_app) + + resp = await client.get( + "/v1/private/us/en/dev_1234/global_e/1/0/0/common/getSystemReminder" + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + + +async def test_getCnWapShopConfig(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + client = await aiohttp_client(create_app) + + resp = await client.get( + "/v1/private/us/en/dev_1234/global_e/1/0/0/shop/getCnWapShopConfig" + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == bumper.RETURN_API_SUCCESS + + +async def test_neng_hasUnreadMessage(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + client = await aiohttp_client(create_app) + + postbody = { + "auth": { + "realm": "ecouser.net", + "resource": "ecoglobe", + "token": "us_token", + "userid": "user123", + "with": "users", + }, + "count": 20, + } + resp = await client.post("/api/neng/message/hasUnreadMsg", json=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == 0 + + async def test_getProductIotMap(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db @@ -271,6 +491,30 @@ async def test_getUsersAPI(aiohttp_client): assert jsonresp["result"] == "fail" +async def test_getUserAccountInfo(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + bumper.user_add("testuser") + bumper.user_add_device("testuser", "dev_1234") + bumper.user_add_token("testuser", "token_1234") + bumper.user_add_authcode("testuser", "token_1234", "auth_1234") + bumper.user_add_bot("testuser", "did_1234") + bumper.bot_add("sn_1234", "did_1234", "class_1234", "res_1234", "com_1234") + + client = await aiohttp_client(create_app) + + resp = await client.get( + "/v1/private/us/en/dev_1234/global_e/1/0/0/user/getUserAccountInfo" + ) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["code"] == "0000" + assert jsonresp["msg"] == "操作成功" + assert jsonresp["data"]["userName"] == "fusername_testuser" + + async def test_postUsersAPI(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db @@ -316,6 +560,38 @@ async def test_postUsersAPI(aiohttp_client): jsonresp = json.loads(text) assert jsonresp["result"] == "ok" + # Test as EcoVacs Home (global_e) + postbody = { + "country": "US", + "edition": "ECOGLOBLE", + "last": "", + "org": "ECOWW", + "resource": "dev_1234", + "todo": "loginByItToken", + "token": "auth_1234", + } + resp = await client.post("/api/users/user.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["result"] == "ok" + + # Test as EcoVacs Home (global_e) & Post Form + postbody = { + "country": "US", + "edition": "ECOGLOBLE", + "last": "", + "org": "ECOWW", + "resource": "dev_1234", + "todo": "loginByItToken", + "token": "auth_1234", + } + resp = await client.post("/api/users/user.do", data=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["result"] == "ok" + # Test GetDeviceList postbody = { "auth": { @@ -391,6 +667,94 @@ async def test_postUsersAPI(aiohttp_client): assert jsonresp["result"] == "ok" +async def test_appsvr_api(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + client = await aiohttp_client(create_app) + + # Test GetGlobalDeviceList + postbody = { + "aliliving": False, + "appVer": "1.1.6", + "auth": { + "realm": "ecouser.net", + "resource": "ECOGLOBLEac5ae987", + "token": "token_1234", + "userid": "testuser", + "with": "users", + }, + "channel": "google_play", + "defaultLang": "en", + "lang": "en", + "platform": "Android", + "todo": "GetGlobalDeviceList", + "userid": "testuser", + } + resp = await client.post("/api/appsvr/app.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["ret"] == "ok" + + bumper.bot_add("sn_1234", "did_1234", "ls1ok3", "res_1234", "eco-ng") + + # Test again with bot added + resp = await client.post("/api/appsvr/app.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["ret"] == "ok" + + +async def test_lg_logs(aiohttp_client): + if os.path.exists("tests/tmp.db"): + os.remove("tests/tmp.db") # Remove existing db + bumper.db = "tests/tmp.db" # Set db location for testing + bumper.bot_add("sn_1234", "did_1234", "ls1ok3", "res_1234", "eco-ng") + bumper.bot_set_mqtt("did_1234", True) + confserver = create_confserver() + client = await aiohttp_client(create_app) + + # Test return get status + command_getstatus_resp = { + "id": "resp_1234", + "resp": "", + "ret": "ok", + } + confserver.helperbot.send_command = mock.MagicMock( + return_value=async_return(command_getstatus_resp) + ) + + + # Test GetGlobalDeviceList + postbody = { + "auth": { + "realm": "ecouser.net", + "resource": "ECOGLOBLEac5ae987", + "token": "token_1234", + "userid": "testuser", + "with": "users", + }, + "did": "did_1234", + "resource": "res_1234", + "td": "GetCleanLogs", + } + resp = await client.post("/api/lg/log.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["ret"] == "ok" + + # Not bot online + bumper.bot_set_mqtt("did_1234", False) + resp = await client.post("/api/lg/log.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + jsonresp = json.loads(text) + assert jsonresp["ret"] == "fail" + + async def test_postLookup(aiohttp_client): if os.path.exists("tests/tmp.db"): os.remove("tests/tmp.db") # Remove existing db @@ -423,12 +787,21 @@ async def test_devmgr(aiohttp_client): # Test PollSCResult postbody = {"td": "PollSCResult"} - resp = await client.post("/api/dim/devmanager.do", json=postbody) + resp = await client.post("/api/iot/devmanager.do", json=postbody) assert resp.status == 200 text = await resp.text() test_resp = json.loads(text) assert test_resp["ret"] == "ok" + # Test HasUnreadMsg + postbody = {"td": "HasUnreadMsg"} + resp = await client.post("/api/iot/devmanager.do", json=postbody) + assert resp.status == 200 + text = await resp.text() + test_resp = json.loads(text) + assert test_resp["ret"] == "ok" + assert test_resp["unRead"] == False + # Test BotCommand bumper.bot_add("sn_1234", "did_1234", "dev_1234", "res_1234", "eco-ng") bumper.bot_set_mqtt("did_1234", True) @@ -443,7 +816,7 @@ async def test_devmgr(aiohttp_client): confserver.helperbot.send_command = mock.MagicMock( return_value=async_return(command_getstatus_resp) ) - resp = await client.post("/api/dim/devmanager.do", json=postbody) + resp = await client.post("/api/iot/devmanager.do", json=postbody) assert resp.status == 200 text = await resp.text() test_resp = json.loads(text) @@ -454,7 +827,7 @@ async def test_devmgr(aiohttp_client): confserver.helperbot.send_command = mock.MagicMock( return_value=async_return(command_timeout_resp) ) - resp = await client.post("/api/dim/devmanager.do", json=postbody) + resp = await client.post("/api/iot/devmanager.do", json=postbody) assert resp.status == 200 text = await resp.text() test_resp = json.loads(text) @@ -465,7 +838,7 @@ async def test_devmgr(aiohttp_client): confserver.helperbot.send_command = mock.MagicMock( return_value=async_return(command_getstatus_resp) ) - resp = await client.post("/api/dim/devmanager.do", json=postbody) + resp = await client.post("/api/iot/devmanager.do", json=postbody) assert resp.status == 200 text = await resp.text() test_resp = json.loads(text)