Skip to content

Commit 5f31822

Browse files
authored
Merge pull request #1336 from guardicore/speed-up-unit-tests
Speed up unit tests
2 parents 0000486 + adb1006 commit 5f31822

File tree

15 files changed

+154
-72
lines changed

15 files changed

+154
-72
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
4141
- MongoDb now gets launched by the Island via python. #1148
4242
- Create/check data directory on Island init. #1170
4343
- The formatting of some log messages to make them more readable. #1283
44+
- Some unit tests to run faster. #1125
4445

4546
### Removed
4647
- Relevant dead code as reported by Vulture. #1149

monkey/monkey_island/cc/services/config.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ def _encrypt_or_decrypt_config(config, is_decrypt=False):
360360
parent_config_arr = config_arr
361361
config_arr = config_arr[config_key_part]
362362

363-
if isinstance(config_arr, collections.Sequence) and not isinstance(config_arr, str):
363+
if isinstance(config_arr, collections.abc.Sequence) and not isinstance(config_arr, str):
364364
for i in range(len(config_arr)):
365365
# Check if array of shh key pairs and then decrypt
366366
if isinstance(config_arr[i], dict) and "public_key" in config_arr[i]:

monkey/tests/conftest.py

-23
This file was deleted.

monkey/tests/unit_tests/conftest.py

+33
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,41 @@
1+
import os
2+
import sys
3+
from pathlib import Path
4+
15
import pytest
6+
from _pytest.monkeypatch import MonkeyPatch
7+
8+
MONKEY_BASE_PATH = str(Path(__file__).parent.parent.parent)
9+
sys.path.insert(0, MONKEY_BASE_PATH)
10+
11+
12+
@pytest.fixture(scope="session")
13+
def data_for_tests_dir(pytestconfig):
14+
return Path(os.path.join(pytestconfig.rootdir, "monkey", "tests", "data_for_tests"))
15+
16+
17+
@pytest.fixture(scope="session")
18+
def stable_file(data_for_tests_dir) -> Path:
19+
return data_for_tests_dir / "stable_file.txt"
20+
21+
22+
@pytest.fixture(scope="session")
23+
def stable_file_sha256_hash() -> str:
24+
return "d9dcaadc91261692dafa86e7275b1bf39bb7e19d2efcfacd6fe2bfc9a1ae1062"
225

326

427
@pytest.fixture
528
def patched_home_env(monkeypatch, tmp_path):
629
monkeypatch.setenv("HOME", str(tmp_path))
730

831
return tmp_path
32+
33+
34+
# The monkeypatch fixture is function scoped, so it cannot be used by session-scoped fixtures. This
35+
# monkeypatch_session fixture can be session-scoped. For more information, see
36+
# https://github.com/pytest-dev/pytest/issues/363#issuecomment-406536200
37+
@pytest.fixture(scope="session")
38+
def monkeypatch_session():
39+
monkeypatch_ = MonkeyPatch()
40+
yield monkeypatch_
41+
monkeypatch_.undo()

monkey/tests/unit_tests/infection_monkey/exploit/test_zerologon.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import pytest
22

3-
from infection_monkey.exploit.zerologon import ZerologonExploiter
43
from infection_monkey.model.host import VictimHost
54

65
DOMAIN_NAME = "domain-name"
@@ -15,6 +14,8 @@
1514

1615
@pytest.fixture
1716
def zerologon_exploiter_object(monkeypatch):
17+
from infection_monkey.exploit.zerologon import ZerologonExploiter
18+
1819
def mock_report_login_attempt(**kwargs):
1920
return None
2021

@@ -25,32 +26,37 @@ def mock_report_login_attempt(**kwargs):
2526
return obj
2627

2728

29+
@pytest.mark.slow
2830
def test_assess_exploit_attempt_result_no_error(zerologon_exploiter_object):
2931
dummy_exploit_attempt_result = {"ErrorCode": 0}
3032
assert zerologon_exploiter_object.assess_exploit_attempt_result(dummy_exploit_attempt_result)
3133

3234

