~ubuntu-branches/ubuntu/quantal/memcached/quantal

« back to all changes in this revision

Viewing changes to testapp.c

  • Committer: Bazaar Package Importer
  • Author(s): David Martínez Moreno
  • Date: 2009-10-16 15:09:43 UTC
  • mfrom: (1.1.6 upstream) (3.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20091016150943-0rhh8x206ebgwzeu
Tags: 1.4.2-1
* New upstream release, primarily bugfixes, some of them critical, hence
  the urgency:
  - Reject keys larger than 250 bytes in the binary protocol.
  - Bounds checking on stats cachedump.
  - Binary protocol set+cas wasn't returning a new cas ID.
  - Binary quitq didn't actually close the connection
  - Slab boundary checking cleanup (bad logic in unreachable code)
  - Get hit memory optimizations
  - Disallow -t options that cause the server to not work
  - Killed off incomplete slab rebalance feature.
* debian/patches:
  - 01_init_script_compliant_with_LSB.patch: Remade as upstream applied a
    whitespace cleanup script that broke the patch.
  - 02_manpage_additions.patch: Added missing parameters to the memcached
    manpage.
* Removed TODO from debian/docs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 
2
#undef NDEBUG
 
3
#include <pthread.h>
 
4
#include <sys/types.h>
 
5
#include <sys/socket.h>
 
6
#include <netdb.h>
 
7
#include <arpa/inet.h>
 
8
#include <netinet/in.h>
 
9
#include <netinet/tcp.h>
 
10
#include <signal.h>
 
11
#include <stdio.h>
 
12
#include <stdlib.h>
 
13
#include <errno.h>
 
14
#include <assert.h>
 
15
#include <string.h>
 
16
#include <inttypes.h>
 
17
#include <stdbool.h>
 
18
#include <unistd.h>
 
19
#include <netinet/in.h>
 
20
 
 
21
#include "protocol_binary.h"
 
22
#include "config.h"
 
23
#include "cache.h"
 
24
#include "util.h"
 
25
 
 
26
#define TMP_TEMPLATE "/tmp/test_file.XXXXXXX"
 
27
 
 
28
enum test_return { TEST_SKIP, TEST_PASS, TEST_FAIL };
 
29
 
 
30
static pid_t server_pid;
 
31
static in_port_t port;
 
32
static int sock;
 
33
static bool allow_closed_read = false;
 
34
 
 
35
static enum test_return cache_create_test(void)
 
36
{
 
37
    cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
 
38
                                  NULL, NULL);
 
39
    assert(cache != NULL);
 
40
    cache_destroy(cache);
 
41
    return TEST_PASS;
 
42
}
 
43
 
 
44
const uint64_t constructor_pattern = 0xdeadcafebabebeef;
 
45
 
 
46
static int cache_constructor(void *buffer, void *notused1, int notused2) {
 
47
    uint64_t *ptr = buffer;
 
48
    *ptr = constructor_pattern;
 
49
    return 0;
 
50
}
 
51
 
 
52
static enum test_return cache_constructor_test(void)
 
53
{
 
54
    cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
 
55
                                  cache_constructor, NULL);
 
56
    assert(cache != NULL);
 
57
    uint64_t *ptr = cache_alloc(cache);
 
58
    uint64_t pattern = *ptr;
 
59
    cache_free(cache, ptr);
 
60
    cache_destroy(cache);
 
61
    return (pattern == constructor_pattern) ? TEST_PASS : TEST_FAIL;
 
62
}
 
63
 
 
64
static int cache_fail_constructor(void *buffer, void *notused1, int notused2) {
 
65
    return 1;
 
66
}
 
67
 
 
68
static enum test_return cache_fail_constructor_test(void)
 
69
{
 
70
    enum test_return ret = TEST_PASS;
 
71
 
 
72
    cache_t *cache = cache_create("test", sizeof(uint64_t), sizeof(uint64_t),
 
73
                                  cache_fail_constructor, NULL);
 
74
    assert(cache != NULL);
 
75
    uint64_t *ptr = cache_alloc(cache);
 
76
    if (ptr != NULL) {
 
77
        ret = TEST_FAIL;
 
78
    }
 
79
    cache_destroy(cache);
 
80
    return ret;
 
81
}
 
82
 
 
83
static void *destruct_data = 0;
 
84
 
 
85
static void cache_destructor(void *buffer, void *notused) {
 
86
    destruct_data = buffer;
 
87
}
 
88
 
 
89
static enum test_return cache_destructor_test(void)
 
90
{
 
91
    cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
 
92
                                  NULL, cache_destructor);
 
93
    assert(cache != NULL);
 
94
    char *ptr = cache_alloc(cache);
 
95
    cache_free(cache, ptr);
 
96
    cache_destroy(cache);
 
97
 
 
98
    return (ptr == destruct_data) ? TEST_PASS : TEST_FAIL;
 
99
}
 
100
 
 
101
static enum test_return cache_reuse_test(void)
 
102
{
 
103
    int ii;
 
104
    cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
 
105
                                  NULL, NULL);
 
106
    char *ptr = cache_alloc(cache);
 
107
    cache_free(cache, ptr);
 
108
    for (ii = 0; ii < 100; ++ii) {
 
109
        char *p = cache_alloc(cache);
 
110
        assert(p == ptr);
 
111
        cache_free(cache, ptr);
 
112
    }
 
113
    cache_destroy(cache);
 
114
    return TEST_PASS;
 
115
}
 
116
 
 
117
static enum test_return cache_redzone_test(void)
 
118
{
 
119
#ifndef HAVE_UMEM_H
 
120
    cache_t *cache = cache_create("test", sizeof(uint32_t), sizeof(char*),
 
121
                                  NULL, NULL);
 
122
 
 
123
    /* Ignore SIGABORT */
 
124
    struct sigaction old_action;
 
125
    struct sigaction action = { .sa_handler = SIG_IGN, .sa_flags = 0};
 
126
    sigemptyset(&action.sa_mask);
 
127
    sigaction(SIGABRT, &action, &old_action);
 
128
 
 
129
    /* check memory debug.. */
 
130
    char *p = cache_alloc(cache);
 
131
    char old = *(p - 1);
 
132
    *(p - 1) = 0;
 
133
    cache_free(cache, p);
 
134
    assert(cache_error == -1);
 
135
    *(p - 1) = old;
 
136
 
 
137
    p[sizeof(uint32_t)] = 0;
 
138
    cache_free(cache, p);
 
139
    assert(cache_error == 1);
 
140
 
 
141
    /* restore signal handler */
 
142
    sigaction(SIGABRT, &old_action, NULL);
 
143
 
 
144
    cache_destroy(cache);
 
145
 
 
146
    return TEST_PASS;
 
147
#else
 
148
    return TEST_SKIP;
 
149
#endif
 
150
}
 
151
 
 
152
static enum test_return test_safe_strtoul(void) {
 
153
    uint32_t val;
 
154
    assert(safe_strtoul("123", &val));
 
155
    assert(val == 123);
 
156
    assert(safe_strtoul("+123", &val));
 
157
    assert(val == 123);
 
158
    assert(!safe_strtoul("", &val));  // empty
 
159
    assert(!safe_strtoul("123BOGUS", &val));  // non-numeric
 
160
    /* Not sure what it does, but this works with ICC :/
 
161
       assert(!safe_strtoul("92837498237498237498029383", &val)); // out of range
 
162
    */
 
163
 
 
164
    // extremes:
 
165
    assert(safe_strtoul("4294967295", &val)); // 2**32 - 1
 
166
    assert(val == 4294967295L);
 
167
    /* This actually works on 64-bit ubuntu
 
168
       assert(!safe_strtoul("4294967296", &val)); // 2**32
 
169
    */
 
170
    assert(!safe_strtoul("-1", &val));  // negative
 
171
    return TEST_PASS;
 
172
}
 
173
 
 
174
 
 
175
static enum test_return test_safe_strtoull(void) {
 
176
    uint64_t val;
 
177
    assert(safe_strtoull("123", &val));
 
178
    assert(val == 123);
 
179
    assert(safe_strtoull("+123", &val));
 
180
    assert(val == 123);
 
181
    assert(!safe_strtoull("", &val));  // empty
 
182
    assert(!safe_strtoull("123BOGUS", &val));  // non-numeric
 
183
    assert(!safe_strtoull("92837498237498237498029383", &val)); // out of range
 
184
 
 
185
    // extremes:
 
186
    assert(safe_strtoull("18446744073709551615", &val)); // 2**64 - 1
 
187
    assert(val == 18446744073709551615ULL);
 
188
    assert(!safe_strtoull("18446744073709551616", &val)); // 2**64
 
189
    assert(!safe_strtoull("-1", &val));  // negative
 
190
    return TEST_PASS;
 
191
}
 
