Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,3 @@ cython_debug/
# Allure files
allure-results/
assets/

21 changes: 19 additions & 2 deletions test/common/common_steps.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
from pytest_bdd import given, then, parsers
from test.helpers import Header, TrolieClient, Role

Expand All @@ -19,6 +20,13 @@ def set_accept_header(content_type, client):
def set_accept_encoding_header(compression_type, client):
client.set_header(Header.Accept_Encoding, compression_type)

@given(parsers.parse("the Content-type header is set to `{request_type}`"))
def set_content_header(request_type, client):
client.set_header(Header.ContentType, request_type)

@given(parsers.parse("the Content-type header is set to `{content_type}`"))
def set_content_header(content_type, client):
client.set_header(Header.ContentType, content_type)

@given("the client has bad query parameters")
def bad_query_parameters(client: TrolieClient):
Expand All @@ -30,6 +38,15 @@ def non_empty_body(client: TrolieClient):
client.set_body({"key": "value"})
client.set_header("Content-Type", "application/json")

@given(parsers.parse("the body is loaded from `{filename}`"))
def set_body_from_file(client: TrolieClient, filename):
with open(filename, "r") as f:
body = json.load(f)
client.set_body(body)

@then("the response is 202 OK")
def request_forecast_limits_snapshot(client: TrolieClient):
assert client.get_status_code() == 202

@then("the response is 200 OK")
def request_forecast_limits_snapshot(client: TrolieClient):
Expand Down Expand Up @@ -60,7 +77,7 @@ def request_forecast_limits_snapshot_406(client: TrolieClient):

@then("the response is schema-valid")
def valid_snapshot(client: TrolieClient):
assert client.validate_response()
assert client.validate_response(), "Schema invalid"


def conditional_get(client: TrolieClient):
Expand All @@ -73,6 +90,6 @@ def empty_response(client: TrolieClient):
assert client.response_is_empty()


@then(parsers.parse("the Content-Type header in the response is `{content_type}`"))
@then(parsers.parse("the Content-Type header of the response is `{content_type}`"))
def content_type_header(content_type, client):
assert content_type == client.get_response_header(Header.ContentType)
36 changes: 35 additions & 1 deletion test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

from glob import glob


pytest_plugins = [
"test.common.common_steps",
"test.forecasting.step_defs"
]



def pytest_bdd_apply_tag(tag, function):
using_mock = os.getenv("TROLIE_BASE_URL") == "http://localhost:4010"
should_skip = tag == "prism_fail" and using_mock
Expand Down Expand Up @@ -44,3 +44,37 @@ def pytest_bdd_after_scenario(request, feature, scenario):

if client.get_status_code() >= 200 and client.get_status_code() < 300:
assert client.get_response_header("ETag")


def pytest_terminal_summary(terminalreporter, exitstatus, config):
"""Add a pretty summary of test results at the end of the pytest run."""
passed = len(terminalreporter.stats.get('passed', []))
failed = len(terminalreporter.stats.get('failed', []))
skipped = len(terminalreporter.stats.get('skipped', []))
deselected = len(terminalreporter.stats.get('deselected', []))
warnings = len(terminalreporter.stats.get('warnings', []))

# Build the summary output as a string
summary_lines = []
summary_lines.append('\n')
summary_lines.append('==================== 🧪 Test Results Summary ====================\n')
summary_lines.append(f' ✅ Passed: {passed}\n')
summary_lines.append(f' ❌ Failed: {failed}\n')
summary_lines.append(f' ⚠️ Skipped: {skipped}\n')
summary_lines.append(f' 🚫 Deselected: {deselected}\n')
summary_lines.append(f' ⚠️ Warnings: {warnings}\n')
if passed:
summary_lines.append(f'\n ✅ Passed Tests:\n')
for rep in terminalreporter.stats.get('passed', []):
if hasattr(rep, 'nodeid'):
summary_lines.append(f' - {rep.nodeid}\n')
if failed:
summary_lines.append(f'\n ❌ Failed Tests:\n')
for rep in terminalreporter.stats.get('failed', []):
if hasattr(rep, 'nodeid'):
summary_lines.append(f' - {rep.nodeid}\n')
summary_lines.append('===============================================================\n')

