UhmServer: libuhttpmock Reference Manual

## UhmServer UhmServer — mock HTTP(S) server |

## Stability Level

Unstable, unless otherwise indicated

## Functions

UhmServer * | uhm_server_new ()
void | uhm_server_run ()
void | uhm_server_stop ()
void | uhm_server_start_trace ()
void | uhm_server_start_trace_full ()
void | uhm_server_end_trace ()
void | uhm_server_load_trace ()
void | uhm_server_load_trace_async ()
void | uhm_server_load_trace_finish ()
void | uhm_server_unload_trace ()
void | uhm_server_received_message_chunk ()
void | uhm_server_received_message_chunk_with_direction ()
void | uhm_server_received_message_chunk_from_soup ()
gboolean | uhm_server_get_enable_logging ()
void | uhm_server_set_enable_logging ()
gboolean | uhm_server_get_enable_online ()
void | uhm_server_set_enable_online ()
GFile * | uhm_server_get_trace_directory ()
void | uhm_server_set_trace_directory ()
GTlsCertificate * | uhm_server_get_tls_certificate ()
void | uhm_server_set_tls_certificate ()
GTlsCertificate * | uhm_server_set_default_tls_certificate ()
void | uhm_server_set_expected_domain_names ()
const gchar * | uhm_server_get_address ()
guint | uhm_server_get_port ()
UhmResolver * | uhm_server_get_resolver ()

## Properties

gchar * | address | Read
gboolean | enable-logging | Read / Write
gboolean | enable-online | Read / Write
guint | port | Read
UhmResolver * | resolver | Read
GTlsCertificate * | tls-certificate | Read / Write
GFile * | trace-directory | Read / Write

## Signals

gboolean | compare-messages | Run Last
gboolean | handle-message | Run Last

## Types and Values

| UhmServer
| UhmServerClass
enum | UhmServerError

## Object Hierarchy

        GObject
        ╰── UhmServer

## Includes

    #include <libuhttpmock/uhm-server.h>

## Description

This is a mock HTTPS server which can be used to run unit tests of network client code on a loopback interface rather than on the real Internet. At its core, it's a simple HTTPS server which runs on a loopback address on an arbitrary port. The code under test must be modified to send its requests to this port, although UhmResolver may be used to transparently redirect all IP addresses to the mock server. A convenience layer on the mock server provides loading of and recording to trace files, which are sequences of request–response HTTPS message pairs where each request is expected by the server (in order). On receiving an expected request, the mock server will return the relevant response and move to expecting the next request in the trace file.

The mock server currently only operates on a single network interface, on HTTPS only. This may change in future. A dummy TLS certificate is used to authenticate the server. This certificate is not signed by a CA, so the “ssl-strict” property must be set to `FALSE` in client code during (and only during!) testing.

The server can operate in three modes: logging, testing, and comparing. These are set by “enable-logging” and “enable-online”. • Logging mode (“enable-logging”: `TRUE`, “enable-online”: `TRUE`): Requests are sent to the real server online, and the request–response pairs recorded to a log file. • Testing mode (“enable-logging”: `FALSE`, “enable-online”: `FALSE`): Requests are sent to the mock server, which responds from the trace file. • Comparing mode (“enable-logging”: `FALSE`, “enable-online”: `TRUE`): Requests are sent to the real server online, and the request–response pairs are compared against those in an existing log file to see if the log file is up-to-date.

## Functions

### uhm_server_new ()

    UhmServer *
    uhm_server_new (void);

Creates a new UhmServer with default properties.

#### Returns

a new UhmServer; unref with `g_object_unref()`.

[transfer full]

Since 0.1.0

### uhm_server_run ()

    void
    uhm_server_run (UhmServer *self);

Runs the mock server, binding to a loopback TCP/IP interface and preparing a HTTPS server which is ready to accept requests. The TCP/IP address and port number are chosen randomly out of the loopback addresses, and are exposed as “address” and “port” once this function has returned. A UhmResolver (exposed as “resolver”) is set as the default GResolver while the server is running.

The server is started in a worker thread, so this function returns immediately and the server continues to run in the background. Use `uhm_server_stop()` to shut it down.