192
 
 
193
static enum test_return test_safe_strtoll(void) {
 
194
    int64_t val;
 
195
    assert(safe_strtoll("123", &val));
 
196
    assert(val == 123);
 
197
    assert(safe_strtoll("+123", &val));
 
198
    assert(val == 123);
 
199
    assert(safe_strtoll("-123", &val));
 
200
    assert(val == -123);
 
201
    assert(!safe_strtoll("", &val));  // empty
 
202
    assert(!safe_strtoll("123BOGUS", &val));  // non-numeric
 
203
    assert(!safe_strtoll("92837498237498237498029383", &val)); // out of range
 
204
 
 
205
    // extremes:
 
206
    assert(!safe_strtoll("18446744073709551615", &val)); // 2**64 - 1
 
207
    assert(safe_strtoll("9223372036854775807", &val)); // 2**63 - 1
 
208
    assert(val == 9223372036854775807LL);
 
209
    /*
 
210
      assert(safe_strtoll("-9223372036854775808", &val)); // -2**63
 
211
      assert(val == -9223372036854775808LL);
 
212
    */
 
213
    assert(!safe_strtoll("-9223372036854775809", &val)); // -2**63 - 1
 
214
 
 
215
    // We'll allow space to terminate the string.  And leading space.
 
216
    assert(safe_strtoll(" 123 foo", &val));
 
217
    assert(val == 123);
 
218
    return TEST_PASS;
 
219
}
 
220
 
 
221
static enum test_return test_safe_strtol(void) {
 
222
    int32_t val;
 
223
    assert(safe_strtol("123", &val));
 
224
    assert(val == 123);
 
225
    assert(safe_strtol("+123", &val));
 
226
    assert(val == 123);
 
227
    assert(safe_strtol("-123", &val));
 
228
    assert(val == -123);
 
229
    assert(!safe_strtol("", &val));  // empty
 
230
    assert(!safe_strtol("123BOGUS", &val));  // non-numeric
 
231
    assert(!safe_strtol("92837498237498237498029383", &val)); // out of range
 
232
 
 
233
    // extremes:
 
234
    /* This actually works on 64-bit ubuntu
 
235
       assert(!safe_strtol("2147483648", &val)); // (expt 2.0 31.0)
 
236
    */
 
237
    assert(safe_strtol("2147483647", &val)); // (- (expt 2.0 31) 1)
 
238
    assert(val == 2147483647L);
 
239
    /* This actually works on 64-bit ubuntu
 
240
       assert(!safe_strtol("-2147483649", &val)); // (- (expt -2.0 31) 1)
 
241
    */
 
242
 
 
243
    // We'll allow space to terminate the string.  And leading space.
 
244
    assert(safe_strtol(" 123 foo", &val));
 
245
    assert(val == 123);
 
246
    return TEST_PASS;
 
247
}
 
248
 
 
249
/**
 
250
 * Function to start the server and let it listen on a random port
 
251
 *
 
252
 * @param port_out where to store the TCP port number the server is
 
253
 *                 listening on
 
254
 * @param daemon set to true if you want to run the memcached server
 
255
 *               as a daemon process
 
256
 * @return the pid of the memcached server
 
257
 */
 
258
static pid_t start_server(in_port_t *port_out, bool daemon, int timeout) {
 
259
    char environment[80];
 
260
    snprintf(environment, sizeof(environment),
 
261
             "MEMCACHED_PORT_FILENAME=/tmp/ports.%lu", (long)getpid());
 
262
    char *filename= environment + strlen("MEMCACHED_PORT_FILENAME=");
 
263
    char pid_file[80];
 
264
    snprintf(pid_file, sizeof(pid_file), "/tmp/pid.%lu", (long)getpid());
 
265
 
 
266
    remove(filename);
 
267
    remove(pid_file);
 
268
 
 
269
#ifdef __sun
 
270
    /* I want to name the corefiles differently so that they don't
 
271
       overwrite each other
 
272
    */
 
273
    char coreadm[128];
 
274
    sprintf(coreadm, "coreadm -p core.%%f.%%p %lu", (unsigned long)getpid());
 
275
    system(coreadm);
 
276
#endif
 
277
 
 
278
    pid_t pid = fork();
 
279
    assert(pid != -1);
 
280
 
 
281
    if (pid == 0) {
 
282
        /* Child */
 
283
        char *argv[20];
 
284
        int arg = 0;
 
285
        char tmo[24];
 
286
        snprintf(tmo, sizeof(tmo), "%u", timeout);
 
287
 
 
288
        putenv(environment);
 
289
#ifdef __sun
 
290
        putenv("LD_PRELOAD=watchmalloc.so.1");
 
291
        putenv("MALLOC_DEBUG=WATCH");
 
292
#endif
 
293
 
 
294
        if (!daemon) {
 
295
            argv[arg++] = "./timedrun";
 
296
            argv[arg++] = tmo;
 
297
        }
 
298
        argv[arg++] = "./memcached-debug";
 
299
        argv[arg++] = "-p";
 
300
        argv[arg++] = "-1";
 
301
        argv[arg++] = "-U";
 
302
        argv[arg++] = "0";
 
303
        /* Handle rpmbuild and the like doing this as root */
 
304
        if (getuid() == 0) {
 
305
            argv[arg++] = "-u";
 
306
            argv[arg++] = "root";
 
307
        }
 
308
        if (daemon) {
 
309
            argv[arg++] = "-d";
 
310
            argv[arg++] = "-P";
 
311
            argv[arg++] = pid_file;
 
312
        }
 
313
#ifdef MESSAGE_DEBUG
 
314
         argv[arg++] = "-vvv";
 
315
#endif
 
316
        argv[arg++] = NULL;
 
317
        assert(execv(argv[0], argv) != -1);
 
318
    }
 
319
 
 
320
    /* Yeah just let us "busy-wait" for the file to be created ;-) */
 
321
    while (access(filename, F_OK) == -1) {
 
322
        usleep(10);
 
323
    }
 
324
 
 
325
    FILE *fp = fopen(filename, "r");
 
326
    if (fp == NULL) {
 
327
        fprintf(stderr, "Failed to open the file containing port numbers: %s\n",
 
328
                strerror(errno));
 
329
        assert(false);
 
330
    }
 
331
 
 
332
    *port_out = (in_port_t)-1;
 
333
    char buffer[80];
 
334
    while ((fgets(buffer, sizeof(buffer), fp)) != NULL) {
 
335
        if (strncmp(buffer, "TCP INET: ", 10) == 0) {
 
336
            int32_t val;
 
337
            assert(safe_strtol(buffer + 10, &val));
 
338
            *port_out = (in_port_t)val;
 
339
        }
 
340
    }
 
341
    fclose(fp);
 
342
    assert(remove(filename) == 0);
 
343
 
 
344
    if (daemon) {
 
345
        /* loop and wait for the pid file.. There is a potential race
 
346
         * condition that the server just created the file but isn't
 
347
         * finished writing the content, but I'll take the chance....
 
348
         */
 
349
        while (access(pid_file, F_OK) == -1) {
 
350
            usleep(10);
 
351
        }
 
352
 
 
353
        fp = fopen(pid_file, "r");
 
354
        if (fp == NULL) {
 
355
            fprintf(stderr, "Failed to open pid file: %s\n",
 
356
                    strerror(errno));
 
357
            assert(false);
 
358
        }
 
359
        assert(fgets(buffer, sizeof(buffer), fp) != NULL);
 
360
        fclose(fp);
 
361
 
 
362
        int32_t val;
 
363
        assert(safe_strtol(buffer, &val));
 
364
        pid = (pid_t)val;
 
365
    }
 
366
 
 
367
    return pid;
 
368
}
 
369
 
 
370
static enum test_return test_issue_44(void) {
 
371
    in_port_t port;
 
372
    pid_t pid = start_server(&port, true, 15);
 
373
    assert(kill(pid, SIGHUP) == 0);
 
374
    sleep(1);
 
375
    assert(kill(pid, SIGTERM) == 0);
 
376
 
 
377
    return TEST_PASS;
 
378
}
 
379
 
 
380
static struct addrinfo *lookuphost(const char *hostname, in_port_t port)
 
381
{
 
382
    struct addrinfo *ai = 0;
 
383
    struct addrinfo hints = { .ai_family = AF_UNSPEC,
 
384
                              .ai_protocol = IPPROTO_TCP,
 
385
                              .ai_socktype = SOCK_STREAM };
 
386
    char service[NI_MAXSERV];
 
387
    int error;
 
388
 
 
389
    (void)snprintf(service, NI_MAXSERV, "%d", port);
 
390
    if ((error = getaddrinfo(hostname, service, &hints, &ai)) != 0) {
 
391
       if (error != EAI_SYSTEM) {
 
392
          fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
 
393
       } else {
 
394
          perror("getaddrinfo()");
 
395
       }
 
396
    }
 
397
 
 
398
    return ai;
 
399
}
 
400
 
 
401
static int connect_server(const char *hostname, in_port_t port)
 
402
{
 
403
    struct addrinfo *ai = lookuphost(hostname, port);
 
404
    int sock = -1;
 
405
    if (ai != NULL) {
 
406
       if ((sock = socket(ai->ai_family, ai->ai_socktype,
 
407
                          ai->ai_protocol)) != -1) {
 
408
          if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
 
409
             fprintf(stderr, "Failed to connect socket: %s\n",
 
410
                     strerror(errno));
 
411
             close(sock);
 
412
             sock = -1;
 
413
          }
 
414
       } else {
 
415
          fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
 
416
       }
 
417
 
 
418
       freeaddrinfo(ai);
 
419
    }
 
420
    return sock;
 
421
}
 
