1f603fdb6STrond Norbye#include "config.h"
21b3dd163SEric Lambert#include <stdlib.h>
31b3dd163SEric Lambert#include <string.h>
41b3dd163SEric Lambert#include <time.h>
51b3dd163SEric Lambert#include <memcached/engine.h>
61b3dd163SEric Lambert#include <memcached/extension.h>
71b3dd163SEric Lambert#include <memcached/extension_loggers.h>
8e1175713SMike Wiederhold#include <memcached/allocator_hooks.h>
9f603fdb6STrond Norbye#include "mock_server.h"
101b3dd163SEric Lambert
111b3dd163SEric Lambert#define REALTIME_MAXDELTA 60*60*24*3
12f603fdb6STrond Norbye#define CONN_MAGIC 0xbeefcafe
131b3dd163SEric Lambert
141b3dd163SEric Lambertstruct mock_extensions {
151b3dd163SEric Lambert    EXTENSION_DAEMON_DESCRIPTOR *daemons;
161b3dd163SEric Lambert    EXTENSION_LOGGER_DESCRIPTOR *logger;
171b3dd163SEric Lambert};
181b3dd163SEric Lambert
191b3dd163SEric Lambertstruct mock_callbacks *mock_event_handlers[MAX_ENGINE_EVENT_TYPE + 1];
201b3dd163SEric Lamberttime_t process_started;     /* when the mock server was started */
213ad7c99fSDustin Sallingsrel_time_t time_travel_offset;
221b3dd163SEric Lambertrel_time_t current_time;
231b3dd163SEric Lambertstruct mock_connstruct *connstructs;
241b3dd163SEric Lambertstruct mock_extensions extensions;
251b3dd163SEric LambertEXTENSION_LOGGER_DESCRIPTOR *null_logger = NULL;
261b3dd163SEric LambertEXTENSION_LOGGER_DESCRIPTOR *stderr_logger = NULL;
271b3dd163SEric LambertENGINE_HANDLE *engine = NULL;
281b3dd163SEric Lambert
294f426e26Sabhinavdangeti/**
304f426e26Sabhinavdangeti * Session cas elements
314f426e26Sabhinavdangeti */
324f426e26Sabhinavdangetiuint64_t session_cas;
334f426e26Sabhinavdangetiuint8_t session_ctr;
344f426e26Sabhinavdangeticb_mutex_t session_mutex;
354f426e26Sabhinavdangeti
361b3dd163SEric Lambert/**
371b3dd163SEric Lambert * SERVER CORE API FUNCTIONS
381b3dd163SEric Lambert */
391b3dd163SEric Lambert
401b3dd163SEric Lambertstatic void mock_get_auth_data(const void *cookie, auth_data_t *data) {
411b3dd163SEric Lambert    struct mock_connstruct *c = (struct mock_connstruct *)cookie;
421b3dd163SEric Lambert    if (c != NULL) {
431b3dd163SEric Lambert        data->username = c->uname;
441b3dd163SEric Lambert        data->config = c->config;
451b3dd163SEric Lambert    }
461b3dd163SEric Lambert}
471b3dd163SEric Lambert
481b3dd163SEric Lambertstatic void mock_store_engine_specific(const void *cookie, void *engine_data) {
491b3dd163SEric Lambert    if (cookie) {
501b3dd163SEric Lambert        struct mock_connstruct *c = (struct mock_connstruct *)cookie;
51464d6f0bSTrond Norbye        cb_assert(c->magic == CONN_MAGIC);
521b3dd163SEric Lambert        c->engine_data = engine_data;
531b3dd163SEric Lambert    }
541b3dd163SEric Lambert}
551b3dd163SEric Lambert
561b3dd163SEric Lambertstatic void *mock_get_engine_specific(const void *cookie) {
571b3dd163SEric Lambert    struct mock_connstruct *c = (struct mock_connstruct *)cookie;
58464d6f0bSTrond Norbye    cb_assert(c == NULL || c->magic == CONN_MAGIC);
591b3dd163SEric Lambert    return c ? c->engine_data : NULL;
601b3dd163SEric Lambert}
611b3dd163SEric Lambert
62bd0ecd24Sabhinavdangetistatic bool mock_is_datatype_supported(const void *cookie) {
63bd0ecd24Sabhinavdangeti    struct mock_connstruct *c = (struct mock_connstruct *)cookie;
64bd0ecd24Sabhinavdangeti    cb_assert(c == NULL || c->magic == CONN_MAGIC);
65bd0ecd24Sabhinavdangeti    return true;
66bd0ecd24Sabhinavdangeti}
67bd0ecd24Sabhinavdangeti
684f426e26Sabhinavdangetistatic uint8_t mock_get_opcode_if_ewouldblock_set(const void *cookie) {
694f426e26Sabhinavdangeti    struct mock_connstruct *c = (struct mock_connstruct *)cookie;
704f426e26Sabhinavdangeti    cb_assert(c == NULL || c->magic == CONN_MAGIC);
714f426e26Sabhinavdangeti    return 0x00;
724f426e26Sabhinavdangeti}
734f426e26Sabhinavdangeti
742c217587Sabhinavdangetistatic bool mock_validate_session_cas(const uint64_t cas) {
754f426e26Sabhinavdangeti    bool ret = true;
764f426e26Sabhinavdangeti    cb_mutex_enter(&(session_mutex));
774f426e26Sabhinavdangeti    if (cas != 0) {
784f426e26Sabhinavdangeti        if (session_cas != cas) {
794f426e26Sabhinavdangeti            ret = false;
804f426e26Sabhinavdangeti        } else {
814f426e26Sabhinavdangeti            session_ctr++;
824f426e26Sabhinavdangeti        }
834f426e26Sabhinavdangeti    } else {
844f426e26Sabhinavdangeti        session_ctr++;
852c217587Sabhinavdangeti    }
864f426e26Sabhinavdangeti    cb_mutex_exit(&(session_mutex));
874f426e26Sabhinavdangeti    return ret;
884f426e26Sabhinavdangeti}
894f426e26Sabhinavdangeti
904f426e26Sabhinavdangetistatic void mock_decrement_session_ctr() {
914f426e26Sabhinavdangeti    cb_mutex_enter(&(session_mutex));
924f426e26Sabhinavdangeti    cb_assert(session_ctr != 0);
934f426e26Sabhinavdangeti    session_ctr--;
944f426e26Sabhinavdangeti    cb_mutex_exit(&(session_mutex));
952c217587Sabhinavdangeti}
962c217587Sabhinavdangeti
97ce9a18d0STrond Norbyestatic SOCKET mock_get_socket_fd(const void *cookie) {
981b3dd163SEric Lambert    struct mock_connstruct *c = (struct mock_connstruct *)cookie;
991b3dd163SEric Lambert    return c->sfd;
1001b3dd163SEric Lambert}
1011b3dd163SEric Lambert
10255627b40STrond Norbyestatic ENGINE_ERROR_CODE mock_cookie_reserve(const void *cookie) {
103934f2578SMike Wiederhold    struct mock_connstruct *c = (struct mock_connstruct *)cookie;
104934f2578SMike Wiederhold    c->references++;
10555627b40STrond Norbye    return ENGINE_SUCCESS;
10683835a25STrond Norbye}
10783835a25STrond Norbye
10855627b40STrond Norbyestatic ENGINE_ERROR_CODE mock_cookie_release(const void *cookie) {
109934f2578SMike Wiederhold    struct mock_connstruct *c = (struct mock_connstruct *)cookie;
110934f2578SMike Wiederhold
111934f2578SMike Wiederhold    c->references--;
112934f2578SMike Wiederhold    if (c->references == 0) {
113934f2578SMike Wiederhold        free(c);
114934f2578SMike Wiederhold    }
11555627b40STrond Norbye    return ENGINE_SUCCESS;
11683835a25STrond Norbye}
11783835a25STrond Norbye
11828e825f7STrond Norbyestatic void mock_set_priority(const void* cookie, CONN_PRIORITY priority) {
11928e825f7STrond Norbye    (void)cookie;
12028e825f7STrond Norbye    (void)priority;
12128e825f7STrond Norbye}
12228e825f7STrond Norbye
123f603fdb6STrond Norbyestatic const char *mock_get_server_version(void) {
1241b3dd163SEric Lambert    return "mock server";
1251b3dd163SEric Lambert}
1261b3dd163SEric Lambert
1271b3dd163SEric Lambertstatic uint32_t mock_hash( const void *key, size_t length, const uint32_t initval) {
128f603fdb6STrond Norbye    /*this is a very stupid hash indeed */
1291b3dd163SEric Lambert    return 1;
1301b3dd163SEric Lambert}
1311b3dd163SEric Lambert
132368a79d5SDustin Sallings/* time-sensitive callers can call it by hand with this, outside the
133368a79d5SDustin Sallings   normal ever-1-second timer */
134368a79d5SDustin Sallingsstatic rel_time_t mock_get_current_time(void) {
135f603fdb6STrond Norbye#ifdef WIN32
136f603fdb6STrond Norbye    current_time = (rel_time_t)(time(NULL) - process_started + time_travel_offset);
137f603fdb6STrond Norbye#else
138368a79d5SDustin Sallings    struct timeval timer;
139368a79d5SDustin Sallings    gettimeofday(&timer, NULL);
140368a79d5SDustin Sallings    current_time = (rel_time_t) (timer.tv_sec - process_started + time_travel_offset);
141f603fdb6STrond Norbye#endif
142f603fdb6STrond Norbye
143368a79d5SDustin Sallings    return current_time;
144368a79d5SDustin Sallings}
145368a79d5SDustin Sallings
1461b3dd163SEric Lambertstatic rel_time_t mock_realtime(const time_t exptime) {
1471b3dd163SEric Lambert    /* no. of seconds in 30 days - largest possible delta exptime */
1481b3dd163SEric Lambert
1491b3dd163SEric Lambert    if (exptime == 0) return 0; /* 0 means never expire */
1501b3dd163SEric Lambert
1511b3dd163SEric Lambert    if (exptime > REALTIME_MAXDELTA) {
1521b3dd163SEric Lambert        /* if item expiration is at/before the server started, give it an
1531b3dd163SEric Lambert           expiration time of 1 second after the server started.
1541b3dd163SEric Lambert           (because 0 means don't expire).  without this, we'd
1551b3dd163SEric Lambert           underflow and wrap around to some large value way in the
1561b3dd163SEric Lambert           future, effectively making items expiring in the past
1571b3dd163SEric Lambert           really expiring never */
1581b3dd163SEric Lambert        if (exptime <= process_started)
1591b3dd163SEric Lambert            return (rel_time_t)1;
160d9017703SDustin Sallings        return (rel_time_t)(exptime - process_started);
1611b3dd163SEric Lambert    } else {
162368a79d5SDustin Sallings        return (rel_time_t)(exptime + mock_get_current_time());
1631b3dd163SEric Lambert    }
1641b3dd163SEric Lambert}
1651b3dd163SEric Lambert
1661b3dd163SEric Lambertstatic void mock_notify_io_complete(const void *cookie, ENGINE_ERROR_CODE status) {
167934f2578SMike Wiederhold    if (cookie) {
168934f2578SMike Wiederhold        struct mock_connstruct *c = (struct mock_connstruct *)cookie;
169934f2578SMike Wiederhold        cb_mutex_enter(&c->mutex);
170934f2578SMike Wiederhold        c->status = status;
171934f2578SMike Wiederhold        cb_cond_signal(&c->cond);
172934f2578SMike Wiederhold        cb_mutex_exit(&c->mutex);
173934f2578SMike Wiederhold    }
1741b3dd163SEric Lambert}
1751b3dd163SEric Lambert
176b27a3767SDustin Sallingsstatic time_t mock_abstime(const rel_time_t exptime)
177b27a3767SDustin Sallings{
178d9017703SDustin Sallings    return process_started + exptime;
179b27a3767SDustin Sallings}
180b27a3767SDustin Sallings
1813ad7c99fSDustin Sallingsvoid mock_time_travel(int by) {
1823ad7c99fSDustin Sallings    time_travel_offset += by;
1833ad7c99fSDustin Sallings}
1843ad7c99fSDustin Sallings
1851b3dd163SEric Lambertstatic int mock_parse_config(const char *str, struct config_item items[], FILE *error) {
1861b3dd163SEric Lambert    return parse_config(str, items, error);
1871b3dd163SEric Lambert}
1881b3dd163SEric Lambert
1891b3dd163SEric Lambert/**
1901b3dd163SEric Lambert * SERVER STAT API FUNCTIONS
1911b3dd163SEric Lambert */
1921b3dd163SEric Lambert
1931b3dd163SEric Lambertstatic void *mock_new_independent_stats(void) {
194273bdbd0SDave Rigby    struct mock_stats *mockstats = calloc(sizeof(*mockstats), 1);
1951b3dd163SEric Lambert    return mockstats;
1961b3dd163SEric Lambert}
1971b3dd163SEric Lambert
1981b3dd163SEric Lambertstatic void mock_release_independent_stats(void *stats) {
199273bdbd0SDave Rigby    struct mock_stats *mockstats = stats;
2001b3dd163SEric Lambert    free(mockstats);
2011b3dd163SEric Lambert}
2021b3dd163SEric Lambert
2031b3dd163SEric Lambertstatic void mock_count_eviction(const void *cookie, const void *key, const int nkey) {
2041b3dd163SEric Lambert    struct mock_connstruct *c = (struct mock_connstruct *)cookie;
2051b3dd163SEric Lambert    c->evictions++;
2061b3dd163SEric Lambert}
2071b3dd163SEric Lambert
2081b3dd163SEric Lambert/**
2091b3dd163SEric Lambert * SERVER STAT API FUNCTIONS
2101b3dd163SEric Lambert */
2111b3dd163SEric Lambert
2121b3dd163SEric Lambertstatic bool mock_register_extension(extension_type_t type, void *extension)
2131b3dd163SEric Lambert{
2141b3dd163SEric Lambert    if (extension == NULL) {
2151b3dd163SEric Lambert        return false;
2161b3dd163SEric Lambert    }
2171b3dd163SEric Lambert
2181b3dd163SEric Lambert    switch (type) {
2191b3dd163SEric Lambert    case EXTENSION_DAEMON:
220f603fdb6STrond Norbye        {
221f603fdb6STrond Norbye            EXTENSION_DAEMON_DESCRIPTOR *ptr;
222f603fdb6STrond Norbye            for (ptr =  extensions.daemons; ptr != NULL; ptr = ptr->next) {
223f603fdb6STrond Norbye                if (ptr == extension) {
224f603fdb6STrond Norbye                    return false;
225f603fdb6STrond Norbye                }
2261b3dd163SEric Lambert            }
227f603fdb6STrond Norbye            ((EXTENSION_DAEMON_DESCRIPTOR *)(extension))->next = extensions.daemons;
228f603fdb6STrond Norbye            extensions.daemons = extension;
2291b3dd163SEric Lambert        }
2301b3dd163SEric Lambert        return true;
2311b3dd163SEric Lambert    case EXTENSION_LOGGER:
2321b3dd163SEric Lambert        extensions.logger = extension;
2331b3dd163SEric Lambert        return true;
2341b3dd163SEric Lambert    default:
2351b3dd163SEric Lambert        return false;
2361b3dd163SEric Lambert    }
2371b3dd163SEric Lambert}
2381b3dd163SEric Lambert
2391b3dd163SEric Lambertstatic void mock_unregister_extension(extension_type_t type, void *extension)
2401b3dd163SEric Lambert{
2411b3dd163SEric Lambert    switch (type) {
2421b3dd163SEric Lambert    case EXTENSION_DAEMON:
2431b3dd163SEric Lambert        {
2441b3dd163SEric Lambert            EXTENSION_DAEMON_DESCRIPTOR *prev = NULL;
2451b3dd163SEric Lambert            EXTENSION_DAEMON_DESCRIPTOR *ptr = extensions.daemons;
2461b3dd163SEric Lambert
2471b3dd163SEric Lambert            while (ptr != NULL && ptr != extension) {
2481b3dd163SEric Lambert                prev = ptr;
2491b3dd163SEric Lambert                ptr = ptr->next;
2501b3dd163SEric Lambert            }
2511b3dd163SEric Lambert
2521b3dd163SEric Lambert            if (ptr != NULL && prev != NULL) {
2531b3dd163SEric Lambert                prev->next = ptr->next;
2541b3dd163SEric Lambert            }
2551b3dd163SEric Lambert
256480eeabdSDave Rigby            if (ptr != NULL && extensions.daemons == ptr) {
2571b3dd163SEric Lambert                extensions.daemons = ptr->next;
2581b3dd163SEric Lambert            }
2591b3dd163SEric Lambert        }
2601b3dd163SEric Lambert        break;
2611b3dd163SEric Lambert    case EXTENSION_LOGGER:
2621b3dd163SEric Lambert        if (extensions.logger == extension) {
2631b3dd163SEric Lambert            if (stderr_logger == extension) {
2641b3dd163SEric Lambert                extensions.logger = null_logger;
2651b3dd163SEric Lambert            } else {
2661b3dd163SEric Lambert                extensions.logger = stderr_logger;
2671b3dd163SEric Lambert            }
2681b3dd163SEric Lambert        }
2691b3dd163SEric Lambert        break;
2701b3dd163SEric Lambert
2711b3dd163SEric Lambert    default:
2721b3dd163SEric Lambert        ;
2731b3dd163SEric Lambert    }
2741b3dd163SEric Lambert
2751b3dd163SEric Lambert}
2761b3dd163SEric Lambert
2771b3dd163SEric Lambertstatic void* mock_get_extension(extension_type_t type)
2781b3dd163SEric Lambert{
2791b3dd163SEric Lambert    switch (type) {
2801b3dd163SEric Lambert    case EXTENSION_DAEMON:
2811b3dd163SEric Lambert        return extensions.daemons;
2821b3dd163SEric Lambert
2831b3dd163SEric Lambert    case EXTENSION_LOGGER:
2841b3dd163SEric Lambert        return extensions.logger;
2851b3dd163SEric Lambert
2861b3dd163SEric Lambert    default:
2871b3dd163SEric Lambert        return NULL;
2881b3dd163SEric Lambert    }
2891b3dd163SEric Lambert}
2901b3dd163SEric Lambert
2911b3dd163SEric Lambert/**
2921b3dd163SEric Lambert * SERVER CALLBACK API FUNCTIONS
2931b3dd163SEric Lambert */
2941b3dd163SEric Lambert
295fc06711bSDustin Sallingsstatic void mock_register_callback(ENGINE_HANDLE *eh,
296fc06711bSDustin Sallings                                   ENGINE_EVENT_TYPE type,
297fc06711bSDustin Sallings                                   EVENT_CALLBACK cb,
298fc06711bSDustin Sallings                                   const void *cb_data) {
2991b3dd163SEric Lambert    struct mock_callbacks *h =
3001b3dd163SEric Lambert        calloc(sizeof(struct mock_callbacks), 1);
301464d6f0bSTrond Norbye    cb_assert(h);
3021b3dd163SEric Lambert    h->cb = cb;
3031b3dd163SEric Lambert    h->cb_data = cb_data;
3041b3dd163SEric Lambert    h->next = mock_event_handlers[type];
3051b3dd163SEric Lambert    mock_event_handlers[type] = h;
3061b3dd163SEric Lambert}
3071b3dd163SEric Lambert
3081b3dd163SEric Lambertstatic void mock_perform_callbacks(ENGINE_EVENT_TYPE type,
309fc06711bSDustin Sallings                                   const void *data,
310fc06711bSDustin Sallings                                   const void *c) {
311f603fdb6STrond Norbye    struct mock_callbacks *h;
312f603fdb6STrond Norbye    for (h = mock_event_handlers[type]; h; h = h->next) {
3131b3dd163SEric Lambert        h->cb(c, type, data, h->cb_data);
3141b3dd163SEric Lambert    }
3151b3dd163SEric Lambert}
3161b3dd163SEric Lambert
317e1175713SMike Wiederholdstatic bool mock_add_new_hook(void (*hook)(const void* ptr, size_t size)) {
318e1175713SMike Wiederhold    return false;
319e1175713SMike Wiederhold}
320e1175713SMike Wiederhold
321e1175713SMike Wiederholdstatic bool mock_remove_new_hook(void (*hook)(const void* ptr, size_t size)) {
322e1175713SMike Wiederhold    return false;
323e1175713SMike Wiederhold}
324e1175713SMike Wiederhold
325e1175713SMike Wiederholdstatic bool mock_add_delete_hook(void (*hook)(const void* ptr)) {
326e1175713SMike Wiederhold    return false;
327e1175713SMike Wiederhold}
328e1175713SMike Wiederhold
329e1175713SMike Wiederholdstatic bool mock_remove_delete_hook(void (*hook)(const void* ptr)) {
330e1175713SMike Wiederhold    return false;
331e1175713SMike Wiederhold}
332e1175713SMike Wiederhold
333f603fdb6STrond Norbyestatic int mock_get_extra_stats_size(void) {
334e1175713SMike Wiederhold    return 0;
335e1175713SMike Wiederhold}
336e1175713SMike Wiederhold
3373a64fd5bSMike Wiederholdstatic void mock_get_allocator_stats(allocator_stats* stats) {
3383a64fd5bSMike Wiederhold    (void) stats;
3393a64fd5bSMike Wiederhold    return;
340e1175713SMike Wiederhold}
341e1175713SMike Wiederhold
342c6c32024STrond Norbyestatic size_t mock_get_allocation_size(const void* ptr) {
343e1175713SMike Wiederhold    return 0;
344e1175713SMike Wiederhold}
345e1175713SMike Wiederhold
346efe7c797SMike Wiederholdstatic void mock_get_detailed_stats(char* buffer, int size) {
347efe7c797SMike Wiederhold    (void) buffer;
348efe7c797SMike Wiederhold    (void) size;
349efe7c797SMike Wiederhold}
350efe7c797SMike Wiederhold
3511b3dd163SEric LambertSERVER_HANDLE_V1 *get_mock_server_api(void)
3521b3dd163SEric Lambert{
353f603fdb6STrond Norbye   static SERVER_CORE_API core_api;
354f603fdb6STrond Norbye   static SERVER_COOKIE_API server_cookie_api;
355f603fdb6STrond Norbye   static SERVER_STAT_API server_stat_api;
356f603fdb6STrond Norbye   static SERVER_EXTENSION_API extension_api;
357f603fdb6STrond Norbye   static SERVER_CALLBACK_API callback_api;
358f603fdb6STrond Norbye   static ALLOCATOR_HOOKS_API hooks_api;
359f603fdb6STrond Norbye   static SERVER_HANDLE_V1 rv;
360f603fdb6STrond Norbye   static int init;
361f603fdb6STrond Norbye   if (!init) {
362f603fdb6STrond Norbye      init = 1;
363f603fdb6STrond Norbye      core_api.server_version = mock_get_server_version;
364f603fdb6STrond Norbye      core_api.hash = mock_hash;
365f603fdb6STrond Norbye      core_api.realtime = mock_realtime;
366f603fdb6STrond Norbye      core_api.get_current_time = mock_get_current_time;
367f603fdb6STrond Norbye      core_api.abstime = mock_abstime;
368f603fdb6STrond Norbye      core_api.parse_config = mock_parse_config;
369f603fdb6STrond Norbye
370f603fdb6STrond Norbye      server_cookie_api.get_auth_data = mock_get_auth_data;
371f603fdb6STrond Norbye      server_cookie_api.store_engine_specific = mock_store_engine_specific;
372f603fdb6STrond Norbye      server_cookie_api.get_engine_specific = mock_get_engine_specific;
373bd0ecd24Sabhinavdangeti      server_cookie_api.is_datatype_supported = mock_is_datatype_supported;
3744f426e26Sabhinavdangeti      server_cookie_api.get_opcode_if_ewouldblock_set = mock_get_opcode_if_ewouldblock_set;
3752c217587Sabhinavdangeti      server_cookie_api.validate_session_cas = mock_validate_session_cas;
3764f426e26Sabhinavdangeti      server_cookie_api.decrement_session_ctr = mock_decrement_session_ctr;
377f603fdb6STrond Norbye      server_cookie_api.get_socket_fd = mock_get_socket_fd;
378f603fdb6STrond Norbye      server_cookie_api.notify_io_complete = mock_notify_io_complete;
379f603fdb6STrond Norbye      server_cookie_api.reserve = mock_cookie_reserve;
380f603fdb6STrond Norbye      server_cookie_api.release = mock_cookie_release;
38128e825f7STrond Norbye      server_cookie_api.set_priority = mock_set_priority;
382f603fdb6STrond Norbye
383f603fdb6STrond Norbye      server_stat_api.new_stats = mock_new_independent_stats;
384f603fdb6STrond Norbye      server_stat_api.release_stats = mock_release_independent_stats;
385f603fdb6STrond Norbye      server_stat_api.evicting = mock_count_eviction;
386f603fdb6STrond Norbye
387f603fdb6STrond Norbye      extension_api.register_extension = mock_register_extension;
388f603fdb6STrond Norbye      extension_api.unregister_extension = mock_unregister_extension;
389f603fdb6STrond Norbye      extension_api.get_extension = mock_get_extension;
390f603fdb6STrond Norbye
391f603fdb6STrond Norbye      callback_api.register_callback = mock_register_callback;
392f603fdb6STrond Norbye      callback_api.perform_callbacks = mock_perform_callbacks;
393f603fdb6STrond Norbye
394f603fdb6STrond Norbye      hooks_api.add_new_hook = mock_add_new_hook;
395f603fdb6STrond Norbye      hooks_api.remove_new_hook = mock_remove_new_hook;
396f603fdb6STrond Norbye      hooks_api.add_delete_hook = mock_add_delete_hook;
397f603fdb6STrond Norbye      hooks_api.remove_delete_hook = mock_remove_delete_hook;
398f603fdb6STrond Norbye      hooks_api.get_extra_stats_size = mock_get_extra_stats_size;
399f603fdb6STrond Norbye      hooks_api.get_allocator_stats = mock_get_allocator_stats;
400f603fdb6STrond Norbye      hooks_api.get_allocation_size = mock_get_allocation_size;
401f603fdb6STrond Norbye      hooks_api.get_detailed_stats = mock_get_detailed_stats;
402f603fdb6STrond Norbye
403f603fdb6STrond Norbye      rv.interface = 1;
404f603fdb6STrond Norbye      rv.core = &core_api;
405f603fdb6STrond Norbye      rv.stat = &server_stat_api;
406f603fdb6STrond Norbye      rv.extension = &extension_api;
407f603fdb6STrond Norbye      rv.callback = &callback_api;
408f603fdb6STrond Norbye      rv.cookie = &server_cookie_api;
409f603fdb6STrond Norbye      rv.alloc_hooks = &hooks_api;
410f603fdb6STrond Norbye   }
411f603fdb6STrond Norbye
412f603fdb6STrond Norbye   return &rv;
4131b3dd163SEric Lambert}
4141b3dd163SEric Lambert
4151b3dd163SEric Lambertvoid init_mock_server(ENGINE_HANDLE *server_engine) {
4161b3dd163SEric Lambert    process_started = time(0);
4171b3dd163SEric Lambert    null_logger = get_null_logger();
4181b3dd163SEric Lambert    stderr_logger = get_stderr_logger();
4191b3dd163SEric Lambert    engine = server_engine;
420f19e2c93SDustin Sallings    extensions.logger = null_logger;
4214f426e26Sabhinavdangeti    session_cas = 0x0102030405060708;
4224f426e26Sabhinavdangeti    session_ctr = 0;
4234f426e26Sabhinavdangeti    cb_mutex_initialize(&session_mutex);
4241b3dd163SEric Lambert}
4251b3dd163SEric Lambert
4261b3dd163SEric Lambertstruct mock_connstruct *mk_mock_connection(const char *user, const char *config) {
4271b3dd163SEric Lambert    struct mock_connstruct *rv = calloc(sizeof(struct mock_connstruct), 1);
4281b3dd163SEric Lambert    auth_data_t ad;
429464d6f0bSTrond Norbye    cb_assert(rv);
4301b3dd163SEric Lambert    rv->magic = CONN_MAGIC;
4311b3dd163SEric Lambert    rv->uname = user ? strdup(user) : NULL;
4321b3dd163SEric Lambert    rv->config = config ? strdup(config) : NULL;
4331b3dd163SEric Lambert    rv->connected = true;
4341b3dd163SEric Lambert    rv->next = connstructs;
4351b3dd163SEric Lambert    rv->evictions = 0;
436f603fdb6STrond Norbye    rv->sfd = 0; /* TODO make this more realistic */
4371b3dd163SEric Lambert    rv->status = ENGINE_SUCCESS;
4381b3dd163SEric Lambert    connstructs = rv;
4391b3dd163SEric Lambert    mock_perform_callbacks(ON_CONNECT, NULL, rv);
4401b3dd163SEric Lambert    if (rv->uname) {
4411b3dd163SEric Lambert        mock_get_auth_data(rv, &ad);
4421b3dd163SEric Lambert        mock_perform_callbacks(ON_AUTH, (const void*)&ad, rv);
4431b3dd163SEric Lambert    }
44472afc4dbSTrond Norbye
445f603fdb6STrond Norbye    cb_mutex_initialize(&rv->mutex);
446f603fdb6STrond Norbye    cb_cond_initialize(&rv->cond);
44772afc4dbSTrond Norbye
4481b3dd163SEric Lambert    return rv;
4491b3dd163SEric Lambert}
4501b3dd163SEric Lambert
45172afc4dbSTrond Norbyeconst void *create_mock_cookie(void) {
45272afc4dbSTrond Norbye    struct mock_connstruct *rv = calloc(sizeof(struct mock_connstruct), 1);
453464d6f0bSTrond Norbye    cb_assert(rv);
45472afc4dbSTrond Norbye    rv->magic = CONN_MAGIC;
45572afc4dbSTrond Norbye    rv->connected = true;
45672afc4dbSTrond Norbye    rv->status = ENGINE_SUCCESS;
45772afc4dbSTrond Norbye    rv->handle_ewouldblock = true;
458934f2578SMike Wiederhold    rv->references = 1;
459f603fdb6STrond Norbye    cb_mutex_initialize(&rv->mutex);
460f603fdb6STrond Norbye    cb_cond_initialize(&rv->cond);
46172afc4dbSTrond Norbye
46272afc4dbSTrond Norbye    return rv;
46372afc4dbSTrond Norbye}
46472afc4dbSTrond Norbye
46572afc4dbSTrond Norbyevoid destroy_mock_cookie(const void *cookie) {
466934f2578SMike Wiederhold    struct mock_connstruct *c = (struct mock_connstruct *)cookie;
467934f2578SMike Wiederhold    disconnect_mock_connection(c);
468934f2578SMike Wiederhold    if (c->references == 0) {
469934f2578SMike Wiederhold        free((void*)cookie);
470934f2578SMike Wiederhold    }
47172afc4dbSTrond Norbye}
47272afc4dbSTrond Norbye
47372afc4dbSTrond Norbyevoid mock_set_ewouldblock_handling(const void *cookie, bool enable) {
47472afc4dbSTrond Norbye    struct mock_connstruct *v = (void*)cookie;
47572afc4dbSTrond Norbye    v->handle_ewouldblock = enable;
47672afc4dbSTrond Norbye}
47772afc4dbSTrond Norbye
478889d7f99STrond Norbyevoid lock_mock_cookie(const void *cookie) {
479889d7f99STrond Norbye   struct mock_connstruct *c = (void*)cookie;
480f603fdb6STrond Norbye   cb_mutex_enter(&c->mutex);
481889d7f99STrond Norbye}
482889d7f99STrond Norbye
483889d7f99STrond Norbyevoid unlock_mock_cookie(const void *cookie) {
484889d7f99STrond Norbye   struct mock_connstruct *c = (void*)cookie;
485f603fdb6STrond Norbye   cb_mutex_exit(&c->mutex);
486889d7f99STrond Norbye}
487889d7f99STrond Norbye
488889d7f99STrond Norbyevoid waitfor_mock_cookie(const void *cookie) {
489889d7f99STrond Norbye   struct mock_connstruct *c = (void*)cookie;
490f603fdb6STrond Norbye   cb_cond_wait(&c->cond, &c->mutex);
491889d7f99STrond Norbye}
492889d7f99STrond Norbye
4931b3dd163SEric Lambertvoid disconnect_mock_connection(struct mock_connstruct *c) {
4941b3dd163SEric Lambert    c->connected = false;
495ca994d1eSMike Wiederhold    c->references--;
4961b3dd163SEric Lambert    mock_perform_callbacks(ON_DISCONNECT, NULL, c);
4971b3dd163SEric Lambert}
4981b3dd163SEric Lambert
4991b3dd163SEric Lambertvoid disconnect_all_mock_connections(struct mock_connstruct *c) {
5001b3dd163SEric Lambert    if (c) {
5011b3dd163SEric Lambert        disconnect_mock_connection(c);
5021b3dd163SEric Lambert        disconnect_all_mock_connections(c->next);
5031b3dd163SEric Lambert        free((void*)c->uname);
5041b3dd163SEric Lambert        free((void*)c->config);
5051b3dd163SEric Lambert        free(c);
5061b3dd163SEric Lambert    }
5071b3dd163SEric Lambert}
5081b3dd163SEric Lambert
5091b3dd163SEric Lambertvoid destroy_mock_event_callbacks_rec(struct mock_callbacks *h) {
5101b3dd163SEric Lambert    if (h) {
5111b3dd163SEric Lambert        destroy_mock_event_callbacks_rec(h->next);
5121b3dd163SEric Lambert        free(h);
5131b3dd163SEric Lambert    }
5141b3dd163SEric Lambert}
5151b3dd163SEric Lambert
5161b3dd163SEric Lambertvoid destroy_mock_event_callbacks(void) {
5171b3dd163SEric Lambert    int i = 0;
5181b3dd163SEric Lambert    for (i = 0; i < MAX_ENGINE_EVENT_TYPE; i++) {
5191b3dd163SEric Lambert        destroy_mock_event_callbacks_rec(mock_event_handlers[i]);
5201b3dd163SEric Lambert        mock_event_handlers[i] = NULL;
5211b3dd163SEric Lambert    }
5221b3dd163SEric Lambert}
523