This function always succeeds.

#### Parameters

self | a UhmServer |

Since 0.1.0

### uhm_server_stop ()

    void
    uhm_server_stop (UhmServer *self);

Stops a mock server started by calling `uhm_server_run()`. This shuts down the server's worker thread and unbinds it from its TCP/IP socket.

This unloads any trace file loaded by calling `uhm_server_load_trace()` (or its asynchronous counterpart). It also resets the set of domain names loaded into the “resolver”.

This function always succeeds.

#### Parameters

self | a UhmServer |

Since 0.1.0

### uhm_server_start_trace ()

    void
    uhm_server_start_trace (UhmServer *self,
                            const gchar *trace_name,
                            GError **error);

Starts a mock server which follows the trace file of filename `trace_name` in the “trace-directory” directory. See `uhm_server_start_trace_full()` for further documentation.

This function has undefined behaviour if “trace-directory” is `NULL`.

On failure, `error` will be set and the UhmServer state will remain unchanged. See `uhm_server_start_trace_full()` for details of the error domains used.

#### Parameters

self | a UhmServer |
trace_name | name of the trace |
error | return location for a GError, or `NULL`. | [allow-none]

Since 0.1.0

### uhm_server_start_trace_full ()

    void
    uhm_server_start_trace_full (UhmServer *self,
                                 GFile *trace_file,
                                 GError **error);

Convenience function to start logging to or reading from the given `trace_file` , depending on the values of “enable-logging” and “enable-online”.

If “enable-logging” is `TRUE`, a log handler will be set up to redirect all client network activity into the given `trace_file` . If `trace_file` already exists, it will be overwritten.

If “enable-online” is `FALSE`, the given `trace_file` is loaded using `uhm_server_load_trace()` and then a mock server is started using `uhm_server_run()`.

On failure, `error` will be set and the UhmServer state will remain unchanged. A GIOError will be set if logging is enabled (“enable-logging”) and there is a problem writing to the trace file; or if a trace needs to be loaded and there is a problem reading from the trace file.

#### Parameters

self | a UhmServer |
trace_file | a trace file to load |
error | return location for a GError, or `NULL`. | [allow-none]

Since 0.1.0

### uhm_server_end_trace ()

    void
    uhm_server_end_trace (UhmServer *self);

Convenience function to finish logging to or reading from a trace file previously passed to `uhm_server_start_trace()` or `uhm_server_start_trace_full()`.

If “enable-online” is `FALSE`, this will shut down the mock server (as if `uhm_server_stop()` had been called).

#### Parameters

self | a UhmServer |

Since 0.1.0

### uhm_server_load_trace ()

    void
    uhm_server_load_trace (UhmServer *self,
                           GFile *trace_file,
                           GCancellable *cancellable,
                           GError **error);

Synchronously loads the given `trace_file` of network messages, ready to simulate a network conversation by matching requests against the file and returning the associated responses. Call `uhm_server_run()` to start the mock server afterwards.

Loading the trace file may be cancelled from another thread using `cancellable` .

On error, `error` will be set and the state of the UhmServer will not change. A GIOError will be set if there is a problem reading the trace file.

#### Parameters

self | a UhmServer |
trace_file | trace file to load |
cancellable | a GCancellable, or `NULL`. | [allow-none]
error | return location for a GError, or `NULL`. | [allow-none]

Since 0.1.0

### uhm_server_load_trace_async ()

    void
    uhm_server_load_trace_async (UhmServer *self,
                                 GFile *trace_file,
                                 GCancellable *cancellable,
                                 GAsyncReadyCallback callback,
                                 gpointer user_data);

Asynchronous version of `uhm_server_load_trace()`. In `callback` , call `uhm_server_load_trace_finish()` to complete the operation.

#### Parameters

self | a UhmServer |
trace_file | trace file to load |
cancellable | a GCancellable, or `NULL`. | [allow-none]
callback | function to call once the async operation is complete |
user_data | user data to pass to `callback` , or `NULL`. | [allow-none]

Since 0.1.0