422
 
 
423
static enum test_return test_vperror(void) {
 
424
    int rv = 0;
 
425
    int oldstderr = dup(STDERR_FILENO);
 
426
    char tmpl[sizeof(TMP_TEMPLATE)+1];
 
427
    strncpy(tmpl, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1);
 
428
 
 
429
    int newfile = mkstemp(tmpl);
 
430
    assert(newfile > 0);
 
431
    rv = dup2(newfile, STDERR_FILENO);
 
432
    assert(rv == STDERR_FILENO);
 
433
    rv = close(newfile);
 
434
    assert(rv == 0);
 
435
 
 
436
    errno = EIO;
 
437
    vperror("Old McDonald had a farm.  %s", "EI EIO");
 
438
 
 
439
    /* Restore stderr */
 
440
    rv = dup2(oldstderr, STDERR_FILENO);
 
441
    assert(rv == STDERR_FILENO);
 
442
 
 
443
 
 
444
    /* Go read the file */
 
445
    char buf[80] = { 0 };
 
446
    FILE *efile = fopen(tmpl, "r");
 
447
    assert(efile);
 
448
    char *prv = fgets(buf, sizeof(buf), efile);
 
449
    assert(prv);
 
450
    fclose(efile);
 
451
 
 
452
    unlink(tmpl);
 
453
 
 
454
    char expected[80] = { 0 };
 
455
    snprintf(expected, sizeof(expected),
 
456
             "Old McDonald had a farm.  EI EIO: %s\n", strerror(EIO));
 
457
 
 
458
    /*
 
459
    fprintf(stderr,
 
460
            "\nExpected:  ``%s''"
 
461
            "\nGot:       ``%s''\n", expected, buf);
 
462
    */
 
463
 
 
464
    return strcmp(expected, buf) == 0 ? TEST_PASS : TEST_FAIL;
 
465
}
 
466
 
 
467
static void send_ascii_command(const char *buf) {
 
468
    off_t offset = 0;
 
469
    const char* ptr = buf;
 
470
    size_t len = strlen(buf);
 
471
 
 
472
    do {
 
473
        ssize_t nw = write(sock, ptr + offset, len - offset);
 
474
        if (nw == -1) {
 
475
            if (errno != EINTR) {
 
476
                fprintf(stderr, "Failed to write: %s\n", strerror(errno));
 
477
                abort();
 
478
            }
 
479
        } else {
 
480
            offset += nw;
 
481
        }
 
482
    } while (offset < len);
 
483
}
 
484
 
 
485
/*
 
486
 * This is a dead slow single byte read, but it should only read out
 
487
 * _one_ response and I don't have an input buffer... The current
 
488
 * implementation only supports single-line responses, so if you want to use
 
489
 * it for get commands you need to implement that first ;-)
 
490
 */
 
491
static void read_ascii_response(char *buffer, size_t size) {
 
492
    off_t offset = 0;
 
493
    bool need_more = true;
 
494
    do {
 
495
        ssize_t nr = read(sock, buffer + offset, 1);
 
496
        if (nr == -1) {
 
497
            if (errno != EINTR) {
 
498
                fprintf(stderr, "Failed to read: %s\n", strerror(errno));
 
499
                abort();
 
500
            }
 
501
        } else {
 
502
            assert(nr == 1);
 
503
            if (buffer[offset] == '\n') {
 
504
                need_more = false;
 
505
                buffer[offset + 1] = '\0';
 
506
            }
 
507
            offset += nr;
 
508
            assert(offset + 1 < size);
 
509
        }
 
510
    } while (need_more);
 
511
}
 
512
 
 
513
static enum test_return test_issue_92(void) {
 
514
    char buffer[1024];
 
515
 
 
516
    close(sock);
 
517
    sock = connect_server("127.0.0.1", port);
 
518
 
 
519
    send_ascii_command("stats cachedump 1 0 0\r\n");
 
520
    read_ascii_response(buffer, sizeof(buffer));
 
521
    assert(strncmp(buffer, "END", strlen("END")) == 0);
 
522
 
 
523
    send_ascii_command("stats cachedump 200 0 0\r\n");
 
524
    read_ascii_response(buffer, sizeof(buffer));
 
525
    assert(strncmp(buffer, "CLIENT_ERROR", strlen("CLIENT_ERROR")) == 0);
 
526
 
 
527
    close(sock);
 
528
    sock = connect_server("127.0.0.1", port);
 
529
    return TEST_PASS;
 
530
}
 
531
 
 
532
static enum test_return start_memcached_server(void) {
 
533
    server_pid = start_server(&port, false, 600);
 
534
    sock = connect_server("127.0.0.1", port);
 
535
    return TEST_PASS;
 
536
}
 
537
 
 
538
static enum test_return stop_memcached_server(void) {
 
539
    close(sock);
 
540
    assert(kill(server_pid, SIGTERM) == 0);
 
541
    return TEST_PASS;
 
542
}
 
543
 
 
544
static void safe_send(const void* buf, size_t len, bool hickup)
 
545
{
 
546
    off_t offset = 0;
 
547
    const char* ptr = buf;
 
548
#ifdef MESSAGE_DEBUG
 
549
    uint8_t val = *ptr;
 
550
    assert(val == (uint8_t)0x80);
 
551
    fprintf(stderr, "About to send %lu bytes:", (unsigned long)len);
 
552
    for (int ii = 0; ii < len; ++ii) {
 
553
        if (ii % 4 == 0) {
 
554
            fprintf(stderr, "\n   ");
 
555
        }
 
556
        val = *(ptr + ii);
 
557
        fprintf(stderr, " 0x%02x", val);
 
558
    }
 
559
    fprintf(stderr, "\n");
 
560
    usleep(500);
 
561
#endif
 
562
 
 
563
    do {
 
564
        size_t num_bytes = len - offset;
 
565
        if (hickup) {
 
566
            if (num_bytes > 1024) {
 
567
                num_bytes = (rand() % 1023) + 1;
 
568
            }
 
569
        }
 
570
 
 
571
        ssize_t nw = write(sock, ptr + offset, num_bytes);
 
572
        if (nw == -1) {
 
573
            if (errno != EINTR) {
 
574
                fprintf(stderr, "Failed to write: %s\n", strerror(errno));
 
575
                abort();
 
576
            }
 
577
        } else {
 
578
            if (hickup) {
 
579
                usleep(100);
 
580
            }
 
581
            offset += nw;
 
582
        }
 
583
    } while (offset < len);
 
584
}
 
585
 
 
586
static bool safe_recv(void *buf, size_t len) {
 
587
    if (len == 0) {
 
588
        return true;
 
589
    }
 
590
    off_t offset = 0;
 
591
    do {
 
592
        ssize_t nr = read(sock, ((char*)buf) + offset, len - offset);
 
593
        if (nr == -1) {
 
594
            if (errno != EINTR) {
 
595
                fprintf(stderr, "Failed to read: %s\n", strerror(errno));
 
596
                abort();
 
597
            }
 
598
        } else {
 
599
            if (nr == 0 && allow_closed_read) {
 
600
                return false;
 
601
            }
 
602
            assert(nr != 0);
 
603
            offset += nr;
 
604
        }
 
605
    } while (offset < len);
 
606
 
 
607
    return true;
 
608
}
 
609
 
 
610
static bool safe_recv_packet(void *buf, size_t size) {
 
611
    protocol_binary_response_no_extras *response = buf;
 
612
    assert(size > sizeof(*response));
 
613
    if (!safe_recv(response, sizeof(*response))) {
 
614
        return false;
 
615
    }
 
616
    response->message.header.response.keylen = ntohs(response->message.header.response.keylen);
 
617
    response->message.header.response.status = ntohs(response->message.header.response.status);
 
618
    response->message.header.response.bodylen = ntohl(response->message.header.response.bodylen);
 
619
 
 
620
    size_t len = sizeof(*response);
 
621
 
 
622
    char *ptr = buf;
 
623
    ptr += len;
 
624
    if (!safe_recv(ptr, response->message.header.response.bodylen)) {
 
625
        return false;
 
626
    }
 
627
 
 
628
#ifdef MESSAGE_DEBUG
 
629
    usleep(500);
 
630
    ptr = buf;
 
631
    len += response->message.header.response.bodylen;
 
632
    uint8_t val = *ptr;
 
633
    assert(val == (uint8_t)0x81);
 
634
    fprintf(stderr, "Received %lu bytes:", (unsigned long)len);
 
635
    for (int ii = 0; ii < len; ++ii) {
 
636
        if (ii % 4 == 0) {
 
637
            fprintf(stderr, "\n   ");
 
638
        }
 
639
        val = *(ptr + ii);
 
640
        fprintf(stderr, " 0x%02x", val);
 
641
    }
 
642
    fprintf(stderr, "\n");
 
643
#endif
 
644
    return true;
 
645
}
 
646
 
 
647
static off_t storage_command(char*buf,
 
648
                             size_t bufsz,
 
649
                             uint8_t cmd,
 
650
                             const void* key,
 
651
                             size_t keylen,
 
652
                             const void* dta,
 
653
                             size_t dtalen,
 
654
                             uint32_t flags,
 
655
                             uint32_t exp) {
 
656
    /* all of the storage commands use the same command layout */
 
657
    protocol_binary_request_set *request = (void*)buf;
 
658
    assert(bufsz > sizeof(*request) + keylen + dtalen);
 
659
 
 
660
    memset(request, 0, sizeof(*request));
 
661
    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
 
662
    request->message.header.request.opcode = cmd;
 
663
    request->message.header.request.keylen = htons(keylen);
 
664
    request->message.header.request.extlen = 8;
 
665
    request->message.header.request.bodylen = htonl(keylen + 8 + dtalen);
 
666
    request->message.header.request.opaque = 0xdeadbeef;
 
667
    request->message.body.flags = flags;
 
668
    request->message.body.expiration = exp;
 
669
 
 
670
    off_t key_offset = sizeof(protocol_binary_request_no_extras) + 8;
 
671
 
 
672
    memcpy(buf + key_offset, key, keylen);
 
673
    if (dta != NULL) {
 
674
        memcpy(buf + key_offset + keylen, dta, dtalen);
 
675
    }
 
676
 
 
677
    return key_offset + keylen + dtalen;
 
678
}
 
