|
21 | 21 | # SOFTWARE.
|
22 | 22 |
|
23 | 23 | import os
|
| 24 | +import socket |
| 25 | +import tempfile |
24 | 26 |
|
25 | 27 | from beartype.roar import BeartypeCallHintParamViolation
|
26 | 28 | import grpc
|
|
44 | 46 | )
|
45 | 47 | from ansys.geometry.core.connection.product_instance import (
|
46 | 48 | ProductInstance,
|
| 49 | + _check_minimal_versions, |
| 50 | + _check_port_or_get_one, |
| 51 | + _get_common_env, |
| 52 | + _is_port_available, |
| 53 | + _manifest_path_provider, |
47 | 54 | prepare_and_start_backend,
|
48 | 55 | )
|
49 | 56 | from ansys.geometry.core.math import Frame, Plane, Point2D, Point3D, UnitVector3D
|
@@ -417,3 +424,193 @@ def test_prepare_and_start_backend_invalid_version():
|
417 | 424 | backend_type=BackendType.WINDOWS_SERVICE,
|
418 | 425 | version="invalid_version", # Pass a non-integer value for version
|
419 | 426 | )
|
| 427 | + |
| 428 | + |
| 429 | +def test_is_port_available(): |
| 430 | + """Test that _is_port_available correctly detects available and unavailable ports.""" |
| 431 | + host = "localhost" |
| 432 | + |
| 433 | + # Test an available port |
| 434 | + available_port = 5000 |
| 435 | + assert _is_port_available(available_port, host) is True |
| 436 | + |
| 437 | + # Test an unavailable port by binding it |
| 438 | + unavailable_port = 5001 |
| 439 | + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: |
| 440 | + s.bind((host, unavailable_port)) # Bind the port to make it unavailable |
| 441 | + assert _is_port_available(unavailable_port, host) is False |
| 442 | + |
| 443 | + # Test port 0 (invalid port) |
| 444 | + assert _is_port_available(0, host) is False |
| 445 | + |
| 446 | + |
| 447 | +def test_manifest_path_exists(tmp_path): |
| 448 | + """Test when the manifest path exists.""" |
| 449 | + # Create a temporary manifest file |
| 450 | + manifest_path = tmp_path / "test_manifest.xml" |
| 451 | + manifest_path.touch() # Create the file |
| 452 | + |
| 453 | + # Call the function |
| 454 | + result = _manifest_path_provider( |
| 455 | + version=241, available_installations={}, manifest_path=str(manifest_path) |
| 456 | + ) |
| 457 | + |
| 458 | + # Assert the returned path is the same as the input |
| 459 | + assert result == str(manifest_path) |
| 460 | + |
| 461 | + |
| 462 | +def test_manifest_path_does_not_exist(tmp_path, caplog): |
| 463 | + """Test when the manifest path does not exist and handle RuntimeError.""" |
| 464 | + |
| 465 | + # Define a non-existent manifest path |
| 466 | + manifest_path = tmp_path / "non_existent_manifest.xml" |
| 467 | + |
| 468 | + # Provide a valid `available_installations` dictionary with the required version key |
| 469 | + available_installations = {241: str(tmp_path)} |
| 470 | + |
| 471 | + # Simulate the default manifest file path |
| 472 | + default_manifest_path = tmp_path / "Addins" / "ApiServer" / "manifest.xml" |
| 473 | + default_manifest_path.parent.mkdir( |
| 474 | + parents=True, exist_ok=True |
| 475 | + ) # Create the directory structure |
| 476 | + |
| 477 | + # Ensure the default manifest file does not exist |
| 478 | + assert not default_manifest_path.exists() |
| 479 | + |
| 480 | + # Call the function and expect a RuntimeError |
| 481 | + with pytest.raises(RuntimeError, match="Default manifest file's path does not exist."): |
| 482 | + _manifest_path_provider( |
| 483 | + version=241, |
| 484 | + available_installations=available_installations, |
| 485 | + manifest_path=str(manifest_path), |
| 486 | + ) |
| 487 | + |
| 488 | + # Assert the warning message is logged |
| 489 | + assert ( |
| 490 | + "Specified manifest file's path does not exist. Taking install default path." in caplog.text |
| 491 | + ) |
| 492 | + |
| 493 | + |
| 494 | +@pytest.mark.parametrize( |
| 495 | + "latest_installed_version, specific_minimum_version, should_raise, expected_message", |
| 496 | + [ |
| 497 | + ( |
| 498 | + 240, |
| 499 | + None, |
| 500 | + True, |
| 501 | + "PyAnsys Geometry is compatible with Ansys Products from version 24.1.0.", |
| 502 | + ), |
| 503 | + (242, None, False, None), |
| 504 | + (250, 251, True, "PyAnsys Geometry is compatible with Ansys Products from version 25.1.0."), |
| 505 | + (252, 251, False, None), |
| 506 | + ], |
| 507 | +) |
| 508 | +def test_check_minimal_versions( |
| 509 | + latest_installed_version, specific_minimum_version, should_raise, expected_message |
| 510 | +): |
| 511 | + """Test _check_minimal_versions with various scenarios.""" |
| 512 | + if should_raise: |
| 513 | + with pytest.raises(SystemError, match=expected_message): |
| 514 | + _check_minimal_versions(latest_installed_version, specific_minimum_version) |
| 515 | + else: |
| 516 | + try: |
| 517 | + _check_minimal_versions(latest_installed_version, specific_minimum_version) |
| 518 | + except SystemError: |
| 519 | + pytest.fail("SystemError raised unexpectedly.") |
| 520 | + |
| 521 | + |
| 522 | +@pytest.mark.parametrize( |
| 523 | + "port, should_raise, expected_message", |
| 524 | + [ |
| 525 | + (5000, False, None), # Test for an available port |
| 526 | + ( |
| 527 | + 5001, |
| 528 | + True, |
| 529 | + "Port 5001 is already in use. Please specify a different one.", |
| 530 | + ), # Test for an unavailable port |
| 531 | + ], |
| 532 | +) |
| 533 | +def test_check_port_or_get_one(port, should_raise, expected_message): |
| 534 | + """Test _check_port_or_get_one with various port availability scenarios.""" |
| 535 | + host = "localhost" |
| 536 | + |
| 537 | + if should_raise: |
| 538 | + # Bind the port to make it unavailable |
| 539 | + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: |
| 540 | + s.bind((host, port)) |
| 541 | + s.listen(1) # Start listening on the port |
| 542 | + |
| 543 | + # Call the function and expect a ConnectionError |
| 544 | + with pytest.raises(ConnectionError, match=expected_message): |
| 545 | + _check_port_or_get_one(port) |
| 546 | + else: |
| 547 | + # Ensure the port is available |
| 548 | + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: |
| 549 | + assert s.connect_ex((host, port)) != 0 # Port should not be in use |
| 550 | + |
| 551 | + # Call the function |
| 552 | + result = _check_port_or_get_one(port) |
| 553 | + |
| 554 | + # Assert the returned port is the same as the input |
| 555 | + assert result == port |
| 556 | + |
| 557 | + |
| 558 | +@pytest.mark.parametrize( |
| 559 | + "host, port, enable_trace, server_log_level, server_logs_folder, expected_env", |
| 560 | + [ |
| 561 | + ( |
| 562 | + "127.0.0.1", |
| 563 | + 8080, |
| 564 | + True, |
| 565 | + 2, |
| 566 | + None, # Use a dynamically created temporary directory |
| 567 | + { |
| 568 | + "API_ADDRESS": "127.0.0.1", |
| 569 | + "API_PORT": "8080", |
| 570 | + "LOG_LEVEL": "0", # Trace mode overrides log level to 0 |
| 571 | + "ENABLE_TRACE": "1", |
| 572 | + }, |
| 573 | + ), |
| 574 | + ( |
| 575 | + "localhost", |
| 576 | + 9090, |
| 577 | + False, |
| 578 | + 3, |
| 579 | + None, |
| 580 | + { |
| 581 | + "API_ADDRESS": "localhost", |
| 582 | + "API_PORT": "9090", |
| 583 | + "LOG_LEVEL": "3", # Log level remains unchanged |
| 584 | + }, |
| 585 | + ), |
| 586 | + ], |
| 587 | +) |
| 588 | +def test_get_common_env( |
| 589 | + host, port, enable_trace, server_log_level, server_logs_folder, expected_env |
| 590 | +): |
| 591 | + """Test the _get_common_env function with various scenarios.""" |
| 592 | + # Dynamically create a temporary directory for logs if server_logs_folder is None |
| 593 | + with tempfile.TemporaryDirectory() as temp_logs_folder: |
| 594 | + if server_logs_folder is None: |
| 595 | + server_logs_folder = temp_logs_folder |
| 596 | + |
| 597 | + # Call the function |
| 598 | + env = _get_common_env( |
| 599 | + host=host, |
| 600 | + port=port, |
| 601 | + enable_trace=enable_trace, |
| 602 | + server_log_level=server_log_level, |
| 603 | + server_logs_folder=server_logs_folder, |
| 604 | + ) |
| 605 | + |
| 606 | + # Update expected_env with the dynamically created logs folder |
| 607 | + if enable_trace: |
| 608 | + expected_env["ANS_DSCO_REMOTE_LOGS_FOLDER"] = server_logs_folder |
| 609 | + |
| 610 | + # Assert environment variables are correctly set |
| 611 | + for key, value in expected_env.items(): |
| 612 | + assert env[key] == value |
| 613 | + |
| 614 | + # Assert keys that should not exist in the environment |
| 615 | + if not enable_trace: |
| 616 | + assert "ENABLE_TRACE" not in env |
0 commit comments