|
| 1 | +/* Copyright (c) ImapTest authors, see the included COPYING file */ |
| 2 | + |
| 3 | +#include "lib.h" |
| 4 | +#include "ioloop.h" |
| 5 | +#include "array.h" |
| 6 | +#include "settings.h" |
| 7 | +#include "client.h" |
| 8 | +#include "imap-client.h" |
| 9 | +#include "user.h" |
| 10 | +#include "mailbox.h" |
| 11 | +#include "mailbox-source.h" |
| 12 | +#include "test-common.h" |
| 13 | + |
| 14 | +struct settings conf; |
| 15 | +bool profile_running = FALSE; |
| 16 | + |
| 17 | +/* Mock net_connect_ip to return a real (but unconnected) socket. |
| 18 | + This allows using real i_stream_create_fd() etc. without real network. |
| 19 | + Since we link against libdovecot, we can provide our own version of this |
| 20 | + function to override the one in the library for this test. */ |
| 21 | +int net_connect_ip(const struct ip_addr *ip, in_port_t port, const struct ip_addr *my_ip) |
| 22 | +{ |
| 23 | + return socket(AF_INET, SOCK_STREAM, 0); |
| 24 | +} |
| 25 | + |
| 26 | +/* These are needed by imap-client.c and other files but are defined in imaptest.c */ |
| 27 | +bool imaptest_has_clients(void) { return FALSE; } |
| 28 | +void sig_die(int signo ATTR_UNUSED, void *context ATTR_UNUSED) { exit(1); } |
| 29 | +void error_quit(void) { exit(1); } |
| 30 | + |
| 31 | +static void test_stalled_client_reassignment(void) |
| 32 | +{ |
| 33 | + struct user *user; |
| 34 | + struct imap_client *c1, *c2, *c3; |
| 35 | + struct ioloop *ioloop; |
| 36 | + struct mailbox_source *source; |
| 37 | + |
| 38 | + test_begin("stalled client index reassignment"); |
| 39 | + |
| 40 | + ioloop = io_loop_create(); |
| 41 | + |
| 42 | + conf.clients_count = 10; |
| 43 | + conf.ips_count = 1; |
| 44 | + conf.ips = i_new(struct ip_addr, 1); |
| 45 | + conf.mailbox = "INBOX"; |
| 46 | + |
| 47 | + clients_init(); |
| 48 | + mailboxes_init(); |
| 49 | + |
| 50 | + source = mailbox_source_new_random(1024); |
| 51 | + users_init(NULL, source); |
| 52 | + user = user_get("testuser", source); |
| 53 | + |
| 54 | + /* 1. Add a client at index 0 */ |
| 55 | + if (imap_client_new(0, user, NULL, &c1) < 0) |
| 56 | + i_fatal("imap_client_new 1 failed"); |
| 57 | + |
| 58 | + test_assert(array_count(&clients) == 1); |
| 59 | + test_assert(*(struct client **)array_idx(&clients, 0) == &c1->client); |
| 60 | + |
| 61 | + /* 2. Set stalled = TRUE, then try to init another client at index 0. |
| 62 | + This simulates clients_unstalled() trying to reuse index 0. */ |
| 63 | + stalled = TRUE; |
| 64 | + /* In the fixed code, client_init should have found that index 0 is occupied, |
| 65 | + found index 1 is free, and appended index 1 to stalled_clients. */ |
| 66 | + if (imap_client_new(0, user, NULL, &c2) != -1) |
| 67 | + i_fatal("imap_client_new 2 should have stalled and returned -1"); |
| 68 | + |
| 69 | + const unsigned int *stalled_idxs; |
| 70 | + unsigned int stalled_count; |
| 71 | + stalled_idxs = array_get(&stalled_clients, &stalled_count); |
| 72 | + test_assert(stalled_count == 1); |
| 73 | + test_assert(stalled_idxs[0] == 1); |
| 74 | + |
| 75 | + /* 3. Now let's occupy index 1 as well */ |
| 76 | + stalled = FALSE; |
| 77 | + if (imap_client_new(1, user, NULL, &c3) < 0) |
| 78 | + i_fatal("imap_client_new 3 failed"); |
| 79 | + |
| 80 | + test_assert(array_count(&clients) == 2); |
| 81 | + test_assert(*(struct client **)array_idx(&clients, 1) == &c3->client); |
| 82 | + |
| 83 | + /* 4. Now try to stall index 0 again. It should find index 2. */ |
| 84 | + stalled = TRUE; |
| 85 | + if (imap_client_new(0, user, NULL, &c2) != -1) |
| 86 | + i_fatal("imap_client_new 4 should have stalled and returned -1"); |
| 87 | + |
| 88 | + stalled_idxs = array_get(&stalled_clients, &stalled_count); |
| 89 | + test_assert(stalled_count == 2); |
| 90 | + test_assert(stalled_idxs[1] == 2); |
| 91 | + |
| 92 | + client_unref(&c1->client, FALSE); |
| 93 | + client_unref(&c3->client, FALSE); |
| 94 | + |
| 95 | + users_deinit(); |
| 96 | + mailbox_source_unref(&source); |
| 97 | + mailboxes_deinit(); |
| 98 | + clients_deinit(); |
| 99 | + array_free(&clients); |
| 100 | + i_free(conf.ips); |
| 101 | + |
| 102 | + io_loop_destroy(&ioloop); |
| 103 | + |
| 104 | + test_end(); |
| 105 | +} |
| 106 | + |
| 107 | +static void test_nonstalled_client_reassignment(void) |
| 108 | +{ |
| 109 | + struct user *user; |
| 110 | + struct imap_client *c1, *c2; |
| 111 | + struct ioloop *ioloop; |
| 112 | + struct mailbox_source *source; |
| 113 | + |
| 114 | + test_begin("non-stalled client index reassignment"); |
| 115 | + |
| 116 | + ioloop = io_loop_create(); |
| 117 | + |
| 118 | + conf.clients_count = 10; |
| 119 | + conf.ips_count = 1; |
| 120 | + conf.ips = i_new(struct ip_addr, 1); |
| 121 | + conf.mailbox = "INBOX"; |
| 122 | + |
| 123 | + clients_init(); |
| 124 | + mailboxes_init(); |
| 125 | + |
| 126 | + source = mailbox_source_new_random(1024); |
| 127 | + users_init(NULL, source); |
| 128 | + user = user_get("testuser", source); |
| 129 | + |
| 130 | + /* 1. Add a client at index 0 */ |
| 131 | + if (imap_client_new(0, user, NULL, &c1) < 0) |
| 132 | + i_fatal("imap_client_new 1 failed"); |
| 133 | + |
| 134 | + test_assert(array_count(&clients) == 1); |
| 135 | + test_assert(c1->client.idx == 0); |
| 136 | + |
| 137 | + /* 2. With stalled = FALSE, request index 0 which is occupied. |
| 138 | + client_init should find index 1 free and create the client there. */ |
| 139 | + stalled = FALSE; |
| 140 | + if (imap_client_new(0, user, NULL, &c2) < 0) |
| 141 | + i_fatal("imap_client_new 2 failed"); |
| 142 | + |
| 143 | + test_assert(array_count(&clients) == 2); |
| 144 | + test_assert(c2->client.idx == 1); |
| 145 | + test_assert(*(struct client **)array_idx(&clients, 1) == &c2->client); |
| 146 | + |
| 147 | + /* 3. Verify stalled_clients array is empty - nothing was stalled */ |
| 148 | + const unsigned int *stalled_idxs; |
| 149 | + unsigned int stalled_count; |
| 150 | + stalled_idxs = array_get(&stalled_clients, &stalled_count); |
| 151 | + test_assert(stalled_count == 0); |
| 152 | + |
| 153 | + client_unref(&c1->client, FALSE); |
| 154 | + client_unref(&c2->client, FALSE); |
| 155 | + |
| 156 | + users_deinit(); |
| 157 | + mailbox_source_unref(&source); |
| 158 | + mailboxes_deinit(); |
| 159 | + clients_deinit(); |
| 160 | + array_free(&clients); |
| 161 | + i_free(conf.ips); |
| 162 | + |
| 163 | + io_loop_destroy(&ioloop); |
| 164 | + |
| 165 | + test_end(); |
| 166 | +} |
| 167 | + |
| 168 | +int main(void) |
| 169 | +{ |
| 170 | + static void (*const test_functions[])(void) = { |
| 171 | + test_stalled_client_reassignment, |
| 172 | + test_nonstalled_client_reassignment, |
| 173 | + NULL |
| 174 | + }; |
| 175 | + return test_run(test_functions); |
| 176 | +} |
0 commit comments