3.9 KiB
lws_fi
Fault Injection
To provide better quality there's a need to not just test the code paths for normal operation, but also that it acts correctly under various fault conditions that may be difficult to arrange at test-time.
Code handling the failures may be anywhere including during early initialization or in user code before lws intialization.
To help with this lws has LWS_WITH_SYS_FAULT_INJECTION
build option that
provides a simple but powerful api for fault injection in any lws or user code.
Fault contexts and faults
lws_fi_t
objects represent a named fault injection rules, just in terms of
whether and how often to inject the fault.
lws_fi_ctx_t
objects are linked-lists of lws_fi_t
objects. When Fault
Injection is enabled at build-time, the key system objects like the
lws_context
, lws_vhost
, wsi
and Secure Stream handles / SSPC handles
contain their own lws_fi_ctx_t
lists that may have any number of lws_fi_t
added to them.
lws_fi_ctx_t
objects are hierarchical, if a named rule is not found in, eg,
a wsi Fault injection context, then the vhost and finally the lws_context Fault
Injection contexts are searched for it before giving up. This allows for both
global and individual overridden Fault Injection rules at each level.
Integrating fault injection conditionals into code
A simple api lws_fi(fi_ctx, "name")
is provided that returns 0 if no fault to
be injected, or 1 if the fault should be synthesized. If there is no rule
matching "name", the answer is always to not inject a fault, ie, returns 0.
By default then just enabling Fault Injection at build does not have any impact on code operation since the user must first add the fault injection rules he wants.
The api keeps track of each time the context was asked and uses this information to drive the decision about when to say yes, according to the type of rule
Injection rule type | Description |
---|---|
LWSFI_ALWAYS |
Unconditionally inject the fault |
LWSFI_DETERMINISTIC |
after pre times without the fault, the next count times exhibit the fault` |
LWSFI_PROBABILISTIC |
exhibit a fault pre percentage of the time |
LWSFI_PATTERN |
Reference pre bits pointed to by pattern and fault if the bit set |
Addings Fault Injection Rules to lws_fi_ctx_t
User code should prepare a lws_fi_ctx_t
cleared down to zero if necessary,
and one of these, eg on the stack
typedef struct lws_fi {
const char *name;
uint8_t *pattern;
uint64_t pre__prob1;
uint64_t count__prob2;
char type; /* LWSFI_* */
} lws_fi_t;
and call lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi);
, this will
allocate and copy the provided fi
into the allocation, and attach it to
the lws_fi_ctx_t
list.
The creation info struct associated with the context, vhost, wsi or Secure
Stream has a *fi
pointer you can set to your lws_fi_ctx_t
, when creating
the object it will take ownership of any lws_fi_t
you attached to it.
So the lws_fi_ctx_t
and the lws_fi_t
used as a template for adding the
rules may be on the stack and safely and go out of scope after the object
creation api is called. The lws_fi_t
name
is also copied into the
allocation and does not need to continue to exist after it is added to the
lws_fi_ctx_t
. The only exception is the pattern
member if used, the
array pointed to is not copied and must exist for the lifetime of the rule.
Passing in fault injection rules
A key requirement is that Fault Injection rules must be availble to the code creating an object before the object has been created. This is why the user code prepares a temporary context listing his rules, and offers it as part of the creation info struct, rather than waiting for the object to be created and then attach Fault Injection rules... it's too late to test faults during the creation by then otherwise.
Using the namespace to target specific instances
Wsi client connection can directly have fault injection objects attached to it at client connection creation time.