mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-23 00:00:06 +01:00
93 lines
3.9 KiB
Markdown
93 lines
3.9 KiB
Markdown
![]() |
# `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.
|
||
|
|