Skip to content

Commit 05b9c74

Browse files
committed
dev(test): method overrides under TestKernel
A modal behavior is introduced in services which can be configured at runtime by calling `.setServiceMode(mode)`. The `mode` parameter takes a property called `override_prefix` which can determine a prefix for method overrides and change the behavior of the service.
1 parent 452e0b7 commit 05b9c74

File tree

4 files changed

+102
-0
lines changed

4 files changed

+102
-0
lines changed

src/backend/src/CoreModule.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,9 @@ const install = async ({ context, services, app, useapi, modapi }) => {
436436

437437
const { FileCacheService } = require('./services/file-cache/FileCacheService');
438438
services.registerService('file-cache', FileCacheService);
439+
440+
const { TestService } = require('./services/TestService');
441+
services.registerService('__test', TestService);
439442
};
440443

441444
const install_legacy = async ({ services }) => {

src/backend/src/services/BaseService.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,82 @@ class BaseService extends concepts.Service {
137137
|| this.constructor[`__on_${id}`]?.bind?.(this.constructor)
138138
|| NOOP;
139139
}
140+
141+
/**
142+
* Sets the service mode, enabling method overriding with prefixed methods.
143+
* This allows services to be "modal" - switching between different behavior modes
144+
* (e.g., test mode, debug mode, etc.) by overriding methods with prefixed versions.
145+
*
146+
* @param {Object|null} mode - Mode configuration object or null to restore normal mode
147+
* @param {string} [mode.override_prefix] - Prefix for methods that should override their unprefixed counterparts
148+
* (e.g., '__test_' will make __test_methodName override methodName)
149+
* @returns {void}
150+
*
151+
* @example
152+
* // Enable test mode
153+
* service.setServiceMode({ override_prefix: '__test_' });
154+
*
155+
* // Restore normal mode
156+
* service.setServiceMode(null);
157+
*/
158+
setServiceMode (mode) {
159+
// Restore previous mode if switching modes
160+
if ( this._serviceModeState ) {
161+
this._restoreServiceMode();
162+
}
163+
164+
// If mode is null or empty, just restore and return
165+
if ( ! mode || ! mode.override_prefix ) {
166+
this._serviceModeState = null;
167+
return;
168+
}
169+
170+
// Store mode state
171+
this._serviceModeState = {
172+
override_prefix: mode.override_prefix,
173+
methodOverrides: {},
174+
};
175+
176+
// Discover and apply method overrides
177+
const checkSources = [
178+
Object.getPrototypeOf(this),
179+
this
180+
];
181+
182+
for ( const source of checkSources ) {
183+
for ( const key of Object.getOwnPropertyNames(source) ) {
184+
if ( key.startsWith(mode.override_prefix) && typeof this[key] === 'function' ) {
185+
const originalMethodName = key.slice(mode.override_prefix.length);
186+
if ( typeof this[originalMethodName] === 'function' ) {
187+
// Store original method for restoration (only if not already stored)
188+
if ( ! this._serviceModeState.methodOverrides[originalMethodName] ) {
189+
this._serviceModeState.methodOverrides[originalMethodName] = this[originalMethodName];
190+
}
191+
// Override with prefixed method
192+
this[originalMethodName] = this[key].bind(this);
193+
}
194+
}
195+
}
196+
}
197+
}
198+
199+
/**
200+
* Restores the service to normal mode by reverting all method overrides.
201+
* @private
202+
* @returns {void}
203+
*/
204+
_restoreServiceMode () {
205+
if ( ! this._serviceModeState || ! this._serviceModeState.methodOverrides ) {
206+
return;
207+
}
208+
209+
// Restore original methods
210+
for ( const [methodName, originalMethod] of Object.entries(this._serviceModeState.methodOverrides) ) {
211+
this[methodName] = originalMethod;
212+
}
213+
214+
this._serviceModeState.methodOverrides = {};
215+
}
140216
}
141217

142218
module.exports = BaseService;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const BaseService = require('./BaseService');
2+
3+
class TestService extends BaseService {
4+
method_to_mock () {
5+
return 5;
6+
}
7+
8+
__test_method_to_mock () {
9+
return 7;
10+
}
11+
12+
_test ({ assert }) {
13+
assert.equal(this.method_to_mock(), 7);
14+
}
15+
}
16+
17+
module.exports = { TestService };

src/backend/tools/test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ const main = async () => {
232232
console.log(`\x1B[33;1m=== [ Service :: ${name} ] ===\x1B[0m`);
233233
});
234234

235+
// Switch service to test mode (enables __test_ method overrides)
236+
ins.setServiceMode({ override_prefix: '__test_' });
237+
235238
const testapi = {
236239
assert: (condition, name) => {
237240
name = name || condition.toString();
@@ -262,6 +265,9 @@ const main = async () => {
262265

263266
await ins._test(testapi);
264267

268+
// Restore service to normal mode
269+
ins.setServiceMode(null);
270+
265271
total_passed += passed;
266272
total_failed += failed;
267273
}

0 commit comments

Comments
 (0)