# Write to terminal as before
for line in summary_lines:
terminalreporter.write(line)
2 changes: 1 addition & 1 deletion test/forecasting/features/limit_snapshot_caching.feature
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Feature: Caching of Forecast Limits Snapshots supporting conditional GET
And the client has obtained the current Forecast Limits Snapshot with an ETag
When the client immediately issues a conditional GET for the same resource
Then the response is 304 Not Modified
And the the response is empty
And the response is empty

Examples:
| accept_header | accept_encoding |
Expand Down
38 changes: 38 additions & 0 deletions test/forecasting/features/limits_proposal_formats.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@forecasting
Feature: Provide forecast proposal limits in appropriate formats

As a Clearinghouse Operator
I want to provide forecast limits in a variety of formats
when a client sends the appropriate media type
So that clients can obtain the data in the format they need
Without defining a generalized query capability, like OData or GraphQL

Background: Authenticated as a Ratings Provider
Given a TROLIE client that has been authenticated as a Ratings Provider

# GET Obtain Forecast Proposal Status
Scenario Outline: Get the forecast proposal status
Given the Accept header is set to `<content_type>`
When the client requests the status of a Forecast Proposal
Then the response is 200 OK
And the Content-Type header of the response is `<content_type>`
And the response is schema-valid


Examples:
| content_type |
| application/vnd.trolie.rating-forecast-proposal-status.v1+json |

# PATCH Submit a Forecast Proposal
Scenario Outline: Submit a forecast proposal
Given the Content-type header is set to `<request_type>`
And the body is loaded from `<file_name>`
When the client submits a Forecast Proposal
Then the response is 202 OK
And the Content-Type header of the response is `<response_type>`
And the response is schema-valid

Examples:
| request_type | file_name | response_type |
| application/vnd.trolie.rating-forecast-proposal.v1+json | data/forecast_proposal.json | application/vnd.trolie.rating-forecast-proposal-status.v1+json |
| application/vnd.trolie.rating-forecast-proposal-slim.v1+json; limit-type=apparent-power | data/forecast_proposal_slim.json |
134 changes: 122 additions & 12 deletions test/forecasting/features/limits_snapshot_filters.feature
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,155 @@ Feature: Support querying subsets of the available forecasted limits
Given a TROLIE client that has been authenticated as a Ratings Provider
And the Accept header is set to `application/vnd.trolie.forecast-limits-snapshot.v1+json`

@prism_fail

# Query parameters for : GET Limits Forecast Snapshot
@prism_fail
Scenario Outline: Query forecast limits with offset-period-start
Given the current wall clock time at the Clearinghouse is today at 11am GMT, i.e., <server_time>
When the client requests forecast limits with `offset-period-start` for an hour from then at <request_offset_time>
Then the response should only include forecast limits starting at the `offset-period-start` in the server's time zone, i.e., <response_first_period>
Given the current wall clock time at the Clearinghouse today is set to the user's current time
When the client requests forecast limits with `offset-period-start` set to <offset_hours> after the current time
Then the response should include only forecast limits beginning at the current time plus <offset_hours>, in the server's time zone


Examples:
| server_time | request_offset_time | response_first_period |
| 06:00:00-05:00 | 06:00:00-06:00 | 07:00:00-05:00 |
| 05:00:00-06:00 | 07:00:00-05:00 | 06:00:00-06:00 |
| offset_hours |
| 1 |
| 5 |
| 7 |


@todo
Scenario: What to do when `offset-period-start` is in the past?

@prism_fail

@prism_fail
Scenario Outline: Query forecast limits with period-end
Given the current wall clock time at the Clearinghouse today is set to the user's current time
When the client requests forecast limits with `period-end` set to <offset_hours> after the current time
Then the response should include forecast limits up to the current time plus <offset_hours>, in the server's time zone

Examples:
| offset_hours |
| 1 |
| 5 |
| 7 |

Given the current wall clock time at the Clearinghouse is today at 11am GMT, i.e., <server_time>
When the client requests forecast limits with period-end <request_last_period>
Then the response should include forecast limits up to <response_last_period> in the server's time zone
Examples:
| server_time | request_last_period | response_last_period |
| 06:00:00-05:00 | 09:00:00-06:00 | 10:00:00-05:00 |
| 18:35:45-05:00 | 14:00:00-05:00 | 14:00:00-05:00 |