### uhm_server_load_trace_finish ()

    void
    uhm_server_load_trace_finish (UhmServer *self,
                                  GAsyncResult *result,
                                  GError **error);

Finishes an asynchronous operation started by `uhm_server_load_trace_async()`.

On error, `error` will be set and the state of the UhmServer will not change. See `uhm_server_load_trace()` for details on the error domains used.

#### Parameters

self | a UhmServer |
result | asynchronous operation result passed to the callback |
error | return location for a GError, or `NULL`. | [allow-none]

Since 0.1.0

### uhm_server_unload_trace ()

    void
    uhm_server_unload_trace (UhmServer *self);

Unloads the current trace file of network messages, as loaded by `uhm_server_load_trace()` or `uhm_server_load_trace_async()`.

#### Parameters

self | a UhmServer |

Since 0.1.0

### uhm_server_received_message_chunk ()

    void
    uhm_server_received_message_chunk (UhmServer *self,
                                       const gchar *message_chunk,
                                       goffset message_chunk_length,
                                       GError **error);

Indicates to the mock server that a single new line of a message was received from the real server. The message line may be appended to the current trace file if logging is enabled (“enable-logging” is `TRUE`), adding a newline character at the end. If logging is disabled but online mode is enabled (“enable-online” is `TRUE`), the message line will be compared to the next expected line in the existing trace file. Otherwise, this function is a no-op.

On failure, `error` will be set and the UhmServer state will remain unchanged apart from the parse state machine, which will remain in the state reached after parsing `message_chunk` . A `G_IO_ERROR` will be returned if writing to the trace file failed. If in comparison mode and the received message chunk corresponds to an unexpected message in the trace file, a `UHM_SERVER_ERROR` will be returned.

In common cases where message log data only needs to be passed to a UhmServer and not (for example) logged to an application-specific file or the command line as well, it is simpler to use `uhm_server_received_message_chunk_from_soup()`, passing it directly to `soup_logger_set_printer()`. See the documentation for `uhm_server_received_message_chunk_from_soup()` for details.

#### Parameters

self | a UhmServer |
message_chunk | single line of a message which was received |
message_chunk_length | length of `message_chunk` in bytes |
error | return location for a GError, or `NULL`. | [allow-none]

Since 0.1.0

### uhm_server_received_message_chunk_with_direction ()

    void
    uhm_server_received_message_chunk_with_direction
                                   (UhmServer *self,
                                    char direction,
                                    const gchar *data,
                                    goffset data_length,
                                    GError **error);

Convenience version of `uhm_server_received_message_chunk()` which takes the message `direction` and `data` separately, as provided by libsoup in a SoupLoggerPrinter callback.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    UhmServer *mock_server;
    SoupSession *session;
    SoupLogger *logger;

    static void
    soup_log_printer (SoupLogger *logger, SoupLoggerLogLevel level, char direction, const char *data, gpointer user_data)
    {
    	/* Pass the data to libuhttpmock. */
    UhmServer *mock_server = UHM_SERVER (user_data);
    	uhm_server_received_message_chunk_with_direction (mock_server, direction, data, strlen (data), NULL);
    }

    mock_server = uhm_server_new ();
    session = soup_session_new ();

    logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
    soup_logger_set_printer (logger, (SoupLoggerPrinter) soup_log_printer, g_object_ref (mock_server), g_object_unref);
    soup_session_add_feature (session, SOUP_SESSION_FEATURE (logger));
    g_object_unref (logger);

    /* Do something with mock_server here. */

#### Parameters

self | a UhmServer |
direction | single character indicating the direction of message transmission |
data | single line of a message which was received |
data_length | length of `data` in bytes |
error | return location for a GError, or `NULL`. | [allow-none]

Since 0.3.0

### uhm_server_received_message_chunk_from_soup ()

    void
    uhm_server_received_message_chunk_from_soup
                                   (SoupLogger *logger,
                                    SoupLoggerLogLevel level,
                                    char direction,
                                    const char *data,
                                    gpointer user_data);