679
 
 
680
static off_t raw_command(char* buf,
 
681
                         size_t bufsz,
 
682
                         uint8_t cmd,
 
683
                         const void* key,
 
684
                         size_t keylen,
 
685
                         const void* dta,
 
686
                         size_t dtalen) {
 
687
    /* all of the storage commands use the same command layout */
 
688
    protocol_binary_request_no_extras *request = (void*)buf;
 
689
    assert(bufsz > sizeof(*request) + keylen + dtalen);
 
690
 
 
691
    memset(request, 0, sizeof(*request));
 
692
    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
 
693
    request->message.header.request.opcode = cmd;
 
694
    request->message.header.request.keylen = htons(keylen);
 
695
    request->message.header.request.bodylen = htonl(keylen + dtalen);
 
696
    request->message.header.request.opaque = 0xdeadbeef;
 
697
 
 
698
    off_t key_offset = sizeof(protocol_binary_request_no_extras);
 
699
 
 
700
    if (key != NULL) {
 
701
        memcpy(buf + key_offset, key, keylen);
 
702
    }
 
703
    if (dta != NULL) {
 
704
        memcpy(buf + key_offset + keylen, dta, dtalen);
 
705
    }
 
706
 
 
707
    return sizeof(*request) + keylen + dtalen;
 
708
}
 
709
 
 
710
static off_t flush_command(char* buf, size_t bufsz, uint8_t cmd, uint32_t exptime, bool use_extra) {
 
711
    protocol_binary_request_flush *request = (void*)buf;
 
712
    assert(bufsz > sizeof(*request));
 
713
 
 
714
    memset(request, 0, sizeof(*request));
 
715
    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
 
716
    request->message.header.request.opcode = cmd;
 
717
 
 
718
    off_t size = sizeof(protocol_binary_request_no_extras);
 
719
    if (use_extra) {
 
720
        request->message.header.request.extlen = 4;
 
721
        request->message.body.expiration = htonl(exptime);
 
722
        request->message.header.request.bodylen = htonl(4);
 
723
        size += 4;
 
724
    }
 
725
 
 
726
    request->message.header.request.opaque = 0xdeadbeef;
 
727
 
 
728
    return size;
 
729
}
 
730
 
 
731
static off_t arithmetic_command(char* buf,
 
732
                                size_t bufsz,
 
733
                                uint8_t cmd,
 
734
                                const void* key,
 
735
                                size_t keylen,
 
736
                                uint64_t delta,
 
737
                                uint64_t initial,
 
738
                                uint32_t exp) {
 
739
    protocol_binary_request_incr *request = (void*)buf;
 
740
    assert(bufsz > sizeof(*request) + keylen);
 
741
 
 
742
    memset(request, 0, sizeof(*request));
 
743
    request->message.header.request.magic = PROTOCOL_BINARY_REQ;
 
744
    request->message.header.request.opcode = cmd;
 
745
    request->message.header.request.keylen = htons(keylen);
 
746
    request->message.header.request.extlen = 20;
 
747
    request->message.header.request.bodylen = htonl(keylen + 20);
 
748
    request->message.header.request.opaque = 0xdeadbeef;
 
749
    request->message.body.delta = htonll(delta);
 
750
    request->message.body.initial = htonll(initial);
 
751
    request->message.body.expiration = htonl(exp);
 
752
 
 
753
    off_t key_offset = sizeof(protocol_binary_request_no_extras) + 20;
 
754
 
 
755
    memcpy(buf + key_offset, key, keylen);
 
756
    return key_offset + keylen;
 
757
}
 
758
 
 
759
static void validate_response_header(protocol_binary_response_no_extras *response,
 
760
                                     uint8_t cmd, uint16_t status)
 
761
{
 
762
    assert(response->message.header.response.magic == PROTOCOL_BINARY_RES);
 
763
    assert(response->message.header.response.opcode == cmd);
 
764
    assert(response->message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
 
765
    assert(response->message.header.response.status == status);
 
766
    assert(response->message.header.response.opaque == 0xdeadbeef);
 
767
 
 
768
    if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
 
769
        switch (cmd) {
 
770
        case PROTOCOL_BINARY_CMD_ADDQ:
 
771
        case PROTOCOL_BINARY_CMD_APPENDQ:
 
772
        case PROTOCOL_BINARY_CMD_DECREMENTQ:
 
773
        case PROTOCOL_BINARY_CMD_DELETEQ:
 
774
        case PROTOCOL_BINARY_CMD_FLUSHQ:
 
775
        case PROTOCOL_BINARY_CMD_INCREMENTQ:
 
776
        case PROTOCOL_BINARY_CMD_PREPENDQ:
 
777
        case PROTOCOL_BINARY_CMD_QUITQ:
 
778
        case PROTOCOL_BINARY_CMD_REPLACEQ:
 
779
        case PROTOCOL_BINARY_CMD_SETQ:
 
780
            assert("Quiet command shouldn't return on success" == NULL);
 
781
        default:
 
782
            break;
 
783
        }
 
784
 
 
785
        switch (cmd) {
 
786
        case PROTOCOL_BINARY_CMD_ADD:
 
787
        case PROTOCOL_BINARY_CMD_REPLACE:
 
788
        case PROTOCOL_BINARY_CMD_SET:
 
789
        case PROTOCOL_BINARY_CMD_APPEND:
 
790
        case PROTOCOL_BINARY_CMD_PREPEND:
 
791
            assert(response->message.header.response.keylen == 0);
 
792
            assert(response->message.header.response.extlen == 0);
 
793
            assert(response->message.header.response.bodylen == 0);
 
794
            assert(response->message.header.response.cas != 0);
 
795
            break;
 
796
        case PROTOCOL_BINARY_CMD_FLUSH:
 
797
        case PROTOCOL_BINARY_CMD_NOOP:
 
798
        case PROTOCOL_BINARY_CMD_QUIT:
 
799
        case PROTOCOL_BINARY_CMD_DELETE:
 
800
            assert(response->message.header.response.keylen == 0);
 
801
            assert(response->message.header.response.extlen == 0);
 
802
            assert(response->message.header.response.bodylen == 0);
 
803
            assert(response->message.header.response.cas == 0);
 
804
            break;
 
805
 
 
806
        case PROTOCOL_BINARY_CMD_DECREMENT:
 
807
        case PROTOCOL_BINARY_CMD_INCREMENT:
 
808
            assert(response->message.header.response.keylen == 0);
 
809
            assert(response->message.header.response.extlen == 0);
 
810
            assert(response->message.header.response.bodylen == 8);
 
811
            assert(response->message.header.response.cas != 0);
 
812
            break;
 
813
 
 
814
        case PROTOCOL_BINARY_CMD_STAT:
 
815
            assert(response->message.header.response.extlen == 0);
 
816
            /* key and value exists in all packets except in the terminating */
 
817
            assert(response->message.header.response.cas == 0);
 
818
            break;
 
819
 
 
820
        case PROTOCOL_BINARY_CMD_VERSION:
 
821
            assert(response->message.header.response.keylen == 0);
 
822
            assert(response->message.header.response.extlen == 0);
 
823
            assert(response->message.header.response.bodylen != 0);
 
824
            assert(response->message.header.response.cas == 0);
 
825
            break;
 
826
 
 
827
        case PROTOCOL_BINARY_CMD_GET:
 
828
        case PROTOCOL_BINARY_CMD_GETQ:
 
829
            assert(response->message.header.response.keylen == 0);
 
830
            assert(response->message.header.response.extlen == 4);
 
831
            assert(response->message.header.response.cas != 0);
 
832
            break;
 
833
 
 
834
        case PROTOCOL_BINARY_CMD_GETK:
 
835
        case PROTOCOL_BINARY_CMD_GETKQ:
 
836
            assert(response->message.header.response.keylen != 0);
 
837
            assert(response->message.header.response.extlen == 4);
 
838
            assert(response->message.header.response.cas != 0);
 
839
            break;
 
840
 
 
841
        default:
 
842
            /* Undefined command code */
 
843
            break;
 
844
        }
 
845
    } else {
 
846
        assert(response->message.header.response.cas == 0);
 
847
        assert(response->message.header.response.extlen == 0);
 
848
        if (cmd != PROTOCOL_BINARY_CMD_GETK) {
 
849
            assert(response->message.header.response.keylen == 0);
 
850
        }
 
851
    }
 
852
}
 
853
 
 
854
static enum test_return test_binary_noop(void) {
 
855
    union {
 
856
        protocol_binary_request_no_extras request;
 
857
        protocol_binary_response_no_extras response;
 
858
        char bytes[1024];
 
859
    } buffer;
 
860
 
 
861
    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
 
862
                             PROTOCOL_BINARY_CMD_NOOP,
 
863
                             NULL, 0, NULL, 0);
 
