mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-26 15:10:22 -05:00
- Remove unused imports in test files - Fix bare except clause to use except Exception - Fix None comparisons to use 'is not None' / 'is None' - Remove unused variable assignments - Add noqa comments for intentional patterns (star imports, method redefinition for different classes, import after sys.path modification) - Apply ruff formatting
306 lines
11 KiB
Python
306 lines
11 KiB
Python
"""
|
|
Test file for issue #12940: Python GRPC interface validates field values
|
|
|
|
This test verifies that validation prevents invalid values from being set.
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
import pytest
|
|
|
|
sys.path.insert(1, os.path.join(sys.path[0], "../../"))
|
|
import rips
|
|
|
|
|
|
def test_range_validation_minimum_enforced(rips_instance, initialize_test):
|
|
"""
|
|
Verifies that setting value below minimum range is rejected.
|
|
|
|
The wellBoreFluidPvtTable field has setMinValue(0) in C++, so negative values
|
|
should be rejected with a clear error message.
|
|
"""
|
|
well_path_coll = rips_instance.project.well_path_collection()
|
|
|
|
# Create a new modeled well path
|
|
well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
|
|
well_path.name = "test_validation"
|
|
well_path.update()
|
|
|
|
# Get completion settings
|
|
completions_settings = well_path.completion_settings()
|
|
|
|
# Set wellBoreFluidPvtTable to a negative value (below minimum of 0)
|
|
completions_settings.well_bore_fluid_pvt_table = -5
|
|
|
|
# Should raise grpc._channel._InactiveRpcError with validation message
|
|
with pytest.raises(Exception) as exc_info:
|
|
completions_settings.update()
|
|
|
|
error_message = str(exc_info.value)
|
|
assert "Validation failed" in error_message
|
|
assert (
|
|
"WellBoreFluidPvtTable" in error_message
|
|
or "well_bore_fluid_pvt_table" in error_message
|
|
)
|
|
assert "-5" in error_message or "below minimum" in error_message
|
|
|
|
|
|
def test_valid_value_should_succeed(rips_instance, initialize_test):
|
|
"""
|
|
Control test: Valid values should always work.
|
|
|
|
This test should pass both before and after implementing validation.
|
|
"""
|
|
well_path_coll = rips_instance.project.well_path_collection()
|
|
|
|
well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
|
|
well_path.name = "test_valid"
|
|
well_path.update()
|
|
|
|
completions_settings = well_path.completion_settings()
|
|
|
|
# Set valid values (within range)
|
|
completions_settings.well_bore_fluid_pvt_table = 5 # Valid: >= 0
|
|
completions_settings.fluid_in_place_region = 10 # Valid
|
|
|
|
# This should succeed both before and after validation implementation
|
|
completions_settings.update()
|
|
|
|
# Verify values were set correctly
|
|
completions_settings_updated = well_path.completion_settings()
|
|
assert completions_settings_updated.well_bore_fluid_pvt_table == 5
|
|
assert completions_settings_updated.fluid_in_place_region == 10
|
|
|
|
|
|
def test_value_unchanged_after_validation_error(rips_instance, initialize_test):
|
|
"""Verifies field value doesn't change if validation fails (rollback)."""
|
|
well_path_coll = rips_instance.project.well_path_collection()
|
|
well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
|
|
well_path.name = "test_rollback"
|
|
well_path.update()
|
|
|
|
completions_settings = well_path.completion_settings()
|
|
|
|
# Set valid initial value
|
|
completions_settings.well_bore_fluid_pvt_table = 42
|
|
completions_settings.fluid_in_place_region = 99
|
|
completions_settings.update()
|
|
|
|
# Try to set invalid value
|
|
completions_settings.well_bore_fluid_pvt_table = -5
|
|
|
|
# Also set a different version for (should also be rolled back)
|
|
completions_settings.fluid_in_place_region = 12
|
|
|
|
with pytest.raises(Exception):
|
|
completions_settings.update()
|
|
|
|
# Value should remain at the previous valid value (42)
|
|
completions_settings_refreshed = well_path.completion_settings()
|
|
assert completions_settings_refreshed.well_bore_fluid_pvt_table == 42, (
|
|
"Field value should not change after failed validation (rollback should occur)"
|
|
)
|
|
|
|
assert completions_settings_refreshed.fluid_in_place_region == 99, (
|
|
"Field value should not change after failed validation (rollback should occur)"
|
|
)
|
|
|
|
|
|
def test_strict_double_validation_extra_text(rips_instance, initialize_test):
|
|
"""Verifies strict validation for double fields."""
|
|
well_path_coll = rips_instance.project.well_path_collection()
|
|
well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
|
|
well_path.name = "test_double_strict_extra"
|
|
well_path.update()
|
|
|
|
fishbones_collection = well_path.completions().fishbones()
|
|
|
|
# Successfully set a value
|
|
fishbones_collection.main_bore_skin_factor = 50.0
|
|
fishbones_collection.update()
|
|
|
|
# Try a badly formatted value
|
|
fishbones_collection.main_bore_skin_factor = "100.5test"
|
|
with pytest.raises(Exception) as exc_info:
|
|
fishbones_collection.update()
|
|
|
|
assert "Extra characters found" in str(exc_info.value)
|
|
assert "100.5test" in str(exc_info.value)
|
|
|
|
# Should not overwrite when validation fails
|
|
assert well_path.completions().fishbones().main_bore_skin_factor == 50.0
|
|
|
|
|
|
def test_strict_double_validation_text(rips_instance, initialize_test):
|
|
"""Verifies strict validation for double fields."""
|
|
well_path_coll = rips_instance.project.well_path_collection()
|
|
well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
|
|
well_path.name = "test_double_strict"
|
|
well_path.update()
|
|
|
|
fishbones_collection = well_path.completions().fishbones()
|
|
fishbones_collection.main_bore_skin_factor = "test"
|
|
|
|
with pytest.raises(Exception) as exc_info:
|
|
fishbones_collection.update()
|
|
|
|
print("Error", exc_info.value)
|
|
assert "unreadable" in str(exc_info.value)
|
|
assert "test" in str(exc_info.value)
|
|
|
|
|
|
def test_strict_int_validation(rips_instance, initialize_test):
|
|
"""Verifies strict validation for int fields."""
|
|
well_path_coll = rips_instance.project.well_path_collection()
|
|
well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
|
|
well_path.name = "test_int_strict"
|
|
well_path.update()
|
|
|
|
completions_settings = well_path.completion_settings()
|
|
|
|
# well_bore_fluid_pvt_table is int
|
|
completions_settings.well_bore_fluid_pvt_table = 0.99
|
|
|
|
with pytest.raises(Exception) as exc_info:
|
|
completions_settings.update()
|
|
|
|
assert "Extra characters found" in str(exc_info.value)
|
|
assert "0.99" in str(exc_info.value)
|
|
|
|
|
|
def test_validation_rollback(rips_instance, initialize_test):
|
|
"""Verifies that failed updates rollback local state."""
|
|
well_path_coll = rips_instance.project.well_path_collection()
|
|
well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
|
|
well_path.update()
|
|
|
|
completions_settings = well_path.completion_settings()
|
|
|
|
# Set valid value
|
|
completions_settings.well_bore_fluid_pvt_table = 5
|
|
completions_settings.update()
|
|
assert completions_settings.well_bore_fluid_pvt_table == 5
|
|
|
|
# Try to set invalid value (float instead of int)
|
|
completions_settings.well_bore_fluid_pvt_table = 0.99
|
|
|
|
with pytest.raises(Exception) as exc_info:
|
|
completions_settings.update()
|
|
|
|
assert "Extra characters found" in str(exc_info.value)
|
|
|
|
# Verify rollback: should be back to 5, not 0.99
|
|
assert completions_settings.well_bore_fluid_pvt_table == 5, (
|
|
"Field should rollback to previous valid value after failed update"
|
|
)
|
|
|
|
|
|
def test_enum_validation_message(rips_instance, initialize_test):
|
|
"""Verifies enum validation error message lists valid options."""
|
|
well_path_coll = rips_instance.project.well_path_collection()
|
|
well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
|
|
well_path.update()
|
|
|
|
completions_settings = well_path.completion_settings()
|
|
|
|
# gas_inflow_eq is an Enum
|
|
# Valid values: STD, R-G, P-P, GPP
|
|
|
|
completions_settings.gas_inflow_eq = "InvalidValue"
|
|
|
|
with pytest.raises(Exception) as exc_info:
|
|
completions_settings.update()
|
|
|
|
error_msg = str(exc_info.value)
|
|
assert "Failed to set enum text value" in error_msg
|
|
assert "Valid options are:" in error_msg
|
|
assert "STD" in error_msg
|
|
assert "GPP" in error_msg
|
|
|
|
|
|
def test_strict_enum_validation(rips_instance, initialize_test):
|
|
"""Verifies strict validation for enum fields (trailing garbage)."""
|
|
well_path_coll = rips_instance.project.well_path_collection()
|
|
well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
|
|
well_path.update()
|
|
|
|
completions_settings = well_path.completion_settings()
|
|
completions_settings.gas_inflow_eq = "R-G"
|
|
completions_settings.update()
|
|
|
|
# STD is valid. "STD.garbage" should fail.
|
|
completions_settings.gas_inflow_eq = "STD.garbage"
|
|
|
|
with pytest.raises(Exception) as exc_info:
|
|
completions_settings.update()
|
|
|
|
error_msg = str(exc_info.value)
|
|
# Expect "Extra characters found" because "STD" is parsed successfully, leaving ".garbage"
|
|
assert "Extra characters found" in error_msg
|
|
|
|
|
|
def test_strict_bool_validation(rips_instance, initialize_test):
|
|
"""Verifies strict validation for bool fields."""
|
|
# Get or create a FractureTemplate to test bool validation
|
|
fracture_templates = rips_instance.project.descendants(rips.FractureTemplate)
|
|
|
|
# Skip test if no FractureTemplate available (need a project with templates)
|
|
if len(fracture_templates) == 0:
|
|
pytest.skip("No FractureTemplate available for testing")
|
|
|
|
fracture_template = fracture_templates[0]
|
|
|
|
# Test 1: True and False should work
|
|
fracture_template.user_defined_perforation_length = True
|
|
fracture_template.update()
|
|
assert fracture_template.user_defined_perforation_length is True
|
|
|
|
fracture_template.user_defined_perforation_length = False
|
|
fracture_template.update()
|
|
assert fracture_template.user_defined_perforation_length is False
|
|
|
|
# Test 2: Integer 1 should fail
|
|
fracture_template.user_defined_perforation_length = 1
|
|
with pytest.raises(Exception) as exc_info:
|
|
fracture_template.update()
|
|
|
|
error_msg = str(exc_info.value)
|
|
assert (
|
|
"Extra characters found" in error_msg
|
|
or "unreadable" in error_msg
|
|
or "does not evaluate to either true or false" in error_msg
|
|
)
|
|
|
|
# Verify automatic rollback: should be back to False
|
|
assert fracture_template.user_defined_perforation_length is False
|
|
|
|
# Test 3: Float 0.99 should fail
|
|
fracture_template.user_defined_perforation_length = 0.99
|
|
with pytest.raises(Exception) as exc_info:
|
|
fracture_template.update()
|
|
|
|
error_msg = str(exc_info.value)
|
|
assert (
|
|
"Extra characters found" in error_msg
|
|
or "unreadable" in error_msg
|
|
or "does not evaluate to either true or false" in error_msg
|
|
)
|
|
|
|
# Verify automatic rollback: should be back to False
|
|
assert fracture_template.user_defined_perforation_length is False
|
|
|
|
# Test 4: String "yes" should fail
|
|
fracture_template.user_defined_perforation_length = "yes"
|
|
with pytest.raises(Exception) as exc_info:
|
|
fracture_template.update()
|
|
|
|
error_msg = str(exc_info.value)
|
|
assert (
|
|
"Extra characters found" in error_msg
|
|
or "unreadable" in error_msg
|
|
or "does not evaluate to either true or false" in error_msg
|
|
)
|
|
|
|
# Verify automatic rollback: should be back to False
|
|
assert fracture_template.user_defined_perforation_length is False
|