cactus-test-definitions 1.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. cactus_test_definitions/__init__.py +39 -0
  2. cactus_test_definitions/__pycache__/__init__.cpython-312.pyc +0 -0
  3. cactus_test_definitions/__pycache__/actions.cpython-312.pyc +0 -0
  4. cactus_test_definitions/__pycache__/checks.cpython-312.pyc +0 -0
  5. cactus_test_definitions/__pycache__/csipaus.cpython-312.pyc +0 -0
  6. cactus_test_definitions/__pycache__/errors.cpython-312.pyc +0 -0
  7. cactus_test_definitions/__pycache__/events.cpython-312.pyc +0 -0
  8. cactus_test_definitions/__pycache__/parameters.cpython-312.pyc +0 -0
  9. cactus_test_definitions/__pycache__/schema.cpython-312.pyc +0 -0
  10. cactus_test_definitions/__pycache__/test_procedures.cpython-312-pytest-8.3.5.pyc +0 -0
  11. cactus_test_definitions/__pycache__/test_procedures.cpython-312.pyc +0 -0
  12. cactus_test_definitions/__pycache__/variable_expressions.cpython-312.pyc +0 -0
  13. cactus_test_definitions/__pycache__/version.cpython-312.pyc +0 -0
  14. cactus_test_definitions/client/__init__.py +30 -0
  15. cactus_test_definitions/client/__pycache__/__init__.cpython-312.pyc +0 -0
  16. cactus_test_definitions/client/__pycache__/actions.cpython-312.pyc +0 -0
  17. cactus_test_definitions/client/__pycache__/checks.cpython-312.pyc +0 -0
  18. cactus_test_definitions/client/__pycache__/events.cpython-312.pyc +0 -0
  19. cactus_test_definitions/client/__pycache__/test_procedures.cpython-312-pytest-8.3.5.pyc +0 -0
  20. cactus_test_definitions/client/__pycache__/validate.cpython-312.pyc +0 -0
  21. cactus_test_definitions/client/actions.py +99 -0
  22. cactus_test_definitions/client/checks.py +128 -0
  23. cactus_test_definitions/client/events.py +71 -0
  24. cactus_test_definitions/client/procedures/ALL-01.yaml +94 -0
  25. cactus_test_definitions/client/procedures/ALL-02.yaml +113 -0
  26. cactus_test_definitions/client/procedures/ALL-03-REJ.yaml +69 -0
  27. cactus_test_definitions/client/procedures/ALL-03.yaml +110 -0
  28. cactus_test_definitions/client/procedures/ALL-04.yaml +69 -0
  29. cactus_test_definitions/client/procedures/ALL-05.yaml +117 -0
  30. cactus_test_definitions/client/procedures/ALL-06.yaml +128 -0
  31. cactus_test_definitions/client/procedures/ALL-07.yaml +76 -0
  32. cactus_test_definitions/client/procedures/ALL-08.yaml +78 -0
  33. cactus_test_definitions/client/procedures/ALL-09.yaml +111 -0
  34. cactus_test_definitions/client/procedures/ALL-10.yaml +128 -0
  35. cactus_test_definitions/client/procedures/ALL-11.yaml +111 -0
  36. cactus_test_definitions/client/procedures/ALL-12.yaml +126 -0
  37. cactus_test_definitions/client/procedures/ALL-13.yaml +112 -0
  38. cactus_test_definitions/client/procedures/ALL-14.yaml +165 -0
  39. cactus_test_definitions/client/procedures/ALL-15.yaml +109 -0
  40. cactus_test_definitions/client/procedures/ALL-16.yaml +102 -0
  41. cactus_test_definitions/client/procedures/ALL-17.yaml +63 -0
  42. cactus_test_definitions/client/procedures/ALL-18.yaml +289 -0
  43. cactus_test_definitions/client/procedures/ALL-19.yaml +78 -0
  44. cactus_test_definitions/client/procedures/ALL-20.yaml +136 -0
  45. cactus_test_definitions/client/procedures/ALL-21.yaml +203 -0
  46. cactus_test_definitions/client/procedures/ALL-22.yaml +82 -0
  47. cactus_test_definitions/client/procedures/ALL-23.yaml +158 -0
  48. cactus_test_definitions/client/procedures/ALL-24.yaml +132 -0
  49. cactus_test_definitions/client/procedures/ALL-25-EXT.yaml +228 -0
  50. cactus_test_definitions/client/procedures/ALL-25.yaml +136 -0
  51. cactus_test_definitions/client/procedures/ALL-26.yaml +147 -0
  52. cactus_test_definitions/client/procedures/ALL-27.yaml +144 -0
  53. cactus_test_definitions/client/procedures/ALL-28.yaml +273 -0
  54. cactus_test_definitions/client/procedures/ALL-29.yaml +87 -0
  55. cactus_test_definitions/client/procedures/ALL-30.yaml +188 -0
  56. cactus_test_definitions/client/procedures/BES-01.yaml +136 -0
  57. cactus_test_definitions/client/procedures/BES-02.yaml +137 -0
  58. cactus_test_definitions/client/procedures/BES-03.yaml +135 -0
  59. cactus_test_definitions/client/procedures/BES-04.yaml +228 -0
  60. cactus_test_definitions/client/procedures/DRA-01.yaml +54 -0
  61. cactus_test_definitions/client/procedures/DRA-02.yaml +64 -0
  62. cactus_test_definitions/client/procedures/DRD-01.yaml +667 -0
  63. cactus_test_definitions/client/procedures/DRL-01.yaml +327 -0
  64. cactus_test_definitions/client/procedures/GEN-01.yaml +73 -0
  65. cactus_test_definitions/client/procedures/GEN-02.yaml +72 -0
  66. cactus_test_definitions/client/procedures/GEN-03.yaml +160 -0
  67. cactus_test_definitions/client/procedures/GEN-04.yaml +161 -0
  68. cactus_test_definitions/client/procedures/GEN-05.yaml +89 -0
  69. cactus_test_definitions/client/procedures/GEN-06.yaml +90 -0
  70. cactus_test_definitions/client/procedures/GEN-07.yaml +145 -0
  71. cactus_test_definitions/client/procedures/GEN-08.yaml +145 -0
  72. cactus_test_definitions/client/procedures/GEN-09.yaml +117 -0
  73. cactus_test_definitions/client/procedures/GEN-10.yaml +793 -0
  74. cactus_test_definitions/client/procedures/GEN-11.yaml +402 -0
  75. cactus_test_definitions/client/procedures/GEN-12.yaml +402 -0
  76. cactus_test_definitions/client/procedures/GEN-13.yaml +70 -0
  77. cactus_test_definitions/client/procedures/LOA-01.yaml +73 -0
  78. cactus_test_definitions/client/procedures/LOA-02.yaml +73 -0
  79. cactus_test_definitions/client/procedures/LOA-03.yaml +160 -0
  80. cactus_test_definitions/client/procedures/LOA-04.yaml +161 -0
  81. cactus_test_definitions/client/procedures/LOA-05.yaml +89 -0
  82. cactus_test_definitions/client/procedures/LOA-06.yaml +89 -0
  83. cactus_test_definitions/client/procedures/LOA-07.yaml +145 -0
  84. cactus_test_definitions/client/procedures/LOA-08.yaml +145 -0
  85. cactus_test_definitions/client/procedures/LOA-09.yaml +117 -0
  86. cactus_test_definitions/client/procedures/LOA-10.yaml +793 -0
  87. cactus_test_definitions/client/procedures/LOA-11.yaml +402 -0
  88. cactus_test_definitions/client/procedures/LOA-12.yaml +402 -0
  89. cactus_test_definitions/client/procedures/LOA-13.yaml +71 -0
  90. cactus_test_definitions/client/procedures/MUL-01.yaml +92 -0
  91. cactus_test_definitions/client/procedures/MUL-02.yaml +80 -0
  92. cactus_test_definitions/client/procedures/MUL-03.yaml +74 -0
  93. cactus_test_definitions/client/test_procedures.py +185 -0
  94. cactus_test_definitions/client/validate.py +98 -0
  95. cactus_test_definitions/csipaus.py +83 -0
  96. cactus_test_definitions/errors.py +15 -0
  97. cactus_test_definitions/parameters.py +153 -0
  98. cactus_test_definitions/py.typed +0 -0
  99. cactus_test_definitions/schema.py +22 -0
  100. cactus_test_definitions/server/README.md +172 -0
  101. cactus_test_definitions/server/__init__.py +27 -0
  102. cactus_test_definitions/server/__pycache__/__init__.cpython-312.pyc +0 -0
  103. cactus_test_definitions/server/__pycache__/actions.cpython-312.pyc +0 -0
  104. cactus_test_definitions/server/__pycache__/checks.cpython-312.pyc +0 -0
  105. cactus_test_definitions/server/__pycache__/test_procedures.cpython-312-pytest-8.3.5.pyc +0 -0
  106. cactus_test_definitions/server/__pycache__/validate.cpython-312.pyc +0 -0
  107. cactus_test_definitions/server/actions.py +140 -0
  108. cactus_test_definitions/server/checks.py +152 -0
  109. cactus_test_definitions/server/procedures/S-ALL-01.yaml +45 -0
  110. cactus_test_definitions/server/procedures/S-ALL-02.yaml +65 -0
  111. cactus_test_definitions/server/procedures/S-ALL-03.yaml +65 -0
  112. cactus_test_definitions/server/procedures/S-ALL-04.yaml +137 -0
  113. cactus_test_definitions/server/procedures/S-ALL-05.yaml +111 -0
  114. cactus_test_definitions/server/procedures/S-ALL-06.yaml +111 -0
  115. cactus_test_definitions/server/procedures/S-ALL-07.yaml +100 -0
  116. cactus_test_definitions/server/procedures/S-ALL-08.yaml +77 -0
  117. cactus_test_definitions/server/procedures/S-ALL-09.yaml +43 -0
  118. cactus_test_definitions/server/procedures/S-ALL-10.yaml +68 -0
  119. cactus_test_definitions/server/procedures/S-ALL-11.yaml +36 -0
  120. cactus_test_definitions/server/procedures/S-ALL-12.yaml +36 -0
  121. cactus_test_definitions/server/procedures/S-ALL-13.yaml +36 -0
  122. cactus_test_definitions/server/procedures/S-ALL-14.yaml +36 -0
  123. cactus_test_definitions/server/procedures/S-ALL-15.yaml +79 -0
  124. cactus_test_definitions/server/procedures/S-ALL-16.yaml +79 -0
  125. cactus_test_definitions/server/procedures/S-ALL-17.yaml +39 -0
  126. cactus_test_definitions/server/procedures/S-ALL-18.yaml +35 -0
  127. cactus_test_definitions/server/procedures/S-ALL-19.yaml +34 -0
  128. cactus_test_definitions/server/procedures/S-ALL-20.yaml +34 -0
  129. cactus_test_definitions/server/procedures/S-ALL-21.yaml +34 -0
  130. cactus_test_definitions/server/procedures/S-ALL-22.yaml +34 -0
  131. cactus_test_definitions/server/procedures/S-ALL-23.yaml +34 -0
  132. cactus_test_definitions/server/procedures/S-ALL-24.yaml +37 -0
  133. cactus_test_definitions/server/procedures/S-ALL-25.yaml +151 -0
  134. cactus_test_definitions/server/procedures/S-ALL-41.yaml +343 -0
  135. cactus_test_definitions/server/procedures/S-ALL-42.yaml +81 -0
  136. cactus_test_definitions/server/procedures/S-ALL-43.yaml +146 -0
  137. cactus_test_definitions/server/procedures/S-ALL-44.yaml +51 -0
  138. cactus_test_definitions/server/procedures/S-ALL-45.yaml +34 -0
  139. cactus_test_definitions/server/procedures/S-ALL-48.yaml +29 -0
  140. cactus_test_definitions/server/procedures/S-ALL-49.yaml +56 -0
  141. cactus_test_definitions/server/procedures/S-ALL-51.yaml +35 -0
  142. cactus_test_definitions/server/procedures/S-ALL-52.yaml +35 -0
  143. cactus_test_definitions/server/procedures/S-ALL-53.yaml +42 -0
  144. cactus_test_definitions/server/procedures/S-ALL-55.yaml +45 -0
  145. cactus_test_definitions/server/procedures/S-ALL-56.yaml +36 -0
  146. cactus_test_definitions/server/procedures/S-ALL-57.yaml +62 -0
  147. cactus_test_definitions/server/procedures/S-OPT-01.yaml +42 -0
  148. cactus_test_definitions/server/procedures/S-OPT-02.yaml +40 -0
  149. cactus_test_definitions/server/procedures/S-OPT-03.yaml +47 -0
  150. cactus_test_definitions/server/procedures/S-OPT-04.yaml +32 -0
  151. cactus_test_definitions/server/procedures/S-OPT-05.yaml +33 -0
  152. cactus_test_definitions/server/test_procedures.py +156 -0
  153. cactus_test_definitions/server/validate.py +30 -0
  154. cactus_test_definitions/variable_expressions.py +419 -0
  155. cactus_test_definitions-1.8.0.dist-info/METADATA +289 -0
  156. cactus_test_definitions-1.8.0.dist-info/RECORD +173 -0
  157. cactus_test_definitions-1.8.0.dist-info/WHEEL +5 -0
  158. cactus_test_definitions-1.8.0.dist-info/licenses/LICENSE.txt +22 -0
  159. cactus_test_definitions-1.8.0.dist-info/top_level.txt +2 -0
  160. tests/__init__.py +0 -0
  161. tests/unit/__init__.py +0 -0
  162. tests/unit/client/__init__.py +0 -0
  163. tests/unit/client/test_actions.py +72 -0
  164. tests/unit/client/test_checks.py +71 -0
  165. tests/unit/client/test_events.py +36 -0
  166. tests/unit/client/test_test_procedures.py +103 -0
  167. tests/unit/client/test_validate.py +200 -0
  168. tests/unit/server/__init__.py +0 -0
  169. tests/unit/server/test_test_procedures.py +60 -0
  170. tests/unit/server/test_validate.py +75 -0
  171. tests/unit/test_csipaus.py +49 -0
  172. tests/unit/test_parameters.py +197 -0
  173. tests/unit/test_variable_expressions.py +402 -0
