Proxy context API reference¶
Every proxy create(name, real, ctx) function receives a ctx object built by
src/utest/mock/proxy_base.uc. The object provides read/write access to the
mock engine's registry for the named module.
ctx.get(channel, key)¶
Searches the layer stack from top to bottom, then falls back to global state,
looking only within channel. Returns the first value found for key, or
null if no entry exists at any level.
Parameters
| Name | Type | Description |
|---|---|---|
channel |
string | Channel name, e.g. 'data' or 'commands' |
key |
string | The key to look up |
Returns: any value stored under key in channel, or null.
Notes: get alone cannot tell an explicitly-stored null from "not found"
(both return null). Use ctx.has(channel, key) / ctx.has_data(key) when
that distinction matters — for example, the fs proxy treats a path stored as
null as explicitly absent rather than unseeded.
ctx.set(channel, key, val)¶
Writes val under key in channel. If any layers are active (i.e. inside a
mock.inject() callback), the write goes to the innermost layer. If no layers
are active, the write goes to global state.
Parameters
| Name | Type | Description |
|---|---|---|
channel |
string | Channel name, e.g. 'data' or 'commands' |
key |
string | The key to write |
val |
any | The value to store |
Returns: nothing.
ctx.all_keys(channel)¶
Returns an array of every key that exists across all layers and global state
within channel, deduplicated. Order is not guaranteed.
Parameters
| Name | Type | Description |
|---|---|---|
channel |
string | Channel name, e.g. 'data' |
Returns: array of strings.
Usage: proxy methods like lsdir and glob use this to enumerate all
virtual paths in the data channel without seeing keys from other channels.
ctx.get_data(key)¶
Shorthand for ctx.get('data', key). Prefer the generic form when writing
new proxy code; this shorthand is retained for backward compatibility.
Parameters
| Name | Type | Description |
|---|---|---|
key |
string | The data key to look up |
Returns: any value stored under key in the data channel, or null.
ctx.set_data(key, val)¶
Shorthand for ctx.set('data', key, val).
Parameters
| Name | Type | Description |
|---|---|---|
key |
string | The data key to write |
val |
any | The value to store |
Returns: nothing.
ctx.get_behavior(name)¶
Returns the override function registered for name, using the same top-down
layer-then-global search as get_data. Returns null if no override is
registered.
Parameters
| Name | Type | Description |
|---|---|---|
name |
string | The function name to look up (e.g. 'readfile', 'call') |
Returns: a function, or null.
Usage pattern in proxy methods:
proxy.readfile = function(path) {
let f = ctx.get_behavior('readfile');
if (f) return f(path); // caller-supplied override takes precedence
// ... data-driven logic below
};
ctx.is_strict()¶
Returns true if any active layer or the global state has strict: true.
In strict mode a proxy method should call die() when no mock data covers the
call, rather than falling through to the real module.
Returns: boolean.
ctx.is_active()¶
Returns true if any mock state is currently active for this module: at least
one layer is present, or global data/behavior/proxy is non-empty.
Returns: boolean.
Usage: proxy write methods use this to decide whether to record the write in mock state or pass it to the real module:
proxy.writefile = function(path, data) {
if (ctx.is_active()) {
ctx.set_data(path, data); // capture in mock state
return length(data);
}
return real.writefile(path, data);
};
ctx.get_all_data_keys()¶
Shorthand for ctx.all_keys('data').
Returns: array of strings.
ctx.has(channel, key) / ctx.has_data(key)¶
Returns true if key exists in channel at any layer or in global state,
even when its stored value is null. has_data(key) is shorthand for
has('data', key). Use this to distinguish an explicitly-stored null from an
absent key (see the note under ctx.get).
Returns: boolean.
ctx.record_call(name, args)¶
Appends args (an array) to the recorded call log for method name, which is
what spy(proxy).calls.<name> reads. Every proxy method must call this (as
its first action) so the method is visible to spy(); a method that skips it
silently records nothing.
Parameters
| Name | Type | Description |
|---|---|---|
name |
string | The method name being recorded (e.g. 'readfile') |
args |
array | The argument list the method received |
Returns: nothing.
proxy.readfile = function(path, size) {
ctx.record_call('readfile', size === null ? [path] : [path, size]);
// ... behavior override → data → strict → real ...
};
ctx.real_call(name, args, fallback)¶
Calls name(...args) on the real module and returns its result, or returns
fallback when the real module is absent (real is null — e.g. a module not
present on the host). Use it for the final fall-through step in a non-strict
proxy method.
Parameters
| Name | Type | Description |
|---|---|---|
name |
string | Real-module function to call |
args |
array | Arguments to pass |
fallback |
any | Returned when the real module is unavailable |
Returns: the real function's result, or fallback.
ctx.clone(v)¶
Returns a deep copy of v. Use it when a read method should hand back a fresh
value the way a real module does (real uci/fs return copies), so a caller
that mutates the result cannot corrupt the mock's stored data.
Returns: a deep copy of v.
ctx.base()¶
Constructs and returns a generic proxy object that covers every exported
function of real. For each function fn on real, the generated proxy
method checks for a behavior override via get_behavior(fn_name) first, then
calls real.fn(...). Non-function properties are copied by reference.
Returns: an object.
Usage: call ctx.base() at the start of create() to get a complete
passthrough proxy, then override only the methods that need custom logic:
create: function(name, real, ctx) {
let proxy = ctx.base(); // all real functions are proxied generically
proxy.read = function(key) {
// custom logic here
};
return proxy;
}
If real is null (module absent from rootfs), ctx.base() returns an empty
object {}.