Scenario Outline: Query forecast limits with monitoring-set filter
When the client requests forecast limits with monitoring-set filter <monitoring_set_id>
Then the response should include forecast limits for the monitoring set <monitoring_set_id>
Examples:
| monitoring_set_id |
| default |
| default |

@requires_model
@requires_model
Scenario Outline: Query forecast limits with resource-id filter
When the client requests forecast limits with resource-id filter <resource_id>
Then the response should include forecast limits for the resource id <resource_id>
Examples:
| resource_id |
| 8badf00d |

@prism_fail
@prism_fail
Scenario: Query forecast limits with static-only
When the client requests forecast limits with static-only set to true
Then the response should include only static forecast limits

# Query parameters for : GET Historical Limits Forecast Snapshot
Scenario Outline: Query historical limits forecast snapshots with offset-period-start
Given the current wall clock time at the Clearinghouse today is set to the user's current time
When the client requests historical forecast limits with `offset-period-start` set to <offset_hours> after the current time
Then the response should include only forecast limits beginning at the current time plus <offset_hours>, in the server's time zone

Examples:
| offset_hours |
| 1 |
| 5 |
| 7 |


Scenario Outline: Query historical limits forecast snapshots with period-end
Given the current wall clock time at the Clearinghouse today is set to the user's current time
When the client requests historical forecast limits with `period-end` set to <offset_hours> after the current time
Then the response should include forecast limits up to the current time plus <offset_hours>, in the server's time zone

Examples:
| offset_hours |
| 1 |
| 5 |
| 7 |


Scenario Outline: Query historical limits forecast snapshots with monitoring-set
When the client requests historical forecast limits with monitoring-set filter <monitoring_set_id>
Then the response should include forecast limits for the monitoring set <monitoring_set_id>

Examples:
| monitoring_set_id |
| TO1 |

Scenario Outline: Query historical limits forcasting snapshots with resource-id
When the client requests historical forecast limits with resource-id filter <resource_id>
Then the response should include forecast limits for the resource id <resource_id>

Examples:
| resource_id |
| DOUGLAS.T538.1 OUT |
| PARKHILL.T5.T5 |
| HEARN.34562.1 |

Scenario Outline: Query historical limits forcasting snapshots with static-only
When the client requests historical forecast limits with static-only set to true
Then the response should include only static forecast limits

# Query parameters for : GET Regional Limits Forecast Snapshot
@offset_regional
Scenario Outline: Query regional limits forecast snapshots with offset-period-start
Given the current wall clock time at the Clearinghouse today is set to the user's current time
When the client requests regional forecast limits with `offset-period-start` set to <offset_hours> after the current time
Then the response should include only forecast limits beginning at the current time plus <offset_hours>, in the server's time zone

Examples:
| offset_hours |
| 1 |
| 5 |
| 7 |
@offset_regional
Scenario Outline: Query regional limits forecast snapshots with period-end
Given the current wall clock time at the Clearinghouse today is set to the user's current time
When the client requests regional forecast limits with `period-end` set to <offset_hours> after the current time
Then the response should include forecast limits up to the current time plus <offset_hours>, in the server's time zone

Examples:
| offset_hours |
| 1 |
| 5 |
| 7 |

Scenario Outline: Query regional limits forecast snapshots with monitoring-set
When the client requests regional forecast limits with monitoring-set filter <monitoring_set_id>
Then the response should include forecast limits for the monitoring set <monitoring_set_id>

Examples:
| monitoring_set_id |
| TO1 |

Scenario Outline: Query regional limits forecast snapshots with resource-id
When the client requests regional forecast limits with resource-id filter <resource_id>
Then the response should include forecast limits for the resource id <resource_id>

Examples:
| resource_id |
| DOUGLAS.T538.1 OUT |
| PARKHILL.T5.T5 |
| HEARN.34562.1 |

Scenario: Query regional limits forecast snapshots with static-only
When the client requests regional forecast limits with static-only set to true
Then the response should include only static forecast limits
Loading