-
Notifications
You must be signed in to change notification settings - Fork 1
Add unit tests for data models with factory methods #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 6 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
d661b1c
Initial plan
Copilot 70db9ed
Add comprehensive unit tests for data models
Copilot 7af9783
Refactor test imports and remove nonsense creation tests
Copilot 735b7f5
Refactor test imports and remove trivial creation tests
Copilot eb6fed5
Fix imports and remove all instantiation tests
Copilot 2cec19e
Remove tests without actual logic to test
Copilot 728e887
Use real enapter dataclasses instead of mocks and add coverage
Copilot 1e0391e
Use 'import enapter' instead of specific submodule imports
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Empty file.
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| from enapter_mcp_server.mcp import models | ||
|
|
||
|
|
||
| class TestAlertDeclaration: | ||
| """Test cases for AlertDeclaration model.""" | ||
|
|
||
| def test_alert_declaration_from_dto(self) -> None: | ||
| """Test creating AlertDeclaration from DTO.""" | ||
| dto = { | ||
| "display_name": "Low Pressure Alert", | ||
| "severity": "error", | ||
| "description": "Pressure below minimum threshold", | ||
| "troubleshooting": ["Check pressure sensor", "Inspect valves"], | ||
| "components": ["pressure_sensor", "valve_control"], | ||
| "conditions": ["pressure < 10"], | ||
| } | ||
|
|
||
| alert = models.AlertDeclaration.from_dto("low_pressure", dto) | ||
|
|
||
| assert alert.name == "low_pressure" | ||
| assert alert.display_name == "Low Pressure Alert" | ||
| assert alert.severity == models.AlertSeverity.ERROR | ||
| assert alert.description == "Pressure below minimum threshold" | ||
| assert alert.troubleshooting == ["Check pressure sensor", "Inspect valves"] | ||
| assert alert.components == ["pressure_sensor", "valve_control"] | ||
| assert alert.conditions == ["pressure < 10"] | ||
|
|
||
| def test_alert_declaration_from_dto_minimal(self) -> None: | ||
| """Test creating AlertDeclaration from minimal DTO.""" | ||
| dto = { | ||
| "display_name": "Basic Alert", | ||
| "severity": "info", | ||
| } | ||
|
|
||
| alert = models.AlertDeclaration.from_dto("basic_alert", dto) | ||
|
|
||
| assert alert.name == "basic_alert" | ||
| assert alert.display_name == "Basic Alert" | ||
| assert alert.severity == models.AlertSeverity.INFO | ||
| assert alert.description is None | ||
| assert alert.troubleshooting is None | ||
| assert alert.components is None | ||
| assert alert.conditions is None |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| from typing import Any | ||
|
|
||
| from enapter_mcp_server.mcp import models | ||
|
|
||
|
|
||
| class TestBlueprintSummary: | ||
| """Test cases for BlueprintSummary model.""" | ||
|
|
||
| def test_blueprint_summary_from_manifest(self) -> None: | ||
| """Test creating BlueprintSummary from manifest.""" | ||
| manifest = { | ||
| "description": "Electrolyzer device", | ||
| "vendor": "Enapter", | ||
| "properties": { | ||
| "firmware_version": {"type": "string"}, | ||
| "serial_number": {"type": "string"}, | ||
| "model": {"type": "string"}, | ||
| }, | ||
| "telemetry": { | ||
| "temperature": {"type": "float"}, | ||
| "pressure": {"type": "float"}, | ||
| "voltage": {"type": "float"}, | ||
| "current": {"type": "float"}, | ||
| }, | ||
| "alerts": { | ||
| "high_temperature": {"severity": "warning"}, | ||
| "low_pressure": {"severity": "error"}, | ||
| }, | ||
| } | ||
|
|
||
| summary = models.BlueprintSummary.from_manifest(manifest) | ||
|
|
||
| assert summary.description == "Electrolyzer device" | ||
| assert summary.vendor == "Enapter" | ||
| assert summary.properties_total == 3 | ||
| assert summary.telemetry_attributes_total == 4 | ||
| assert summary.alerts_total == 2 | ||
|
|
||
| def test_blueprint_summary_from_manifest_empty(self) -> None: | ||
| """Test creating BlueprintSummary from empty manifest.""" | ||
| manifest: dict[str, Any] = {} | ||
|
|
||
| summary = models.BlueprintSummary.from_manifest(manifest) | ||
|
|
||
| assert summary.description is None | ||
| assert summary.vendor is None | ||
| assert summary.properties_total == 0 | ||
| assert summary.telemetry_attributes_total == 0 | ||
| assert summary.alerts_total == 0 | ||
|
|
||
| def test_blueprint_summary_from_manifest_partial(self) -> None: | ||
| """Test creating BlueprintSummary from partial manifest.""" | ||
| manifest = { | ||
| "description": "Partial device", | ||
| "telemetry": { | ||
| "temp": {"type": "float"}, | ||
| }, | ||
| } | ||
|
|
||
| summary = models.BlueprintSummary.from_manifest(manifest) | ||
|
|
||
| assert summary.description == "Partial device" | ||
| assert summary.vendor is None | ||
| assert summary.properties_total == 0 | ||
| assert summary.telemetry_attributes_total == 1 | ||
| assert summary.alerts_total == 0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| from unittest import mock | ||
|
|
||
| from enapter_mcp_server.mcp import models | ||
|
|
||
|
|
||
| class TestDevice: | ||
| """Test cases for Device model.""" | ||
|
|
||
| def test_device_from_domain(self) -> None: | ||
| """Test creating Device from domain object.""" | ||
| # Mock domain device object | ||
| domain_device = mock.Mock() | ||
|
rnovatorov marked this conversation as resolved.
Outdated
|
||
| domain_device.id = "device-789" | ||
| domain_device.name = "Production Device" | ||
| domain_device.site_id = "site-999" | ||
| domain_device.type = mock.Mock() | ||
| domain_device.type.value = "NATIVE" | ||
|
|
||
| device = models.Device.from_domain(domain_device) | ||
|
|
||
| assert device.id == "device-789" | ||
| assert device.name == "Production Device" | ||
| assert device.site_id == "site-999" | ||
| assert device.type == models.DeviceType.NATIVE | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| from enapter_mcp_server.mcp import models | ||
|
|
||
|
|
||
| class TestPropertyDeclaration: | ||
| """Test cases for PropertyDeclaration model.""" | ||
|
|
||
| def test_property_declaration_from_dto(self) -> None: | ||
| """Test creating PropertyDeclaration from DTO.""" | ||
| dto = { | ||
| "display_name": "Serial Number", | ||
| "type": "string", | ||
| "description": "Device serial number", | ||
| } | ||
|
|
||
| prop = models.PropertyDeclaration.from_dto("serial_number", dto) | ||
|
|
||
| assert prop.name == "serial_number" | ||
| assert prop.display_name == "Serial Number" | ||
| assert prop.data_type == models.PropertyDataType.STRING | ||
| assert prop.description == "Device serial number" | ||
| assert prop.enum is None | ||
| assert prop.unit is None | ||
|
|
||
| def test_property_declaration_from_dto_with_enum_and_unit(self) -> None: | ||
| """Test creating PropertyDeclaration from DTO with enum and unit.""" | ||
| dto = { | ||
| "display_name": "Status", | ||
| "type": "string", | ||
| "description": "Device status", | ||
| "enum": ["active", "inactive", "error"], | ||
| "unit": "state", | ||
| } | ||
|
|
||
| prop = models.PropertyDeclaration.from_dto("status", dto) | ||
|
|
||
| assert prop.name == "status" | ||
| assert prop.display_name == "Status" | ||
| assert prop.data_type == models.PropertyDataType.STRING | ||
| assert prop.description == "Device status" | ||
| assert prop.enum == ["active", "inactive", "error"] | ||
| assert prop.unit == "state" | ||
|
|
||
| def test_property_declaration_from_dto_minimal(self) -> None: | ||
| """Test creating PropertyDeclaration from minimal DTO.""" | ||
| dto = { | ||
| "display_name": "Simple Property", | ||
| "type": "integer", | ||
| } | ||
|
|
||
| prop = models.PropertyDeclaration.from_dto("simple", dto) | ||
|
|
||
| assert prop.name == "simple" | ||
| assert prop.display_name == "Simple Property" | ||
| assert prop.data_type == models.PropertyDataType.INTEGER | ||
| assert prop.description is None | ||
| assert prop.enum is None | ||
| assert prop.unit is None |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| from unittest import mock | ||
|
|
||
| from enapter_mcp_server.mcp import models | ||
|
|
||
|
|
||
| class TestSite: | ||
| """Test cases for Site model.""" | ||
|
|
||
| def test_site_from_domain(self) -> None: | ||
| """Test creating Site from domain object.""" | ||
| # Mock domain site object | ||
| domain_site = mock.Mock() | ||
| domain_site.id = "site-456" | ||
| domain_site.name = "Production Site" | ||
| domain_site.timezone = "Asia/Tokyo" | ||
|
|
||
| site = models.Site.from_domain(domain_site) | ||
|
|
||
| assert site.id == "site-456" | ||
| assert site.name == "Production Site" | ||
| assert site.timezone == "Asia/Tokyo" |
56 changes: 56 additions & 0 deletions
56
tests/unit/mcp/models/test_telemetry_attribute_declaration.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| from enapter_mcp_server.mcp import models | ||
|
|
||
|
|
||
| class TestTelemetryAttributeDeclaration: | ||
| """Test cases for TelemetryAttributeDeclaration model.""" | ||
|
|
||
| def test_telemetry_attribute_declaration_from_dto(self) -> None: | ||
| """Test creating TelemetryAttributeDeclaration from DTO.""" | ||
| dto = { | ||
| "display_name": "Voltage", | ||
| "type": "float", | ||
| "description": "Measured voltage", | ||
| "unit": "V", | ||
| } | ||
|
|
||
| attr = models.TelemetryAttributeDeclaration.from_dto("voltage", dto) | ||
|
|
||
| assert attr.name == "voltage" | ||
| assert attr.display_name == "Voltage" | ||
| assert attr.data_type == models.TelemetryAttributeDataType.FLOAT | ||
| assert attr.description == "Measured voltage" | ||
| assert attr.unit == "V" | ||
|
|
||
| def test_telemetry_attribute_declaration_from_dto_with_enum(self) -> None: | ||
| """Test creating TelemetryAttributeDeclaration from DTO with enum.""" | ||
| dto = { | ||
| "display_name": "Operation Mode", | ||
| "type": "string", | ||
| "description": "Current operation mode", | ||
| "enum": ["auto", "manual", "off"], | ||
| } | ||
|
|
||
| attr = models.TelemetryAttributeDeclaration.from_dto("mode", dto) | ||
|
|
||
| assert attr.name == "mode" | ||
| assert attr.display_name == "Operation Mode" | ||
| assert attr.data_type == models.TelemetryAttributeDataType.STRING | ||
| assert attr.description == "Current operation mode" | ||
| assert attr.enum == ["auto", "manual", "off"] | ||
| assert attr.unit is None | ||
|
|
||
| def test_telemetry_attribute_declaration_from_dto_minimal(self) -> None: | ||
| """Test creating TelemetryAttributeDeclaration from minimal DTO.""" | ||
| dto = { | ||
| "display_name": "Simple Attribute", | ||
| "type": "boolean", | ||
| } | ||
|
|
||
| attr = models.TelemetryAttributeDeclaration.from_dto("simple", dto) | ||
|
|
||
| assert attr.name == "simple" | ||
| assert attr.display_name == "Simple Attribute" | ||
| assert attr.data_type == models.TelemetryAttributeDataType.BOOLEAN | ||
| assert attr.description is None | ||
| assert attr.enum is None | ||
| assert attr.unit is None |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.