Convenience version of `uhm_server_received_message_chunk()` which can be passed directly to `soup_logger_set_printer()` to forward all libsoup traffic logging to a UhmServer. The UhmServer must be passed to `soup_logger_set_printer()` as its user data.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    UhmServer *mock_server;
    SoupSession *session;
    SoupLogger *logger;

    mock_server = uhm_server_new ();
    session = soup_session_new ();

    logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
    soup_logger_set_printer (logger, uhm_server_received_message_chunk_from_soup, g_object_ref (mock_server), g_object_unref);
    soup_session_add_feature (session, SOUP_SESSION_FEATURE (logger));
    g_object_unref (logger);

    /* Do something with mock_server here. */

#### Parameters

logger | a SoupLogger |
level | the detail level of this log message |
direction | the transmission direction of the message |
data | message data |
user_data | user data passed to the SoupLogger, or `NULL`. | [allow-none]

Since 0.3.0

### uhm_server_get_enable_logging ()

    gboolean
    uhm_server_get_enable_logging (UhmServer *self);

Gets the value of the “enable-logging” property.

#### Parameters

self | a UhmServer |

#### Returns

`TRUE` if client network traffic is being logged to a trace file; `FALSE` otherwise

Since 0.1.0

### uhm_server_set_enable_logging ()

    void
    uhm_server_set_enable_logging (UhmServer *self,
                                   gboolean enable_logging);

Sets the value of the “enable-logging” property.

#### Parameters

self | a UhmServer |
enable_logging | `TRUE` to log client network traffic to a trace file; `FALSE` otherwise |

Since 0.1.0

### uhm_server_get_enable_online ()

    gboolean
    uhm_server_get_enable_online (UhmServer *self);

Gets the value of the “enable-online” property.

#### Parameters

self | a UhmServer |

#### Returns

`TRUE` if the server does not intercept and handle network connections from client code; `FALSE` otherwise

Since 0.1.0

### uhm_server_set_enable_online ()

    void
    uhm_server_set_enable_online (UhmServer *self,
                                  gboolean enable_online);

Sets the value of the “enable-online” property.

#### Parameters

self | a UhmServer |
enable_online | `TRUE` to not intercept and handle network connections from client code; `FALSE` otherwise |

Since 0.1.0

### uhm_server_get_trace_directory ()

    GFile *
    uhm_server_get_trace_directory (UhmServer *self);

Gets the value of the “trace-directory” property.

#### Parameters

self | a UhmServer |

#### Returns

the directory to load/store trace files from, or `NULL`.

[allow-none][transfer none]

Since 0.1.0

### uhm_server_set_trace_directory ()

    void
    uhm_server_set_trace_directory (UhmServer *self,
                                    GFile *trace_directory);

Sets the value of the “trace-directory” property.

#### Parameters

self | a UhmServer |
trace_directory | a directory to load/store trace files from, or `NULL` to unset it. | [allow-none][transfer none]

Since 0.1.0

### uhm_server_get_tls_certificate ()

    GTlsCertificate *
    uhm_server_get_tls_certificate (UhmServer *self);

Gets the value of the “tls-certificate” property.

#### Parameters

self | a UhmServer |

#### Returns

the server's current TLS certificate; or `NULL` if it's serving HTTP only.

[transfer none][allow-none]

Since 0.1.0

### uhm_server_set_tls_certificate ()

    void
    uhm_server_set_tls_certificate (UhmServer *self,
                                    GTlsCertificate *tls_certificate);

Sets the value of the “tls-certificate” property.

#### Parameters

self | a UhmServer |
tls_certificate | TLS certificate for the server to use; or `NULL` to serve HTTP only. | [allow-none]

Since 0.1.0

### uhm_server_set_default_tls_certificate ()

    GTlsCertificate *
    uhm_server_set_default_tls_certificate
                                   (UhmServer *self);

Sets the value of the “tls-certificate” property to the default TLS certificate built in to libuhttpmock. This default certificate is not signed by any certificate authority, and contains minimal metadata details. It may be used by clients which have no special certificate requirements; clients which have special requirements should construct a custom GTlsCertificate and pass it to `uhm_server_set_tls_certificate()`.

#### Parameters

self | a UhmServer |

#### Returns

the default certificate set as “tls-certificate”.

[transfer none]

Since 0.1.0