35+
@pytest.mark.slow
3336
def test_assess_exploit_attempt_result_with_error(zerologon_exploiter_object):
3437
dummy_exploit_attempt_result = {"ErrorCode": 1}
3538
assert not zerologon_exploiter_object.assess_exploit_attempt_result(
3639
dummy_exploit_attempt_result
3740
)
3841

3942

43+
@pytest.mark.slow
4044
def test_assess_restoration_attempt_result_restored(zerologon_exploiter_object):
4145
dummy_restoration_attempt_result = object()
4246
assert zerologon_exploiter_object.assess_restoration_attempt_result(
4347
dummy_restoration_attempt_result
4448
)
4549

4650

51+
@pytest.mark.slow
4752
def test_assess_restoration_attempt_result_not_restored(zerologon_exploiter_object):
4853
dummy_restoration_attempt_result = False
4954
assert not zerologon_exploiter_object.assess_restoration_attempt_result(
5055
dummy_restoration_attempt_result
5156
)
5257

5358

59+
@pytest.mark.slow
5460
def test__extract_user_creds_from_secrets_good_data(zerologon_exploiter_object):
5561
mock_dumped_secrets = [
5662
f"{USERS[i]}:{RIDS[i]}:{LM_HASHES[i]}:{NT_HASHES[i]}:::" for i in range(len(USERS))
@@ -71,6 +77,7 @@ def test__extract_user_creds_from_secrets_good_data(zerologon_exploiter_object):
7177
assert zerologon_exploiter_object._extracted_creds == expected_extracted_creds
7278

7379

80+
@pytest.mark.slow
7481
def test__extract_user_creds_from_secrets_bad_data(zerologon_exploiter_object):
7582
mock_dumped_secrets = [
7683
f"{USERS[i]}:{RIDS[i]}:::{LM_HASHES[i]}:{NT_HASHES[i]}:::" for i in range(len(USERS))

monkey/tests/unit_tests/infection_monkey/exploit/zerologon_utils/test_vuln_assessment.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from nmb.NetBIOS import NetBIOS
33

44
from common.utils.exceptions import DomainControllerNameFetchError
5-
from infection_monkey.exploit.zerologon_utils.vuln_assessment import get_dc_details
65
from infection_monkey.model.host import VictimHost
76

87
DOMAIN_NAME = "domain-name"
@@ -21,7 +20,10 @@ def stub_queryIPForName(*args, **kwargs):
2120
return stub_queryIPForName
2221

2322

23+
@pytest.mark.slow
2424
def test_get_dc_details_multiple_netbios_names(host, monkeypatch):
25+
from infection_monkey.exploit.zerologon_utils.vuln_assessment import get_dc_details
26+
2527
NETBIOS_NAMES = ["Name1", "Name2", "Name3"]
2628

2729
stub_queryIPForName = _get_stub_queryIPForName(NETBIOS_NAMES)
@@ -33,7 +35,10 @@ def test_get_dc_details_multiple_netbios_names(host, monkeypatch):
3335
assert dc_handle == f"\\\\{NETBIOS_NAMES[0]}"
3436

3537

38+
@pytest.mark.slow
3639
def test_get_dc_details_no_netbios_names(host, monkeypatch):
40+
from infection_monkey.exploit.zerologon_utils.vuln_assessment import get_dc_details
41+
3742
NETBIOS_NAMES = []
3843

3944
stub_queryIPForName = _get_stub_queryIPForName(NETBIOS_NAMES)

monkey/tests/unit_tests/infection_monkey/telemetry/test_exploit_telem.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import pytest
44

5-
from infection_monkey.exploit.wmiexec import WmiExploiter
5+
from infection_monkey.exploit.sshexec import SSHExploiter
66
from infection_monkey.model.host import VictimHost
77
from infection_monkey.telemetry.exploit_telem import ExploitTelem
88

@@ -19,10 +19,10 @@
1919
"default_tunnel": None,
2020
"default_server": None,
2121
}
22-
EXPLOITER = WmiExploiter(HOST)
23-
EXPLOITER_NAME = "WmiExploiter"
22+
EXPLOITER = SSHExploiter(HOST)
23+
EXPLOITER_NAME = "SSHExploiter"
2424
EXPLOITER_INFO = {
25-
"display_name": WmiExploiter._EXPLOITED_SERVICE,
25+
"display_name": SSHExploiter._EXPLOITED_SERVICE,
2626
"started": "",
2727
"finished": "",
2828
"vulnerable_urls": [],

monkey/tests/unit_tests/monkey_island/cc/models/test_monkey.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import logging
22
import uuid
3-
from time import sleep
43

54
import pytest
65

@@ -24,9 +23,9 @@ def test_is_dead(self):
2423
mia_monkey_ttl.save()
2524
mia_monkey = Monkey(guid=str(uuid.uuid4()), dead=False, ttl_ref=mia_monkey_ttl.id)
2625
mia_monkey.save()
26+
2727
# Emulate timeout - ttl is manually deleted here, since we're using mongomock and not a
2828
# real mongo instance.
29-
sleep(1)
3029
mia_monkey_ttl.delete()
3130

3231
dead_monkey = Monkey(guid=str(uuid.uuid4()), dead=True)

monkey/tests/unit_tests/monkey_island/cc/resources/conftest.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,9 @@
99
from monkey_island.cc.services.representations import output_json
1010

1111

12-
# We can't scope to module, because monkeypatch is a function scoped decorator.
13-
# Potential solutions: https://github.com/pytest-dev/pytest/issues/363#issuecomment-406536200 or
14-
# https://stackoverflow.com/questions/53963822/python-monkeypatch-setattr-with-pytest-fixture-at-module-scope
15-
@pytest.fixture(scope="function")
16-
def flask_client(monkeypatch):
17-
monkeypatch.setattr(flask_jwt_extended, "verify_jwt_in_request", lambda: None)
12+
@pytest.fixture(scope="session")
13+
def flask_client(monkeypatch_session):
14+
monkeypatch_session.setattr(flask_jwt_extended, "verify_jwt_in_request", lambda: None)
1815

1916
with mock_init_app().test_client() as client:
2017
yield client

monkey/tests/unit_tests/monkey_island/cc/resources/test_configuration_import.py

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ def test_is_config_encrypted__json(monkey_config_json):
1313
assert not ConfigurationImport.is_config_encrypted(monkey_config_json)
1414

1515

16+
@pytest.mark.slow
1617
def test_is_config_encrypted__ciphertext(monkey_config_json):
1718
encrypted_config = encrypt_string(monkey_config_json, PASSWORD)
1819
assert ConfigurationImport.is_config_encrypted(encrypted_config)
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
from unittest import TestCase
1+
import pytest
22

33
from monkey_island.cc.services.attack.mitre_api_interface import MitreApiInterface
44

55

6-
class TestMitreApiInterface(TestCase):
7-
def test_get_all_mitigations(self):
8-
mitigations = MitreApiInterface.get_all_mitigations()
9-
self.assertIsNotNone((len(mitigations.items()) >= 282))
10-
mitigation = next(iter(mitigations.values()))
11-
self.assertEqual(mitigation["type"], "course-of-action")
12-
self.assertIsNotNone(mitigation["name"])
13-
self.assertIsNotNone(mitigation["description"])
14-
self.assertIsNotNone(mitigation["external_references"])
6+
@pytest.mark.slow
7+
def test_get_all_mitigations():
8+
mitigations = MitreApiInterface.get_all_mitigations()
9+
assert len(mitigations.items()) >= 282
10+
mitigation = next(iter(mitigations.values()))
11+
assert mitigation["type"] == "course-of-action"
12+
assert mitigation["name"] is not None
13+
assert mitigation["description"] is not None
14+
assert mitigation["external_references"] is not None

monkey/tests/unit_tests/monkey_island/cc/services/ransomware/test_ransomware_report.py

+17-17
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ def fake_mongo(monkeypatch):
2323

2424
@pytest.mark.usefixtures("uses_database")
2525
def test_get_encrypted_files_table(fake_mongo, monkeypatch):
26-
fake_mongo.db.monkey.insert(MONKEY_AT_ISLAND)
27-
fake_mongo.db.monkey.insert(MONKEY_AT_VICTIM)
28-
fake_mongo.db.edge.insert(EDGE_EXPLOITED)
29-
fake_mongo.db.edge.insert(EDGE_SCANNED)
30-
fake_mongo.db.telemetry.insert(ENCRYPTED)
31-
fake_mongo.db.telemetry.insert(ENCRYPTED_2)
32-
fake_mongo.db.telemetry.insert(ENCRYPTION_ERROR)
33-
fake_mongo.db.telemetry.insert(ENCRYPTION_ONE_FILE)
26+
fake_mongo.db.monkey.insert_one(MONKEY_AT_ISLAND)
27+
fake_mongo.db.monkey.insert_one(MONKEY_AT_VICTIM)
28+
fake_mongo.db.edge.insert_one(EDGE_EXPLOITED)
29+
fake_mongo.db.edge.insert_one(EDGE_SCANNED)
30+
fake_mongo.db.telemetry.insert_one(ENCRYPTED)
31+
fake_mongo.db.telemetry.insert_one(ENCRYPTED_2)
32+
fake_mongo.db.telemetry.insert_one(ENCRYPTION_ERROR)
33+
fake_mongo.db.telemetry.insert_one(ENCRYPTION_ONE_FILE)
3434

3535
monkeypatch.setattr(
3636
ReportService,
@@ -58,11 +58,11 @@ def test_get_encrypted_files_table(fake_mongo, monkeypatch):
5858

5959
@pytest.mark.usefixtures("uses_database")
6060
def test_get_encrypted_files_table__only_errors(fake_mongo, monkeypatch):
61-
fake_mongo.db.monkey.insert(MONKEY_AT_ISLAND)
62-
fake_mongo.db.monkey.insert(MONKEY_AT_VICTIM)
63-
fake_mongo.db.edge.insert(EDGE_EXPLOITED)
64-
fake_mongo.db.edge.insert(EDGE_SCANNED)
65-
fake_mongo.db.telemetry.insert(ENCRYPTION_ERROR)
61+
fake_mongo.db.monkey.insert_one(MONKEY_AT_ISLAND)
62+
fake_mongo.db.monkey.insert_one(MONKEY_AT_VICTIM)
63+
fake_mongo.db.edge.insert_one(EDGE_EXPLOITED)
64+
fake_mongo.db.edge.insert_one(EDGE_SCANNED)
65+
fake_mongo.db.telemetry.insert_one(ENCRYPTION_ERROR)
6666

6767
monkeypatch.setattr(
6868
ReportService,
@@ -84,10 +84,10 @@ def test_get_encrypted_files_table__only_errors(fake_mongo, monkeypatch):
8484

8585
@pytest.mark.usefixtures("uses_database")
8686
def test_get_encrypted_files_table__no_telemetries(fake_mongo, monkeypatch):
87-
fake_mongo.db.monkey.insert(MONKEY_AT_ISLAND)
88-
fake_mongo.db.monkey.insert(MONKEY_AT_VICTIM)
89-
fake_mongo.db.edge.insert(EDGE_EXPLOITED)
90-
fake_mongo.db.edge.insert(EDGE_SCANNED)
87+
fake_mongo.db.monkey.insert_one(MONKEY_AT_ISLAND)
88+
fake_mongo.db.monkey.insert_one(MONKEY_AT_VICTIM)
89+
fake_mongo.db.edge.insert_one(EDGE_EXPLOITED)
90+
fake_mongo.db.edge.insert_one(EDGE_SCANNED)
9191

9292
monkeypatch.setattr(
9393
ReportService,

monkey/tests/unit_tests/monkey_island/cc/services/utils/ciphertexts_for_encryption_test.py

+58
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,61 @@
1+
VALID_CIPHER_TEXT = (
2+
"QUVTAgAAG0NSRUFURURfQlkAcHlBZXNDcnlwdCA2LjAuMACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
4+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPzzL7yzdvBdhwJiYrRRb/0f4hmQSN9OaYNfqcXKk/c0vnzqWh1Yo7AAjODs2D"
5+
"nZU7bp1VxM3OE/iHLK8+YOD6TVcJMMSk5TdaHyuo/oCcWSA5xHGhSUPQEXk+sPglNv/PO1qyHFQl9m2nAvwdfsJpdYi5Fi"
6+
"6euP9XBy3mViu70IrxqNAgc8DdWqAII4Y9UW+x2jnLgnBT6NBk0DWXMyWZ3+aji+D1hb9DTwAn+/5HQWviFASwEwMaoYFV"
7+
"/Guy3M7NGfSD15wpYaLN5ZszBWGUSi7Ewf7TBRK2Vc1DFJClj05A8/TyjeCyHKnjdGoOl3qqszvj8D8fVAuMkXsqu0G7Lb"
8+
"TjTYDnBxZ8rEV8uRLQrvnLGULkKXyeFP2yfuzfyYSbXRYIAw+lY1EIzcNhmMzaZVFOVd/q6/e7FTJd/JoyhK7gD+zErn0T"
9+
"u4k6c6/2kkZlc4MQYCMZGBNzdnuTEKrFsiFjWI9b4oz2mVRI2anXXYRMCqN1+L9XBCfscaUlc/NPDMFGdsZGsRpFJCbda6"
10+
"X5j/45luqSdVU8l4M+uW7xGe/jroRtTooCFjk0r0miNToJZunafluTCfFSnbLAkaYxBRe0kYryfbP/38geWU46tIenKEQD"
11+
"YDlDYVc1lr1CKjn39NJdACgOzzY/I0ZmXLNreonYjjRZ1+0rxeTqYiPwlUJdfdEkRDhii404Wxb9l9rUWaK2sGXq2Ykh1r"
12+
"VLPjEa8bRaqWzguqk+k8aHjzHSSkSIl+8PXC8RSnmsJXka33xX9quOqUMT+hp2IhRu8L86ub1K635/b82i9T2R/bghkLy4"
13+
"d/+k5bOUPXlNAA0OyGC/7JQgNWV/3ddiO6/k5tREaM9H44r0dJuFSS3+fjTwnlQMvp/ypOrGjgYpY77H0VubPma0Y3m2VB"
14+
"U8pNPd0Mpv7qe9iQsJPG93I4rP/vzwi5TbeK4Gsg0gBSL2HsP/mGTUNpj1CwrBj+JridWEnwCsq7yaQacVoYqxiB4zKNS5"
15+
"XupVlrkNxf8GyaBFonQNWPlmtvoY7dnG81YwLdKF4GwcP23SLfgtnHjSRtgdVgmO498HBTJVg7nJcvGuZiBqJbXRFcMgik"
16+
"HwgBVA8F/WzrTtzhzd+bazOHWaU+4Tlo3fkQq/tQvfGawNbXCoakn69jWMV7xP6K2w3oeJie3d3YfqNbCBiaVGiF8KB7ui"
17+
"ly6G+8pirNWihIZJ+r2PORsTkQwNMzff1odnP6e4lYs3LbVwdS5Pwzkp4LjzUKJBtXo7vCS+WXlGpMz30CwXR8tnyg+4QK"
18+
"NrdprPkqTOHLz/EmBdfjS1MG9fv6U3pTHM2oZnaLQIqs167FS8OQejE6c6t0Wn/bIlkn7i7Xw3pq/ICWx4pR0Mq9RLDr55"
19+
"EfUW0gPJiGquDMgmLcvoJmNY6ENYdG/cPvbbqxCZIlMjPWk3+8myH8QB6b5J/FKEXh2IcMHrKETM+X0XhrueWLclTFCVwE"
20+
"AkBN4V6oWlKUnuFJscSKQKhzJQ94iSTiwzZphktCDvgVncTSa3YqLZ0wPsdmdy7QDdP7xh1SYAAyTQKvanHAgEakDQ+gVF"
21+
"EfPhJhTfYEEXxMdaUmorxaCbH0xzpqJZPuaq7Xt97dQeZOaJvXDBiJ7ek+ZFJCrtxmUaEF4vHCDjOMbggrfINTErDngFT8"
22+
"/SiFeSy17/pz6Bv39xxhdzTtWqc29ffW1uK/hlK4g2sPaCuHEu/55+gQoZpsqHDJCkmfBlL1BSoWBbSAZrE07T+Qb7oigu"
23+
"/Ko4Z+cL3npSsn9btkN3XNaHH9q4vN+ut9etLi8TmpAUJqvTlGCy9tlWmdRe5346LVHLfHNFHZ9nyZhwMWfiQaMWlwcLel"
24+
"MP3CKsez9u7Cd2ybR0e2SFRLC1bY7H9Vg4/RMJjPsCHFDU0FAan8X5estTBBFKA3OfNc8DxcbS+jXMWYjdLv6M9cS7rAS4"
25+
"zdumgz++f0y+4TKkFQdC3LKGEGYpJ+KoG7HStbUIkqp4YvLaQFsnt/gwrPOlAAYfso/ot3KjhBXILyfsA4EgbJt295uD8P"
26+
"2cCB/2s8tdTb78L1k2vhnvDv+1lox7n3PgfqYqsnB8Rjd/XhwzKfJJUcwmjCBG2IdWycy0zKOoeU0WEr7rphwFIG7wnAuG"
27+
"uufmZX75GZ9BIRbFoiRprLeCU45ha0Wwm7UJwP5os3ER6nLWzQyEOTG0s1HWd8MqdMCwZK/1MHwAVIXrRh+xpESwpABZ6O"
28+
"ZQbb/Rp9DddEKy7d5XDQhStbApYnlayVrYUHzCnJrvLYxxO938n0bD+itPyWXs+Nizta+XUFbmuDmjdR60Vzp7AHzgNlJD"
29+
"BtxJltAX29JA08BG4+W/tOI0YfoeaYrHbmRlw9USXa411th9lvvMgfEGDR4ql9nLUsb/gFv4UKpcsG/MQkWT1CnSXCBTmc"
30+
"574HQgRLdakkAGaWekU5zI7h4LWgQVqu2K7zTyqn0cFKfiaBW4r8i56+nlzfq++MgFDsJ2z3hj7OFFv9d97G5lw+ftpYP3"
31+
"QIpNDnniOGJuV1b3Aqvr1RCS6xhE7ljpI+lJnDk0mKZfKumUFV/EA5QIa1B5s5lnREm4iqGwOpvSb1gm/guYiO+sNQLn9w"
32+
"SZDj4iPPHl8vpRvj5FyCxLKj4CP/lGHXBhu5d6LtoUQT5mG4NrygJRsV7iym1IRdrRl1CSkwl7f1lBj00KZ9s1YQftWbTp"
33+
"UtUCq+cMeF07GqoAjDUqfUMd3L70o5LGkhqxceZBusS5MiED56QAWbHJ0YIY+lNwttqf9njzgUs3ZjH9WM8+xVy6PK7g1Z"
34+
"sRn2H6mpajwoHzzHdVdCw7Az+OCyf2ZP4k5aM8ZxUFmaQhyO//rhMJYeyPNzpxaXxQkAU6w39BId1hQA2n0rhaeVfdo0Ry"
35+
"NJNn23PVHUlTHxLoAMiop/BbbY3sqGlB2Cc6X9FDGMhvQQMinQ09hUwEpYX5bZli2J8MiPDHSiQ490zJlVn3QDyhfPDcve"
36+
"mq68kzRp/BkoRkoqp8aUkJ7mb4EYxPtJMSg4eBq4uaJY+vEISCSXDaZBn5kL+KL93ttkykkbWf0Z8RN290Pc4Tq76Oj5oX"
37+
"2BSlCpBXbxqpOvi7Msccb8ZtTEoha4wTZzrTD6P+P44u9UycZgjz6jZdzNKy4RCG8O2ow1RIxEtexKG+YRu3jWNb7T92Jy"
38+
"iFDvuUfd7jj3dzhdeRGK9jnhyHxduqw92XbPBgXLOcXB0uszI0I+bd0OATfvbK+gTsRutxHDb5R2f0lSoMsIQcv9PnwJPV"
39+
"HpvWsY82/6s6Jq9HAni9E/PCK3RbLs+VkO5BFwFLC1euG1AyfI/M8C/dZjDdZjdInITfvGukqv/81mnGdcwGFA6b3S6tjA"
40+
"Oc8vKHYm3xS0GG89GEHzTYMGz3d+OvkIIPal3C/F99wNUv2WiJ+uOB5mVVaplaulWM/uOdlbHTwKYJeBEr/US0Tnju0gYc"
41+
"R4wTZwTzPfqf/zMaazB6M0J0XI/WWWPfES8mABrPvD29Sd2BSXL5vQoXT39gSPYO+/8Gc7oySD0SPrXXUFmqzblUmDeYkO"
42+
"K2BwGNfVZOpuZA+Aals+Rb9Cexzmj2Jxkl0qj/1e9YoWjpVumIAQkgl5WmlXDb0/BJ4zuPThwgFhSIkocnytUmfKlYoZGQ"
43+
"fH4snJ183nUCct3QK5/WMgRPsZh7jKQtx5KDwX4rAbNkH99KPEwOaQSUcDxzeCVKU74c81FX0EmewovknBQLC3x5cBmuPN"
44+
"HRAGvvST0275f2FkaFgXfLwCbHnf5o+EPeoRxm4NGcosjXdhaU6bXCPWyBuwZUpgaoR94FC/xe0wRKhM6xLucOoo599CLA"
45+
"kIv820DkbHBikiIpOw/7NmpztRMtH7Kq2ZESmpBnU7wUxWBqrlgBo+ywEjSItsah54mOExpOiF/1hg0Swg48WD2Z1Mw1Gz"
46+
"6BRqgJnLfjEGeBHty2wuq06qgepQPfy2/N3QFUOXU+Y/akNlxgyQN7sULYq0Elrhnif0uiJVaj8H53wmyPq2zKAzwPos4P"
47+
"m4DnoDgBOuTqdwRAANg5m7idaKnXBsvpF+DKGi3b1HXuGttTXiZIHDutB3oLGQHQ3+uT6rdzwLlQNuKqCkOjTH0NXL7cio"
48+
"1ldCclvNFRoEEzk4aW4djpESRqgFBac62UJpsoflmxEzdqaHlWrqJ6IK5knjv8PREY1Cf0mXVE7bmsSyonI7Tu0JhkRquN"
49+
"8T+Eg1I7DGsqO3buWmAiulN/TTqC92uid3c+PiSGXJ6nEQ+RDlwwd2iq/wmDAu8hq6AbW6wA3Atu7xKQC0xkD2RhzF9yIu"
50+
"t9tNYNWWRl14tjwmfvurE65F0mMqgbLhepQ3ajYXqSOytOBNxlrhpGJ7ZFngNiRLP90jYOcZ4tWIMpt5XPCDQXiehtvU+M"
51+
"zRoDfKjtSXbux9/w92es+2nVJUxrWQPvjsoRphYK6eVO5FbClmc+w7np2ugFZ231isdHYaMRe4VaXA7YkVqMuiBY4ZXrnA"
52+
"vtBZRzNGgSoFMmHQ0WebwipLXjJpLoQDktWItFbY1AI5MeJDu1fLR6EK9c5opCk/doK9RozfPfyinh9oBfZ3ZmSdY1WOxj"
53+
"LGc3QmCXFbxapAFNdzS8satGjn/VV1ZbhZBU7fzW1auiRxk1H0/CjWK0w1g2KQ2DRPG2vPpLAJVjy3cyNn0oS6YgDStDN2"
54+
"fUtRYH1oBt6cIeW4K8Mp7I1fD+Wa45ZFonmeeuBj53S6k+Ov2aX5cIUeRrB4tvmkBosYdL9N+lr1wORZLj2us8IWmnlKh4"
55+
"nmV0tcZxh5kBZW1vgP+LWHEN4ialItBPmsggRWqyBSVTr8tbtLEaJrlZ2NXiUFhcVJkggItwU02Ueesvjpjngfd/UluO/d"
56+
"5pnm3dizp6Q="
57+
)
58+
159
MALFORMED_CIPHER_TEXT_CORRUPTED = (
260
"QUVTAgAAGM0NKEYTESTURfQlkAcHlBZXNDcnlwdCA2LjAuMACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
361
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"

0 commit comments

Comments
 (0)