864
 
 
865
    safe_send(buffer.bytes, len, false);
 
866
    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
 
867
    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_NOOP,
 
868
                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
869
 
 
870
    return TEST_PASS;
 
871
}
 
872
 
 
873
static enum test_return test_binary_quit_impl(uint8_t cmd) {
 
874
    union {
 
875
        protocol_binary_request_no_extras request;
 
876
        protocol_binary_response_no_extras response;
 
877
        char bytes[1024];
 
878
    } buffer;
 
879
    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
 
880
                             cmd, NULL, 0, NULL, 0);
 
881
 
 
882
    safe_send(buffer.bytes, len, false);
 
883
    if (cmd == PROTOCOL_BINARY_CMD_QUIT) {
 
884
        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
 
885
        validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_QUIT,
 
886
                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
887
    }
 
888
 
 
889
    /* Socket should be closed now, read should return 0 */
 
890
    assert(read(sock, buffer.bytes, sizeof(buffer.bytes)) == 0);
 
891
    close(sock);
 
892
    sock = connect_server("127.0.0.1", port);
 
893
 
 
894
    return TEST_PASS;
 
895
}
 
896
 
 
897
static enum test_return test_binary_quit(void) {
 
898
    return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
 
899
}
 
900
 
 
901
static enum test_return test_binary_quitq(void) {
 
902
    return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
 
903
}
 
904
 
 
905
static enum test_return test_binary_set_impl(const char *key, uint8_t cmd) {
 
906
    union {
 
907
        protocol_binary_request_no_extras request;
 
908
        protocol_binary_response_no_extras response;
 
909
        char bytes[1024];
 
910
    } send, receive;
 
911
    uint64_t value = 0xdeadbeefdeadcafe;
 
912
    size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
 
913
                                 key, strlen(key), &value, sizeof(value),
 
914
                                 0, 0);
 
915
 
 
916
    /* Set should work over and over again */
 
917
    int ii;
 