### uhm_server_set_expected_domain_names ()

    void
    uhm_server_set_expected_domain_names (UhmServer *self,
                                          const gchar * const *domain_names);

Set the domain names which are expected to have requests made of them by the client code interacting with this UhmServer. This is a convenience method which calls `uhm_resolver_add_A()` on the server’s UhmResolver for each of the domain names listed in `domain_names` . It associates them with the server’s current IP address, and automatically updates the mappings if the IP address or resolver change.

Note that this will reset all records on the server’s UhmResolver, replacing all of them with the provided `domain_names` .

It is safe to add further domain names to the UhmResolver in a callback for the “notify” signal for “resolver”; that signal is emitted after the resolver is cleared and these `domain_names` are added.

#### Parameters

self | a UhmServer |
domain_names | `NULL`-terminated array of domain names to expect, or `NULL` to not expect any. | [array zero-terminated=1][allow-none][element-type utf8]

Since 0.3.0

### uhm_server_get_address ()

    const gchar *
    uhm_server_get_address (UhmServer *self);

Gets the value of the “address” property.

#### Parameters

self | a UhmServer |

#### Returns

the physical address of the listening socket the server is currently bound to; or `NULL` if the server is not running.

[allow-none][transfer none]

Since 0.1.0

### uhm_server_get_port ()

    guint
    uhm_server_get_port (UhmServer *self);

Gets the value of the “port” property.

#### Parameters

self | a UhmServer |

#### Returns

the port of the listening socket the server is currently bound to; or `0` if the server is not running

Since 0.1.0

### uhm_server_get_resolver ()

    UhmResolver *
    uhm_server_get_resolver (UhmServer *self);

Gets the value of the “resolver” property.

#### Parameters

self | a UhmServer |

#### Returns

the mock resolver in use by the mock server, or `NULL` if no resolver is active.

[allow-none][transfer none]

Since 0.1.0

## Types and Values

### UhmServer

    typedef struct _UhmServer UhmServer;

All the fields in the UhmServer structure are private and should never be accessed directly.

Since 0.1.0

### UhmServerClass

    typedef struct {
    	gboolean (*handle_message) (UhmServer *self, SoupMessage *message, SoupClientContext *client);
    	gboolean (*compare_messages) (UhmServer *self, SoupMessage *expected_message, SoupMessage *actual_message, SoupClientContext *actual_client);
    } UhmServerClass;

Most of the fields in the UhmServerClass structure are private and should never be accessed directly.

#### Members

`handle_message` () | Class handler for the “handle-message” signal. Subclasses may implement this to override the default handler for the signal. The default handler should always return `TRUE` to indicate that it has handled the `message` from `client` by setting an appropriate response on the SoupMessage. |
`compare_messages` () | Class handler for the “compare-messages” signal. Subclasses may implement this to override the default handler for the signal. The handler should return `TRUE` if `expected_message` and `actual_message` compare equal, and `FALSE` otherwise. |

Since 0.1.0

### enum UhmServerError

Error codes for UhmServer operations.

#### Members

UHM_SERVER_ERROR_MESSAGE_MISMATCH | In comparison mode, a message received from the client did not match the next message in the current trace file. |

## Property Details

### The `“address”` property

      “address”                  gchar *

Address of the local mock server if it's running, or `NULL` otherwise. This will be non-`NULL` between calls to `uhm_server_run()` and `uhm_server_stop()`. The address is a physical IP address, e.g. `127.0.0.1`.

This should not normally need to be passed into client code under test, unless the code references IP addresses specifically. The mock server runs a DNS resolver which automatically redirects client requests for known domain names to this address (“resolver”).

Flags: Read

Default value: NULL

Since 0.1.0

### The `“enable-logging”` property

      “enable-logging”           gboolean

`TRUE` if network traffic should be logged to a trace file (specified by calling `uhm_server_start_trace()`). This operates independently of whether traffic is online or being handled locally by the mock server. Use this in conjunction with “enable-online” to either log online traffic, or replay logged traffic locally.

Flags: Read / Write

Default value: FALSE

Since 0.1.0

### The `“enable-online”` property

      “enable-online”            gboolean

