s4:NBT-WINSREPLICATION: test replication with names including scopes
[ira/wip.git] / source4 / torture / nbt / winsreplication.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    WINS replication testing
5
6    Copyright (C) Andrew Tridgell        2005
7    Copyright (C) Stefan Metzmacher      2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "libcli/wrepl/winsrepl.h"
25 #include "lib/events/events.h"
26 #include "lib/socket/socket.h"
27 #include "system/network.h"
28 #include "lib/socket/netif.h"
29 #include "librpc/gen_ndr/ndr_nbt.h"
30 #include "torture/torture.h"
31 #include "torture/nbt/proto.h"
32 #include "param/param.h"
33
34 #define CHECK_STATUS(tctx, status, correct) \
35         torture_assert_ntstatus_equal(tctx, status, correct, \
36                                                                   "Incorrect status")
37
38 #define CHECK_VALUE(tctx, v, correct) \
39         torture_assert(tctx, (v) == (correct), \
40                                    talloc_asprintf(tctx, "Incorrect value %s=%d - should be %d\n", \
41                        #v, v, correct))
42
43 #define CHECK_VALUE_UINT64(tctx, v, correct) \
44         torture_assert(tctx, (v) == (correct), \
45                 talloc_asprintf(tctx, "Incorrect value %s=%llu - should be %llu\n", \
46                        #v, (long long)v, (long long)correct))
47
48 #define CHECK_VALUE_STRING(tctx, v, correct) \
49         torture_assert_str_equal(tctx, v, correct, "Invalid value")
50
51 #define _NBT_NAME(n,t,s) {\
52         .name   = n,\
53         .type   = t,\
54         .scope  = s\
55 }
56
57 static const char *wrepl_name_type_string(enum wrepl_name_type type)
58 {
59         switch (type) {
60         case WREPL_TYPE_UNIQUE: return "UNIQUE";
61         case WREPL_TYPE_GROUP: return "GROUP";
62         case WREPL_TYPE_SGROUP: return "SGROUP";
63         case WREPL_TYPE_MHOMED: return "MHOMED";
64         }
65         return "UNKNOWN_TYPE";
66 }
67
68 static const char *wrepl_name_state_string(enum wrepl_name_state state)
69 {
70         switch (state) {
71         case WREPL_STATE_ACTIVE: return "ACTIVE";
72         case WREPL_STATE_RELEASED: return "RELEASED";
73         case WREPL_STATE_TOMBSTONE: return "TOMBSTONE";
74         case WREPL_STATE_RESERVED: return "RESERVED";
75         }
76         return "UNKNOWN_STATE";
77 }
78
79 /*
80   test how assoc_ctx's are only usable on the connection
81   they are created on.
82 */
83 static bool test_assoc_ctx1(struct torture_context *tctx)
84 {
85         bool ret = true;
86         struct wrepl_request *req;
87         struct wrepl_socket *wrepl_socket1;
88         struct wrepl_associate associate1;
89         struct wrepl_socket *wrepl_socket2;
90         struct wrepl_associate associate2;
91         struct wrepl_pull_table pull_table;
92         struct wrepl_packet packet;
93         struct wrepl_send_ctrl ctrl;
94         struct wrepl_packet *rep_packet;
95         struct wrepl_associate_stop assoc_stop;
96         NTSTATUS status;
97         struct nbt_name name;
98         const char *address;
99
100         if (!torture_nbt_get_name(tctx, &name, &address))
101                 return false;
102
103         torture_comment(tctx, "Test if assoc_ctx is only valid on the conection it was created on\n");
104
105         wrepl_socket1 = wrepl_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
106         wrepl_socket2 = wrepl_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
107
108         torture_comment(tctx, "Setup 2 wrepl connections\n");
109         status = wrepl_connect(wrepl_socket1, wrepl_best_ip(tctx->lp_ctx, address), address);
110         CHECK_STATUS(tctx, status, NT_STATUS_OK);
111
112         status = wrepl_connect(wrepl_socket2, wrepl_best_ip(tctx->lp_ctx, address), address);
113         CHECK_STATUS(tctx, status, NT_STATUS_OK);
114
115         torture_comment(tctx, "Send a start association request (conn1)\n");
116         status = wrepl_associate(wrepl_socket1, &associate1);
117         CHECK_STATUS(tctx, status, NT_STATUS_OK);
118
119         torture_comment(tctx, "association context (conn1): 0x%x\n", associate1.out.assoc_ctx);
120
121         torture_comment(tctx, "Send a start association request (conn2)\n");
122         status = wrepl_associate(wrepl_socket2, &associate2);
123         CHECK_STATUS(tctx, status, NT_STATUS_OK);
124
125         torture_comment(tctx, "association context (conn2): 0x%x\n", associate2.out.assoc_ctx);
126
127         torture_comment(tctx, "Send a replication table query, with assoc 1 (conn2), the anwser should be on conn1\n");
128         ZERO_STRUCT(packet);
129         packet.opcode                      = WREPL_OPCODE_BITS;
130         packet.assoc_ctx                   = associate1.out.assoc_ctx;
131         packet.mess_type                   = WREPL_REPLICATION;
132         packet.message.replication.command = WREPL_REPL_TABLE_QUERY;
133         ZERO_STRUCT(ctrl);
134         ctrl.send_only = true;
135         req = wrepl_request_send(wrepl_socket2, &packet, &ctrl);
136         status = wrepl_request_recv(req, tctx, &rep_packet);
137         CHECK_STATUS(tctx, status, NT_STATUS_OK);
138
139         torture_comment(tctx, "Send a association request (conn2), to make sure the last request was ignored\n");
140         status = wrepl_associate(wrepl_socket2, &associate2);
141         CHECK_STATUS(tctx, status, NT_STATUS_OK);
142
143         torture_comment(tctx, "Send a replication table query, with invalid assoc (conn1), receive answer from conn2\n");
144         pull_table.in.assoc_ctx = 0;
145         req = wrepl_pull_table_send(wrepl_socket1, &pull_table);
146         status = wrepl_request_recv(req, tctx, &rep_packet);
147         CHECK_STATUS(tctx, status, NT_STATUS_OK);
148
149         torture_comment(tctx, "Send a association request (conn1), to make sure the last request was handled correct\n");
150         status = wrepl_associate(wrepl_socket1, &associate2);
151         CHECK_STATUS(tctx, status, NT_STATUS_OK);
152
153         assoc_stop.in.assoc_ctx = associate1.out.assoc_ctx;
154         assoc_stop.in.reason    = 4;
155         torture_comment(tctx, "Send a association stop request (conn1), reson: %u\n", assoc_stop.in.reason);
156         status = wrepl_associate_stop(wrepl_socket1, &assoc_stop);
157         CHECK_STATUS(tctx, status, NT_STATUS_END_OF_FILE);
158
159         assoc_stop.in.assoc_ctx = associate2.out.assoc_ctx;
160         assoc_stop.in.reason    = 0;
161         torture_comment(tctx, "Send a association stop request (conn2), reson: %u\n", assoc_stop.in.reason);
162         status = wrepl_associate_stop(wrepl_socket2, &assoc_stop);
163         CHECK_STATUS(tctx, status, NT_STATUS_OK);
164
165         torture_comment(tctx, "Close 2 wrepl connections\n");
166         talloc_free(wrepl_socket1);
167         talloc_free(wrepl_socket2);
168         return ret;
169 }
170
171 /*
172   test if we always get back the same assoc_ctx
173 */
174 static bool test_assoc_ctx2(struct torture_context *tctx)
175 {
176         struct wrepl_socket *wrepl_socket;
177         struct wrepl_associate associate;
178         uint32_t assoc_ctx1;
179         struct nbt_name name;
180         NTSTATUS status;
181         const char *address;
182
183         if (!torture_nbt_get_name(tctx, &name, &address))
184                 return false;
185
186         torture_comment(tctx, "Test if we always get back the same assoc_ctx\n");
187
188         wrepl_socket = wrepl_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
189         
190         torture_comment(tctx, "Setup wrepl connections\n");
191         status = wrepl_connect(wrepl_socket, wrepl_best_ip(tctx->lp_ctx, address), address);
192         CHECK_STATUS(tctx, status, NT_STATUS_OK);
193
194         torture_comment(tctx, "Send 1st start association request\n");
195         status = wrepl_associate(wrepl_socket, &associate);
196         CHECK_STATUS(tctx, status, NT_STATUS_OK);
197         assoc_ctx1 = associate.out.assoc_ctx;
198         torture_comment(tctx, "1st association context: 0x%x\n", associate.out.assoc_ctx);
199
200         torture_comment(tctx, "Send 2nd start association request\n");
201         status = wrepl_associate(wrepl_socket, &associate);
202         torture_assert_ntstatus_ok(tctx, status, "2nd start association failed");
203         torture_assert(tctx, associate.out.assoc_ctx == assoc_ctx1, 
204                                    "Different context returned");
205         torture_comment(tctx, "2nd association context: 0x%x\n", associate.out.assoc_ctx);
206
207         torture_comment(tctx, "Send 3rd start association request\n");
208         status = wrepl_associate(wrepl_socket, &associate);
209         torture_assert(tctx, associate.out.assoc_ctx == assoc_ctx1, 
210                                    "Different context returned");
211         CHECK_STATUS(tctx, status, NT_STATUS_OK);
212         torture_comment(tctx, "3rd association context: 0x%x\n", associate.out.assoc_ctx);
213
214         torture_comment(tctx, "Close wrepl connections\n");
215         talloc_free(wrepl_socket);
216         return true;
217 }
218
219
220 /*
221   display a replication entry
222 */
223 static void display_entry(struct torture_context *tctx, struct wrepl_name *name)
224 {
225         int i;
226
227         torture_comment(tctx, "%s\n", nbt_name_string(tctx, &name->name));
228         torture_comment(tctx, "\tTYPE:%u STATE:%u NODE:%u STATIC:%u VERSION_ID: %llu\n",
229                 name->type, name->state, name->node, name->is_static, (long long)name->version_id);
230         torture_comment(tctx, "\tRAW_FLAGS: 0x%08X OWNER: %-15s\n",
231                 name->raw_flags, name->owner);
232         for (i=0;i<name->num_addresses;i++) {
233                 torture_comment(tctx, "\tADDR: %-15s OWNER: %-15s\n", 
234                         name->addresses[i].address, name->addresses[i].owner);
235         }
236 }
237
238 /*
239   test a full replication dump from a WINS server
240 */
241 static bool test_wins_replication(struct torture_context *tctx)
242 {
243         struct wrepl_socket *wrepl_socket;
244         NTSTATUS status;
245         int i, j;
246         struct wrepl_associate associate;
247         struct wrepl_pull_table pull_table;
248         struct wrepl_pull_names pull_names;
249         struct nbt_name name;
250         const char *address;
251
252         if (!torture_nbt_get_name(tctx, &name, &address))
253                 return false;
254
255         torture_comment(tctx, "Test one pull replication cycle\n");
256
257         wrepl_socket = wrepl_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
258         
259         torture_comment(tctx, "Setup wrepl connections\n");
260         status = wrepl_connect(wrepl_socket, wrepl_best_ip(tctx->lp_ctx, address), address);
261         CHECK_STATUS(tctx, status, NT_STATUS_OK);
262
263         torture_comment(tctx, "Send a start association request\n");
264
265         status = wrepl_associate(wrepl_socket, &associate);
266         CHECK_STATUS(tctx, status, NT_STATUS_OK);
267
268         torture_comment(tctx, "association context: 0x%x\n", associate.out.assoc_ctx);
269
270         torture_comment(tctx, "Send a replication table query\n");
271         pull_table.in.assoc_ctx = associate.out.assoc_ctx;
272
273         status = wrepl_pull_table(wrepl_socket, tctx, &pull_table);
274         if (NT_STATUS_EQUAL(NT_STATUS_NETWORK_ACCESS_DENIED,status)) {
275                 struct wrepl_packet packet;
276                 struct wrepl_request *req;
277
278                 ZERO_STRUCT(packet);
279                 packet.opcode                      = WREPL_OPCODE_BITS;
280                 packet.assoc_ctx                   = associate.out.assoc_ctx;
281                 packet.mess_type                   = WREPL_STOP_ASSOCIATION;
282                 packet.message.stop.reason         = 0;
283
284                 req = wrepl_request_send(wrepl_socket, &packet, NULL);
285                 talloc_free(req);
286
287                 torture_fail(tctx, "We are not a valid pull partner for the server");
288         }
289         CHECK_STATUS(tctx, status, NT_STATUS_OK);
290
291         torture_comment(tctx, "Found %d replication partners\n", pull_table.out.num_partners);
292
293         for (i=0;i<pull_table.out.num_partners;i++) {
294                 struct wrepl_wins_owner *partner = &pull_table.out.partners[i];
295                 torture_comment(tctx, "%s   max_version=%6llu   min_version=%6llu type=%d\n",
296                        partner->address, 
297                        (long long)partner->max_version, 
298                        (long long)partner->min_version, 
299                        partner->type);
300
301                 pull_names.in.assoc_ctx = associate.out.assoc_ctx;
302                 pull_names.in.partner = *partner;
303                 
304                 status = wrepl_pull_names(wrepl_socket, tctx, &pull_names);
305                 CHECK_STATUS(tctx, status, NT_STATUS_OK);
306
307                 torture_comment(tctx, "Received %d names\n", pull_names.out.num_names);
308
309                 for (j=0;j<pull_names.out.num_names;j++) {
310                         display_entry(tctx, &pull_names.out.names[j]);
311                 }
312         }
313
314         torture_comment(tctx, "Close wrepl connections\n");
315         talloc_free(wrepl_socket);
316         return true;
317 }
318
319 struct test_wrepl_conflict_conn {
320         const char *address;
321         struct wrepl_socket *pull;
322         uint32_t pull_assoc;
323
324 #define TEST_OWNER_A_ADDRESS "127.65.65.1"
325 #define TEST_ADDRESS_A_PREFIX "127.0.65"
326 #define TEST_OWNER_B_ADDRESS "127.66.66.1"
327 #define TEST_ADDRESS_B_PREFIX "127.0.66"
328 #define TEST_OWNER_X_ADDRESS "127.88.88.1"
329 #define TEST_ADDRESS_X_PREFIX "127.0.88"
330
331         struct wrepl_wins_owner a, b, c, x;
332
333         struct socket_address *myaddr;
334         struct socket_address *myaddr2;
335         struct nbt_name_socket *nbtsock;
336         struct nbt_name_socket *nbtsock2;
337
338         struct nbt_name_socket *nbtsock_srv;
339         struct nbt_name_socket *nbtsock_srv2;
340
341         uint32_t addresses_best_num;
342         struct wrepl_ip *addresses_best;
343
344         uint32_t addresses_best2_num;
345         struct wrepl_ip *addresses_best2;
346
347         uint32_t addresses_all_num;
348         struct wrepl_ip *addresses_all;
349
350         uint32_t addresses_mhomed_num;
351         struct wrepl_ip *addresses_mhomed;
352 };
353
354 static const struct wrepl_ip addresses_A_1[] = {
355         {
356         .owner  = TEST_OWNER_A_ADDRESS,
357         .ip     = TEST_ADDRESS_A_PREFIX".1"
358         }
359 };
360 static const struct wrepl_ip addresses_A_2[] = {
361         {
362         .owner  = TEST_OWNER_A_ADDRESS,
363         .ip     = TEST_ADDRESS_A_PREFIX".2"
364         }
365 };
366 static const struct wrepl_ip addresses_A_3_4[] = {
367         {
368         .owner  = TEST_OWNER_A_ADDRESS,
369         .ip     = TEST_ADDRESS_A_PREFIX".3"
370         },
371         {
372         .owner  = TEST_OWNER_A_ADDRESS,
373         .ip     = TEST_ADDRESS_A_PREFIX".4"
374         }
375 };
376 static const struct wrepl_ip addresses_A_3_4_X_3_4[] = {
377         {
378         .owner  = TEST_OWNER_A_ADDRESS,
379         .ip     = TEST_ADDRESS_A_PREFIX".3"
380         },
381         {
382         .owner  = TEST_OWNER_A_ADDRESS,
383         .ip     = TEST_ADDRESS_A_PREFIX".4"
384         },
385         {
386         .owner  = TEST_OWNER_X_ADDRESS,
387         .ip     = TEST_ADDRESS_X_PREFIX".3"
388         },
389         {
390         .owner  = TEST_OWNER_X_ADDRESS,
391         .ip     = TEST_ADDRESS_X_PREFIX".4"
392         }
393 };
394 static const struct wrepl_ip addresses_A_3_4_B_3_4[] = {
395         {
396         .owner  = TEST_OWNER_A_ADDRESS,
397         .ip     = TEST_ADDRESS_A_PREFIX".3"
398         },
399         {
400         .owner  = TEST_OWNER_A_ADDRESS,
401         .ip     = TEST_ADDRESS_A_PREFIX".4"
402         },
403         {
404         .owner  = TEST_OWNER_B_ADDRESS,
405         .ip     = TEST_ADDRESS_B_PREFIX".3"
406         },
407         {
408         .owner  = TEST_OWNER_B_ADDRESS,
409         .ip     = TEST_ADDRESS_B_PREFIX".4"
410         }
411 };
412 static const struct wrepl_ip addresses_A_3_4_OWNER_B[] = {
413         {
414         .owner  = TEST_OWNER_B_ADDRESS,
415         .ip     = TEST_ADDRESS_A_PREFIX".3"
416         },
417         {
418         .owner  = TEST_OWNER_B_ADDRESS,
419         .ip     = TEST_ADDRESS_A_PREFIX".4"
420         }
421 };
422 static const struct wrepl_ip addresses_A_3_4_X_3_4_OWNER_B[] = {
423         {
424         .owner  = TEST_OWNER_B_ADDRESS,
425         .ip     = TEST_ADDRESS_A_PREFIX".3"
426         },
427         {
428         .owner  = TEST_OWNER_B_ADDRESS,
429         .ip     = TEST_ADDRESS_A_PREFIX".4"
430         },
431         {
432         .owner  = TEST_OWNER_B_ADDRESS,
433         .ip     = TEST_ADDRESS_X_PREFIX".3"
434         },
435         {
436         .owner  = TEST_OWNER_B_ADDRESS,
437         .ip     = TEST_ADDRESS_X_PREFIX".4"
438         }
439 };
440
441 static const struct wrepl_ip addresses_A_3_4_X_1_2[] = {
442         {
443         .owner  = TEST_OWNER_A_ADDRESS,
444         .ip     = TEST_ADDRESS_A_PREFIX".3"
445         },
446         {
447         .owner  = TEST_OWNER_A_ADDRESS,
448         .ip     = TEST_ADDRESS_A_PREFIX".4"
449         },
450         {
451         .owner  = TEST_OWNER_X_ADDRESS,
452         .ip     = TEST_ADDRESS_X_PREFIX".1"
453         },
454         {
455         .owner  = TEST_OWNER_X_ADDRESS,
456         .ip     = TEST_ADDRESS_X_PREFIX".2"
457         }
458 };
459
460 static const struct wrepl_ip addresses_B_1[] = {
461         {
462         .owner  = TEST_OWNER_B_ADDRESS,
463         .ip     = TEST_ADDRESS_B_PREFIX".1"
464         }
465 };
466 static const struct wrepl_ip addresses_B_2[] = {
467         {
468         .owner  = TEST_OWNER_B_ADDRESS,
469         .ip     = TEST_ADDRESS_B_PREFIX".2"
470         }
471 };
472 static const struct wrepl_ip addresses_B_3_4[] = {
473         {
474         .owner  = TEST_OWNER_B_ADDRESS,
475         .ip     = TEST_ADDRESS_B_PREFIX".3"
476         },
477         {
478         .owner  = TEST_OWNER_B_ADDRESS,
479         .ip     = TEST_ADDRESS_B_PREFIX".4"
480         }
481 };
482 static const struct wrepl_ip addresses_B_3_4_X_3_4[] = {
483         {
484         .owner  = TEST_OWNER_B_ADDRESS,
485         .ip     = TEST_ADDRESS_B_PREFIX".3"
486         },
487         {
488         .owner  = TEST_OWNER_B_ADDRESS,
489         .ip     = TEST_ADDRESS_B_PREFIX".4"
490         },
491         {
492         .owner  = TEST_OWNER_X_ADDRESS,
493         .ip     = TEST_ADDRESS_X_PREFIX".3"
494         },
495         {
496         .owner  = TEST_OWNER_X_ADDRESS,
497         .ip     = TEST_ADDRESS_X_PREFIX".4"
498         }
499 };
500 static const struct wrepl_ip addresses_B_3_4_X_1_2[] = {
501         {
502         .owner  = TEST_OWNER_B_ADDRESS,
503         .ip     = TEST_ADDRESS_B_PREFIX".3"
504         },
505         {
506         .owner  = TEST_OWNER_B_ADDRESS,
507         .ip     = TEST_ADDRESS_B_PREFIX".4"
508         },
509         {
510         .owner  = TEST_OWNER_X_ADDRESS,
511         .ip     = TEST_ADDRESS_X_PREFIX".1"
512         },
513         {
514         .owner  = TEST_OWNER_X_ADDRESS,
515         .ip     = TEST_ADDRESS_X_PREFIX".2"
516         }
517 };
518
519 static const struct wrepl_ip addresses_X_1_2[] = {
520         {
521         .owner  = TEST_OWNER_X_ADDRESS,
522         .ip     = TEST_ADDRESS_X_PREFIX".1"
523         },
524         {
525         .owner  = TEST_OWNER_X_ADDRESS,
526         .ip     = TEST_ADDRESS_X_PREFIX".2"
527         }
528 };
529 static const struct wrepl_ip addresses_X_3_4[] = {
530         {
531         .owner  = TEST_OWNER_X_ADDRESS,
532         .ip     = TEST_ADDRESS_X_PREFIX".3"
533         },
534         {
535         .owner  = TEST_OWNER_X_ADDRESS,
536         .ip     = TEST_ADDRESS_X_PREFIX".4"
537         }
538 };
539
540 static struct test_wrepl_conflict_conn *test_create_conflict_ctx(
541                 struct torture_context *tctx, const char *address)
542 {
543         struct test_wrepl_conflict_conn *ctx;
544         struct wrepl_associate associate;
545         struct wrepl_pull_table pull_table;
546         struct socket_address *nbt_srv_addr;
547         NTSTATUS status;
548         uint32_t i;
549         struct interface *ifaces;
550
551         ctx = talloc_zero(tctx, struct test_wrepl_conflict_conn);
552         if (!ctx) return NULL;
553
554         ctx->address    = address;
555         ctx->pull       = wrepl_socket_init(ctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
556         if (!ctx->pull) return NULL;
557
558         torture_comment(tctx, "Setup wrepl conflict pull connection\n");
559         status = wrepl_connect(ctx->pull, wrepl_best_ip(tctx->lp_ctx, ctx->address), ctx->address);
560         if (!NT_STATUS_IS_OK(status)) return NULL;
561
562         status = wrepl_associate(ctx->pull, &associate);
563         if (!NT_STATUS_IS_OK(status)) return NULL;
564
565         ctx->pull_assoc = associate.out.assoc_ctx;
566
567         ctx->a.address          = TEST_OWNER_A_ADDRESS;
568         ctx->a.max_version      = 0;
569         ctx->a.min_version      = 0;
570         ctx->a.type             = 1;
571
572         ctx->b.address          = TEST_OWNER_B_ADDRESS;
573         ctx->b.max_version      = 0;
574         ctx->b.min_version      = 0;
575         ctx->b.type             = 1;
576
577         ctx->x.address          = TEST_OWNER_X_ADDRESS;
578         ctx->x.max_version      = 0;
579         ctx->x.min_version      = 0;
580         ctx->x.type             = 1;
581
582         ctx->c.address          = address;
583         ctx->c.max_version      = 0;
584         ctx->c.min_version      = 0;
585         ctx->c.type             = 1;
586
587         pull_table.in.assoc_ctx = ctx->pull_assoc;
588         status = wrepl_pull_table(ctx->pull, ctx->pull, &pull_table);
589         if (!NT_STATUS_IS_OK(status)) return NULL;
590
591         for (i=0; i < pull_table.out.num_partners; i++) {
592                 if (strcmp(TEST_OWNER_A_ADDRESS,pull_table.out.partners[i].address)==0) {
593                         ctx->a.max_version      = pull_table.out.partners[i].max_version;
594                         ctx->a.min_version      = pull_table.out.partners[i].min_version;
595                 }
596                 if (strcmp(TEST_OWNER_B_ADDRESS,pull_table.out.partners[i].address)==0) {
597                         ctx->b.max_version      = pull_table.out.partners[i].max_version;
598                         ctx->b.min_version      = pull_table.out.partners[i].min_version;
599                 }
600                 if (strcmp(TEST_OWNER_X_ADDRESS,pull_table.out.partners[i].address)==0) {
601                         ctx->x.max_version      = pull_table.out.partners[i].max_version;
602                         ctx->x.min_version      = pull_table.out.partners[i].min_version;
603                 }
604                 if (strcmp(address,pull_table.out.partners[i].address)==0) {
605                         ctx->c.max_version      = pull_table.out.partners[i].max_version;
606                         ctx->c.min_version      = pull_table.out.partners[i].min_version;
607                 }
608         }
609
610         talloc_free(pull_table.out.partners);
611
612         ctx->nbtsock = nbt_name_socket_init(ctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
613         if (!ctx->nbtsock) return NULL;
614
615         load_interfaces(tctx, lp_interfaces(tctx->lp_ctx), &ifaces);
616
617         ctx->myaddr = socket_address_from_strings(tctx, ctx->nbtsock->sock->backend_name, iface_best_ip(ifaces, address), 0);
618         if (!ctx->myaddr) return NULL;
619
620         for (i = 0; i < iface_count(ifaces); i++) {
621                 if (strcmp(ctx->myaddr->addr, iface_n_ip(ifaces, i)) == 0) continue;
622                 ctx->myaddr2 = socket_address_from_strings(tctx, ctx->nbtsock->sock->backend_name, iface_n_ip(ifaces, i), 0);
623                 if (!ctx->myaddr2) return NULL;
624                 break;
625         }
626
627         status = socket_listen(ctx->nbtsock->sock, ctx->myaddr, 0, 0);
628         if (!NT_STATUS_IS_OK(status)) return NULL;
629
630         ctx->nbtsock_srv = nbt_name_socket_init(ctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
631         if (!ctx->nbtsock_srv) return NULL;
632
633         /* Make a port 137 version of ctx->myaddr */
634         nbt_srv_addr = socket_address_from_strings(tctx, ctx->nbtsock_srv->sock->backend_name, ctx->myaddr->addr, lp_nbt_port(tctx->lp_ctx));
635         if (!nbt_srv_addr) return NULL;
636
637         /* And if possible, bind to it.  This won't work unless we are root or in sockewrapper */
638         status = socket_listen(ctx->nbtsock_srv->sock, nbt_srv_addr, 0, 0);
639         talloc_free(nbt_srv_addr);
640         if (!NT_STATUS_IS_OK(status)) {
641                 /* this isn't fatal */
642                 talloc_free(ctx->nbtsock_srv);
643                 ctx->nbtsock_srv = NULL;
644         }
645
646         if (ctx->myaddr2 && ctx->nbtsock_srv) {
647                 ctx->nbtsock2 = nbt_name_socket_init(ctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
648                 if (!ctx->nbtsock2) return NULL;
649
650                 status = socket_listen(ctx->nbtsock2->sock, ctx->myaddr2, 0, 0);
651                 if (!NT_STATUS_IS_OK(status)) return NULL;
652
653                 ctx->nbtsock_srv2 = nbt_name_socket_init(ctx, ctx->nbtsock_srv->event_ctx, lp_iconv_convenience(tctx->lp_ctx));
654                 if (!ctx->nbtsock_srv2) return NULL;
655
656                 /* Make a port 137 version of ctx->myaddr2 */
657                 nbt_srv_addr = socket_address_from_strings(tctx, 
658                                                            ctx->nbtsock_srv->sock->backend_name, 
659                                                            ctx->myaddr2->addr, 
660                                                            lp_nbt_port(tctx->lp_ctx));
661                 if (!nbt_srv_addr) return NULL;
662
663                 /* And if possible, bind to it.  This won't work unless we are root or in sockewrapper */
664                 status = socket_listen(ctx->nbtsock_srv2->sock, ctx->myaddr2, 0, 0);
665                 talloc_free(nbt_srv_addr);
666                 if (!NT_STATUS_IS_OK(status)) {
667                         /* this isn't fatal */
668                         talloc_free(ctx->nbtsock_srv2);
669                         ctx->nbtsock_srv2 = NULL;
670                 }
671         }
672
673         ctx->addresses_best_num = 1;
674         ctx->addresses_best = talloc_array(ctx, struct wrepl_ip, ctx->addresses_best_num);
675         if (!ctx->addresses_best) return NULL;
676         ctx->addresses_best[0].owner    = ctx->b.address;
677         ctx->addresses_best[0].ip       = ctx->myaddr->addr;
678
679         ctx->addresses_all_num = iface_count(ifaces);
680         ctx->addresses_all = talloc_array(ctx, struct wrepl_ip, ctx->addresses_all_num);
681         if (!ctx->addresses_all) return NULL;
682         for (i=0; i < ctx->addresses_all_num; i++) {
683                 ctx->addresses_all[i].owner     = ctx->b.address;
684                 ctx->addresses_all[i].ip        = talloc_strdup(ctx->addresses_all, iface_n_ip(ifaces, i));
685                 if (!ctx->addresses_all[i].ip) return NULL;
686         }
687
688         if (ctx->nbtsock_srv2) {
689                 ctx->addresses_best2_num = 1;
690                 ctx->addresses_best2 = talloc_array(ctx, struct wrepl_ip, ctx->addresses_best2_num);
691                 if (!ctx->addresses_best2) return NULL;
692                 ctx->addresses_best2[0].owner   = ctx->b.address;
693                 ctx->addresses_best2[0].ip      = ctx->myaddr2->addr;
694
695                 ctx->addresses_mhomed_num = 2;
696                 ctx->addresses_mhomed = talloc_array(ctx, struct wrepl_ip, ctx->addresses_mhomed_num);
697                 if (!ctx->addresses_mhomed) return NULL;
698                 ctx->addresses_mhomed[0].owner  = ctx->b.address;
699                 ctx->addresses_mhomed[0].ip     = ctx->myaddr->addr;
700                 ctx->addresses_mhomed[1].owner  = ctx->b.address;
701                 ctx->addresses_mhomed[1].ip     = ctx->myaddr2->addr;
702         }
703
704         return ctx;
705 }
706
707 static bool test_wrepl_update_one(struct torture_context *tctx, 
708                                                                   struct test_wrepl_conflict_conn *ctx,
709                                   const struct wrepl_wins_owner *owner,
710                                   const struct wrepl_wins_name *name)
711 {
712         struct wrepl_socket *wrepl_socket;
713         struct wrepl_associate associate;
714         struct wrepl_packet update_packet, repl_send;
715         struct wrepl_table *update;
716         struct wrepl_wins_owner wrepl_wins_owners[1];
717         struct wrepl_packet *repl_recv;
718         struct wrepl_wins_owner *send_request;
719         struct wrepl_send_reply *send_reply;
720         struct wrepl_wins_name wrepl_wins_names[1];
721         uint32_t assoc_ctx;
722         NTSTATUS status;
723
724         wrepl_socket = wrepl_socket_init(ctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
725
726         status = wrepl_connect(wrepl_socket, wrepl_best_ip(tctx->lp_ctx, ctx->address), ctx->address);
727         CHECK_STATUS(tctx, status, NT_STATUS_OK);
728
729         status = wrepl_associate(wrepl_socket, &associate);
730         CHECK_STATUS(tctx, status, NT_STATUS_OK);
731         assoc_ctx = associate.out.assoc_ctx;
732
733         /* now send a WREPL_REPL_UPDATE message */
734         ZERO_STRUCT(update_packet);
735         update_packet.opcode                    = WREPL_OPCODE_BITS;
736         update_packet.assoc_ctx                 = assoc_ctx;
737         update_packet.mess_type                 = WREPL_REPLICATION;
738         update_packet.message.replication.command       = WREPL_REPL_UPDATE;
739         update  = &update_packet.message.replication.info.table;
740
741         update->partner_count   = ARRAY_SIZE(wrepl_wins_owners);
742         update->partners        = wrepl_wins_owners;
743         update->initiator       = "0.0.0.0";
744
745         wrepl_wins_owners[0]    = *owner;
746
747         status = wrepl_request(wrepl_socket, wrepl_socket,
748                                &update_packet, &repl_recv);
749         CHECK_STATUS(tctx, status, NT_STATUS_OK);
750         CHECK_VALUE(tctx, repl_recv->mess_type, WREPL_REPLICATION);
751         CHECK_VALUE(tctx, repl_recv->message.replication.command, WREPL_REPL_SEND_REQUEST);
752         send_request = &repl_recv->message.replication.info.owner;
753
754         ZERO_STRUCT(repl_send);
755         repl_send.opcode                        = WREPL_OPCODE_BITS;
756         repl_send.assoc_ctx                     = assoc_ctx;
757         repl_send.mess_type                     = WREPL_REPLICATION;
758         repl_send.message.replication.command   = WREPL_REPL_SEND_REPLY;
759         send_reply = &repl_send.message.replication.info.reply;
760
761         send_reply->num_names   = ARRAY_SIZE(wrepl_wins_names);
762         send_reply->names       = wrepl_wins_names;
763
764         wrepl_wins_names[0]     = *name;
765
766         status = wrepl_request(wrepl_socket, wrepl_socket,
767                                &repl_send, &repl_recv);
768         CHECK_STATUS(tctx, status, NT_STATUS_OK);
769         CHECK_VALUE(tctx, repl_recv->mess_type, WREPL_STOP_ASSOCIATION);
770         CHECK_VALUE(tctx, repl_recv->message.stop.reason, 0);
771
772         talloc_free(wrepl_socket);
773         return true;
774 }
775
776 static bool test_wrepl_is_applied(struct torture_context *tctx, 
777                                                                   struct test_wrepl_conflict_conn *ctx,
778                                   const struct wrepl_wins_owner *owner,
779                                   const struct wrepl_wins_name *name,
780                                   bool expected)
781 {
782         NTSTATUS status;
783         struct wrepl_pull_names pull_names;
784         struct wrepl_name *names;
785
786         pull_names.in.assoc_ctx = ctx->pull_assoc;
787         pull_names.in.partner   = *owner;
788         pull_names.in.partner.min_version = pull_names.in.partner.max_version;
789                 
790         status = wrepl_pull_names(ctx->pull, ctx->pull, &pull_names);
791         CHECK_STATUS(tctx, status, NT_STATUS_OK);
792         torture_assert(tctx, pull_names.out.num_names == (expected?1:0), 
793                        talloc_asprintf(tctx, "Invalid number of records returned - expected %d got %d", expected, pull_names.out.num_names));
794
795         names = pull_names.out.names;
796
797         if (expected) {
798                 uint32_t flags = WREPL_NAME_FLAGS(names[0].type,
799                                                   names[0].state,
800                                                   names[0].node,
801                                                   names[0].is_static);
802                 char *expected_scope = NULL;
803                 CHECK_VALUE(tctx, names[0].name.type, name->name->type);
804                 CHECK_VALUE_STRING(tctx, names[0].name.name, name->name->name);
805
806                 if (names[0].name.scope) {
807                         expected_scope = talloc_strndup(tctx,
808                                                         name->name->scope,
809                                                         237);
810                 }
811                 CHECK_VALUE_STRING(tctx, names[0].name.scope, expected_scope);
812                 CHECK_VALUE(tctx, flags, name->flags);
813                 CHECK_VALUE_UINT64(tctx, names[0].version_id, name->id);
814
815                 if (flags & 2) {
816                         CHECK_VALUE(tctx, names[0].num_addresses,
817                                     name->addresses.addresses.num_ips);
818                 } else {
819                         CHECK_VALUE(tctx, names[0].num_addresses, 1);
820                         CHECK_VALUE_STRING(tctx, names[0].addresses[0].address,
821                                            name->addresses.ip);
822                 }
823         }
824         talloc_free(pull_names.out.names);
825         return true;
826 }
827
828 static bool test_wrepl_mhomed_merged(struct torture_context *tctx, 
829                                                                          struct test_wrepl_conflict_conn *ctx,
830                                      const struct wrepl_wins_owner *owner1,
831                                      uint32_t num_ips1, const struct wrepl_ip *ips1,
832                                      const struct wrepl_wins_owner *owner2,
833                                      uint32_t num_ips2, const struct wrepl_ip *ips2,
834                                      const struct wrepl_wins_name *name2)
835 {
836         NTSTATUS status;
837         struct wrepl_pull_names pull_names;
838         struct wrepl_name *names;
839         uint32_t flags;
840         uint32_t i, j;
841         uint32_t num_ips = num_ips1 + num_ips2;
842
843         for (i = 0; i < num_ips2; i++) {
844                 for (j = 0; j < num_ips1; j++) {
845                         if (strcmp(ips2[i].ip,ips1[j].ip) == 0) {
846                                 num_ips--;
847                                 break;
848                         }
849                 } 
850         }
851
852         pull_names.in.assoc_ctx = ctx->pull_assoc;
853         pull_names.in.partner   = *owner2;
854         pull_names.in.partner.min_version = pull_names.in.partner.max_version;
855
856         status = wrepl_pull_names(ctx->pull, ctx->pull, &pull_names);
857         CHECK_STATUS(tctx, status, NT_STATUS_OK);
858         CHECK_VALUE(tctx, pull_names.out.num_names, 1);
859
860         names = pull_names.out.names;
861
862         flags = WREPL_NAME_FLAGS(names[0].type,
863                                  names[0].state,
864                                  names[0].node,
865                                  names[0].is_static);
866         CHECK_VALUE(tctx, names[0].name.type, name2->name->type);
867         CHECK_VALUE_STRING(tctx, names[0].name.name, name2->name->name);
868         CHECK_VALUE_STRING(tctx, names[0].name.scope, name2->name->scope);
869         CHECK_VALUE(tctx, flags, name2->flags | WREPL_TYPE_MHOMED);
870         CHECK_VALUE_UINT64(tctx, names[0].version_id, name2->id);
871
872         CHECK_VALUE(tctx, names[0].num_addresses, num_ips);
873
874         for (i = 0; i < names[0].num_addresses; i++) {
875                 const char *addr = names[0].addresses[i].address; 
876                 const char *owner = names[0].addresses[i].owner;
877                 bool found = false;
878
879                 for (j = 0; j < num_ips2; j++) {
880                         if (strcmp(addr, ips2[j].ip) == 0) {
881                                 found = true;
882                                 CHECK_VALUE_STRING(tctx, owner, owner2->address);
883                                 break;
884                         }
885                 }
886
887                 if (found) continue;
888
889                 for (j = 0; j < num_ips1; j++) {
890                         if (strcmp(addr, ips1[j].ip) == 0) {
891                                 found = true;
892                                 CHECK_VALUE_STRING(tctx, owner, owner1->address);
893                                 break;
894                         }
895                 }
896
897                 if (found) continue;
898
899                 CHECK_VALUE_STRING(tctx, addr, "not found in address list");
900         }
901         talloc_free(pull_names.out.names);
902         return true;
903 }
904
905 static bool test_wrepl_sgroup_merged(struct torture_context *tctx, 
906                                                                          struct test_wrepl_conflict_conn *ctx,
907                                      struct wrepl_wins_owner *merge_owner,
908                                      struct wrepl_wins_owner *owner1,
909                                      uint32_t num_ips1, const struct wrepl_ip *ips1,
910                                      struct wrepl_wins_owner *owner2,
911                                      uint32_t num_ips2, const struct wrepl_ip *ips2,
912                                      const struct wrepl_wins_name *name2)
913 {
914         NTSTATUS status;
915         struct wrepl_pull_names pull_names;
916         struct wrepl_name *names;
917         struct wrepl_name *name = NULL;
918         uint32_t flags;
919         uint32_t i, j;
920         uint32_t num_ips = num_ips1 + num_ips2;
921
922         if (!merge_owner) {
923                 merge_owner = &ctx->c;
924         }
925
926         for (i = 0; i < num_ips1; i++) {
927                 if (owner1 != &ctx->c && strcmp(ips1[i].owner,owner2->address) == 0) {
928                         num_ips--;
929                         continue;
930                 }
931                 for (j = 0; j < num_ips2; j++) {
932                         if (strcmp(ips1[i].ip,ips2[j].ip) == 0) {
933                                 num_ips--;
934                                 break;
935                         }
936                 }
937         }
938
939
940         pull_names.in.assoc_ctx = ctx->pull_assoc;
941         pull_names.in.partner   = *merge_owner;
942         pull_names.in.partner.min_version = pull_names.in.partner.max_version;
943         pull_names.in.partner.max_version = 0;
944
945         status = wrepl_pull_names(ctx->pull, ctx->pull, &pull_names);
946         CHECK_STATUS(tctx, status, NT_STATUS_OK);
947
948         names = pull_names.out.names;
949         
950         for (i = 0; i < pull_names.out.num_names; i++) {
951                 if (names[i].name.type != name2->name->type)    continue;
952                 if (!names[i].name.name) continue;
953                 if (strcmp(names[i].name.name, name2->name->name) != 0) continue;
954                 if (names[i].name.scope) continue;
955
956                 name = &names[i];
957         }
958
959         if (pull_names.out.num_names > 0) {
960                 merge_owner->max_version        = names[pull_names.out.num_names-1].version_id;
961         }
962
963         if (!name) {
964                 torture_comment(tctx, "%s: Name '%s' not found\n", __location__, nbt_name_string(ctx, name2->name));
965                 return false;
966         }
967
968         flags = WREPL_NAME_FLAGS(name->type,
969                                  name->state,
970                                  name->node,
971                                  name->is_static);
972         CHECK_VALUE(tctx, name->name.type, name2->name->type);
973         CHECK_VALUE_STRING(tctx, name->name.name, name2->name->name);
974         CHECK_VALUE_STRING(tctx, name->name.scope, name2->name->scope);
975         CHECK_VALUE(tctx, flags, name2->flags);
976
977         CHECK_VALUE(tctx, name->num_addresses, num_ips);
978
979         for (i = 0; i < name->num_addresses; i++) {
980                 const char *addr = name->addresses[i].address; 
981                 const char *owner = name->addresses[i].owner;
982                 bool found = false;
983
984                 for (j = 0; j < num_ips2; j++) {
985                         if (strcmp(addr, ips2[j].ip) == 0) {
986                                 found = true;
987                                 CHECK_VALUE_STRING(tctx, owner, ips2[j].owner);
988                                 break;
989                         }
990                 }
991
992                 if (found) continue;
993
994                 for (j = 0; j < num_ips1; j++) {
995                         if (strcmp(addr, ips1[j].ip) == 0) {
996                                 found = true;
997                                 if (owner1 == &ctx->c) {
998                                         CHECK_VALUE_STRING(tctx, owner, owner1->address);
999                                 } else {
1000                                         CHECK_VALUE_STRING(tctx, owner, ips1[j].owner);
1001                                 }
1002                                 break;
1003                         }
1004                 }
1005
1006                 if (found) continue;
1007
1008                 CHECK_VALUE_STRING(tctx, addr, "not found in address list");
1009         }
1010         talloc_free(pull_names.out.names);
1011         return true;
1012 }
1013
1014 static char *test_nbt_winsrepl_scope_string(TALLOC_CTX *mem_ctx, uint8_t count)
1015 {
1016         char *res;
1017         uint8_t i;
1018
1019         res = talloc_array(mem_ctx, char, count+1);
1020         if (res == NULL) {
1021                 return NULL;
1022         }
1023
1024         for (i=0; i < count; i++) {
1025                 res[i] = '0' + (i%10);
1026         }
1027
1028         res[count] = '\0';
1029
1030         talloc_set_name_const(res, res);
1031
1032         return res;
1033 }
1034
1035 static bool test_conflict_same_owner(struct torture_context *tctx, 
1036                                                                          struct test_wrepl_conflict_conn *ctx)
1037 {
1038         static bool ret = true;
1039         struct wrepl_wins_name wins_name1;
1040         struct wrepl_wins_name wins_name2;
1041         struct wrepl_wins_name *wins_name_tmp;
1042         struct wrepl_wins_name *wins_name_last;
1043         struct wrepl_wins_name *wins_name_cur;
1044         uint32_t i,j;
1045         struct nbt_name names[] = {
1046                 _NBT_NAME("_SAME_OWNER_A", 0x00, NULL),
1047                 _NBT_NAME("_SAME_OWNER_A", 0x00,
1048                           test_nbt_winsrepl_scope_string(tctx, 1)),
1049                 _NBT_NAME("_SAME_OWNER_A", 0x00,
1050                           test_nbt_winsrepl_scope_string(tctx, 2)),
1051                 _NBT_NAME("_SAME_OWNER_A", 0x00,
1052                           test_nbt_winsrepl_scope_string(tctx, 3)),
1053                 _NBT_NAME("_SAME_OWNER_A", 0x00,
1054                           test_nbt_winsrepl_scope_string(tctx, 4)),
1055                 _NBT_NAME("_SAME_OWNER_A", 0x00,
1056                           test_nbt_winsrepl_scope_string(tctx, 5)),
1057                 _NBT_NAME("_SAME_OWNER_A", 0x00,
1058                           test_nbt_winsrepl_scope_string(tctx, 6)),
1059                 _NBT_NAME("_SAME_OWNER_A", 0x00,
1060                           test_nbt_winsrepl_scope_string(tctx, 7)),
1061                 _NBT_NAME("_SAME_OWNER_A", 0x00,
1062                           test_nbt_winsrepl_scope_string(tctx, 8)),
1063                 _NBT_NAME("_SAME_OWNER_A", 0x00,
1064                           test_nbt_winsrepl_scope_string(tctx, 9)),
1065                 _NBT_NAME("_SAME_OWNER_A", 0x00,
1066                           test_nbt_winsrepl_scope_string(tctx, 237)),
1067                 _NBT_NAME("_SAME_OWNER_A", 0x00,
1068                           test_nbt_winsrepl_scope_string(tctx, 238)),
1069                 _NBT_NAME("_SAME_OWNER_A", 0x1C, NULL),
1070         };
1071         struct {
1072                 enum wrepl_name_type type;
1073                 enum wrepl_name_state state;
1074                 enum wrepl_name_node node;
1075                 bool is_static;
1076                 uint32_t num_ips;
1077                 const struct wrepl_ip *ips;
1078         } records[] = {
1079                 {
1080                 .type           = WREPL_TYPE_GROUP,
1081                 .state          = WREPL_STATE_ACTIVE,
1082                 .node           = WREPL_NODE_B,
1083                 .is_static      = false,
1084                 .num_ips        = ARRAY_SIZE(addresses_A_1),
1085                 .ips            = addresses_A_1,
1086                 },{
1087                 .type           = WREPL_TYPE_UNIQUE,
1088                 .state          = WREPL_STATE_ACTIVE,
1089                 .node           = WREPL_NODE_B,
1090                 .is_static      = false,
1091                 .num_ips        = ARRAY_SIZE(addresses_A_1),
1092                 .ips            = addresses_A_1,
1093                 },{
1094                 .type           = WREPL_TYPE_UNIQUE,
1095                 .state          = WREPL_STATE_ACTIVE,
1096                 .node           = WREPL_NODE_B,
1097                 .is_static      = false,
1098                 .num_ips        = ARRAY_SIZE(addresses_A_2),
1099                 .ips            = addresses_A_2,
1100                 },{
1101                 .type           = WREPL_TYPE_UNIQUE,
1102                 .state          = WREPL_STATE_ACTIVE,
1103                 .node           = WREPL_NODE_B,
1104                 .is_static      = true,
1105                 .num_ips        = ARRAY_SIZE(addresses_A_1),
1106                 .ips            = addresses_A_1,
1107                 },{
1108                 .type           = WREPL_TYPE_UNIQUE,
1109                 .state          = WREPL_STATE_ACTIVE,
1110                 .node           = WREPL_NODE_B,
1111                 .is_static      = false,
1112                 .num_ips        = ARRAY_SIZE(addresses_A_2),
1113                 .ips            = addresses_A_2,
1114                 },{
1115                 .type           = WREPL_TYPE_SGROUP,
1116                 .state          = WREPL_STATE_TOMBSTONE,
1117                 .node           = WREPL_NODE_B,
1118                 .is_static      = false,
1119                 .num_ips        = ARRAY_SIZE(addresses_A_2),
1120                 .ips            = addresses_A_2,
1121                 },{
1122                 .type           = WREPL_TYPE_MHOMED,
1123                 .state          = WREPL_STATE_TOMBSTONE,
1124                 .node           = WREPL_NODE_B,
1125                 .is_static      = false,
1126                 .num_ips        = ARRAY_SIZE(addresses_A_1),
1127                 .ips            = addresses_A_1,
1128                 },{
1129                 .type           = WREPL_TYPE_MHOMED,
1130                 .state          = WREPL_STATE_RELEASED,
1131                 .node           = WREPL_NODE_B,
1132                 .is_static      = false,
1133                 .num_ips        = ARRAY_SIZE(addresses_A_2),
1134                 .ips            = addresses_A_2,
1135                 },{
1136                 .type           = WREPL_TYPE_SGROUP,
1137                 .state          = WREPL_STATE_ACTIVE,
1138                 .node           = WREPL_NODE_B,
1139                 .is_static      = false,
1140                 .num_ips        = ARRAY_SIZE(addresses_A_1),
1141                 .ips            = addresses_A_1,
1142                 },{
1143                 .type           = WREPL_TYPE_SGROUP,
1144                 .state          = WREPL_STATE_ACTIVE,
1145                 .node           = WREPL_NODE_B,
1146                 .is_static      = false,
1147                 .num_ips        = ARRAY_SIZE(addresses_A_3_4),
1148                 .ips            = addresses_A_3_4,
1149                 },{
1150                 .type           = WREPL_TYPE_SGROUP,
1151                 .state          = WREPL_STATE_TOMBSTONE,
1152                 .node           = WREPL_NODE_B,
1153                 .is_static      = false,
1154                 .num_ips        = ARRAY_SIZE(addresses_B_3_4),
1155                 .ips            = addresses_B_3_4,
1156                 },{
1157                 /* the last one should always be a unique,tomstone record! */
1158                 .type           = WREPL_TYPE_UNIQUE,
1159                 .state          = WREPL_STATE_TOMBSTONE,
1160                 .node           = WREPL_NODE_B,
1161                 .is_static      = false,
1162                 .num_ips        = ARRAY_SIZE(addresses_A_1),
1163                 .ips            = addresses_A_1,
1164                 }
1165         };
1166
1167         wins_name_tmp   = NULL;
1168         wins_name_last  = &wins_name2;
1169         wins_name_cur   = &wins_name1;
1170
1171         for (j=0; ret && j < ARRAY_SIZE(names); j++) {
1172                 torture_comment(tctx, "Test Replica Conflicts with same owner[%s] for %s\n",
1173                         nbt_name_string(ctx, &names[j]), ctx->a.address);
1174
1175                 for(i=0; ret && i < ARRAY_SIZE(records); i++) {
1176                         wins_name_tmp   = wins_name_last;
1177                         wins_name_last  = wins_name_cur;
1178                         wins_name_cur   = wins_name_tmp;
1179
1180                         if (i > 0) {
1181                                 torture_comment(tctx, "%s,%s%s vs. %s,%s%s with %s ip(s) => %s\n",
1182                                         wrepl_name_type_string(records[i-1].type),
1183                                         wrepl_name_state_string(records[i-1].state),
1184                                         (records[i-1].is_static?",static":""),
1185                                         wrepl_name_type_string(records[i].type),
1186                                         wrepl_name_state_string(records[i].state),
1187                                         (records[i].is_static?",static":""),
1188                                         (records[i-1].ips==records[i].ips?"same":"different"),
1189                                         "REPLACE");
1190                         }
1191
1192                         wins_name_cur->name     = &names[j];
1193                         wins_name_cur->flags    = WREPL_NAME_FLAGS(records[i].type,
1194                                                                    records[i].state,
1195                                                                    records[i].node,
1196                                                                    records[i].is_static);
1197                         wins_name_cur->id       = ++ctx->a.max_version;
1198                         if (wins_name_cur->flags & 2) {
1199                                 wins_name_cur->addresses.addresses.num_ips = records[i].num_ips;
1200                                 wins_name_cur->addresses.addresses.ips     = discard_const_p(struct wrepl_ip,
1201                                                                              records[i].ips);
1202                         } else {
1203                                 wins_name_cur->addresses.ip = records[i].ips[0].ip;
1204                         }
1205                         wins_name_cur->unknown  = "255.255.255.255";
1206
1207                         ret &= test_wrepl_update_one(tctx, ctx, &ctx->a,wins_name_cur);
1208                         if (records[i].state == WREPL_STATE_RELEASED) {
1209                                 ret &= test_wrepl_is_applied(tctx, ctx, &ctx->a, wins_name_last, false);
1210                                 ret &= test_wrepl_is_applied(tctx, ctx, &ctx->a, wins_name_cur, false);
1211                         } else {
1212                                 ret &= test_wrepl_is_applied(tctx, ctx, &ctx->a, wins_name_cur, true);
1213                         }
1214
1215                         /* the first one is a cleanup run */
1216                         if (!ret && i == 0) ret = true;
1217
1218                         if (!ret) {
1219                                 torture_comment(tctx, "conflict handled wrong or record[%u]: %s\n", i, __location__);
1220                                 return ret;
1221                         }
1222                 }
1223         }
1224         return ret;
1225 }
1226
1227 static bool test_conflict_different_owner(struct torture_context *tctx, 
1228                                                                                   struct test_wrepl_conflict_conn *ctx)
1229 {
1230         bool ret = true;
1231         struct wrepl_wins_name wins_name1;
1232         struct wrepl_wins_name wins_name2;
1233         struct wrepl_wins_name *wins_name_r1;
1234         struct wrepl_wins_name *wins_name_r2;
1235         uint32_t i;
1236         struct {
1237                 const char *line; /* just better debugging */
1238                 struct nbt_name name;
1239                 const char *comment;
1240                 bool extra; /* not the worst case, this is an extra test */
1241                 bool cleanup;
1242                 struct {
1243                         struct wrepl_wins_owner *owner;
1244                         enum wrepl_name_type type;
1245                         enum wrepl_name_state state;
1246                         enum wrepl_name_node node;
1247                         bool is_static;
1248                         uint32_t num_ips;
1249                         const struct wrepl_ip *ips;
1250                         bool apply_expected;
1251                         bool sgroup_merge;
1252                         struct wrepl_wins_owner *merge_owner;
1253                         bool sgroup_cleanup;
1254                 } r1, r2;
1255         } records[] = {
1256         /* 
1257          * NOTE: the first record and the last applied one
1258          *       needs to be from the same owner,
1259          *       to not conflict in the next smbtorture run!!!
1260          */
1261         {
1262                 .line   = __location__,
1263                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1264                 .cleanup= true,
1265                 .r1     = {
1266                         .owner          = &ctx->b,
1267                         .type           = WREPL_TYPE_UNIQUE,
1268                         .state          = WREPL_STATE_TOMBSTONE,
1269                         .node           = WREPL_NODE_B,
1270                         .is_static      = false,
1271                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1272                         .ips            = addresses_B_1,
1273                         .apply_expected = true /* ignored */
1274                 },
1275                 .r2     = {
1276                         .owner          = &ctx->a,
1277                         .type           = WREPL_TYPE_UNIQUE,
1278                         .state          = WREPL_STATE_TOMBSTONE,
1279                         .node           = WREPL_NODE_B,
1280                         .is_static      = false,
1281                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1282                         .ips            = addresses_A_1,
1283                         .apply_expected = true /* ignored */
1284                 }
1285         },
1286
1287 /*
1288  * unique vs unique section
1289  */
1290         /* 
1291          * unique,active vs. unique,active
1292          * => should be replaced
1293          */
1294         {
1295                 .line   = __location__,
1296                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1297                 .r1     = {
1298                         .owner          = &ctx->a,
1299                         .type           = WREPL_TYPE_UNIQUE,
1300                         .state          = WREPL_STATE_ACTIVE,
1301                         .node           = WREPL_NODE_B,
1302                         .is_static      = false,
1303                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1304                         .ips            = addresses_A_1,
1305                         .apply_expected = true
1306                 },
1307                 .r2     = {
1308                         .owner          = &ctx->b,
1309                         .type           = WREPL_TYPE_UNIQUE,
1310                         .state          = WREPL_STATE_ACTIVE,
1311                         .node           = WREPL_NODE_B,
1312                         .is_static      = false,
1313                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1314                         .ips            = addresses_B_1,
1315                         .apply_expected = true
1316                 }
1317         },
1318
1319         /* 
1320          * unique,active vs. unique,tombstone
1321          * => should NOT be replaced
1322          */
1323         {
1324                 .line   = __location__,
1325                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1326                 .r1     = {
1327                         .owner          = &ctx->b,
1328                         .type           = WREPL_TYPE_UNIQUE,
1329                         .state          = WREPL_STATE_ACTIVE,
1330                         .node           = WREPL_NODE_B,
1331                         .is_static      = false,
1332                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1333                         .ips            = addresses_B_1,
1334                         .apply_expected = true
1335                 },
1336                 .r2     = {
1337                         .owner          = &ctx->a,
1338                         .type           = WREPL_TYPE_UNIQUE,
1339                         .state          = WREPL_STATE_TOMBSTONE,
1340                         .node           = WREPL_NODE_B,
1341                         .is_static      = false,
1342                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1343                         .ips            = addresses_B_1,
1344                         .apply_expected = false
1345                 }
1346         },
1347
1348         /* 
1349          * unique,released vs. unique,active
1350          * => should be replaced
1351          */
1352         {
1353                 .line   = __location__,
1354                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1355                 .r1     = {
1356                         .owner          = &ctx->b,
1357                         .type           = WREPL_TYPE_UNIQUE,
1358                         .state          = WREPL_STATE_RELEASED,
1359                         .node           = WREPL_NODE_B,
1360                         .is_static      = false,
1361                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1362                         .ips            = addresses_B_1,
1363                         .apply_expected = false
1364                 },
1365                 .r2     = {
1366                         .owner          = &ctx->a,
1367                         .type           = WREPL_TYPE_UNIQUE,
1368                         .state          = WREPL_STATE_ACTIVE,
1369                         .node           = WREPL_NODE_B,
1370                         .is_static      = false,
1371                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1372                         .ips            = addresses_A_1,
1373                         .apply_expected = true
1374                 }
1375         },
1376
1377         /* 
1378          * unique,released vs. unique,tombstone
1379          * => should be replaced
1380          */
1381         {
1382                 .line   = __location__,
1383                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1384                 .r1     = {
1385                         .owner          = &ctx->a,
1386                         .type           = WREPL_TYPE_UNIQUE,
1387                         .state          = WREPL_STATE_RELEASED,
1388                         .node           = WREPL_NODE_B,
1389                         .is_static      = false,
1390                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1391                         .ips            = addresses_A_1,
1392                         .apply_expected = false
1393                 },
1394                 .r2     = {
1395                         .owner          = &ctx->b,
1396                         .type           = WREPL_TYPE_UNIQUE,
1397                         .state          = WREPL_STATE_TOMBSTONE,
1398                         .node           = WREPL_NODE_B,
1399                         .is_static      = false,
1400                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1401                         .ips            = addresses_B_1,
1402                         .apply_expected = true
1403                 }
1404         },
1405
1406         /* 
1407          * unique,tombstone vs. unique,active
1408          * => should be replaced
1409          */
1410         {
1411                 .line   = __location__,
1412                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1413                 .r1     = {
1414                         .owner          = &ctx->b,
1415                         .type           = WREPL_TYPE_UNIQUE,
1416                         .state          = WREPL_STATE_TOMBSTONE,
1417                         .node           = WREPL_NODE_B,
1418                         .is_static      = false,
1419                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1420                         .ips            = addresses_B_1,
1421                         .apply_expected = true
1422                 },
1423                 .r2     = {
1424                         .owner          = &ctx->a,
1425                         .type           = WREPL_TYPE_UNIQUE,
1426                         .state          = WREPL_STATE_ACTIVE,
1427                         .node           = WREPL_NODE_B,
1428                         .is_static      = false,
1429                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1430                         .ips            = addresses_A_1,
1431                         .apply_expected = true
1432                 }
1433         },
1434
1435         /* 
1436          * unique,tombstone vs. unique,tombstone
1437          * => should be replaced
1438          */
1439         {
1440                 .line   = __location__,
1441                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1442                 .r1     = {
1443                         .owner          = &ctx->a,
1444                         .type           = WREPL_TYPE_UNIQUE,
1445                         .state          = WREPL_STATE_TOMBSTONE,
1446                         .node           = WREPL_NODE_B,
1447                         .is_static      = false,
1448                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1449                         .ips            = addresses_A_1,
1450                         .apply_expected = true
1451                 },
1452                 .r2     = {
1453                         .owner          = &ctx->b,
1454                         .type           = WREPL_TYPE_UNIQUE,
1455                         .state          = WREPL_STATE_TOMBSTONE,
1456                         .node           = WREPL_NODE_B,
1457                         .is_static      = false,
1458                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1459                         .ips            = addresses_B_1,
1460                         .apply_expected = true
1461                 }
1462         },
1463
1464
1465 /*
1466  * unique vs normal groups section,
1467  */
1468         /* 
1469          * unique,active vs. group,active
1470          * => should be replaced
1471          */
1472         {
1473                 .line   = __location__,
1474                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1475                 .r1     = {
1476                         .owner          = &ctx->b,
1477                         .type           = WREPL_TYPE_UNIQUE,
1478                         .state          = WREPL_STATE_ACTIVE,
1479                         .node           = WREPL_NODE_B,
1480                         .is_static      = false,
1481                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1482                         .ips            = addresses_B_1,
1483                         .apply_expected = true
1484                 },
1485                 .r2     = {
1486                         .owner          = &ctx->a,
1487                         .type           = WREPL_TYPE_GROUP,
1488                         .state          = WREPL_STATE_ACTIVE,
1489                         .node           = WREPL_NODE_B,
1490                         .is_static      = false,
1491                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1492                         .ips            = addresses_A_1,
1493                         .apply_expected = true
1494                 }
1495         },
1496
1497         /* 
1498          * unique,active vs. group,tombstone
1499          * => should NOT be replaced
1500          */
1501         {
1502                 .line   = __location__,
1503                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1504                 .r1     = {
1505                         .owner          = &ctx->a,
1506                         .type           = WREPL_TYPE_UNIQUE,
1507                         .state          = WREPL_STATE_ACTIVE,
1508                         .node           = WREPL_NODE_B,
1509                         .is_static      = false,
1510                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1511                         .ips            = addresses_A_1,
1512                         .apply_expected = true
1513                 },
1514                 .r2     = {
1515                         .owner          = &ctx->b,
1516                         .type           = WREPL_TYPE_GROUP,
1517                         .state          = WREPL_STATE_TOMBSTONE,
1518                         .node           = WREPL_NODE_B,
1519                         .is_static      = false,
1520                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1521                         .ips            = addresses_A_1,
1522                         .apply_expected = false
1523                 }
1524         },
1525
1526         /* 
1527          * unique,released vs. group,active
1528          * => should be replaced
1529          */
1530         {
1531                 .line   = __location__,
1532                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1533                 .r1     = {
1534                         .owner          = &ctx->a,
1535                         .type           = WREPL_TYPE_UNIQUE,
1536                         .state          = WREPL_STATE_RELEASED,
1537                         .node           = WREPL_NODE_B,
1538                         .is_static      = false,
1539                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1540                         .ips            = addresses_A_1,
1541                         .apply_expected = false
1542                 },
1543                 .r2     = {
1544                         .owner          = &ctx->b,
1545                         .type           = WREPL_TYPE_GROUP,
1546                         .state          = WREPL_STATE_ACTIVE,
1547                         .node           = WREPL_NODE_B,
1548                         .is_static      = false,
1549                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1550                         .ips            = addresses_B_1,
1551                         .apply_expected = true
1552                 }
1553         },
1554
1555         /* 
1556          * unique,released vs. group,tombstone
1557          * => should be replaced
1558          */
1559         {
1560                 .line   = __location__,
1561                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1562                 .r1     = {
1563                         .owner          = &ctx->b,
1564                         .type           = WREPL_TYPE_UNIQUE,
1565                         .state          = WREPL_STATE_RELEASED,
1566                         .node           = WREPL_NODE_B,
1567                         .is_static      = false,
1568                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1569                         .ips            = addresses_B_1,
1570                         .apply_expected = false
1571                 },
1572                 .r2     = {
1573                         .owner          = &ctx->a,
1574                         .type           = WREPL_TYPE_GROUP,
1575                         .state          = WREPL_STATE_TOMBSTONE,
1576                         .node           = WREPL_NODE_B,
1577                         .is_static      = false,
1578                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1579                         .ips            = addresses_A_1,
1580                         .apply_expected = true
1581                 }
1582         },
1583
1584         /* 
1585          * unique,tombstone vs. group,active
1586          * => should be replaced
1587          */
1588         {
1589                 .line   = __location__,
1590                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1591                 .r1     = {
1592                         .owner          = &ctx->a,
1593                         .type           = WREPL_TYPE_UNIQUE,
1594                         .state          = WREPL_STATE_TOMBSTONE,
1595                         .node           = WREPL_NODE_B,
1596                         .is_static      = false,
1597                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1598                         .ips            = addresses_A_1,
1599                         .apply_expected = true
1600                 },
1601                 .r2     = {
1602                         .owner          = &ctx->b,
1603                         .type           = WREPL_TYPE_GROUP,
1604                         .state          = WREPL_STATE_ACTIVE,
1605                         .node           = WREPL_NODE_B,
1606                         .is_static      = false,
1607                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1608                         .ips            = addresses_B_1,
1609                         .apply_expected = true
1610                 }
1611         },
1612
1613         /* 
1614          * unique,tombstone vs. group,tombstone
1615          * => should be replaced
1616          */
1617         {
1618                 .line   = __location__,
1619                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1620                 .r1     = {
1621                         .owner          = &ctx->b,
1622                         .type           = WREPL_TYPE_UNIQUE,
1623                         .state          = WREPL_STATE_TOMBSTONE,
1624                         .node           = WREPL_NODE_B,
1625                         .is_static      = false,
1626                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1627                         .ips            = addresses_B_1,
1628                         .apply_expected = true
1629                 },
1630                 .r2     = {
1631                         .owner          = &ctx->a,
1632                         .type           = WREPL_TYPE_GROUP,
1633                         .state          = WREPL_STATE_TOMBSTONE,
1634                         .node           = WREPL_NODE_B,
1635                         .is_static      = false,
1636                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1637                         .ips            = addresses_A_1,
1638                         .apply_expected = true
1639                 }
1640         },
1641
1642 /*
1643  * unique vs special groups section,
1644  */
1645         /* 
1646          * unique,active vs. sgroup,active
1647          * => should NOT be replaced
1648          */
1649         {
1650                 .line   = __location__,
1651                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1652                 .r1     = {
1653                         .owner          = &ctx->a,
1654                         .type           = WREPL_TYPE_UNIQUE,
1655                         .state          = WREPL_STATE_ACTIVE,
1656                         .node           = WREPL_NODE_B,
1657                         .is_static      = false,
1658                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1659                         .ips            = addresses_A_1,
1660                         .apply_expected = true
1661                 },
1662                 .r2     = {
1663                         .owner          = &ctx->b,
1664                         .type           = WREPL_TYPE_SGROUP,
1665                         .state          = WREPL_STATE_ACTIVE,
1666                         .node           = WREPL_NODE_B,
1667                         .is_static      = false,
1668                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1669                         .ips            = addresses_A_1,
1670                         .apply_expected = false
1671                 }
1672         },
1673
1674         /* 
1675          * unique,active vs. sgroup,tombstone
1676          * => should NOT be replaced
1677          */
1678         {
1679                 .line   = __location__,
1680                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1681                 .r1     = {
1682                         .owner          = &ctx->a,
1683                         .type           = WREPL_TYPE_UNIQUE,
1684                         .state          = WREPL_STATE_ACTIVE,
1685                         .node           = WREPL_NODE_B,
1686                         .is_static      = false,
1687                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1688                         .ips            = addresses_A_1,
1689                         .apply_expected = true
1690                 },
1691                 .r2     = {
1692                         .owner          = &ctx->b,
1693                         .type           = WREPL_TYPE_SGROUP,
1694                         .state          = WREPL_STATE_TOMBSTONE,
1695                         .node           = WREPL_NODE_B,
1696                         .is_static      = false,
1697                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1698                         .ips            = addresses_A_1,
1699                         .apply_expected = false
1700                 }
1701         },
1702
1703         /* 
1704          * unique,released vs. sgroup,active
1705          * => should be replaced
1706          */
1707         {
1708                 .line   = __location__,
1709                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1710                 .r1     = {
1711                         .owner          = &ctx->a,
1712                         .type           = WREPL_TYPE_UNIQUE,
1713                         .state          = WREPL_STATE_RELEASED,
1714                         .node           = WREPL_NODE_B,
1715                         .is_static      = false,
1716                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1717                         .ips            = addresses_A_1,
1718                         .apply_expected = false
1719                 },
1720                 .r2     = {
1721                         .owner          = &ctx->b,
1722                         .type           = WREPL_TYPE_SGROUP,
1723                         .state          = WREPL_STATE_ACTIVE,
1724                         .node           = WREPL_NODE_B,
1725                         .is_static      = false,
1726                         .num_ips        = ARRAY_SIZE(addresses_B_3_4),
1727                         .ips            = addresses_B_3_4,
1728                         .apply_expected = true
1729                 }
1730         },
1731
1732         /* 
1733          * unique,released vs. sgroup,tombstone
1734          * => should be replaced
1735          */
1736         {
1737                 .line   = __location__,
1738                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1739                 .r1     = {
1740                         .owner          = &ctx->b,
1741                         .type           = WREPL_TYPE_UNIQUE,
1742                         .state          = WREPL_STATE_RELEASED,
1743                         .node           = WREPL_NODE_B,
1744                         .is_static      = false,
1745                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1746                         .ips            = addresses_B_1,
1747                         .apply_expected = false
1748                 },
1749                 .r2     = {
1750                         .owner          = &ctx->a,
1751                         .type           = WREPL_TYPE_SGROUP,
1752                         .state          = WREPL_STATE_TOMBSTONE,
1753                         .node           = WREPL_NODE_B,
1754                         .is_static      = false,
1755                         .num_ips        = ARRAY_SIZE(addresses_A_3_4),
1756                         .ips            = addresses_A_3_4,
1757                         .apply_expected = true
1758                 }
1759         },
1760
1761         /* 
1762          * unique,tombstone vs. sgroup,active
1763          * => should be replaced
1764          */
1765         {
1766                 .line   = __location__,
1767                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1768                 .r1     = {
1769                         .owner          = &ctx->a,
1770                         .type           = WREPL_TYPE_UNIQUE,
1771                         .state          = WREPL_STATE_TOMBSTONE,
1772                         .node           = WREPL_NODE_B,
1773                         .is_static      = false,
1774                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1775                         .ips            = addresses_A_1,
1776                         .apply_expected = true
1777                 },
1778                 .r2     = {
1779                         .owner          = &ctx->b,
1780                         .type           = WREPL_TYPE_SGROUP,
1781                         .state          = WREPL_STATE_ACTIVE,
1782                         .node           = WREPL_NODE_B,
1783                         .is_static      = false,
1784                         .num_ips        = ARRAY_SIZE(addresses_B_3_4),
1785                         .ips            = addresses_B_3_4,
1786                         .apply_expected = true
1787                 }
1788         },
1789
1790         /* 
1791          * unique,tombstone vs. sgroup,tombstone
1792          * => should be replaced
1793          */
1794         {
1795                 .line   = __location__,
1796                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1797                 .r1     = {
1798                         .owner          = &ctx->b,
1799                         .type           = WREPL_TYPE_UNIQUE,
1800                         .state          = WREPL_STATE_TOMBSTONE,
1801                         .node           = WREPL_NODE_B,
1802                         .is_static      = false,
1803                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1804                         .ips            = addresses_B_1,
1805                         .apply_expected = true
1806                 },
1807                 .r2     = {
1808                         .owner          = &ctx->a,
1809                         .type           = WREPL_TYPE_SGROUP,
1810                         .state          = WREPL_STATE_TOMBSTONE,
1811                         .node           = WREPL_NODE_B,
1812                         .is_static      = false,
1813                         .num_ips        = ARRAY_SIZE(addresses_A_3_4),
1814                         .ips            = addresses_A_3_4,
1815                         .apply_expected = true
1816                 }
1817         },
1818
1819 /*
1820  * unique vs multi homed section,
1821  */
1822         /* 
1823          * unique,active vs. mhomed,active
1824          * => should be replaced
1825          */
1826         {
1827                 .line   = __location__,
1828                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1829                 .r1     = {
1830                         .owner          = &ctx->a,
1831                         .type           = WREPL_TYPE_UNIQUE,
1832                         .state          = WREPL_STATE_ACTIVE,
1833                         .node           = WREPL_NODE_B,
1834                         .is_static      = false,
1835                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1836                         .ips            = addresses_A_1,
1837                         .apply_expected = true
1838                 },
1839                 .r2     = {
1840                         .owner          = &ctx->b,
1841                         .type           = WREPL_TYPE_MHOMED,
1842                         .state          = WREPL_STATE_ACTIVE,
1843                         .node           = WREPL_NODE_B,
1844                         .is_static      = false,
1845                         .num_ips        = ARRAY_SIZE(addresses_B_3_4),
1846                         .ips            = addresses_B_3_4,
1847                         .apply_expected = true
1848                 }
1849         },
1850
1851         /* 
1852          * unique,active vs. mhomed,tombstone
1853          * => should NOT be replaced
1854          */
1855         {
1856                 .line   = __location__,
1857                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1858                 .r1     = {
1859                         .owner          = &ctx->b,
1860                         .type           = WREPL_TYPE_UNIQUE,
1861                         .state          = WREPL_STATE_ACTIVE,
1862                         .node           = WREPL_NODE_B,
1863                         .is_static      = false,
1864                         .num_ips        = ARRAY_SIZE(addresses_B_3_4),
1865                         .ips            = addresses_B_3_4,
1866                         .apply_expected = true
1867                 },
1868                 .r2     = {
1869                         .owner          = &ctx->a,
1870                         .type           = WREPL_TYPE_MHOMED,
1871                         .state          = WREPL_STATE_TOMBSTONE,
1872                         .node           = WREPL_NODE_B,
1873                         .is_static      = false,
1874                         .num_ips        = ARRAY_SIZE(addresses_B_3_4),
1875                         .ips            = addresses_B_3_4,
1876                         .apply_expected = false
1877                 }
1878         },
1879
1880         /* 
1881          * unique,released vs. mhomed,active
1882          * => should be replaced
1883          */
1884         {
1885                 .line   = __location__,
1886                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1887                 .r1     = {
1888                         .owner          = &ctx->b,
1889                         .type           = WREPL_TYPE_UNIQUE,
1890                         .state          = WREPL_STATE_RELEASED,
1891                         .node           = WREPL_NODE_B,
1892                         .is_static      = false,
1893                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1894                         .ips            = addresses_B_1,
1895                         .apply_expected = false
1896                 },
1897                 .r2     = {
1898                         .owner          = &ctx->a,
1899                         .type           = WREPL_TYPE_MHOMED,
1900                         .state          = WREPL_STATE_ACTIVE,
1901                         .node           = WREPL_NODE_B,
1902                         .is_static      = false,
1903                         .num_ips        = ARRAY_SIZE(addresses_A_3_4),
1904                         .ips            = addresses_A_3_4,
1905                         .apply_expected = true
1906                 }
1907         },
1908
1909         /* 
1910          * unique,released vs. mhomed,tombstone
1911          * => should be replaced
1912          */
1913         {
1914                 .line   = __location__,
1915                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1916                 .r1     = {
1917                         .owner          = &ctx->a,
1918                         .type           = WREPL_TYPE_UNIQUE,
1919                         .state          = WREPL_STATE_RELEASED,
1920                         .node           = WREPL_NODE_B,
1921                         .is_static      = false,
1922                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1923                         .ips            = addresses_A_1,
1924                         .apply_expected = false
1925                 },
1926                 .r2     = {
1927                         .owner          = &ctx->b,
1928                         .type           = WREPL_TYPE_MHOMED,
1929                         .state          = WREPL_STATE_TOMBSTONE,
1930                         .node           = WREPL_NODE_B,
1931                         .is_static      = false,
1932                         .num_ips        = ARRAY_SIZE(addresses_B_3_4),
1933                         .ips            = addresses_B_3_4,
1934                         .apply_expected = true
1935                 }
1936         },
1937
1938         /* 
1939          * unique,tombstone vs. mhomed,active
1940          * => should be replaced
1941          */
1942         {
1943                 .line   = __location__,
1944                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1945                 .r1     = {
1946                         .owner          = &ctx->b,
1947                         .type           = WREPL_TYPE_UNIQUE,
1948                         .state          = WREPL_STATE_TOMBSTONE,
1949                         .node           = WREPL_NODE_B,
1950                         .is_static      = false,
1951                         .num_ips        = ARRAY_SIZE(addresses_B_1),
1952                         .ips            = addresses_B_1,
1953                         .apply_expected = true
1954                 },
1955                 .r2     = {
1956                         .owner          = &ctx->a,
1957                         .type           = WREPL_TYPE_MHOMED,
1958                         .state          = WREPL_STATE_ACTIVE,
1959                         .node           = WREPL_NODE_B,
1960                         .is_static      = false,
1961                         .num_ips        = ARRAY_SIZE(addresses_A_3_4),
1962                         .ips            = addresses_A_3_4,
1963                         .apply_expected = true
1964                 }
1965         },
1966
1967         /* 
1968          * unique,tombstone vs. mhomed,tombstone
1969          * => should be replaced
1970          */
1971         {
1972                 .line   = __location__,
1973                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1974                 .r1     = {
1975                         .owner          = &ctx->a,
1976                         .type           = WREPL_TYPE_UNIQUE,
1977                         .state          = WREPL_STATE_TOMBSTONE,
1978                         .node           = WREPL_NODE_B,
1979                         .is_static      = false,
1980                         .num_ips        = ARRAY_SIZE(addresses_A_1),
1981                         .ips            = addresses_A_1,
1982                         .apply_expected = true
1983                 },
1984                 .r2     = {
1985                         .owner          = &ctx->b,
1986                         .type           = WREPL_TYPE_MHOMED,
1987                         .state          = WREPL_STATE_TOMBSTONE,
1988                         .node           = WREPL_NODE_B,
1989                         .is_static      = false,
1990                         .num_ips        = ARRAY_SIZE(addresses_B_3_4),
1991                         .ips            = addresses_B_3_4,
1992                         .apply_expected = true
1993                 }
1994         },
1995
1996 /*
1997  * normal groups vs unique section,
1998  */
1999         /* 
2000          * group,active vs. unique,active
2001          * => should NOT be replaced
2002          */
2003         {
2004                 .line   = __location__,
2005                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2006                 .r1     = {
2007                         .owner          = &ctx->a,
2008                         .type           = WREPL_TYPE_GROUP,
2009                         .state          = WREPL_STATE_ACTIVE,
2010                         .node           = WREPL_NODE_B,
2011                         .is_static      = false,
2012                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2013                         .ips            = addresses_A_1,
2014                         .apply_expected = true
2015                 },
2016                 .r2     = {
2017                         .owner          = &ctx->b,
2018                         .type           = WREPL_TYPE_UNIQUE,
2019                         .state          = WREPL_STATE_ACTIVE,
2020                         .node           = WREPL_NODE_B,
2021                         .is_static      = false,
2022                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2023                         .ips            = addresses_A_1,
2024                         .apply_expected = false
2025                 }
2026         },
2027
2028         /* 
2029          * group,active vs. unique,tombstone
2030          * => should NOT be replaced
2031          */
2032         {
2033                 .line   = __location__,
2034                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2035                 .r1     = {
2036                         .owner          = &ctx->a,
2037                         .type           = WREPL_TYPE_GROUP,
2038                         .state          = WREPL_STATE_ACTIVE,
2039                         .node           = WREPL_NODE_B,
2040                         .is_static      = false,
2041                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2042                         .ips            = addresses_A_1,
2043                         .apply_expected = true
2044                 },
2045                 .r2     = {
2046                         .owner          = &ctx->b,
2047                         .type           = WREPL_TYPE_UNIQUE,
2048                         .state          = WREPL_STATE_TOMBSTONE,
2049                         .node           = WREPL_NODE_B,
2050                         .is_static      = false,
2051                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2052                         .ips            = addresses_A_1,
2053                         .apply_expected = false
2054                 }
2055         },
2056
2057         /* 
2058          * group,released vs. unique,active
2059          * => should NOT be replaced
2060          */
2061         {
2062                 .line   = __location__,
2063                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2064                 .r1     = {
2065                         .owner          = &ctx->a,
2066                         .type           = WREPL_TYPE_GROUP,
2067                         .state          = WREPL_STATE_RELEASED,
2068                         .node           = WREPL_NODE_B,
2069                         .is_static      = false,
2070                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2071                         .ips            = addresses_A_1,
2072                         .apply_expected = false
2073                 },
2074                 .r2     = {
2075                         .owner          = &ctx->b,
2076                         .type           = WREPL_TYPE_UNIQUE,
2077                         .state          = WREPL_STATE_ACTIVE,
2078                         .node           = WREPL_NODE_B,
2079                         .is_static      = false,
2080                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2081                         .ips            = addresses_A_1,
2082                         .apply_expected = false
2083                 }
2084         },
2085
2086         /* 
2087          * group,released vs. unique,tombstone
2088          * => should NOT be replaced
2089          */
2090         {
2091                 .line   = __location__,
2092                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2093                 .r1     = {
2094                         .owner          = &ctx->a,
2095                         .type           = WREPL_TYPE_GROUP,
2096                         .state          = WREPL_STATE_RELEASED,
2097                         .node           = WREPL_NODE_B,
2098                         .is_static      = false,
2099                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2100                         .ips            = addresses_A_1,
2101                         .apply_expected = false
2102                 },
2103                 .r2     = {
2104                         .owner          = &ctx->b,
2105                         .type           = WREPL_TYPE_UNIQUE,
2106                         .state          = WREPL_STATE_TOMBSTONE,
2107                         .node           = WREPL_NODE_B,
2108                         .is_static      = false,
2109                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2110                         .ips            = addresses_A_1,
2111                         .apply_expected = false
2112                 }
2113         },
2114
2115         /* 
2116          * group,tombstone vs. unique,active
2117          * => should NOT be replaced
2118          */
2119         {
2120                 .line   = __location__,
2121                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2122                 .r1     = {
2123                         .owner          = &ctx->a,
2124                         .type           = WREPL_TYPE_GROUP,
2125                         .state          = WREPL_STATE_TOMBSTONE,
2126                         .node           = WREPL_NODE_B,
2127                         .is_static      = false,
2128                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2129                         .ips            = addresses_A_1,
2130                         .apply_expected = true
2131                 },
2132                 .r2     = {
2133                         .owner          = &ctx->b,
2134                         .type           = WREPL_TYPE_UNIQUE,
2135                         .state          = WREPL_STATE_ACTIVE,
2136                         .node           = WREPL_NODE_B,
2137                         .is_static      = false,
2138                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2139                         .ips            = addresses_A_1,
2140                         .apply_expected = false
2141                 }
2142         },
2143
2144         /* 
2145          * group,tombstone vs. unique,tombstone
2146          * => should NOT be replaced
2147          */
2148         {
2149                 .line   = __location__,
2150                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2151                 .r1     = {
2152                         .owner          = &ctx->a,
2153                         .type           = WREPL_TYPE_GROUP,
2154                         .state          = WREPL_STATE_TOMBSTONE,
2155                         .node           = WREPL_NODE_B,
2156                         .is_static      = false,
2157                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2158                         .ips            = addresses_A_1,
2159                         .apply_expected = true
2160                 },
2161                 .r2     = {
2162                         .owner          = &ctx->b,
2163                         .type           = WREPL_TYPE_UNIQUE,
2164                         .state          = WREPL_STATE_TOMBSTONE,
2165                         .node           = WREPL_NODE_B,
2166                         .is_static      = false,
2167                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2168                         .ips            = addresses_A_1,
2169                         .apply_expected = false
2170                 }
2171         },
2172
2173 /*
2174  * normal groups vs normal groups section,
2175  */
2176         /* 
2177          * group,active vs. group,active
2178          * => should NOT be replaced
2179          */
2180         {
2181                 .line   = __location__,
2182                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2183                 .r1     = {
2184                         .owner          = &ctx->a,
2185                         .type           = WREPL_TYPE_GROUP,
2186                         .state          = WREPL_STATE_ACTIVE,
2187                         .node           = WREPL_NODE_B,
2188                         .is_static      = false,
2189                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2190                         .ips            = addresses_A_1,
2191                         .apply_expected = true
2192                 },
2193                 .r2     = {
2194                         .owner          = &ctx->b,
2195                         .type           = WREPL_TYPE_GROUP,
2196                         .state          = WREPL_STATE_ACTIVE,
2197                         .node           = WREPL_NODE_B,
2198                         .is_static      = false,
2199                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2200                         .ips            = addresses_A_1,
2201                         .apply_expected = false
2202                 }
2203         },
2204
2205         /* 
2206          * group,active vs. group,tombstone
2207          * => should NOT be replaced
2208          */
2209         {
2210                 .line   = __location__,
2211                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2212                 .r1     = {
2213                         .owner          = &ctx->a,
2214                         .type           = WREPL_TYPE_GROUP,
2215                         .state          = WREPL_STATE_ACTIVE,
2216                         .node           = WREPL_NODE_B,
2217                         .is_static      = false,
2218                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2219                         .ips            = addresses_A_1,
2220                         .apply_expected = true
2221                 },
2222                 .r2     = {
2223                         .owner          = &ctx->b,
2224                         .type           = WREPL_TYPE_GROUP,
2225                         .state          = WREPL_STATE_TOMBSTONE,
2226                         .node           = WREPL_NODE_B,
2227                         .is_static      = false,
2228                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2229                         .ips            = addresses_A_1,
2230                         .apply_expected = false
2231                 }
2232         },
2233
2234         /* 
2235          * group,released vs. group,active
2236          * => should be replaced
2237          */
2238         {
2239                 .line   = __location__,
2240                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2241                 .r1     = {
2242                         .owner          = &ctx->a,
2243                         .type           = WREPL_TYPE_GROUP,
2244                         .state          = WREPL_STATE_RELEASED,
2245                         .node           = WREPL_NODE_B,
2246                         .is_static      = false,
2247                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2248                         .ips            = addresses_A_1,
2249                         .apply_expected = false
2250                 },
2251                 .r2     = {
2252                         .owner          = &ctx->b,
2253                         .type           = WREPL_TYPE_GROUP,
2254                         .state          = WREPL_STATE_ACTIVE,
2255                         .node           = WREPL_NODE_B,
2256                         .is_static      = false,
2257                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2258                         .ips            = addresses_B_1,
2259                         .apply_expected = true
2260                 }
2261         },
2262
2263         /* 
2264          * group,released vs. group,tombstone
2265          * => should be replaced
2266          */
2267         {
2268                 .line   = __location__,
2269                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2270                 .r1     = {
2271                         .owner          = &ctx->a,
2272                         .type           = WREPL_TYPE_GROUP,
2273                         .state          = WREPL_STATE_RELEASED,
2274                         .node           = WREPL_NODE_B,
2275                         .is_static      = false,
2276                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2277                         .ips            = addresses_A_1,
2278                         .apply_expected = false
2279                 },
2280                 .r2     = {
2281                         .owner          = &ctx->b,
2282                         .type           = WREPL_TYPE_GROUP,
2283                         .state          = WREPL_STATE_TOMBSTONE,
2284                         .node           = WREPL_NODE_B,
2285                         .is_static      = false,
2286                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2287                         .ips            = addresses_B_1,
2288                         .apply_expected = true
2289                 }
2290         },
2291
2292         /* 
2293          * group,tombstone vs. group,active
2294          * => should be replaced
2295          */
2296         {
2297                 .line   = __location__,
2298                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2299                 .r1     = {
2300                         .owner          = &ctx->b,
2301                         .type           = WREPL_TYPE_GROUP,
2302                         .state          = WREPL_STATE_TOMBSTONE,
2303                         .node           = WREPL_NODE_B,
2304                         .is_static      = false,
2305                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2306                         .ips            = addresses_B_1,
2307                         .apply_expected = true
2308                 },
2309                 .r2     = {
2310                         .owner          = &ctx->a,
2311                         .type           = WREPL_TYPE_GROUP,
2312                         .state          = WREPL_STATE_ACTIVE,
2313                         .node           = WREPL_NODE_B,
2314                         .is_static      = false,
2315                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2316                         .ips            = addresses_A_1,
2317                         .apply_expected = true
2318                 }
2319         },
2320
2321         /* 
2322          * group,tombstone vs. group,tombstone
2323          * => should be replaced
2324          */
2325         {
2326                 .line   = __location__,
2327                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2328                 .r1     = {
2329                         .owner          = &ctx->a,
2330                         .type           = WREPL_TYPE_GROUP,
2331                         .state          = WREPL_STATE_TOMBSTONE,
2332                         .node           = WREPL_NODE_B,
2333                         .is_static      = false,
2334                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2335                         .ips            = addresses_A_1,
2336                         .apply_expected = true
2337                 },
2338                 .r2     = {
2339                         .owner          = &ctx->b,
2340                         .type           = WREPL_TYPE_GROUP,
2341                         .state          = WREPL_STATE_TOMBSTONE,
2342                         .node           = WREPL_NODE_B,
2343                         .is_static      = false,
2344                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2345                         .ips            = addresses_B_1,
2346                         .apply_expected = true
2347                 }
2348         },
2349
2350 /*
2351  * normal groups vs special groups section,
2352  */
2353         /* 
2354          * group,active vs. sgroup,active
2355          * => should NOT be replaced
2356          */
2357         {
2358                 .line   = __location__,
2359                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2360                 .r1     = {
2361                         .owner          = &ctx->b,
2362                         .type           = WREPL_TYPE_GROUP,
2363                         .state          = WREPL_STATE_ACTIVE,
2364                         .node           = WREPL_NODE_B,
2365                         .is_static      = false,
2366                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2367                         .ips            = addresses_B_1,
2368                         .apply_expected = true
2369                 },
2370                 .r2     = {
2371                         .owner          = &ctx->a,
2372                         .type           = WREPL_TYPE_SGROUP,
2373                         .state          = WREPL_STATE_ACTIVE,
2374                         .node           = WREPL_NODE_B,
2375                         .is_static      = false,
2376                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2377                         .ips            = addresses_B_1,
2378                         .apply_expected = false
2379                 }
2380         },
2381
2382         /* 
2383          * group,active vs. sgroup,tombstone
2384          * => should NOT be replaced
2385          */
2386         {
2387                 .line   = __location__,
2388                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2389                 .r1     = {
2390                         .owner          = &ctx->b,
2391                         .type           = WREPL_TYPE_GROUP,
2392                         .state          = WREPL_STATE_ACTIVE,
2393                         .node           = WREPL_NODE_B,
2394                         .is_static      = false,
2395                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2396                         .ips            = addresses_B_1,
2397                         .apply_expected = true
2398                 },
2399                 .r2     = {
2400                         .owner          = &ctx->a,
2401                         .type           = WREPL_TYPE_SGROUP,
2402                         .state          = WREPL_STATE_TOMBSTONE,
2403                         .node           = WREPL_NODE_B,
2404                         .is_static      = false,
2405                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2406                         .ips            = addresses_B_1,
2407                         .apply_expected = false
2408                 }
2409         },
2410
2411         /* 
2412          * group,released vs. sgroup,active
2413          * => should be replaced
2414          */
2415         {
2416                 .line   = __location__,
2417                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2418                 .r1     = {
2419                         .owner          = &ctx->a,
2420                         .type           = WREPL_TYPE_GROUP,
2421                         .state          = WREPL_STATE_RELEASED,
2422                         .node           = WREPL_NODE_B,
2423                         .is_static      = false,
2424                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2425                         .ips            = addresses_A_1,
2426                         .apply_expected = false
2427                 },
2428                 .r2     = {
2429                         .owner          = &ctx->b,
2430                         .type           = WREPL_TYPE_SGROUP,
2431                         .state          = WREPL_STATE_ACTIVE,
2432                         .node           = WREPL_NODE_B,
2433                         .is_static      = false,
2434                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2435                         .ips            = addresses_B_1,
2436                         .apply_expected = true
2437                 }
2438         },
2439
2440         /* 
2441          * group,released vs. sgroup,tombstone
2442          * => should NOT be replaced
2443          */
2444         {
2445                 .line   = __location__,
2446                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2447                 .r1     = {
2448                         .owner          = &ctx->b,
2449                         .type           = WREPL_TYPE_GROUP,
2450                         .state          = WREPL_STATE_RELEASED,
2451                         .node           = WREPL_NODE_B,
2452                         .is_static      = false,
2453                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2454                         .ips            = addresses_B_1,
2455                         .apply_expected = false
2456                 },
2457                 .r2     = {
2458                         .owner          = &ctx->a,
2459                         .type           = WREPL_TYPE_SGROUP,
2460                         .state          = WREPL_STATE_TOMBSTONE,
2461                         .node           = WREPL_NODE_B,
2462                         .is_static      = false,
2463                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2464                         .ips            = addresses_B_1,
2465                         .apply_expected = false
2466                 }
2467         },
2468
2469         /* 
2470          * group,tombstone vs. sgroup,active
2471          * => should be replaced
2472          */
2473         {
2474                 .line   = __location__,
2475                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2476                 .r1     = {
2477                         .owner          = &ctx->b,
2478                         .type           = WREPL_TYPE_GROUP,
2479                         .state          = WREPL_STATE_TOMBSTONE,
2480                         .node           = WREPL_NODE_B,
2481                         .is_static      = false,
2482                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2483                         .ips            = addresses_B_1,
2484                         .apply_expected = true
2485                 },
2486                 .r2     = {
2487                         .owner          = &ctx->a,
2488                         .type           = WREPL_TYPE_SGROUP,
2489                         .state          = WREPL_STATE_ACTIVE,
2490                         .node           = WREPL_NODE_B,
2491                         .is_static      = false,
2492                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2493                         .ips            = addresses_A_1,
2494                         .apply_expected = true
2495                 }
2496         },
2497
2498         /* 
2499          * group,tombstone vs. sgroup,tombstone
2500          * => should be replaced
2501          */
2502         {
2503                 .line   = __location__,
2504                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2505                 .r1     = {
2506                         .owner          = &ctx->a,
2507                         .type           = WREPL_TYPE_GROUP,
2508                         .state          = WREPL_STATE_TOMBSTONE,
2509                         .node           = WREPL_NODE_B,
2510                         .is_static      = false,
2511                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2512                         .ips            = addresses_A_1,
2513                         .apply_expected = true
2514                 },
2515                 .r2     = {
2516                         .owner          = &ctx->b,
2517                         .type           = WREPL_TYPE_SGROUP,
2518                         .state          = WREPL_STATE_TOMBSTONE,
2519                         .node           = WREPL_NODE_B,
2520                         .is_static      = false,
2521                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2522                         .ips            = addresses_B_1,
2523                         .apply_expected = true
2524                 }
2525         },
2526
2527 /*
2528  * normal groups vs multi homed section,
2529  */
2530         /* 
2531          * group,active vs. mhomed,active
2532          * => should NOT be replaced
2533          */
2534         {
2535                 .line   = __location__,
2536                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2537                 .r1     = {
2538                         .owner          = &ctx->b,
2539                         .type           = WREPL_TYPE_GROUP,
2540                         .state          = WREPL_STATE_ACTIVE,
2541                         .node           = WREPL_NODE_B,
2542                         .is_static      = false,
2543                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2544                         .ips            = addresses_B_1,
2545                         .apply_expected = true
2546                 },
2547                 .r2     = {
2548                         .owner          = &ctx->a,
2549                         .type           = WREPL_TYPE_MHOMED,
2550                         .state          = WREPL_STATE_ACTIVE,
2551                         .node           = WREPL_NODE_B,
2552                         .is_static      = false,
2553                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2554                         .ips            = addresses_B_1,
2555                         .apply_expected = false
2556                 }
2557         },
2558
2559         /* 
2560          * group,active vs. mhomed,tombstone
2561          * => should NOT be replaced
2562          */
2563         {
2564                 .line   = __location__,
2565                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2566                 .r1     = {
2567                         .owner          = &ctx->b,
2568                         .type           = WREPL_TYPE_GROUP,
2569                         .state          = WREPL_STATE_ACTIVE,
2570                         .node           = WREPL_NODE_B,
2571                         .is_static      = false,
2572                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2573                         .ips            = addresses_B_1,
2574                         .apply_expected = true
2575                 },
2576                 .r2     = {
2577                         .owner          = &ctx->a,
2578                         .type           = WREPL_TYPE_MHOMED,
2579                         .state          = WREPL_STATE_TOMBSTONE,
2580                         .node           = WREPL_NODE_B,
2581                         .is_static      = false,
2582                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2583                         .ips            = addresses_B_1,
2584                         .apply_expected = false
2585                 }
2586         },
2587
2588         /* 
2589          * group,released vs. mhomed,active
2590          * => should NOT be replaced
2591          */
2592         {
2593                 .line   = __location__,
2594                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2595                 .r1     = {
2596                         .owner          = &ctx->b,
2597                         .type           = WREPL_TYPE_GROUP,
2598                         .state          = WREPL_STATE_RELEASED,
2599                         .node           = WREPL_NODE_B,
2600                         .is_static      = false,
2601                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2602                         .ips            = addresses_B_1,
2603                         .apply_expected = false
2604                 },
2605                 .r2     = {
2606                         .owner          = &ctx->a,
2607                         .type           = WREPL_TYPE_MHOMED,
2608                         .state          = WREPL_STATE_ACTIVE,
2609                         .node           = WREPL_NODE_B,
2610                         .is_static      = false,
2611                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2612                         .ips            = addresses_B_1,
2613                         .apply_expected = false
2614                 }
2615         },
2616
2617         /* 
2618          * group,released vs. mhomed,tombstone
2619          * => should NOT be replaced
2620          */
2621         {
2622                 .line   = __location__,
2623                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2624                 .r1     = {
2625                         .owner          = &ctx->b,
2626                         .type           = WREPL_TYPE_GROUP,
2627                         .state          = WREPL_STATE_RELEASED,
2628                         .node           = WREPL_NODE_B,
2629                         .is_static      = false,
2630                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2631                         .ips            = addresses_B_1,
2632                         .apply_expected = false
2633                 },
2634                 .r2     = {
2635                         .owner          = &ctx->a,
2636                         .type           = WREPL_TYPE_MHOMED,
2637                         .state          = WREPL_STATE_TOMBSTONE,
2638                         .node           = WREPL_NODE_B,
2639                         .is_static      = false,
2640                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2641                         .ips            = addresses_B_1,
2642                         .apply_expected = false
2643                 }
2644         },
2645
2646         /* 
2647          * group,tombstone vs. mhomed,active
2648          * => should be replaced
2649          */
2650         {
2651                 .line   = __location__,
2652                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2653                 .r1     = {
2654                         .owner          = &ctx->b,
2655                         .type           = WREPL_TYPE_GROUP,
2656                         .state          = WREPL_STATE_TOMBSTONE,
2657                         .node           = WREPL_NODE_B,
2658                         .is_static      = false,
2659                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2660                         .ips            = addresses_B_1,
2661                         .apply_expected = true
2662                 },
2663                 .r2     = {
2664                         .owner          = &ctx->a,
2665                         .type           = WREPL_TYPE_MHOMED,
2666                         .state          = WREPL_STATE_ACTIVE,
2667                         .node           = WREPL_NODE_B,
2668                         .is_static      = false,
2669                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2670                         .ips            = addresses_A_1,
2671                         .apply_expected = true
2672                 }
2673         },
2674
2675         /* 
2676          * group,tombstone vs. mhomed,tombstone
2677          * => should be replaced
2678          */
2679         {
2680                 .line   = __location__,
2681                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2682                 .r1     = {
2683                         .owner          = &ctx->a,
2684                         .type           = WREPL_TYPE_GROUP,
2685                         .state          = WREPL_STATE_TOMBSTONE,
2686                         .node           = WREPL_NODE_B,
2687                         .is_static      = false,
2688                         .num_ips        = ARRAY_SIZE(addresses_A_1),
2689                         .ips            = addresses_A_1,
2690                         .apply_expected = true
2691                 },
2692                 .r2     = {
2693                         .owner          = &ctx->b,
2694                         .type           = WREPL_TYPE_MHOMED,
2695                         .state          = WREPL_STATE_TOMBSTONE,
2696                         .node           = WREPL_NODE_B,
2697                         .is_static      = false,
2698                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2699                         .ips            = addresses_B_1,
2700                         .apply_expected = true
2701                 }
2702         },
2703
2704 /*
2705  * special groups vs unique section,
2706  */
2707         /* 
2708          * sgroup,active vs. unique,active
2709          * => should NOT be replaced
2710          */
2711         {
2712                 .line   = __location__,
2713                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2714                 .r1     = {
2715                         .owner          = &ctx->b,
2716                         .type           = WREPL_TYPE_SGROUP,
2717                         .state          = WREPL_STATE_ACTIVE,
2718                         .node           = WREPL_NODE_B,
2719                         .is_static      = false,
2720                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2721                         .ips            = addresses_B_1,
2722                         .apply_expected = true
2723                 },
2724                 .r2     = {
2725                         .owner          = &ctx->a,
2726                         .type           = WREPL_TYPE_UNIQUE,
2727                         .state          = WREPL_STATE_ACTIVE,
2728                         .node           = WREPL_NODE_B,
2729                         .is_static      = false,
2730                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2731                         .ips            = addresses_B_1,
2732                         .apply_expected = false
2733                 }
2734         },
2735
2736         /* 
2737          * sgroup,active vs. unique,tombstone
2738          * => should NOT be replaced
2739          */
2740         {
2741                 .line   = __location__,
2742                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2743                 .r1     = {
2744                         .owner          = &ctx->b,
2745                         .type           = WREPL_TYPE_SGROUP,
2746                         .state          = WREPL_STATE_ACTIVE,
2747                         .node           = WREPL_NODE_B,
2748                         .is_static      = false,
2749                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2750                         .ips            = addresses_B_1,
2751                         .apply_expected = true
2752                 },
2753                 .r2     = {
2754                         .owner          = &ctx->a,
2755                         .type           = WREPL_TYPE_UNIQUE,
2756                         .state          = WREPL_STATE_TOMBSTONE,
2757                         .node           = WREPL_NODE_B,
2758                         .is_static      = false,
2759                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2760                         .ips            = addresses_B_1,
2761                         .apply_expected = false
2762                 }
2763         },
2764
2765         /* 
2766          * sgroup,released vs. unique,active
2767          * => should be replaced
2768          */
2769         {
2770                 .line   = __location__,
2771                 .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
2772                 .r1     = {
2773                         .owner          = &ctx->b,
2774                         .type           = WREPL_TYPE_SGROUP,
2775                         .state          = WREPL_STATE_RELEASED,
2776                         .node           = WREPL_NODE_B,
2777                         .is_static      = false,
2778                         .num_ips        = ARRAY_SIZE(addresses_B_1),
2779                         .ips            = addresses_B_1,
2780                         .apply_expected = false
2781                 },
2782                 .r2     = {
2783                         .owner          = &ctx->a,
2784                         .type           = WREPL_TYPE_UNIQUE,
2785                         .state          = WREPL_STATE_ACTIVE,
2786                         .node           = WREPL_NODE_B,
2787                         .is_static      = false,
2788            &n