918
    for (ii = 0; ii < 10; ++ii) {
 
919
        safe_send(send.bytes, len, false);
 
920
        if (cmd == PROTOCOL_BINARY_CMD_SET) {
 
921
            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
922
            validate_response_header(&receive.response, cmd,
 
923
                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
924
        }
 
925
    }
 
926
 
 
927
    if (cmd == PROTOCOL_BINARY_CMD_SETQ) {
 
928
        return test_binary_noop();
 
929
    }
 
930
 
 
931
    send.request.message.header.request.cas = receive.response.message.header.response.cas;
 
932
    safe_send(send.bytes, len, false);
 
933
    if (cmd == PROTOCOL_BINARY_CMD_SET) {
 
934
        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
935
        validate_response_header(&receive.response, cmd,
 
936
                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
937
        assert(receive.response.message.header.response.cas != send.request.message.header.request.cas);
 
938
    } else {
 
939
        return test_binary_noop();
 
940
    }
 
941
 
 
942
    return TEST_PASS;
 
943
}
 
944
 
 
945
static enum test_return test_binary_set(void) {
 
946
    return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
 
947
}
 
948
 
 
949
static enum test_return test_binary_setq(void) {
 
950
    return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
 
951
}
 
952
 
 
953
 
 
954
static enum test_return test_binary_add_impl(const char *key, uint8_t cmd) {
 
955
    uint64_t value = 0xdeadbeefdeadcafe;
 
956
    union {
 
957
        protocol_binary_request_no_extras request;
 
958
        protocol_binary_response_no_extras response;
 
959
        char bytes[1024];
 
960
    } send, receive;
 
961
    size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd, key,
 
962
                                 strlen(key), &value, sizeof(value),
 
963
                                 0, 0);
 
964
 
 
965
    /* Add should only work the first time */
 
966
    int ii;
 
967
    for (ii = 0; ii < 10; ++ii) {
 
968
        safe_send(send.bytes, len, false);
 
969
        if (ii == 0) {
 
970
            if (cmd == PROTOCOL_BINARY_CMD_ADD) {
 
971
                safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
972
                validate_response_header(&receive.response, cmd,
 
973
                                         PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
974
            }
 
975
        } else {
 
976
            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
977
            validate_response_header(&receive.response, cmd,
 
978
                                     PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
 
979
        }
 
980
    }
 
981
 
 
982
    return TEST_PASS;
 
983
}
 
984
 
 
985
static enum test_return test_binary_add(void) {
 
986
    return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
 
987
}
 
988
 
 
989
static enum test_return test_binary_addq(void) {
 
990
    return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
 
991
}
 
992
 
 
993
static enum test_return test_binary_replace_impl(const char* key, uint8_t cmd) {
 
994
    uint64_t value = 0xdeadbeefdeadcafe;
 
995
    union {
 
996
        protocol_binary_request_no_extras request;
 
997
        protocol_binary_response_no_extras response;
 
998
        char bytes[1024];
 
999
    } send, receive;
 
1000
    size_t len = storage_command(send.bytes, sizeof(send.bytes), cmd,
 
1001
                                 key, strlen(key), &value, sizeof(value),
 
1002
                                 0, 0);
 
1003
    safe_send(send.bytes, len, false);
 
1004
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1005
    validate_response_header(&receive.response, cmd,
 
1006
                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
 
1007
    len = storage_command(send.bytes, sizeof(send.bytes),
 
1008
                          PROTOCOL_BINARY_CMD_ADD,
 
1009
                          key, strlen(key), &value, sizeof(value), 0, 0);
 
1010
    safe_send(send.bytes, len, false);
 
1011
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1012
    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
 
1013
                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1014
 
 
1015
    len = storage_command(send.bytes, sizeof(send.bytes), cmd,
 
1016
                          key, strlen(key), &value, sizeof(value), 0, 0);
 
1017
    int ii;
 
1018
    for (ii = 0; ii < 10; ++ii) {
 
1019
        safe_send(send.bytes, len, false);
 
1020
        if (cmd == PROTOCOL_BINARY_CMD_REPLACE) {
 
1021
            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1022
            validate_response_header(&receive.response,
 
1023
                                     PROTOCOL_BINARY_CMD_REPLACE,
 
1024
                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1025
        }
 
1026
    }
 
1027
 
 
1028
    if (cmd == PROTOCOL_BINARY_CMD_REPLACEQ) {
 
1029
        test_binary_noop();
 
1030
    }
 
1031
 
 
1032
    return TEST_PASS;
 
1033
}
 
1034
 
 
1035
static enum test_return test_binary_replace(void) {
 
1036
    return test_binary_replace_impl("test_binary_replace",
 
1037
                                    PROTOCOL_BINARY_CMD_REPLACE);
 
1038
}
 
1039
 
 
1040
static enum test_return test_binary_replaceq(void) {
 
1041
    return test_binary_replace_impl("test_binary_replaceq",
 
1042
                                    PROTOCOL_BINARY_CMD_REPLACEQ);
 
1043
}
 
1044
 
 
1045
static enum test_return test_binary_delete_impl(const char *key, uint8_t cmd) {
 
1046
    union {
 
1047
        protocol_binary_request_no_extras request;
 
1048
        protocol_binary_response_no_extras response;
 
1049
        char bytes[1024];
 
1050
    } send, receive;
 
1051
    size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
 
1052
                             key, strlen(key), NULL, 0);
 
1053
 
 
1054
    safe_send(send.bytes, len, false);
 
1055
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1056
    validate_response_header(&receive.response, cmd,
 
1057
                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
 
1058
    len = storage_command(send.bytes, sizeof(send.bytes),
 
1059
                          PROTOCOL_BINARY_CMD_ADD,
 
1060
                          key, strlen(key), NULL, 0, 0, 0);
 
1061
    safe_send(send.bytes, len, false);
 
1062
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1063
    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
 
1064
                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1065
 
 
1066
    len = raw_command(send.bytes, sizeof(send.bytes),
 
1067
                      cmd, key, strlen(key), NULL, 0);
 
1068
    safe_send(send.bytes, len, false);
 
1069
 
 
1070
    if (cmd == PROTOCOL_BINARY_CMD_DELETE) {
 
1071
        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1072
        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_DELETE,
 
1073
                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1074
    }
 
1075
 
 
1076
    safe_send(send.bytes, len, false);
 
1077
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1078
    validate_response_header(&receive.response, cmd,
 
1079
                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
 
1080
 
 
1081
    return TEST_PASS;
 
1082
}
 
1083
 
 
1084
static enum test_return test_binary_delete(void) {
 
1085
    return test_binary_delete_impl("test_binary_delete",
 
1086
                                   PROTOCOL_BINARY_CMD_DELETE);
 
1087
}
 
1088
 
 
1089
static enum test_return test_binary_deleteq(void) {
 
1090
    return test_binary_delete_impl("test_binary_deleteq",
 
1091
                                   PROTOCOL_BINARY_CMD_DELETEQ);
 
1092
}
 
1093
 
 
1094
static enum test_return test_binary_get_impl(const char *key, uint8_t cmd) {
 
1095
    union {
 
1096
        protocol_binary_request_no_extras request;
 
1097
        protocol_binary_response_no_extras response;
 
1098
        char bytes[1024];
 
1099
    } send, receive;
 
1100
    size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
 
1101
                             key, strlen(key), NULL, 0);
 
1102
 
 
1103
    safe_send(send.bytes, len, false);
 
1104
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1105
    validate_response_header(&receive.response, cmd,
 
1106
                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
 
1107
 
 
1108
    len = storage_command(send.bytes, sizeof(send.bytes),
 
1109
                          PROTOCOL_BINARY_CMD_ADD,
 
1110
                          key, strlen(key), NULL, 0,
 
1111
                          0, 0);
 
1112
    safe_send(send.bytes, len, false);
 
1113
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1114
    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
 
1115
                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1116
 
 
1117
    /* run a little pipeline test ;-) */
 
1118
    len = 0;
 
1119
    int ii;
 
1120
    for (ii = 0; ii < 10; ++ii) {
 
1121
        union {
 
1122
            protocol_binary_request_no_extras request;
 
1123
            char bytes[1024];
 
1124
        } temp;
 
1125
        size_t l = raw_command(temp.bytes, sizeof(temp.bytes),
 
1126
                               cmd, key, strlen(key), NULL, 0);
 
1127
        memcpy(send.bytes + len, temp.bytes, l);
 
1128
        len += l;
 
1129
    }
 
1130
 
 
1131
    safe_send(send.bytes, len, false);
 
1132
    for (ii = 0; ii < 10; ++ii) {
 
1133
        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1134
        validate_response_header(&receive.response, cmd,
 
1135
                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1136
    }
 
1137
 
 
1138
    return TEST_PASS;
 
1139
}
 
1140
 
 
1141
static enum test_return test_binary_get(void) {
 
1142
    return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
 
1143
}
 
1144
 
 
1145
static enum test_return test_binary_getk(void) {
 
1146
    return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
 
1147
}
 
1148
 
 
1149
static enum test_return test_binary_getq_impl(const char *key, uint8_t cmd) {
 
1150
    const char *missing = "test_binary_getq_missing";
 
1151
    union {
 
1152
        protocol_binary_request_no_extras request;
 
1153
        protocol_binary_response_no_extras response;
 
1154
        char bytes[1024];
 
1155
    } send, temp, receive;
 
1156
    size_t len = storage_command(send.bytes, sizeof(send.bytes),
 
1157
                                 PROTOCOL_BINARY_CMD_ADD,
 
1158
                                 key, strlen(key), NULL, 0,
 
1159
                                 0, 0);
 
1160
    size_t len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
 
1161
                             missing, strlen(missing), NULL, 0);
 
1162
    /* I need to change the first opaque so that I can separate the two
 
1163
     * return packets */
 
1164
    temp.request.message.header.request.opaque = 0xfeedface;
 
1165
    memcpy(send.bytes + len, temp.bytes, len2);
 
1166
    len += len2;
 
1167
 
 
1168
    len2 = raw_command(temp.bytes, sizeof(temp.bytes), cmd,
 
1169
                       key, strlen(key), NULL, 0);
 
1170
    memcpy(send.bytes + len, temp.bytes, len2);
 
1171
    len += len2;
 
1172
 
 
1173
    safe_send(send.bytes, len, false);
 
1174
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1175
    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
 
1176
                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1177
    /* The first GETQ shouldn't return anything */
 
1178
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1179
    validate_response_header(&receive.response, cmd,
 
1180
                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1181
 
 
1182
    return TEST_PASS;
 
1183
}
 
1184
 
 
1185
static enum test_return test_binary_getq(void) {
 
1186
    return test_binary_getq_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
 
1187
}
 
1188
 
 
1189
static enum test_return test_binary_getkq(void) {
 
1190
    return test_binary_getq_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
 
1191
}
 
1192
 
 
1193
static enum test_return test_binary_incr_impl(const char* key, uint8_t cmd) {
 
1194
    union {
 
1195
        protocol_binary_request_no_extras request;
 
1196
        protocol_binary_response_no_extras response_header;
 
1197
        protocol_binary_response_incr response;
 
1198
        char bytes[1024];
 
1199
    } send, receive;
 
1200
    size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
 
1201
                                    key, strlen(key), 1, 0, 0);
 
1202
 
 
1203
    int ii;
 
1204
    for (ii = 0; ii < 10; ++ii) {
 
1205
        safe_send(send.bytes, len, false);
 
1206
        if (cmd == PROTOCOL_BINARY_CMD_INCREMENT) {
 
1207
            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1208
            validate_response_header(&receive.response_header, cmd,
 
1209
                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1210
            assert(ntohll(receive.response.message.body.value) == ii);
 
1211
        }
 
1212
    }
 
1213
 
 
1214
    if (cmd == PROTOCOL_BINARY_CMD_INCREMENTQ) {
 
1215
        test_binary_noop();
 
1216
    }
 
1217
    return TEST_PASS;
 
1218
}
 
1219
 
 
1220
static enum test_return test_binary_incr(void) {
 
1221
    return test_binary_incr_impl("test_binary_incr",
 
1222
                                 PROTOCOL_BINARY_CMD_INCREMENT);
 
1223
}
 
1224
 
 
1225
static enum test_return test_binary_incrq(void) {
 
1226
    return test_binary_incr_impl("test_binary_incrq",
 
1227
                                 PROTOCOL_BINARY_CMD_INCREMENTQ);
 
1228
}
 
1229
 
 
1230
static enum test_return test_binary_decr_impl(const char* key, uint8_t cmd) {
 
1231
    union {
 
1232
        protocol_binary_request_no_extras request;
 
1233
        protocol_binary_response_no_extras response_header;
 
1234
        protocol_binary_response_decr response;
 
1235
        char bytes[1024];
 
1236
    } send, receive;
 
1237
    size_t len = arithmetic_command(send.bytes, sizeof(send.bytes), cmd,
 
1238
                                    key, strlen(key), 1, 9, 0);
 
1239
 
 
1240
    int ii;
 
1241
    for (ii = 9; ii >= 0; --ii) {
 
1242
        safe_send(send.bytes, len, false);
 
1243
        if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
 
1244
            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1245
            validate_response_header(&receive.response_header, cmd,
 
1246
                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1247
            assert(ntohll(receive.response.message.body.value) == ii);
 
1248
        }
 
1249
    }
 
1250
 
 
1251
    /* decr on 0 should not wrap */
 
1252
    safe_send(send.bytes, len, false);
 
1253
    if (cmd == PROTOCOL_BINARY_CMD_DECREMENT) {
 
1254
        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1255
        validate_response_header(&receive.response_header, cmd,
 
1256
                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1257
        assert(ntohll(receive.response.message.body.value) == 0);
 
1258
    } else {
 
1259
        test_binary_noop();
 
1260
    }
 
1261
 
 
1262
    return TEST_PASS;
 
1263
}
 
1264
 
 
1265
static enum test_return test_binary_decr(void) {
 
1266
    return test_binary_decr_impl("test_binary_decr",
 
1267
                                 PROTOCOL_BINARY_CMD_DECREMENT);
 
1268
}
 
1269
 
 
1270
static enum test_return test_binary_decrq(void) {
 
1271
    return test_binary_decr_impl("test_binary_decrq",
 
1272
                                 PROTOCOL_BINARY_CMD_DECREMENTQ);
 
1273
}
 
1274
 
 
1275
static enum test_return test_binary_version(void) {
 
1276
    union {
 
1277
        protocol_binary_request_no_extras request;
 
1278
        protocol_binary_response_no_extras response;
 
1279
        char bytes[1024];
 
1280
    } buffer;
 
1281
 
 
1282
    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
 
1283
                             PROTOCOL_BINARY_CMD_VERSION,
 
1284
                             NULL, 0, NULL, 0);
 
1285
 
 
1286
    safe_send(buffer.bytes, len, false);
 
1287
    safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
 
1288
    validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_VERSION,
 
1289
                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1290
 
 
1291
    return TEST_PASS;
 
1292
}
 
1293
 
 
1294
static enum test_return test_binary_flush_impl(const char *key, uint8_t cmd) {
 
1295
    union {
 
1296
        protocol_binary_request_no_extras request;
 
1297
        protocol_binary_response_no_extras response;
 
1298
        char bytes[1024];
 
1299
    } send, receive;
 
1300
 
 
1301
    size_t len = storage_command(send.bytes, sizeof(send.bytes),
 
1302
                                 PROTOCOL_BINARY_CMD_ADD,
 
1303
                                 key, strlen(key), NULL, 0, 0, 0);
 
1304
    safe_send(send.bytes, len, false);
 
1305
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1306
    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
 
1307
                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1308
 
 
1309
    len = flush_command(send.bytes, sizeof(send.bytes), cmd, 2, true);
 
1310
    safe_send(send.bytes, len, false);
 
1311
    if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
 
1312
        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1313
        validate_response_header(&receive.response, cmd,
 
1314
                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1315
    }
 
1316
 
 
1317
    len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GET,
 
1318
                      key, strlen(key), NULL, 0);
 
1319
    safe_send(send.bytes, len, false);
 
1320
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1321
    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
 
1322
                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1323
 
 
1324
    sleep(2);
 
1325
    safe_send(send.bytes, len, false);
 
1326
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1327
    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
 
1328
                             PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
 
1329
 
 
1330
    int ii;
 
1331
    for (ii = 0; ii < 2; ++ii) {
 
1332
        len = storage_command(send.bytes, sizeof(send.bytes),
 
1333
                              PROTOCOL_BINARY_CMD_ADD,
 
1334
                              key, strlen(key), NULL, 0, 0, 0);
 
1335
        safe_send(send.bytes, len, false);
 
1336
        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1337
        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
 
1338
                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1339
 
 
1340
        len = flush_command(send.bytes, sizeof(send.bytes), cmd, 0, ii == 0);
 
1341
        safe_send(send.bytes, len, false);
 
1342
        if (cmd == PROTOCOL_BINARY_CMD_FLUSH) {
 
1343
            safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1344
            validate_response_header(&receive.response, cmd,
 
1345
                                     PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1346
        }
 
1347
 
 
1348
        len = raw_command(send.bytes, sizeof(send.bytes),
 
1349
                          PROTOCOL_BINARY_CMD_GET,
 
1350
                          key, strlen(key), NULL, 0);
 
1351
        safe_send(send.bytes, len, false);
 
1352
        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1353
        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GET,
 
1354
                                 PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
 
1355
    }
 
1356
 
 
1357
    return TEST_PASS;
 
1358
}
 
1359
 
 
1360
static enum test_return test_binary_flush(void) {
 
1361
    return test_binary_flush_impl("test_binary_flush",
 
1362
                                  PROTOCOL_BINARY_CMD_FLUSH);
 
1363
}
 
1364
 
 
1365
static enum test_return test_binary_flushq(void) {
 
1366
    return test_binary_flush_impl("test_binary_flushq",
 
1367
                                  PROTOCOL_BINARY_CMD_FLUSHQ);
 
1368
}
 
1369
 
 
1370
static enum test_return test_binary_concat_impl(const char *key, uint8_t cmd) {
 
1371
    union {
 
1372
        protocol_binary_request_no_extras request;
 
1373
        protocol_binary_response_no_extras response;
 
1374
        char bytes[1024];
 
1375
    } send, receive;
 
1376
    const char *value = "world";
 
1377
 
 
1378
    size_t len = raw_command(send.bytes, sizeof(send.bytes), cmd,
 
1379
                              key, strlen(key), value, strlen(value));
 
1380
 
 
1381
 
 
1382
    safe_send(send.bytes, len, false);
 
1383
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1384
    validate_response_header(&receive.response, cmd,
 
1385
                             PROTOCOL_BINARY_RESPONSE_NOT_STORED);
 
1386
 
 
1387
    len = storage_command(send.bytes, sizeof(send.bytes),
 
1388
                          PROTOCOL_BINARY_CMD_ADD,
 
1389
                          key, strlen(key), value, strlen(value), 0, 0);
 
1390
    safe_send(send.bytes, len, false);
 
1391
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1392
    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_ADD,
 
1393
                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1394
 
 
1395
    len = raw_command(send.bytes, sizeof(send.bytes), cmd,
 
1396
                      key, strlen(key), value, strlen(value));
 
1397
    safe_send(send.bytes, len, false);
 
1398
 
 
1399
    if (cmd == PROTOCOL_BINARY_CMD_APPEND || cmd == PROTOCOL_BINARY_CMD_PREPEND) {
 
1400
        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1401
        validate_response_header(&receive.response, cmd,
 
1402
                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1403
    } else {
 
1404
        len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_NOOP,
 
1405
                          NULL, 0, NULL, 0);
 
1406
        safe_send(send.bytes, len, false);
 
1407
        safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1408
        validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_NOOP,
 
1409
                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1410
    }
 
1411
 
 
1412
    len = raw_command(send.bytes, sizeof(send.bytes), PROTOCOL_BINARY_CMD_GETK,
 
1413
                      key, strlen(key), NULL, 0);
 
1414
 
 
1415
    safe_send(send.bytes, len, false);
 
1416
    safe_recv_packet(receive.bytes, sizeof(receive.bytes));
 
1417
    validate_response_header(&receive.response, PROTOCOL_BINARY_CMD_GETK,
 
1418
                             PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1419
 
 
1420
    assert(receive.response.message.header.response.keylen == strlen(key));
 
1421
    assert(receive.response.message.header.response.bodylen == (strlen(key) + 2*strlen(value) + 4));
 
1422
 
 
1423
    char *ptr = receive.bytes;
 
1424
    ptr += sizeof(receive.response);
 
1425
    ptr += 4;
 
1426
 
 
1427
    assert(memcmp(ptr, key, strlen(key)) == 0);
 
1428
    ptr += strlen(key);
 
1429
    assert(memcmp(ptr, value, strlen(value)) == 0);
 
1430
    ptr += strlen(value);
 
1431
    assert(memcmp(ptr, value, strlen(value)) == 0);
 
1432
 
 
1433
    return TEST_PASS;
 
1434
}
 
1435
 
 
1436
static enum test_return test_binary_append(void) {
 
1437
    return test_binary_concat_impl("test_binary_append",
 
1438
                                   PROTOCOL_BINARY_CMD_APPEND);
 
1439
}
 
1440
 
 
1441
static enum test_return test_binary_prepend(void) {
 
1442
    return test_binary_concat_impl("test_binary_prepend",
 
1443
                                   PROTOCOL_BINARY_CMD_PREPEND);
 
1444
}
 
1445
 
 
1446
static enum test_return test_binary_appendq(void) {
 
1447
    return test_binary_concat_impl("test_binary_appendq",
 
1448
                                   PROTOCOL_BINARY_CMD_APPENDQ);
 
1449
}
 
1450
 
 
1451
static enum test_return test_binary_prependq(void) {
 
1452
    return test_binary_concat_impl("test_binary_prependq",
 
1453
                                   PROTOCOL_BINARY_CMD_PREPENDQ);
 
1454
}
 
1455
 
 
1456
static enum test_return test_binary_stat(void) {
 
1457
    union {
 
1458
        protocol_binary_request_no_extras request;
 
1459
        protocol_binary_response_no_extras response;
 
1460
        char bytes[1024];
 
1461
    } buffer;
 
1462
 
 
1463
    size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
 
1464
                             PROTOCOL_BINARY_CMD_STAT,
 
1465
                             NULL, 0, NULL, 0);
 
1466
 
 
1467
    safe_send(buffer.bytes, len, false);
 
1468
    do {
 
1469
        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
 
1470
        validate_response_header(&buffer.response, PROTOCOL_BINARY_CMD_STAT,
 
1471
                                 PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
1472
    } while (buffer.response.message.header.response.keylen != 0);
 
1473
 
 
1474
    return TEST_PASS;
 
1475
}
 
1476
 
 
1477
static enum test_return test_binary_illegal(void) {
 
1478
    uint8_t cmd = 0x1b;
 
1479
    while (cmd != 0x00) {
 
1480
        union {
 
1481
            protocol_binary_request_no_extras request;
 
1482
            protocol_binary_response_no_extras response;
 
1483
            char bytes[1024];
 
1484
        } buffer;
 
1485
        size_t len = raw_command(buffer.bytes, sizeof(buffer.bytes),
 
1486
                                 cmd, NULL, 0, NULL, 0);
 
1487
        safe_send(buffer.bytes, len, false);
 
1488
        safe_recv_packet(buffer.bytes, sizeof(buffer.bytes));
 
1489
        validate_response_header(&buffer.response, cmd,
 
1490
                                 PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND);
 
1491
        ++cmd;
 
1492
    }
 
1493
 
 
1494
    return TEST_PASS;
 
1495
}
 
1496
 
 
1497
volatile bool hickup_thread_running;
 
1498
 
 
1499
static void *binary_hickup_recv_verification_thread(void *arg) {
 
1500
    protocol_binary_response_no_extras *response = malloc(65*1024);
 
1501
    if (response != NULL) {
 
1502
        while (safe_recv_packet(response, 65*1024)) {
 
1503
            /* Just validate the packet format */
 
1504
            validate_response_header(response,
 
1505
                                     response->message.header.response.opcode,
 
1506
                                     response->message.header.response.status);
 
1507
        }
 
1508
        free(response);
 
1509
    }
 
1510
    hickup_thread_running = false;
 
1511
    allow_closed_read = false;
 
1512
    return NULL;
 
1513
}
 
1514
 
 
1515
static enum test_return test_binary_pipeline_hickup_chunk(void *buffer, size_t buffersize) {
 
1516
    off_t offset = 0;
 
1517
    char *key[256];
 
1518
    uint64_t value = 0xfeedfacedeadbeef;
 
1519
 
 
1520
    while (hickup_thread_running &&
 
1521
           offset + sizeof(protocol_binary_request_no_extras) < buffersize) {
 
1522
        union {
 
1523
            protocol_binary_request_no_extras request;
 
1524
            char bytes[65 * 1024];
 
1525
        } command;
 
1526
        uint8_t cmd = (uint8_t)(rand() & 0xff);
 
1527
        size_t len;
 
1528
        size_t keylen = (rand() % 250) + 1;
 
1529
 
 
1530
        switch (cmd) {
 
1531
        case PROTOCOL_BINARY_CMD_ADD:
 
1532
        case PROTOCOL_BINARY_CMD_ADDQ:
 
1533
        case PROTOCOL_BINARY_CMD_REPLACE:
 
1534
        case PROTOCOL_BINARY_CMD_REPLACEQ:
 
1535
        case PROTOCOL_BINARY_CMD_SET:
 
1536
        case PROTOCOL_BINARY_CMD_SETQ:
 
1537
            len = storage_command(command.bytes, sizeof(command.bytes), cmd,
 
1538
                                  key, keylen , &value, sizeof(value),
 
1539
                                  0, 0);
 
1540
            break;
 
1541
        case PROTOCOL_BINARY_CMD_APPEND:
 
1542
        case PROTOCOL_BINARY_CMD_APPENDQ:
 
1543
        case PROTOCOL_BINARY_CMD_PREPEND:
 
1544
        case PROTOCOL_BINARY_CMD_PREPENDQ:
 
1545
            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
 
1546
                              key, keylen, &value, sizeof(value));
 
1547
            break;
 
1548
        case PROTOCOL_BINARY_CMD_FLUSH:
 
1549
        case PROTOCOL_BINARY_CMD_FLUSHQ:
 
1550
            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
 
1551
                              NULL, 0, NULL, 0);
 
1552
            break;
 
1553
        case PROTOCOL_BINARY_CMD_NOOP:
 
1554
            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
 
1555
                              NULL, 0, NULL, 0);
 
1556
            break;
 
1557
        case PROTOCOL_BINARY_CMD_DELETE:
 
1558
        case PROTOCOL_BINARY_CMD_DELETEQ:
 
1559
            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
 
1560
                             key, keylen, NULL, 0);
 
1561
            break;
 
1562
        case PROTOCOL_BINARY_CMD_DECREMENT:
 
1563
        case PROTOCOL_BINARY_CMD_DECREMENTQ:
 
1564
        case PROTOCOL_BINARY_CMD_INCREMENT:
 
1565
        case PROTOCOL_BINARY_CMD_INCREMENTQ:
 
1566
            len = arithmetic_command(command.bytes, sizeof(command.bytes), cmd,
 
1567
                                     key, keylen, 1, 0, 0);
 
1568
            break;
 
1569
        case PROTOCOL_BINARY_CMD_VERSION:
 
1570
            len = raw_command(command.bytes, sizeof(command.bytes),
 
1571
                             PROTOCOL_BINARY_CMD_VERSION,
 
1572
                             NULL, 0, NULL, 0);
 
1573
            break;
 
1574
        case PROTOCOL_BINARY_CMD_GET:
 
1575
        case PROTOCOL_BINARY_CMD_GETK:
 
1576
        case PROTOCOL_BINARY_CMD_GETKQ:
 
1577
        case PROTOCOL_BINARY_CMD_GETQ:
 
1578
            len = raw_command(command.bytes, sizeof(command.bytes), cmd,
 
1579
                             key, keylen, NULL, 0);
 
1580
            break;
 
1581
 
 
1582
        case PROTOCOL_BINARY_CMD_STAT:
 
1583
            len = raw_command(command.bytes, sizeof(command.bytes),
 
1584
                              PROTOCOL_BINARY_CMD_STAT,
 
1585
                              NULL, 0, NULL, 0);
 
1586
            break;
 
1587
 
 
1588
        case PROTOCOL_BINARY_CMD_QUITQ:
 
1589
        case PROTOCOL_BINARY_CMD_QUIT:
 
1590
            /* I don't want to pass on the quit commands ;-) */
 
1591
            cmd |= 0xf0;
 
1592
            /* FALLTHROUGH */
 
1593
        default:
 
1594
            len = raw_command(command.bytes, sizeof(command.bytes),
 
1595
                              cmd, NULL, 0, NULL, 0);
 
1596
        }
 
1597
 
 
1598
        if ((len + offset) < buffersize) {
 
1599
            memcpy(((char*)buffer) + offset, command.bytes, len);
 
1600
            offset += len;
 
1601
        } else {
 
1602
            break;
 
1603
        }
 
1604
    }
 
1605
    safe_send(buffer, offset, true);
 
1606
 
 
1607
    return TEST_PASS;
 
1608
}
 
1609
 
 
1610
static enum test_return test_binary_pipeline_hickup(void)
 
1611
{
 
1612
    size_t buffersize = 65 * 1024;
 
1613
    void *buffer = malloc(buffersize);
 
1614
    int ii;
 
1615
 
 
1616
    pthread_t tid;
 
1617
    int ret;
 
1618
    allow_closed_read = true;
 
1619
    hickup_thread_running = true;
 
1620
    if ((ret = pthread_create(&tid, NULL,
 
1621
                              binary_hickup_recv_verification_thread, NULL)) != 0) {
 
1622
        fprintf(stderr, "Can't create thread: %s\n", strerror(ret));
 
1623
        return TEST_FAIL;
 
1624
    }
 
1625
 
 
1626
    /* Allow the thread to start */
 
1627
    usleep(250);
 
1628
 
 
1629
    srand((int)time(NULL));
 
1630
    for (ii = 0; ii < 2; ++ii) {
 
1631
        test_binary_pipeline_hickup_chunk(buffer, buffersize);
 
1632
    }
 
1633
 
 
1634
    /* send quitq to shut down the read thread ;-) */
 
1635
    size_t len = raw_command(buffer, buffersize, PROTOCOL_BINARY_CMD_QUITQ,
 
1636
                             NULL, 0, NULL, 0);
 
1637
    safe_send(buffer, len, false);
 
1638
 
 
1639
    pthread_join(tid, NULL);
 
1640
    free(buffer);
 
1641
    return TEST_PASS;
 
1642
}
 
1643
 
 
1644
typedef enum test_return (*TEST_FUNC)(void);
 
1645
struct testcase {
 
1646
    const char *description;
 
1647
    TEST_FUNC function;
 
1648
};
 
1649
 
 
1650
struct testcase testcases[] = {
 
1651
    { "cache_create", cache_create_test },
 
1652
    { "cache_constructor", cache_constructor_test },
 
1653
    { "cache_constructor_fail", cache_fail_constructor_test },
 
1654
    { "cache_destructor", cache_destructor_test },
 
1655
    { "cache_reuse", cache_reuse_test },
 
1656
    { "cache_redzone", cache_redzone_test },
 
1657
    { "strtol", test_safe_strtol },
 
1658
    { "strtoll", test_safe_strtoll },
 
1659
    { "strtoul", test_safe_strtoul },
 
1660
    { "strtoull", test_safe_strtoull },
 
1661
    { "issue_44", test_issue_44 },
 
1662
    { "vperror", test_vperror },
 
1663
    /* The following tests all run towards the same server */
 
1664
    { "start_server", start_memcached_server },
 
1665
    { "issue_92", test_issue_92 },
 
1666
    { "binary_noop", test_binary_noop },
 
1667
    { "binary_quit", test_binary_quit },
 
1668
    { "binary_quitq", test_binary_quitq },
 
1669
    { "binary_set", test_binary_set },
 
1670
    { "binary_setq", test_binary_setq },
 
1671
    { "binary_add", test_binary_add },
 
1672
    { "binary_addq", test_binary_addq },
 
1673
    { "binary_replace", test_binary_replace },
 
1674
    { "binary_replaceq", test_binary_replaceq },
 
1675
    { "binary_delete", test_binary_delete },
 
1676
    { "binary_deleteq", test_binary_deleteq },
 
1677
    { "binary_get", test_binary_get },
 
1678
    { "binary_getq", test_binary_getq },
 
1679
    { "binary_getk", test_binary_getk },
 
1680
    { "binary_getkq", test_binary_getkq },
 
1681
    { "binary_incr", test_binary_incr },
 
1682
    { "binary_incrq", test_binary_incrq },
 
1683
    { "binary_decr", test_binary_decr },
 
1684
    { "binary_decrq", test_binary_decrq },
 
1685
    { "binary_version", test_binary_version },
 
1686
    { "binary_flush", test_binary_flush },
 
1687
    { "binary_flushq", test_binary_flushq },
 
1688
    { "binary_append", test_binary_append },
 
1689
    { "binary_appendq", test_binary_appendq },
 
1690
    { "binary_prepend", test_binary_prepend },
 
1691
    { "binary_prependq", test_binary_prependq },
 
1692
    { "binary_stat", test_binary_stat },
 
1693
    { "binary_illegal", test_binary_illegal },
 
1694
    { "binary_pipeline_hickup", test_binary_pipeline_hickup },
 
1695
    { "stop_server", stop_memcached_server },
 
1696
    { NULL, NULL }
 
1697
};
 
1698
 
 
1699
int main(int argc, char **argv)
 
1700
{
 
1701
    int exitcode = 0;
 
1702
    int ii = 0, num_cases = 0;
 
1703
 
 
1704
    for (num_cases = 0; testcases[num_cases].description; num_cases++) {
 
1705
        /* Just counting */
 
1706
    }
 
1707
 
 
1708
    printf("1..%d\n", num_cases);
 
1709
 
 
1710
    for (ii = 0; testcases[ii].description != NULL; ++ii) {
 
1711
        fflush(stdout);
 
1712
#ifndef DEBUG
 
1713
        /* the test program shouldn't run longer than 10 minutes... */
 
1714
        alarm(600);
 
1715
#endif
 
1716
        enum test_return ret = testcases[ii].function();
 
1717
        if (ret == TEST_SKIP) {
 
1718
            fprintf(stdout, "ok # SKIP %d - %s\n", ii + 1, testcases[ii].description);
 
1719
        } else if (ret == TEST_PASS) {
 
1720
            fprintf(stdout, "ok %d - %s\n", ii + 1, testcases[ii].description);
 
1721
        } else {
 
1722
            fprintf(stdout, "not ok %d - %s\n", ii + 1, testcases[ii].description);
 
1723
            exitcode = 1;
 
1724
        }
 
1725
        fflush(stdout);
 
1726
    }
 
1727
 
 
1728
    return exitcode;
 
1729
}