`TRUE` if network traffic should reach the Internet as normal; `FALSE` to redirect it to the local mock server. Use this in conjunction with “enable-logging” to either log online traffic, or replay logged traffic locally.

Flags: Read / Write

Default value: FALSE

Since 0.1.0

### The `“port”` property

      “port”                     guint

Port of the local mock server if it's running, or `0` otherwise. This will be non-`0` between calls to `uhm_server_run()` and `uhm_server_stop()`.

It is intended that this port be passed into the client code under test, to substitute for the default HTTPS port (443) which it would otherwise use.

Flags: Read

Default value: 0

Since 0.1.0

### The `“resolver”` property

      “resolver”                 UhmResolver *

Mock resolver used to redirect HTTP requests from specified domain names to the local mock server instance. This will always be set while the server is running (between calls to `uhm_server_run()` and `uhm_server_stop()`), and is `NULL` otherwise.

Use the resolver specified in this property to add domain names which are expected to be requested by the current trace. Domain names not added to the resolver will be rejected by the mock server. The set of domain names in the resolver will be reset when `uhm_server_stop()` is called.

Flags: Read

Since 0.1.0

### The `“tls-certificate”` property

      “tls-certificate”          GTlsCertificate *

TLS certificate for the mock server to use when serving HTTPS pages. If this is non-`NULL`, the server will always use HTTPS. If it is `NULL`, the server will always use HTTP. The TLS certificate may be changed after constructing the UhmServer, but changes to the property will not take effect until the next call to `uhm_server_run()`.

A certificate and private key may be generated by executing:

`openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -nodes`. These files may then be used to construct a

GTlsCertificate by calling `g_tls_certificate_new_from_files()`.

Alternatively, a default GTlsCertificate which wraps a dummy certificate (not signed by any certificate authority) may be set by calling `uhm_server_set_default_tls_certificate()`. This may be used as the “tls-certificate” if the code under test has no specific requirements of the certificate used by the mock server it's tested against.

Flags: Read / Write

Since 0.1.0

### The `“trace-directory”` property

      “trace-directory”          GFile *

Directory relative to which all trace files specified in calls to `uhm_server_start_trace()` will be resolved. This is not used for any other methods, but must be non-`NULL` if `uhm_server_start_trace()` is called.

Flags: Read / Write

Since 0.1.0

## Signal Details

### The `“compare-messages”` signal

    gboolean
    user_function (UhmServer         *self,
                   SoupMessage       *expected_message,
                   SoupMessage       *actual_message,
                   SoupClientContext *actual_client,
                   gpointer           user_data)

Emitted whenever the mock server must compare two SoupMessages for equality; e.g. when in the testing or comparison modes. Test code may connect to this signal and implement a handler which checks custom properties of the messages. The default handler compares the URI and method of the messages, but no headers and not the message bodies.

Signal handlers should return `TRUE` if the messages match; and `FALSE` otherwise. The first signal handler executed when this signal is emitted wins.

#### Parameters

self | a UhmServer |
expected_message | a message containing the expected HTTP(S) message provided by “handle-message” |
actual_message | a message containing the incoming HTTP(S) request |
actual_client | additional data about the HTTP client making the request |
user_data | user data set when the signal handler was connected. |

Flags: Run Last

Since 0.1.0

### The `“handle-message”` signal

    gboolean
    user_function (UhmServer         *self,
                   SoupMessage       *message,
                   SoupClientContext *client,
                   gpointer           user_data)

Emitted whenever the mock server is running and receives a request from a client. Test code may connect to this signal and implement a handler which builds and returns a suitable response for a given message. The default handler reads a request–response pair from the current trace file, matches the requests and then returns the given response. If the requests don't match, an error is raised.

Signal handlers should return `TRUE` if they have handled the request and set an appropriate response; and `FALSE` otherwise.

#### Parameters

self | a UhmServer |
message | a message containing the incoming HTTP(S) request, and which the outgoing HTTP(S) response should be set on |
client | additional data about the HTTP client making the request |
user_data | user data set when the signal handler was connected. |

Flags: Run Last

Since 0.1.0