testrium 0.1.0__tar.gz → 0.2.0__tar.gz

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.
@@ -0,0 +1,293 @@
1
+ Metadata-Version: 2.1
2
+ Name: testrium
3
+ Version: 0.2.0
4
+ Summary: A modern, advanced testing framework.
5
+ Home-page: https://github.com/letalboy/testrium
6
+ License: MIT
7
+ Author: Cristian Camargo
8
+ Author-email: ccf@cdone.com.br
9
+ Requires-Python: >=3.10,<4.0
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Requires-Dist: colorama (>=0.4.6,<0.5.0)
16
+ Requires-Dist: pandas (>=2.2.2,<3.0.0)
17
+ Requires-Dist: toml (>=0.10.2,<0.11.0)
18
+ Project-URL: Documentation, https://github.com/letalboy/testrium#readme
19
+ Project-URL: Repository, https://github.com/letalboy/testrium
20
+ Description-Content-Type: text/markdown
21
+
22
+ # Testrium
23
+
24
+ Testrium is a circuit-level end-to-end testing framework for Python systems.
25
+
26
+ It is built for tests where the important question is not only "did this function return the right value?", but:
27
+
28
+ ```text
29
+ Did this event, command, request, or message travel through the whole system correctly?
30
+ ```
31
+
32
+ Testrium helps coordinate multiple Python processes, record probes from each unit, verify that the expected endpoints were activated, and measure latency and consistency across the full circuit.
33
+
34
+ ## What Testrium Is For
35
+
36
+ Use Testrium when a test needs to prove behavior across multiple runtime units:
37
+
38
+ - a host and one or more clients
39
+ - two services exchanging messages
40
+ - an API that triggers a worker
41
+ - a producer writing to a queue and a consumer processing it
42
+ - a scheduler activating downstream logic
43
+ - a local microservice flow
44
+ - a module-to-module circuit where the final effect happens away from the source
45
+
46
+ Testrium is designed for tests where success means:
47
+
48
+ ```text
49
+ processes started
50
+ units synchronized
51
+ events happened
52
+ messages crossed boundaries
53
+ expected probes completed
54
+ the target endpoint activated
55
+ latency and consistency were measured
56
+ the whole circuit passed
57
+ ```
58
+
59
+ ## What Testrium Is Not
60
+
61
+ Testrium is not a replacement for `pytest`, `unittest`, or direct API test tools.
62
+
63
+ Those tools are excellent for direct tests:
64
+
65
+ - function input/output
66
+ - class behavior
67
+ - isolated modules
68
+ - single endpoint responses
69
+ - fixtures and local assertions
70
+
71
+ Testrium sits beside them. It exists for the cases where direct assertions are not enough because the behavior crosses process, service, module, queue, socket, or callback boundaries.
72
+
73
+ ## Why This Library Exists
74
+
75
+ In many systems, the actual behavior is a circuit:
76
+
77
+ ```text
78
+ source unit -> event/message/request -> intermediate unit -> endpoint activation
79
+ ```
80
+
81
+ Traditional test tools can test each piece, but the full circuit often becomes custom scripts, fixed sleeps, process joins, shared status flags, log scraping, and repeated manual assertions.
82
+
83
+ Testrium turns that repeated pattern into a framework:
84
+
85
+ ```text
86
+ declare units
87
+ start coordinated processes
88
+ emit probes
89
+ collect events
90
+ verify the circuit
91
+ measure latency
92
+ report pass/fail
93
+ store history
94
+ ```
95
+
96
+ ## Core Concepts
97
+
98
+ ### Unit
99
+
100
+ A unit is one actor in the scenario, such as `host`, `client`, `api`, `worker`, `scheduler`, or `consumer`.
101
+
102
+ ### Probe
103
+
104
+ A probe is a completion tag emitted by a unit when something important happens.
105
+
106
+ Examples:
107
+
108
+ ```text
109
+ host-ready
110
+ client-contacted
111
+ command-sent
112
+ command-received
113
+ worker-activated
114
+ response-received
115
+ ```
116
+
117
+ ### Event
118
+
119
+ An event is the stored record of a probe. Events include the unit, completed step, event type, event key, and timestamp.
120
+
121
+ ### Circuit
122
+
123
+ A circuit is the full path from cause to effect.
124
+
125
+ Examples:
126
+
127
+ ```text
128
+ client command -> host receives -> host callback runs -> client receives response
129
+ API request -> event emitted -> worker consumes -> database update completes
130
+ service A sends -> service B receives -> service B responds -> service A completes
131
+ ```
132
+
133
+ ## What Testrium Measures
134
+
135
+ Testrium should make these checks first-class:
136
+
137
+ | Circuit concern | What Testrium verifies |
138
+ | --- | --- |
139
+ | Start point | Which unit emitted the event or command |
140
+ | Route | Which units should receive or process it |
141
+ | Endpoint activation | Which callback, handler, worker, or endpoint ran |
142
+ | Completion tags | Which probes completed in each unit |
143
+ | Consistency | Whether `Send` and `Receive` pairs match by `EventKey` |
144
+ | Latency | Time between send/receive events and total scenario duration |
145
+ | Failure evidence | Missing probes, exception events, orphan sends, orphan receives, duplicate keys |
146
+
147
+ ## Comparison
148
+
149
+ | Tool or category | Best for | Where Testrium fits |
150
+ | --- | --- | --- |
151
+ | `pytest` | Direct function, class, fixture, and module tests | Use Testrium when the assertion depends on events crossing runtime boundaries |
152
+ | `unittest` | Standard-library direct tests | Use Testrium for coordinated multi-unit scenarios |
153
+ | API test tools | One endpoint request/response | Use Testrium when the endpoint triggers async or downstream behavior |
154
+ | Contract testing | Schema/provider compatibility | Use Testrium to prove the live circuit actually executed |
155
+ | Browser E2E tools | UI flows | Use Testrium for backend/service/module circuits |
156
+ | Load tools | Throughput and stress | Use Testrium for per-circuit correctness and latency |
157
+ | Custom scripts | Project-specific orchestration | Use Testrium to avoid rebuilding process coordination and probe verification |
158
+
159
+ ## Current Features
160
+
161
+ - Config-driven test groups
162
+ - Unit definitions through TOML files
163
+ - Config-first unit entrypoints using `module:function`
164
+ - Coordinated Python unit processes
165
+ - Unit lifecycle states and readiness probes
166
+ - Isolated SQLite runtime state per test group run
167
+ - Process-based setup support
168
+ - Event/probe logging with SQLite
169
+ - `Default`, `Exception`, `Send`, and `Receive` event types
170
+ - Required probe verification
171
+ - Send/receive correlation with latency metrics
172
+ - Callback hooks for extra validation and final result handling
173
+ - Basic result summaries
174
+ - Template generation for starter config files
175
+
176
+ The remaining near-term work is focused on richer fixtures, public history APIs, and broader reporting polish.
177
+
178
+ ## Installation
179
+
180
+ Using Poetry:
181
+
182
+ ```bash
183
+ poetry add testrium
184
+ ```
185
+
186
+ Using pip:
187
+
188
+ ```bash
189
+ pip install testrium
190
+ ```
191
+
192
+ ## Quick Start
193
+
194
+ Generate a starter config:
195
+
196
+ ```bash
197
+ testrium gen config-template .
198
+ ```
199
+
200
+ Run Testrium from a folder that contains test groups:
201
+
202
+ ```bash
203
+ testrium run
204
+ ```
205
+
206
+ Run with verbose logs:
207
+
208
+ ```bash
209
+ testrium --verbose run
210
+ ```
211
+
212
+ Exclude specific test groups:
213
+
214
+ ```bash
215
+ testrium --less test_redirect run
216
+ ```
217
+
218
+ ## Example Shape
219
+
220
+ ```text
221
+ tests/
222
+ test_connection/
223
+ config.toml
224
+ setup.py
225
+ test_case.py
226
+ units/
227
+ target.toml
228
+ source.toml
229
+ ```
230
+
231
+ Example unit config:
232
+
233
+ ```toml
234
+ ["source"]
235
+ init = 1
236
+ enabled = true
237
+ entrypoint = "test_case:run_source"
238
+ ready_event = "source-ready"
239
+ use_setup = false
240
+ in-except = "Resume"
241
+ unit_dependencies = ["target"]
242
+ events = [
243
+ "source-ready",
244
+ "command-sent",
245
+ "response-received"
246
+ ]
247
+ ```
248
+
249
+ Example probe:
250
+
251
+ ```python
252
+ from testrium.modules.events import Events_Manager
253
+
254
+ events = Events_Manager(Unit="source", path=".")
255
+
256
+ events.Set_Event("source-ready")
257
+ events.Set_Event("command-sent", event_type="Send", event_key="request-001")
258
+ ```
259
+
260
+ The receiving unit can emit:
261
+
262
+ ```python
263
+ from testrium.modules.events import Events_Manager
264
+
265
+ events = Events_Manager(Unit="target", path=".")
266
+
267
+ events.Set_Event("command-received", event_type="Receive", event_key="request-001")
268
+ ```
269
+
270
+ Testrium can then verify that the expected probes happened and that the circuit completed.
271
+
272
+ ## Documentation
273
+
274
+ - [Developer guide](docs/developer-guide.md): how to structure scenarios, units, probes, and circuit-level tests.
275
+ - [Design decisions](docs/design-decisions.md): architecture, module responsibilities, flow diagrams, and implementation direction.
276
+ - [Implementation roadmap](docs/implementation-roadmap.md): issue-aligned gaps, acceptance gates, and MVP follow-up work.
277
+
278
+ ## Project Direction
279
+
280
+ The near-term implementation priority is:
281
+
282
+ 1. Make the CLI runnable and dependency-complete.
283
+ 2. Add strict config and unit validation.
284
+ 3. Implement unit orchestration by order, dependency, and setup policy.
285
+ 4. Implement event/probe verification.
286
+ 5. Add event correlation and history metrics.
287
+
288
+ Testrium's core promise is simple:
289
+
290
+ ```text
291
+ test the whole circuit, not only one component inside it
292
+ ```
293
+
@@ -0,0 +1,271 @@
1
+ # Testrium
2
+
3
+ Testrium is a circuit-level end-to-end testing framework for Python systems.
4
+
5
+ It is built for tests where the important question is not only "did this function return the right value?", but:
6
+
7
+ ```text
8
+ Did this event, command, request, or message travel through the whole system correctly?
9
+ ```
10
+
11
+ Testrium helps coordinate multiple Python processes, record probes from each unit, verify that the expected endpoints were activated, and measure latency and consistency across the full circuit.
12
+
13
+ ## What Testrium Is For
14
+
15
+ Use Testrium when a test needs to prove behavior across multiple runtime units:
16
+
17
+ - a host and one or more clients
18
+ - two services exchanging messages
19
+ - an API that triggers a worker
20
+ - a producer writing to a queue and a consumer processing it
21
+ - a scheduler activating downstream logic
22
+ - a local microservice flow
23
+ - a module-to-module circuit where the final effect happens away from the source
24
+
25
+ Testrium is designed for tests where success means:
26
+
27
+ ```text
28
+ processes started
29
+ units synchronized
30
+ events happened
31
+ messages crossed boundaries
32
+ expected probes completed
33
+ the target endpoint activated
34
+ latency and consistency were measured
35
+ the whole circuit passed
36
+ ```
37
+
38
+ ## What Testrium Is Not
39
+
40
+ Testrium is not a replacement for `pytest`, `unittest`, or direct API test tools.
41
+
42
+ Those tools are excellent for direct tests:
43
+
44
+ - function input/output
45
+ - class behavior
46
+ - isolated modules
47
+ - single endpoint responses
48
+ - fixtures and local assertions
49
+
50
+ Testrium sits beside them. It exists for the cases where direct assertions are not enough because the behavior crosses process, service, module, queue, socket, or callback boundaries.
51
+
52
+ ## Why This Library Exists
53
+
54
+ In many systems, the actual behavior is a circuit:
55
+
56
+ ```text
57
+ source unit -> event/message/request -> intermediate unit -> endpoint activation
58
+ ```
59
+
60
+ Traditional test tools can test each piece, but the full circuit often becomes custom scripts, fixed sleeps, process joins, shared status flags, log scraping, and repeated manual assertions.
61
+
62
+ Testrium turns that repeated pattern into a framework:
63
+
64
+ ```text
65
+ declare units
66
+ start coordinated processes
67
+ emit probes
68
+ collect events
69
+ verify the circuit
70
+ measure latency
71
+ report pass/fail
72
+ store history
73
+ ```
74
+
75
+ ## Core Concepts
76
+
77
+ ### Unit
78
+
79
+ A unit is one actor in the scenario, such as `host`, `client`, `api`, `worker`, `scheduler`, or `consumer`.
80
+
81
+ ### Probe
82
+
83
+ A probe is a completion tag emitted by a unit when something important happens.
84
+
85
+ Examples:
86
+
87
+ ```text
88
+ host-ready
89
+ client-contacted
90
+ command-sent
91
+ command-received
92
+ worker-activated
93
+ response-received
94
+ ```
95
+
96
+ ### Event
97
+
98
+ An event is the stored record of a probe. Events include the unit, completed step, event type, event key, and timestamp.
99
+
100
+ ### Circuit
101
+
102
+ A circuit is the full path from cause to effect.
103
+
104
+ Examples:
105
+
106
+ ```text
107
+ client command -> host receives -> host callback runs -> client receives response
108
+ API request -> event emitted -> worker consumes -> database update completes
109
+ service A sends -> service B receives -> service B responds -> service A completes
110
+ ```
111
+
112
+ ## What Testrium Measures
113
+
114
+ Testrium should make these checks first-class:
115
+
116
+ | Circuit concern | What Testrium verifies |
117
+ | --- | --- |
118
+ | Start point | Which unit emitted the event or command |
119
+ | Route | Which units should receive or process it |
120
+ | Endpoint activation | Which callback, handler, worker, or endpoint ran |
121
+ | Completion tags | Which probes completed in each unit |
122
+ | Consistency | Whether `Send` and `Receive` pairs match by `EventKey` |
123
+ | Latency | Time between send/receive events and total scenario duration |
124
+ | Failure evidence | Missing probes, exception events, orphan sends, orphan receives, duplicate keys |
125
+
126
+ ## Comparison
127
+
128
+ | Tool or category | Best for | Where Testrium fits |
129
+ | --- | --- | --- |
130
+ | `pytest` | Direct function, class, fixture, and module tests | Use Testrium when the assertion depends on events crossing runtime boundaries |
131
+ | `unittest` | Standard-library direct tests | Use Testrium for coordinated multi-unit scenarios |
132
+ | API test tools | One endpoint request/response | Use Testrium when the endpoint triggers async or downstream behavior |
133
+ | Contract testing | Schema/provider compatibility | Use Testrium to prove the live circuit actually executed |
134
+ | Browser E2E tools | UI flows | Use Testrium for backend/service/module circuits |
135
+ | Load tools | Throughput and stress | Use Testrium for per-circuit correctness and latency |
136
+ | Custom scripts | Project-specific orchestration | Use Testrium to avoid rebuilding process coordination and probe verification |
137
+
138
+ ## Current Features
139
+
140
+ - Config-driven test groups
141
+ - Unit definitions through TOML files
142
+ - Config-first unit entrypoints using `module:function`
143
+ - Coordinated Python unit processes
144
+ - Unit lifecycle states and readiness probes
145
+ - Isolated SQLite runtime state per test group run
146
+ - Process-based setup support
147
+ - Event/probe logging with SQLite
148
+ - `Default`, `Exception`, `Send`, and `Receive` event types
149
+ - Required probe verification
150
+ - Send/receive correlation with latency metrics
151
+ - Callback hooks for extra validation and final result handling
152
+ - Basic result summaries
153
+ - Template generation for starter config files
154
+
155
+ The remaining near-term work is focused on richer fixtures, public history APIs, and broader reporting polish.
156
+
157
+ ## Installation
158
+
159
+ Using Poetry:
160
+
161
+ ```bash
162
+ poetry add testrium
163
+ ```
164
+
165
+ Using pip:
166
+
167
+ ```bash
168
+ pip install testrium
169
+ ```
170
+
171
+ ## Quick Start
172
+
173
+ Generate a starter config:
174
+
175
+ ```bash
176
+ testrium gen config-template .
177
+ ```
178
+
179
+ Run Testrium from a folder that contains test groups:
180
+
181
+ ```bash
182
+ testrium run
183
+ ```
184
+
185
+ Run with verbose logs:
186
+
187
+ ```bash
188
+ testrium --verbose run
189
+ ```
190
+
191
+ Exclude specific test groups:
192
+
193
+ ```bash
194
+ testrium --less test_redirect run
195
+ ```
196
+
197
+ ## Example Shape
198
+
199
+ ```text
200
+ tests/
201
+ test_connection/
202
+ config.toml
203
+ setup.py
204
+ test_case.py
205
+ units/
206
+ target.toml
207
+ source.toml
208
+ ```
209
+
210
+ Example unit config:
211
+
212
+ ```toml
213
+ ["source"]
214
+ init = 1
215
+ enabled = true
216
+ entrypoint = "test_case:run_source"
217
+ ready_event = "source-ready"
218
+ use_setup = false
219
+ in-except = "Resume"
220
+ unit_dependencies = ["target"]
221
+ events = [
222
+ "source-ready",
223
+ "command-sent",
224
+ "response-received"
225
+ ]
226
+ ```
227
+
228
+ Example probe:
229
+
230
+ ```python
231
+ from testrium.modules.events import Events_Manager
232
+
233
+ events = Events_Manager(Unit="source", path=".")
234
+
235
+ events.Set_Event("source-ready")
236
+ events.Set_Event("command-sent", event_type="Send", event_key="request-001")
237
+ ```
238
+
239
+ The receiving unit can emit:
240
+
241
+ ```python
242
+ from testrium.modules.events import Events_Manager
243
+
244
+ events = Events_Manager(Unit="target", path=".")
245
+
246
+ events.Set_Event("command-received", event_type="Receive", event_key="request-001")
247
+ ```
248
+
249
+ Testrium can then verify that the expected probes happened and that the circuit completed.
250
+
251
+ ## Documentation
252
+
253
+ - [Developer guide](docs/developer-guide.md): how to structure scenarios, units, probes, and circuit-level tests.
254
+ - [Design decisions](docs/design-decisions.md): architecture, module responsibilities, flow diagrams, and implementation direction.
255
+ - [Implementation roadmap](docs/implementation-roadmap.md): issue-aligned gaps, acceptance gates, and MVP follow-up work.
256
+
257
+ ## Project Direction
258
+
259
+ The near-term implementation priority is:
260
+
261
+ 1. Make the CLI runnable and dependency-complete.
262
+ 2. Add strict config and unit validation.
263
+ 3. Implement unit orchestration by order, dependency, and setup policy.
264
+ 4. Implement event/probe verification.
265
+ 5. Add event correlation and history metrics.
266
+
267
+ Testrium's core promise is simple:
268
+
269
+ ```text
270
+ test the whole circuit, not only one component inside it
271
+ ```
@@ -1,27 +1,28 @@
1
- [tool.poetry]
2
- name = "testrium"
3
- version = "0.1.0"
4
- description = "A modern, advanced testing framework."
5
- authors = ["Cristian Camargo <ccf@cdone.com.br>"]
6
- readme = "README.md"
7
- homepage = "https://github.com/letalboy/testrium"
8
- repository = "https://github.com/letalboy/testrium"
9
- license = "MIT"
10
-
11
- [tool.poetry.dependencies]
12
- python = "^3.10"
13
- toml = "^0.10.2"
14
- pandas = "^2.2.2"
15
-
16
- [tool.poetry.group.dev.dependencies]
17
- pytest = "^8.2.2"
18
-
19
- [build-system]
20
- requires = ["poetry-core"]
21
- build-backend = "poetry.core.masonry.api"
22
-
23
- [tool.poetry.scripts]
24
- testrium = "testrium.core:main"
25
-
26
- [tool.poetry.urls]
27
- Documentation = "https://github.com/letalboy/testrium#readme"
1
+ [tool.poetry]
2
+ name = "testrium"
3
+ version = "0.2.0"
4
+ description = "A modern, advanced testing framework."
5
+ authors = ["Cristian Camargo <ccf@cdone.com.br>"]
6
+ readme = "README.md"
7
+ homepage = "https://github.com/letalboy/testrium"
8
+ repository = "https://github.com/letalboy/testrium"
9
+ license = "MIT"
10
+
11
+ [tool.poetry.dependencies]
12
+ python = "^3.10"
13
+ toml = "^0.10.2"
14
+ pandas = "^2.2.2"
15
+ colorama = "^0.4.6"
16
+
17
+ [tool.poetry.group.dev.dependencies]
18
+ pytest = "^9.0.3"
19
+
20
+ [build-system]
21
+ requires = ["poetry-core"]
22
+ build-backend = "poetry.core.masonry.api"
23
+
24
+ [tool.poetry.scripts]
25
+ testrium = "testrium.core:main"
26
+
27
+ [tool.poetry.urls]
28
+ Documentation = "https://github.com/letalboy/testrium#readme"
@@ -0,0 +1,15 @@
1
+ # This is the overall config for a circuit-level test group
2
+ ["Configs"]
3
+ units = ["target", "source"]
4
+ debug-modes = ["DEBUG", "INFO", "WARNING", "EXCEPT"]
5
+ test-modes = ["DEBUG"] # Can be "<MODE>", ["<MODE1>", <"MODE2">, ...], "All"
6
+ enabled = true
7
+ timeout = 10
8
+ use-ai = false
9
+ diagnostics = true
10
+ detect-bad-behavior = true
11
+ save-resume = true
12
+ repeat = 0 # can be any between 0 - 10
13
+ gen-metrics = true
14
+ save-metrics = true
15
+ save-scores = true
@@ -0,0 +1,38 @@
1
+ import os
2
+ import shutil
3
+ from colorama import Fore
4
+
5
+
6
+ def resolve_generation_path(path: str | None) -> str:
7
+ target_path = path or "."
8
+ return os.path.abspath(os.path.expanduser(target_path))
9
+
10
+
11
+ def _copy_template_file(source: str, destination: str) -> None:
12
+ destination_file = os.path.join(destination, os.path.basename(source))
13
+ if os.path.isfile(destination_file):
14
+ print(f"{Fore.BLUE} {os.path.basename(source)} already exists")
15
+ return
16
+ shutil.copy2(source, destination)
17
+
18
+
19
+ def resolve_template(type: str, path: str | None = "."):
20
+ if type == "config-template":
21
+ target_path = resolve_generation_path(path)
22
+ if not os.path.isdir(target_path):
23
+ print(f"{Fore.RED} path argument is invalid")
24
+ return
25
+
26
+ template_dir = os.path.dirname(__file__)
27
+ _copy_template_file(os.path.join(template_dir, "config.toml"), target_path)
28
+ _copy_template_file(os.path.join(template_dir, "test_case.py"), target_path)
29
+
30
+ units_source = os.path.join(template_dir, "units")
31
+ units_target = os.path.join(target_path, "units")
32
+ os.makedirs(units_target, exist_ok=True)
33
+ for filename in os.listdir(units_source):
34
+ if filename.endswith(".toml"):
35
+ _copy_template_file(os.path.join(units_source, filename), units_target)
36
+
37
+ print(f"{Fore.GREEN} config template generated in {target_path}")
38
+
@@ -0,0 +1,27 @@
1
+ from testrium.modules.events import Events_Manager
2
+
3
+
4
+ def run_target():
5
+ events = Events_Manager(Unit="target", path=".")
6
+ all_events = Events_Manager(Unit="*", path=".")
7
+
8
+ events.Set_Event("target-ready")
9
+ if not all_events.wait_for_event("command-sent", unit="source", timeout=5):
10
+ events.Set_Event("source-command-timeout", event_type="Exception")
11
+ return
12
+
13
+ events.Set_Event("command-received", event_type="Receive", event_key="request-001")
14
+ events.Set_Event("endpoint-activated")
15
+
16
+
17
+ def run_source():
18
+ events = Events_Manager(Unit="source", path=".")
19
+ all_events = Events_Manager(Unit="*", path=".")
20
+
21
+ events.Set_Event("source-ready")
22
+ events.Set_Event("command-sent", event_type="Send", event_key="request-001")
23
+
24
+ if all_events.wait_for_event("endpoint-activated", unit="target", timeout=5):
25
+ events.Set_Event("response-received")
26
+ else:
27
+ events.Set_Event("response-timeout", event_type="Exception")