@@ -0,0 +1,172 @@
1
+
2
+ # Server Test Schema
3
+
4
+ This is for the **SERVER** test procedures.
5
+
6
+ At its most basic level, a server test is a series of actions by a virtual "client" that will probe the server and look for unexpected behaviour/responses.
7
+
8
+ ## Clients and Context
9
+
10
+ Each test will define one or more "virtual clients" as a precondition. These can be restricted to a specific client type (eg Aggregator or Device) or left unspecified.
11
+
12
+ At the beginning of each test, the client will only know it's LFDI, PEN, PIN and certificate details. Through running actions it will discover resources and populate a local "context" which represents the last seen CSIP-Aus resources. Each client's context is seperate, so if Client A performs discovery, those resources will be invisible to Client B.
13
+
14
+ ## Steps Schema
15
+
16
+ The most basic building block of a server `TestProcedure` is a `Step`. Each `Step` will always define a single `Action` which dictates the behaviour of a virtual client (eg sending a particular request) which is then followed by a series of `Check` objects to evaluate. In order for a step to pass it must:
17
+
18
+ 1) Execute with any errors (eg - able to successfully make a HTTP request to the utility server)
19
+ 2) Have all checks return passed
20
+
21
+
22
+ Steps:
23
+ - id: DISCOVERY
24
+ action:
25
+ type: discovery
26
+ parameters:
27
+ resources:
28
+ - DeviceCapability
29
+ - Time
30
+ - MirrorUsagePointList
31
+ - EndDevice
32
+ - DER
33
+ checks:
34
+ - type: discovered
35
+ parameters:
36
+ resources:
37
+ - DeviceCapability
38
+ - Time
39
+ - MirrorUsagePointList
40
+ - EndDevice
41
+ - DER
42
+ links:
43
+ - ConnectionPoint
44
+ - Registration
45
+ - DERCapability
46
+ - DERSettings
47
+ - DERStatus
48
+ - type: end-device
49
+ parameters:
50
+ matches_client: true
51
+ - type: time-synced
52
+
53
+
54
+ Step Schema:
55
+ ```
56
+ Steps:
57
+ - DESCRIPTIVE_TITLE_OF_STEP: # This is used for display
58
+ action: #
59
+ type: # string identifier of the action type - see table below
60
+ parameters: # Any parameters to modify the default behaviour of the action - see table below
61
+ checks: # A list of Check definitions that will need to be true for this event to trigger - see section on Checks below
62
+ - type: # string identifier of the check type - see table below
63
+ parameters: # Any parameters to modify the default behaviour of the check - see table below
64
+
65
+ client: # The string descriptor of the "Required Client" in the preconditions that will execute this step
66
+ # (Defaults to the first required client)
67
+
68
+ use_client_context: # The string descriptor of the "Required Client" in the preconditions whose context/memory
69
+ # of discovered resources will be used (for testing cross client authentication issues)
70
+ instructions: # List of text strings to render while this test is executing
71
+ repeat_until_pass: # Most steps if failed will abort the test, setting this to true will repeat this step regularly
72
+ # until a pass is recorded (eg - use it to prompt a server to inject a DERControl)
73
+ ```
74
+
75
+
76
+ ### Actions
77
+
78
+ These are the currently defined `Action` elements that can be included in a test.
79
+
80
+ This is an example of an `Action` elements that trigger a client to requests links from the device capability URI until all nominated resources are reached.
81
+
82
+ ```
83
+ action:
84
+ type: discovery
85
+ parameters:
86
+ resources:
87
+ - Time
88
+ - MirrorUsagePointList
89
+ - EndDevice
90
+ - DER
91
+ ```
92
+
93
+
94
+ | **name** | **params** | **description** |
95
+ | -------- | ---------- | --------------- |
96
+ | `discovery` | `resources: list[CSIPAusResource]` `next_polling_window: bool/None` `list_limit: int/None` | Performs a full discovery / refresh of the client's context from DeviceCapability downwards, looking to discover the specific resources. Can be delayed until the next polling window and/or fixed to ONLY fetch a maximum number of entities. |
97
+ | `notifications` | `sub_id: str` `collect: bool/None` `disable: bool/None` | `sub_id` must match a previously created subscription. If `collect`, consumes subscription notifications and inserts them into the current context, if `disable` causes the subscription notification webhook to simulate an outage (return HTTP 5XX) |
98
+ | `wait` | `duration_seconds: int` | Performs no action for the nominated period of time |
99
+ | `refresh-resource` | `resource: CSIPAusResource` `expect_rejection: bool/None` `expect_rejection_or_empty: bool/None` | Forces a particular resource to be refreshed (using existing hrefs in context). Can be set to expect a HTTP 4XX ErrorResponse and/or an empty list resource (if appropriate). |
100
+ | `insert-end-device` | `force_lfdi: str/None` `expect_rejection: bool/None` | Causes the client to submit a new EndDevice registration and resolves the returned Location header |
101
+ | `upsert-connection-point` | `connectionPointId: str` `expect_rejection: bool/None` | Causes the client to submit a new ConnectionPoint with ID for the client's EndDevice |
102
+ | `upsert-mup` | `mup_id: str` `location: CSIPAusReadingLocation` `reading_types: list[CSIPAusReadingType]` `mmr_mrids: list[str]/None` `pow10_multiplier: int/None` `expect_rejection: bool/None` | Submits a MirrorUsagePoint with MirrorMeterReading's. Will ensure stable MRID values for the same sets of parameters (unless overridden with mmr_mrids). `mup_id` will alias this MirrorUsagePoint for future action calls. |
103
+ | `insert-readings` | `mup_id: str` `values: ReadingTypeValues` `expect_rejection: bool/None` | Begins the submission of readings (at MUP post rate, to an earlier call to `upsert-mup` with the same `mup_id`). Will interleave transmission with subsequent steps (non blocking) if multiple sets of values are specified |
104
+ | `upsert-der-status` | `genConnectStatus: int/None` `operationalModeStatus: int/None` `alarmStatus: int/None` `expect_rejection: bool/None` | Sends DERStatus - validates that the server persisted the values correctly |
105
+ | `upsert-der-capability` | `type: int` `rtgMaxW: int` `modesSupported: int` `doeModesSupported: int` | Sends DERCapability - validates that the server persisted the values correctly |
106
+ | `upsert-der-settings` | `setMaxW: int` `setGradW: int` `modesEnabled: int` `doeModesEnabled: int` | Sends DERSettings - validates that the server persisted the values correctly |
107
+ | `send-malformed-der-settings` | `updatedTime_missing: bool` | Sends a malformed DERSettings - expects a failure and that the server will NOT change anything |
108
+ | `send-malformed-response` | `mrid_unknown: bool` `endDeviceLFDI_unknown: bool` `response_invalid: bool` | Sends a malformed Response (using the most recent DERControl replyTo) - expects a failure response |
109
+ | `create-subscription` | `sub_id: str` `resource: CSIPAusResource` | Sends a new Subscription - validates that the server persisted the values correctly via Location. `sub_id` will alias this subscription for future action calls. |
110
+ | `delete-subscription` | `sub_id: str` | Sends a deletion for a previously created Subscription. |
111
+ | `respond-der-controls` | None | Enumerates all known DERControls and sends a Response for any that require it. |
112
+
113
+
114
+ ### Checks
115
+
116
+ A `Check` is a boolean test of what the client has in its current context. They are typically defined as a success/failure condition to be run at the end of a `Step`.
117
+
118
+ | **name** | **params** | **description** |
119
+ | -------- | ---------- | --------------- |
120
+ | `discovered` | `resources: list[CSIPAusResource]` `links: list[CSIPAusResource]` | Does the client's context have the nominated resources (or the parent resource with an appropriate link). |
121
+ | `time-sync` | None | Does the client have a TimeResponse and does it closely map to the client's local time. |
122
+ | `function-set-assignment` | `minimum_count: int/None` `maximum_count: int/None` `matches_client_edev: bool/None` | Are there the correct number of FunctionSetAssignments that may or may not belong solely under the client's EndDevice (or any accessible EndDevice) |
123
+ | `end-device-list` | `minimum_count: int/None` `maximum_count: int/None` `poll_rate: int/None` `sub_id: str/None` | Are there a correct number of EndDeviceList that match the filter criteria |
124
+ | `end-device` | `matches_client: bool` `matches_pin` | Is there an EndDevice that matches the client's LFDI (can be negatively asserted) and does it have a specific Registration PIN |
125
+ | `der-program` | `minimum_count: int/None` `maximum_count: int/None` `primacy: int/None` `fsa_index: int/None` `sub_id: str/None` | Are there enough DERProgram(s) that satisfy the filter criteria? `fsa_index` matches DERPrograms that belong to the nth (0 based) FunctionSetAssignment (negative values count from end of list - eg -1 would match the last FSA) |
126
+ | `der-control` | `minimum_count: int/None` `maximum_count: int/None` `latest: bool/None` `opModImpLimW: float/None` `opModExpLimW: float/None` `opModLoadLimW: float/None` `opModGenLimW: float/None` `opModEnergize: bool/None` `opModConnect: bool/None` `opModFixedW: float/None` `rampTms: int/None` `randomizeStart: int/None` `event_status: int/None` `responseRequired: int/None` `derp_primacy: int/None` `sub_id: str/None` | Are there enough DERProgram(s) that satisfy the filter criteria? `latest` will ONLY match the most recent DERControl. |
127
+ | `default-der-control` | `minimum_count: int/None` `maximum_count: int/None` `opModExpLimW: float/None` `opModLoadLimW: float/None` `opModGenLimW: float/None` `setGradW: int/None` `sub_id: str/None` | Are there the correct number of DefaultDERControl instances with the specified values |
128
+ | `mirror-usage-point` | `matches: bool` `location: CSIPAusReadingLocation/None` `reading_types: list[CSIPAusReadingType]/None` `mmr_mrids: list[str]/None` `post_rate_seconds: int/None` | Does a MirrorUsagePoint exist with the specified values (or not exist if `matches` is false). Only asserts specified values. |
129
+ | `subscription` | `matches: bool` `resource: CSIPAusResource`| Does a Subscription exist for the specified resource (or not exist if `matches` is false). |
130
+ | `poll-rate` | `resource: CSIPAusResource` `poll_rate_seconds: int` | Does the nominated resource have the specified poll rate. |
131
+
132
+
133
+ ### Parameter Variable Resolution
134
+
135
+ Any `parameter` element expects a series of name/value pairs to pass to the "parent" `Action` or `Check` . For example:
136
+
137
+ ```
138
+ parameters:
139
+ number_param: 123
140
+ text_param: Text Content
141
+ date_param: 2020-01-02 03:04:05Z
142
+ csip_aus_resource: EndDeviceList
143
+
144
+ ```
145
+
146
+ But placeholder variables may also be used to reference things that aren't known until the test is underway. For example, the following would instead set `number_param` to the current setMaxW supplied by the client while `date_param` would be set to the moment in time that the `Action`, `Check` or `Event` is being evaluated.
147
+
148
+ ```
149
+ parameters:
150
+ number_param: $setMaxW
151
+ text_param: Text Content
152
+ date_param: $now
153
+
154
+ ```
155
+
156
+ The following are all the `NamedVariable` types currently implemented (these are distinct from the named variables
157
+ defined in the client test procedures)
158
+
159
+ | **name** | **description** |
160
+ | -------- | --------------- |
161
+ | `$now` | Resolves to the current moment in time (timezone aware). Returns a datetime |
162
+ | `$setMaxW` | Resolves to the current client configuration value for `DERSetting.setMaxW` as a number. |
163
+
164
+
165
+ Expressions are also supported.
166
+
167
+ ```
168
+ parameters:
169
+ number_param: $(setMaxW / 2)
170
+ text_param: Text Content
171
+ date_param: $(now - '5 mins')
172
+ ```
@@ -0,0 +1,27 @@
1
+ from cactus_test_definitions.server.actions import ACTION_PARAMETER_SCHEMA, Action
2
+ from cactus_test_definitions.server.checks import CHECK_PARAMETER_SCHEMA, Check
3
+ from cactus_test_definitions.server.test_procedures import (
4
+ Preconditions,
5
+ Step,
6
+ TestProcedure,
7
+ TestProcedureId,
8
+ get_all_test_procedures,
9
+ get_test_procedure,
10
+ get_yaml_contents,
11
+ parse_test_procedure,
12
+ )
13
+
14
+ __all__ = [
15
+ "TestProcedureId",
16
+ "Action",
17
+ "ACTION_PARAMETER_SCHEMA",
18
+ "Check",
19
+ "CHECK_PARAMETER_SCHEMA",
20
+ "Step",
21
+ "Preconditions",
22
+ "TestProcedure",
23
+ "get_all_test_procedures",
24
+ "get_test_procedure",
25
+ "get_yaml_contents",
26
+ "parse_test_procedure",
27
+ ]
@@ -0,0 +1,140 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any
3
+
4
+ from cactus_test_definitions.errors import TestProcedureDefinitionError
5
+ from cactus_test_definitions.parameters import (
6
+ ParameterSchema,
7
+ ParameterType,
8
+ validate_parameters,
9
+ )
10
+ from cactus_test_definitions.variable_expressions import (
11
+ parse_variable_expression_body,
12
+ try_extract_variable_expression,
13
+ )
14
+
15
+
16
+ @dataclass
17
+ class Action:
18
+ type: str
19
+ client: str | None = None # use the client with this id to execute this action. If None, use the 0th client
20
+ parameters: dict[str, Any] = None # type: ignore # This will be forced in __post_init__
21
+
22
+ def __post_init__(self):
23
+ """Some parameter values might contain variable expressions (eg: a string "$now") that needs to be replaced
24
+ with an parsed Expression object instead."""
25
+ if self.parameters is None:
26
+ self.parameters = {}
27
+
28
+ for k, v in self.parameters.items():
29
+ variable_expr = try_extract_variable_expression(v)
30
+ if variable_expr:
31
+ self.parameters[k] = parse_variable_expression_body(variable_expr, k)
32
+
33
+
34
+ # The parameter schema for each action, keyed by the action name
35
+ ACTION_PARAMETER_SCHEMA: dict[str, dict[str, ParameterSchema]] = {
36
+ "discovery": {
37
+ "resources": ParameterSchema(True, ParameterType.ListCSIPAusResource), # What resources to try and resolve?
38
+ "next_polling_window": ParameterSchema(
39
+ False, ParameterType.Boolean
40
+ ), # If set - delay this until the upcoming polling window (eg- wait for the next whole minute)
41
+ "list_limit": ParameterSchema(False, ParameterType.Integer),
42
+ }, # Performs a full discovery / refresh of the client's context from DeviceCapability downwards
43
+ "notifications": {
44
+ "sub_id": ParameterSchema(True, ParameterType.String), # Must match a previously created subscription
45
+ "collect": ParameterSchema(
46
+ False, ParameterType.Boolean
47
+ ), # Collects latest subscription notifications into context
48
+ "disable": ParameterSchema(False, ParameterType.Boolean), # Simulates HTTP 5XX outage at the endpoint
49
+ },
50
+ "wait": {
51
+ "duration_seconds": ParameterSchema(True, ParameterType.Integer)
52
+ }, # Waits (doing nothing - blocking other step actions) until the specified time period has passed
53
+ "comms-status": {
54
+ "notifications_enabled": ParameterSchema(True, ParameterType.Boolean) # Enable/Disble notification webhook
55
+ }, # Enables or disables certain communications
56
+ "refresh-resource": {
57
+ "resource": ParameterSchema(True, ParameterType.CSIPAusResource),
58
+ "expect_rejection": ParameterSchema(False, ParameterType.Boolean), # if set - expect 4XX and ErrorPayload
59
+ "expect_rejection_or_empty": ParameterSchema(
60
+ False, ParameterType.Boolean
61
+ ), # Similar to expect_rejection but also allow en empty list (if it's a list resource)
62
+ }, # Force an existing resource (in the client's context) to be re-fetched via href. Updates context on success
63
+ "insert-end-device": {
64
+ "force_lfdi": ParameterSchema(False, ParameterType.String), # Forces the use of this LFDI
65
+ "expect_rejection": ParameterSchema(False, ParameterType.Boolean), # If set - expect 4XX and ErrorPayload
66
+ }, # Inserts an EndDevice and then validates the returned Location header
67
+ "upsert-connection-point": {
68
+ "connectionPointId": ParameterSchema(True, ParameterType.String),
69
+ "expect_rejection": ParameterSchema(False, ParameterType.Boolean), # If set - expect ErrorPayload reasonCode 1
70
+ },
71
+ "upsert-mup": {
72
+ "mup_id": ParameterSchema(True, ParameterType.String), # Used to alias the returned MUP ID
73
+ "location": ParameterSchema(True, ParameterType.CSIPAusReadingLocation),
74
+ "reading_types": ParameterSchema(True, ParameterType.ListCSIPAusReadingType),
75
+ "expect_rejection": ParameterSchema(False, ParameterType.Boolean), # If set - expect 4XX and ErrorPayload
76
+ "mmr_mrids": ParameterSchema(
77
+ False, ParameterType.ListString
78
+ ), # Must correspond 1-1 with reading_types. Used for forcing specific mrid values
79
+ "pow10_multiplier": ParameterSchema(
80
+ False, ParameterType.Integer
81
+ ), # Force the use a particular pow10. Defaults to 0 otherwise
82
+ }, # Register a MUP with the specified values. MMR's based on hash of current client / reading types
83
+ "insert-readings": {
84
+ "mup_id": ParameterSchema(True, ParameterType.String), # Must be previously defined with register-mup
85
+ "values": ParameterSchema(
86
+ True, ParameterType.ReadingTypeValues
87
+ ), # The sequences of values to send at the MUP post rate
88
+ "expect_rejection": ParameterSchema(False, ParameterType.Boolean), # If set - expect 4XX and ErrorPayload
89
+ }, # Sends readings - validates that the telemetry is parsed correctly by the server
90
+ "upsert-der-status": {
91
+ "genConnectStatus": ParameterSchema(False, ParameterType.Integer),
92
+ "operationalModeStatus": ParameterSchema(False, ParameterType.Integer),
93
+ "alarmStatus": ParameterSchema(False, ParameterType.Integer),
94
+ "expect_rejection": ParameterSchema(False, ParameterType.Boolean), # If set - expect 4XX and ErrorPayload
95
+ }, # Sends DERStatus - validates that the server persisted the values correctly
96
+ "upsert-der-capability": {
97
+ "type": ParameterSchema(True, ParameterType.Integer),
98
+ "rtgMaxW": ParameterSchema(True, ParameterType.Integer),
99
+ "modesSupported": ParameterSchema(True, ParameterType.Integer),
100
+ "doeModesSupported": ParameterSchema(True, ParameterType.Integer),
101
+ }, # Sends DERCapability - validates that the server persisted the values correctly
102
+ "upsert-der-settings": {
103
+ "setMaxW": ParameterSchema(True, ParameterType.Integer),
104
+ "setGradW": ParameterSchema(True, ParameterType.Integer),
105
+ "modesEnabled": ParameterSchema(True, ParameterType.Integer),
106
+ "doeModesEnabled": ParameterSchema(True, ParameterType.Integer),
107
+ }, # Sends DERSettings - validates that the server persisted the values correctly
108
+ "send-malformed-der-settings": {
109
+ "updatedTime_missing": ParameterSchema(True, ParameterType.Boolean), # If true - updatedTime will be stripped
110
+ }, # Sends a malformed DERSettings - expects a failure and that the server will NOT change anything
111
+ "send-malformed-response": {
112
+ "mrid_unknown": ParameterSchema(True, ParameterType.Boolean), # If true - mrid will be random
113
+ "endDeviceLFDI_unknown": ParameterSchema(True, ParameterType.Boolean), # If true - endDeviceLfdi will be random
114
+ "response_invalid": ParameterSchema(True, ParameterType.Boolean), # If true - response will be a reserved value
115
+ }, # Sends a malformed Response (using the most recent DERControl replyTo) - expects a failure response
116
+ "create-subscription": {
117
+ "sub_id": ParameterSchema(True, ParameterType.String), # Used to alias the returned subscription ID
118
+ "resource": ParameterSchema(True, ParameterType.CSIPAusResource),
119
+ }, # Sends a new Subscription - validates that the server persisted the values correctly via Location
120
+ "delete-subscription": {
121
+ "sub_id": ParameterSchema(True, ParameterType.String), # Must match a previously
122
+ }, # Sends a Subscription deletion
123
+ "respond-der-controls": {}, # Enumerates all known DERControls and sends a Response for any that require it
124
+ }
125
+ VALID_ACTION_NAMES: set[str] = set(ACTION_PARAMETER_SCHEMA.keys())
126
+
127
+
128
+ def validate_action_parameters(procedure_name: str, step_name: str, action: Action) -> None:
129
+ """Validates the action parameters for the parent TestProcedure based on the ACTION_PARAMETER_SCHEMA
130
+
131
+ raises TestProcedureDefinitionError on failure"""
132
+ location = f"{procedure_name}.step[{step_name}]" # Descriptive location
133
+
134
+ parameter_schema = ACTION_PARAMETER_SCHEMA.get(action.type, None)
135
+ if parameter_schema is None:
136
+ raise TestProcedureDefinitionError(
137
+ f"{location} has an invalid action name '{action.type}'. Valid Names: {VALID_ACTION_NAMES}"
138
+ )
139
+
140
+ validate_parameters(location, action.parameters, parameter_schema)
@@ -0,0 +1,152 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any
3
+
4
+ from cactus_test_definitions.errors import TestProcedureDefinitionError
5
+ from cactus_test_definitions.parameters import (
6
+ ParameterSchema,
7
+ ParameterType,
8
+ validate_parameters,
9
+ )
10
+ from cactus_test_definitions.variable_expressions import (
11
+ parse_variable_expression_body,
12
+ try_extract_variable_expression,
13
+ )
14
+
15
+
16
+ @dataclass
17
+ class Check:
18
+ """A check represents some validation logic that runs during a Test Step and provides a pass/fail result with a
19
+ description. It will typically inspect the state of the client based on what it has seen from the server
20
+
21
+ eg: Ensuring that the client was able to see an EndDevice registration"""
22
+
23
+ type: str
24
+ parameters: dict[str, Any] = None # type: ignore # This will be forced in __post_init__
25
+
26
+ def __post_init__(self):
27
+ """Some parameter values might contain variable expressions (eg: a string "$now") that needs to be replaced
28
+ with an parsed Expression object instead."""
29
+ if self.parameters is None:
30
+ self.parameters = {}
31
+ for k, v in self.parameters.items():
32
+ variable_expr = try_extract_variable_expression(v)
33
+ if variable_expr:
34
+ self.parameters[k] = parse_variable_expression_body(variable_expr, k)
35
+
36
+
37
+ # The parameter schema for each action, keyed by the action name
38
+ CHECK_PARAMETER_SCHEMA: dict[str, dict[str, ParameterSchema]] = {
39
+ "discovered": {
40
+ "resources": ParameterSchema(False, ParameterType.ListCSIPAusResource),
41
+ "links": ParameterSchema(False, ParameterType.ListCSIPAusResource),
42
+ },
43
+ "time-synced": {}, # Passes if the current Time resource is synced with this client's date/time
44
+ "function-set-assignment": {
45
+ "minimum_count": ParameterSchema(False, ParameterType.Integer), # Needs at least this many FSAs to pass
46
+ "maximum_count": ParameterSchema(False, ParameterType.Integer), # Needs at most this many FSAs to pass
47
+ "matches_client_edev": ParameterSchema(
48
+ False, ParameterType.Boolean
49
+ ), # If True - only FSAs assigned to the client's EndDevice will be counted
50
+ "sub_id": ParameterSchema(
51
+ False, ParameterType.String
52
+ ), # If set - only FSAs received via this subscription will be counted
53
+ },
54
+ "end-device-list": {
55
+ "minimum_count": ParameterSchema(False, ParameterType.Integer), # Needs at least this many edev lists to pass
56
+ "maximum_count": ParameterSchema(False, ParameterType.Integer), # Needs at most this many edev lists to pass
57
+ "poll_rate": ParameterSchema(
58
+ False, ParameterType.Integer
59
+ ), # If set - will only count an EndDeviceList with this exact pollRate
60
+ "sub_id": ParameterSchema(
61
+ False, ParameterType.String
62
+ ), # If set - only EndDeviceLists received via this subscription will be counted
63
+ },
64
+ "end-device": {
65
+ "matches_client": ParameterSchema(
66
+ True, ParameterType.Boolean
67
+ ), # assert the existence / non existence of an EndDevice for the current client
68
+ "matches_pin": ParameterSchema(
69
+ False, ParameterType.Boolean
70
+ ), # if set - The matches_client criteria will ALSO check the registration PIN for the EndDevice. Default False
71
+ },
72
+ "der-program": {
73
+ "minimum_count": ParameterSchema(False, ParameterType.Integer), # Needs at least this many derps to pass
74
+ "maximum_count": ParameterSchema(False, ParameterType.Integer), # Needs at most this many derps to pass
75
+ "primacy": ParameterSchema(False, ParameterType.Integer), # Filters derps based on this primacy value
76
+ "fsa_index": ParameterSchema(
77
+ False, ParameterType.Integer
78
+ ), # Filters derps that belong to the nth (0 based) FunctionSetAssignment index
79
+ "sub_id": ParameterSchema(
80
+ False, ParameterType.String
81
+ ), # Filters derps to only those received via this named subscription
82
+ },
83
+ "der-control": {
84
+ "minimum_count": ParameterSchema(False, ParameterType.Integer), # Needs at least this many controls to pass
85
+ "maximum_count": ParameterSchema(False, ParameterType.Integer), # Needs at most this many controls to pass
86
+ "latest": ParameterSchema(False, ParameterType.Boolean), # forces filter checks against the most recent control
87
+ "opModImpLimW": ParameterSchema(False, ParameterType.Float), # Filters controls based on this value
88
+ "opModExpLimW": ParameterSchema(False, ParameterType.Float), # Filters controls based on this value
89
+ "opModLoadLimW": ParameterSchema(False, ParameterType.Float), # Filters controls based on this value
90
+ "opModGenLimW": ParameterSchema(False, ParameterType.Float), # Filters controls based on this value
91
+ "opModEnergize": ParameterSchema(False, ParameterType.Boolean), # Filters controls based on this value
92
+ "opModConnect": ParameterSchema(False, ParameterType.Boolean), # Filters controls based on this value
93
+ "opModFixedW": ParameterSchema(False, ParameterType.Float), # Filters controls based on this value
94
+ "rampTms": ParameterSchema(False, ParameterType.Integer), # Filter on this val. 0 means negative assertion
95
+ "randomizeStart": ParameterSchema(False, ParameterType.Integer), # Filter on this val (in seconds)
96
+ "event_status": ParameterSchema(False, ParameterType.Integer), # Filter on Event.status value
97
+ "responseRequired": ParameterSchema(False, ParameterType.Integer), # Filter on responseRequired value
98
+ "derp_primacy": ParameterSchema(
99
+ False, ParameterType.Integer
100
+ ), # Filter to control's belonging to a DERProgram with this primacy value
101
+ "sub_id": ParameterSchema(
102
+ False, ParameterType.String
103
+ ), # Filters control to only those received via this named subscription
104
+ "duration": ParameterSchema(False, ParameterType.Integer), # Filter on duration value
105
+ }, # Matches many DERControls (specified by minimum_count) against additional other filter criteria
106
+ "default-der-control": {
107
+ "minimum_count": ParameterSchema(False, ParameterType.Integer), # Needs at least this many default der controls
108
+ "maximum_count": ParameterSchema(False, ParameterType.Integer), # Needs at most this many default der controls
109
+ "opModImpLimW": ParameterSchema(False, ParameterType.Float),
110
+ "opModExpLimW": ParameterSchema(False, ParameterType.Float),
111
+ "opModGenLimW": ParameterSchema(False, ParameterType.Float),
112
+ "opModLoadLimW": ParameterSchema(False, ParameterType.Float),
113
+ "setGradW": ParameterSchema(False, ParameterType.Integer), # Hundredths of a percent / second
114
+ "sub_id": ParameterSchema(
115
+ False, ParameterType.String
116
+ ), # Filters default control to only those received via this named subscription
117
+ "derp_primacy": ParameterSchema(
118
+ False, ParameterType.Integer
119
+ ), # Filter to control's belonging to a DERProgram with this primacy value
120
+ }, # matches any DefaultDERControl with the specified values
121
+ "mirror-usage-point": {
122
+ "matches": ParameterSchema(True, ParameterType.Boolean), # True for positive assert, False for negative assert
123
+ "location": ParameterSchema(False, ParameterType.CSIPAusReadingLocation), # If not specified - match anything
124
+ "reading_types": ParameterSchema(False, ParameterType.ListCSIPAusReadingType), # If not specified - match all
125
+ "mmr_mrids": ParameterSchema(
126
+ False, ParameterType.ListString
127
+ ), # Must correspond 1-1 with reading_types. Used for forcing specific mrid values
128
+ "post_rate_seconds": ParameterSchema(False, ParameterType.Integer), # Only asserted if specified
129
+ }, # True if the matches assertion finds a MirrorUsagePoint with the specified parameters (requires exact match)
130
+ "subscription": {
131
+ "matches": ParameterSchema(True, ParameterType.Boolean), # True for positive assert, False for negative assert
132
+ "resource": ParameterSchema(True, ParameterType.CSIPAusResource),
133
+ }, # Matches the existence/nonexistence of a subscription for the specified resource
134
+ "poll-rate": {
135
+ "resource": ParameterSchema(True, ParameterType.CSIPAusResource),
136
+ "poll_rate_seconds": ParameterSchema(True, ParameterType.Integer),
137
+ }, # Asserts a specific poll rate value
138
+ }
139
+ VALID_CHECK_NAMES: set[str] = set(CHECK_PARAMETER_SCHEMA.keys())
140
+
141
+
142
+ def validate_check_parameters(procedure_name: str, check: Check) -> None:
143
+ """Validates the check parameters for the parent TestProcedure based on the CHECK_PARAMETER_SCHEMA
144
+
145
+ raises TestProcedureDefinitionError on failure"""
146
+ location = f"{procedure_name} Check: {check.type}" # Descriptive location of this action being validated
147
+
148
+ parameter_schema = CHECK_PARAMETER_SCHEMA.get(check.type, None)
149
+ if parameter_schema is None:
150
+ raise TestProcedureDefinitionError(f"{location} not a valid action name. {VALID_CHECK_NAMES}")
151
+
152
+ validate_parameters(location, check.parameters, parameter_schema)
@@ -0,0 +1,45 @@
1
+ Description: Discovery with Out-Of-Band registration
2
+ Category: Registration
3
+ Classes:
4
+ - A
5
+
6
+ TargetVersions:
7
+ - v1.2
8
+
9
+ Preconditions:
10
+ required_clients:
11
+ - id: client
12
+
13
+ Steps:
14
+ - id: DISCOVERY
15
+ repeat_until_pass: true
16
+ instructions:
17
+ - Create an EndDevice record with an lfdi/sfdi that matches your client. Ensure it has a single DER record.
18
+ action:
19
+ type: discovery
20
+ parameters:
21
+ resources:
22
+ - DeviceCapability
23
+ - Time
24
+ - MirrorUsagePointList
25
+ - EndDevice
26
+ - DER
27
+ checks:
28
+ - type: discovered
29
+ parameters:
30
+ resources:
31
+ - DeviceCapability
32
+ - Time
33
+ - MirrorUsagePointList
34
+ - EndDevice
35
+ - DER
36
+ links:
37
+ - ConnectionPoint
38
+ - Registration
39
+ - DERCapability
40
+ - DERSettings
41
+ - DERStatus
42
+ - type: end-device
43
+ parameters:
44
+ matches_client: true
45
+ - type: time-synced
@@ -0,0 +1,65 @@
1
+ Description: Discovery with In-Band Registration for Direct Clients
2
+ Category: Registration
3
+ Classes:
4
+ - A
5
+
6
+ TargetVersions:
7
+ - v1.2
8
+
9
+ Preconditions:
10
+ required_clients:
11
+ - id: client
12
+ client_type: device
13
+
14
+ Steps:
15
+ - id: PRECONDITION
16
+ repeat_until_pass: true
17
+ instructions:
18
+ - Remove any existing EndDevice registrations for client.
19
+ action:
20
+ type: discovery
21
+ parameters:
22
+ resources:
23
+ - DeviceCapability
24
+ - Time
25
+ - MirrorUsagePointList
26
+ - EndDevice
27
+ - DER
28
+ checks:
29
+ - type: discovered
30
+ parameters:
31
+ resources:
32
+ - DeviceCapability
33
+ - Time
34
+ - MirrorUsagePointList
35
+ - EndDeviceList
36
+ - type: end-device # This will be the check that will block if there is an existing EndDevice registration
37
+ parameters:
38
+ matches_client: false
39
+ - type: time-synced
40
+
41
+ - id: REGISTER
42
+ action:
43
+ type: insert-end-device
44
+ checks:
45
+ - type: end-device
46
+ parameters:
47
+ matches_client: true
48
+
49
+ - id: FETCHING DER INFO
50
+ repeat_until_pass: true
51
+ instructions:
52
+ - Populate DERList with an entry that has a DERCapabilityLink, DERSettingsLink and DERStatusLink.
53
+ action:
54
+ type: discovery
55
+ parameters:
56
+ resources:
57
+ - DER
58
+ checks:
59
+ - type: discovered
60
+ parameters:
61
+ links:
62
+ - DERCapability
63
+ - DERSettings
64
+ - DERStatus
65
+