From cae40ac6d349cb0a40aa257a136d803588aa6184 Mon Sep 17 00:00:00 2001 From: Alex Ruddick Date: Wed, 24 Apr 2024 15:05:40 -0500 Subject: [PATCH 1/6] ci: pytest -s no longer exists since pytest 3.4 --- .github/workflows/python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index e4f9ad522..f160e4aba 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -41,4 +41,4 @@ jobs: python -m mypy asyncua/ - name: Test with pytest run: | - pytest -v -s + pytest -v From c2c037e7102a649545350c3ec1dacf33147b48eb Mon Sep 17 00:00:00 2001 From: Alex Ruddick Date: Wed, 24 Apr 2024 14:41:16 -0500 Subject: [PATCH 2/6] ci: use pytest-xdist to parallelize tests --- .github/workflows/python-package.yml | 2 +- dev_requirements.txt | 1 + setup.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index f160e4aba..06d7d0178 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -41,4 +41,4 @@ jobs: python -m mypy asyncua/ - name: Test with pytest run: | - pytest -v + pytest -v -n auto diff --git a/dev_requirements.txt b/dev_requirements.txt index 54f2668b4..827512906 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -3,6 +3,7 @@ pytest-asyncio == 0.21.1 coverage pytest-cov pytest-mock +pytest-xdist == 3.5.0 asynctest types-aiofiles types-pyOpenSSL diff --git a/setup.py b/setup.py index d8f592756..8c5714d3b 100644 --- a/setup.py +++ b/setup.py @@ -49,5 +49,5 @@ ] }, setup_requires=[] + pytest_runner, - tests_require=['pytest', 'pytest-mock', 'asynctest'], + tests_require=['pytest', 'pytest-mock', 'pytest-xdist', 'asynctest'], ) From 9dbf46439197bb5af1a026b9d3558b083a5b5157 Mon Sep 17 00:00:00 2001 From: Alex Ruddick Date: Fri, 26 Apr 2024 10:03:09 -0500 Subject: [PATCH 3/6] demonstrate use of port 0 (OS will select unassigned port) --- tests/test_crypto_connect.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_crypto_connect.py b/tests/test_crypto_connect.py index ffea7a542..d34e9ca0e 100644 --- a/tests/test_crypto_connect.py +++ b/tests/test_crypto_connect.py @@ -26,8 +26,8 @@ pytestmark = pytest.mark.asyncio port_num1 = 48515 -port_num2 = 48512 port_num3 = 48516 +port_num2 = 0 uri_crypto = "opc.tcp://127.0.0.1:{0:d}".format(port_num1) uri_no_crypto = "opc.tcp://127.0.0.1:{0:d}".format(port_num2) uri_crypto_cert = "opc.tcp://127.0.0.1:{0:d}".format(port_num3) @@ -145,13 +145,15 @@ async def test_cert_warning(): async def test_nocrypto(srv_no_crypto): - clt = Client(uri_no_crypto) + port = srv_no_crypto.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") async with clt: await clt.nodes.objects.get_children() async def test_nocrypto_fail(srv_no_crypto): - clt = Client(uri_no_crypto) + port = srv_no_crypto.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") with pytest.raises(ua.UaError): await clt.set_security_string( f"Basic256Sha256,Sign,{EXAMPLE_PATH / 'certificate-example.der'},{EXAMPLE_PATH / 'private-key-example.pem'}") From 558267bc4b76997427430d5bee81b9c315b578bc Mon Sep 17 00:00:00 2001 From: Alex Ruddick Date: Mon, 29 Apr 2024 14:10:13 -0500 Subject: [PATCH 4/6] Use port 0 (OS will select) for all crypto tests --- tests/test_crypto_connect.py | 107 ++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 47 deletions(-) diff --git a/tests/test_crypto_connect.py b/tests/test_crypto_connect.py index d34e9ca0e..4049cfc2a 100644 --- a/tests/test_crypto_connect.py +++ b/tests/test_crypto_connect.py @@ -25,12 +25,7 @@ pytestmark = pytest.mark.asyncio -port_num1 = 48515 -port_num3 = 48516 -port_num2 = 0 -uri_crypto = "opc.tcp://127.0.0.1:{0:d}".format(port_num1) -uri_no_crypto = "opc.tcp://127.0.0.1:{0:d}".format(port_num2) -uri_crypto_cert = "opc.tcp://127.0.0.1:{0:d}".format(port_num3) +uri = "opc.tcp://127.0.0.1:0" BASE_DIR = Path(__file__).parent.parent EXAMPLE_PATH = BASE_DIR / "examples" srv_crypto_params = [(EXAMPLE_PATH / "private-key-example.pem", @@ -65,7 +60,7 @@ async def srv_crypto_encrypted_key_one_cert(request): srv = Server(user_manager=user_manager) await srv.init() - srv.set_endpoint(uri_crypto_cert) + srv.set_endpoint(uri) srv.set_security_policy([ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt]) await srv.load_certificate(cert) await srv.load_private_key(key) @@ -81,7 +76,7 @@ async def srv_crypto_all_certs(request): srv = Server() key, cert = request.param await srv.init() - srv.set_endpoint(uri_crypto) + srv.set_endpoint(uri) await srv.load_certificate(cert) await srv.load_private_key(key) await srv.start() @@ -100,7 +95,7 @@ async def srv_crypto_one_cert(request): srv = Server(user_manager=user_manager) await srv.init() - srv.set_endpoint(uri_crypto_cert) + srv.set_endpoint(uri) srv.set_security_policy([ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt]) await srv.load_certificate(cert) await srv.load_private_key(key) @@ -116,7 +111,7 @@ async def srv_crypto_all_cert_basic128rsa15(request): srv = Server() key, cert = request.param await srv.init() - srv.set_endpoint(uri_crypto) + srv.set_endpoint(uri) srv.set_security_policy([ua.SecurityPolicyType.Basic128Rsa15_Sign]) await srv.load_certificate(cert) await srv.load_private_key(key) @@ -131,7 +126,7 @@ async def srv_no_crypto(): # start our own server srv = Server() await srv.init() - srv.set_endpoint(uri_no_crypto) + srv.set_endpoint(uri) await srv.start() yield srv # stop the server @@ -160,8 +155,9 @@ async def test_nocrypto_fail(srv_no_crypto): async def test_basic256(srv_crypto_all_certs): - _, cert = srv_crypto_all_certs - clt = Client(uri_crypto) + srv, cert = srv_crypto_all_certs + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") await clt.set_security_string( f"Basic256Sha256,Sign,{EXAMPLE_PATH / 'certificate-example.der'},{EXAMPLE_PATH / 'private-key-example.pem'},{cert}" ) @@ -170,8 +166,9 @@ async def test_basic256(srv_crypto_all_certs): async def test_basic128rsa15(srv_crypto_all_cert_basic128rsa15): - _, cert = srv_crypto_all_cert_basic128rsa15 - clt = Client(uri_crypto) + srv, cert = srv_crypto_all_cert_basic128rsa15 + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") print(await clt.connect_and_get_server_endpoints()) await clt.set_security_string( f"Basic128Rsa15,Sign,{EXAMPLE_PATH / 'certificate-example.der'},{EXAMPLE_PATH / 'private-key-example.pem'},{cert}" @@ -181,8 +178,9 @@ async def test_basic128rsa15(srv_crypto_all_cert_basic128rsa15): async def test_basic256_encrypt(srv_crypto_all_certs): - _, cert = srv_crypto_all_certs - clt = Client(uri_crypto) + srv, cert = srv_crypto_all_certs + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") await clt.set_security_string( f"Basic256Sha256,SignAndEncrypt,{EXAMPLE_PATH / 'certificate-example.der'},{EXAMPLE_PATH / 'private-key-example.pem'},{cert}") async with clt: @@ -190,8 +188,9 @@ async def test_basic256_encrypt(srv_crypto_all_certs): async def test_basic256_encrypt_success(srv_crypto_all_certs): - clt = Client(uri_crypto) - _, cert = srv_crypto_all_certs + srv, cert = srv_crypto_all_certs + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") await clt.set_security( security_policies.SecurityPolicyBasic256Sha256, f"{EXAMPLE_PATH / 'certificate-example.der'}", @@ -206,8 +205,9 @@ async def test_basic256_encrypt_success(srv_crypto_all_certs): async def test_basic256_encrypt_use_certificate_bytes(srv_crypto_all_certs): - clt = Client(uri_crypto) - _, cert = srv_crypto_all_certs + srv, cert = srv_crypto_all_certs + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") with open(cert, 'rb') as server_cert, \ open(f"{EXAMPLE_PATH / 'certificate-example.der'}", 'rb') as user_cert, \ open(f"{EXAMPLE_PATH / 'private-key-example.pem'}", 'rb') as user_key: @@ -227,8 +227,9 @@ async def test_basic256_encrypt_use_certificate_bytes(srv_crypto_all_certs): @pytest.mark.skip("# FIXME: how to make it fail???") async def test_basic256_encrypt_fail(srv_crypto_all_certs): # FIXME: how to make it fail??? - _, cert = srv_crypto_all_certs - clt = Client(uri_crypto) + srv, cert = srv_crypto_all_certs + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") with pytest.raises(ua.UaError): await clt.set_security( security_policies.SecurityPolicyBasic256Sha256, @@ -241,8 +242,9 @@ async def test_basic256_encrypt_fail(srv_crypto_all_certs): async def test_Aes128Sha256RsaOaep_encrypt_success(srv_crypto_all_certs): - clt = Client(uri_crypto) - _, cert = srv_crypto_all_certs + srv, cert = srv_crypto_all_certs + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") await clt.set_security( security_policies.SecurityPolicyAes128Sha256RsaOaep, f"{EXAMPLE_PATH / 'certificate-example.der'}", @@ -257,8 +259,9 @@ async def test_Aes128Sha256RsaOaep_encrypt_success(srv_crypto_all_certs): async def test_Aes256Sha256RsaPss_encrypt_success(srv_crypto_all_certs): - clt = Client(uri_crypto) - _, cert = srv_crypto_all_certs + srv, cert = srv_crypto_all_certs + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") await clt.set_security( security_policies.SecurityPolicyAes256Sha256RsaPss, f"{EXAMPLE_PATH / 'certificate-example.der'}", @@ -273,8 +276,9 @@ async def test_Aes256Sha256RsaPss_encrypt_success(srv_crypto_all_certs): async def test_certificate_handling_success(srv_crypto_one_cert): - _, cert = srv_crypto_one_cert - clt = Client(uri_crypto_cert) + srv, cert = srv_crypto_one_cert + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") await clt.set_security( security_policies.SecurityPolicyBasic256Sha256, peer_creds['certificate'], @@ -288,8 +292,9 @@ async def test_certificate_handling_success(srv_crypto_one_cert): async def test_encrypted_private_key_handling_success(srv_crypto_encrypted_key_one_cert): - _, cert = srv_crypto_encrypted_key_one_cert - clt = Client(uri_crypto_cert) + srv, cert = srv_crypto_encrypted_key_one_cert + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") await clt.set_security( security_policies.SecurityPolicyBasic256Sha256, encrypted_private_key_peer_creds['certificate'], @@ -303,8 +308,9 @@ async def test_encrypted_private_key_handling_success(srv_crypto_encrypted_key_o async def test_encrypted_private_key_handling_success_with_cert_props(srv_crypto_encrypted_key_one_cert): - _, cert = srv_crypto_encrypted_key_one_cert - clt = Client(uri_crypto_cert) + srv, cert = srv_crypto_encrypted_key_one_cert + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") user_cert = uacrypto.CertProperties(encrypted_private_key_peer_creds['certificate'], "DER") user_key = uacrypto.CertProperties( path_or_content=encrypted_private_key_peer_creds['private_key'], @@ -324,8 +330,9 @@ async def test_encrypted_private_key_handling_success_with_cert_props(srv_crypto async def test_certificate_handling_failure(srv_crypto_one_cert): - _, cert = srv_crypto_one_cert - clt = Client(uri_crypto_cert) + srv, _ = srv_crypto_one_cert + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") with pytest.raises(ua.uaerrors.BadUserAccessDenied): await clt.set_security( @@ -341,8 +348,9 @@ async def test_certificate_handling_failure(srv_crypto_one_cert): async def test_encrypted_private_key_handling_failure(srv_crypto_one_cert): - _, cert = srv_crypto_one_cert - clt = Client(uri_crypto_cert) + srv, cert = srv_crypto_one_cert + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") with pytest.raises(ua.uaerrors.BadUserAccessDenied): await clt.set_security( @@ -358,8 +366,9 @@ async def test_encrypted_private_key_handling_failure(srv_crypto_one_cert): async def test_certificate_handling_mismatched_creds(srv_crypto_one_cert): - _, cert = srv_crypto_one_cert - clt = Client(uri_crypto_cert) + srv, cert = srv_crypto_one_cert + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") with pytest.raises((AttributeError, TimeoutError)): # either exception can be raise, depending on used python version # and crypto library version @@ -377,8 +386,9 @@ async def test_certificate_handling_mismatched_creds(srv_crypto_one_cert): async def test_secure_channel_key_expiration(srv_crypto_one_cert, mocker): timeout = 3 - _, cert = srv_crypto_one_cert - clt = Client(uri_crypto_cert) + srv, cert = srv_crypto_one_cert + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") clt.secure_channel_timeout = timeout * 1000 user_cert = uacrypto.CertProperties(peer_creds['certificate'], "DER") user_key = uacrypto.CertProperties( @@ -431,13 +441,14 @@ async def test_always_catch_new_cert_on_set_security(): # Client connecting with encryption to server srv = Server() await srv.init() - srv.set_endpoint(uri_crypto_cert) + srv.set_endpoint(uri) srv.set_security_policy([ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt]) key, cert = srv_crypto_params[0] await srv.load_certificate(cert) await srv.load_private_key(key) await srv.start() - clt = Client(uri_crypto_cert) + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") peer_cert = peer_creds["certificate"] peer_key = peer_creds["private_key"] security_string = f"Basic256Sha256,SignAndEncrypt,{peer_cert},{peer_key}" @@ -449,7 +460,7 @@ async def test_always_catch_new_cert_on_set_security(): # Simulation of a server cert renewal srv = Server() await srv.init() - srv.set_endpoint(uri_crypto_cert) + srv.set_endpoint(f"opc.tcp://127.0.0.1:{port}") srv.set_security_policy([ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt]) key, cert = srv_crypto_params[1] await srv.load_certificate(cert) @@ -481,13 +492,14 @@ async def test_anonymous_rejection(): srv = Server(user_manager=user_manager) await srv.init() - srv.set_endpoint(uri_crypto_cert) + srv.set_endpoint(uri) srv.set_security_policy([ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt]) srv.set_security_IDs(["Username", "Basic256Sha256"]) await srv.load_certificate(cert) await srv.load_private_key(key) await srv.start() - clt = Client(uri_crypto_cert) + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") await clt.set_security( security_policies.SecurityPolicyBasic256Sha256, peer_creds['certificate'], @@ -537,7 +549,8 @@ async def test_certificate_validator(srv_crypto_one_cert): validator = CertificateValidator(options=CertificateValidatorOptions.BASIC_VALIDATION | CertificateValidatorOptions.PEER_CLIENT) srv.set_certificate_validator(validator) - clt = Client(uri_crypto_cert) + port = srv.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") await clt.set_security( security_policies.SecurityPolicyBasic256Sha256, peer_creds['certificate'], From 5ad688bce0670a0f44217cbbf9861e92f8592378 Mon Sep 17 00:00:00 2001 From: Alex Ruddick Date: Mon, 29 Apr 2024 19:04:35 -0500 Subject: [PATCH 5/6] Use port 0 (OS will select) for sync tests --- tests/test_sync.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_sync.py b/tests/test_sync.py index d1d9b9083..d82cfd5c1 100644 --- a/tests/test_sync.py +++ b/tests/test_sync.py @@ -38,7 +38,7 @@ def tloop(): def server(tloop): s = Server(tloop=tloop) s.disable_clock(True) - s.set_endpoint('opc.tcp://0.0.0.0:8840/freeopcua/server/') + s.set_endpoint('opc.tcp://0.0.0.0:0/freeopcua/server/') uri = "http://examples.freeopcua.github.io" ns_idx = s.register_namespace(uri) myobj = s.nodes.objects.add_object(ns_idx, "MyObject") @@ -51,14 +51,16 @@ def server(tloop): @pytest.fixture def client(tloop, server): - c = Client("opc.tcp://admin@localhost:8840/freeopcua/server", tloop=tloop) + port = server.aio_obj.bserver.port + c = Client(f"opc.tcp://admin@localhost:{port}/freeopcua/server", tloop=tloop) with c: yield c @pytest.fixture def client_no_tloop(server): - with Client("opc.tcp://admin@localhost:8840/freeopcua/server") as c: + port = server.aio_obj.bserver.port + with Client(f"opc.tcp://admin@localhost:{port}/freeopcua/server") as c: yield c From 89f33b2aa48d1760b9756d2fabbc0deaae50c02a Mon Sep 17 00:00:00 2001 From: Alex Ruddick Date: Mon, 29 Apr 2024 19:12:18 -0500 Subject: [PATCH 6/6] Use port 0 (OS will select) for permissions tests --- tests/test_permissions.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/test_permissions.py b/tests/test_permissions.py index ad09ac3e5..8d69b2b27 100644 --- a/tests/test_permissions.py +++ b/tests/test_permissions.py @@ -18,12 +18,7 @@ pytestmark = pytest.mark.asyncio -port_num1 = 48515 -port_num2 = 48512 -port_num3 = 48516 -uri_crypto = "opc.tcp://127.0.0.1:{0:d}".format(port_num1) -uri_no_crypto = "opc.tcp://127.0.0.1:{0:d}".format(port_num2) -uri_crypto_cert = "opc.tcp://127.0.0.1:{0:d}".format(port_num3) +uri = "opc.tcp://127.0.0.1:0" BASE_DIR = Path(__file__).parent.parent EXAMPLE_PATH = BASE_DIR / "examples" srv_crypto_params = [(EXAMPLE_PATH / "private-key-example.pem", @@ -57,7 +52,7 @@ async def srv_crypto_one_cert(request): await cert_user_manager.add_role(anonymous_peer_certificate, name='Anonymous', user_role=UserRole.Anonymous) srv = Server(user_manager=cert_user_manager) - srv.set_endpoint(uri_crypto_cert) + srv.set_endpoint(uri) srv.set_security_policy([ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt], permission_ruleset=SimpleRoleRuleset()) await srv.init() @@ -76,7 +71,8 @@ async def srv_crypto_one_cert(request): async def test_permissions_admin(srv_crypto_one_cert): - clt = Client(uri_crypto_cert) + port = srv_crypto_one_cert.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") await clt.set_security( security_policies.SecurityPolicyBasic256Sha256, admin_peer_creds['certificate'], @@ -95,7 +91,8 @@ async def test_permissions_admin(srv_crypto_one_cert): async def test_permissions_user(srv_crypto_one_cert): - clt = Client(uri_crypto_cert) + port = srv_crypto_one_cert.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") await clt.set_security( security_policies.SecurityPolicyBasic256Sha256, user_peer_creds['certificate'], @@ -114,7 +111,8 @@ async def test_permissions_user(srv_crypto_one_cert): async def test_permissions_anonymous(srv_crypto_one_cert): - clt = Client(uri_crypto_cert) + port = srv_crypto_one_cert.bserver.port + clt = Client(f"opc.tcp://127.0.0.1:{port}") await clt.set_security( security_policies.SecurityPolicyBasic256Sha256, anonymous_peer_creds['certificate'],