r15259: try to find the place that causes trouble on some build farm host
[samba.git] / source / torture / nbt / winsreplication.c
index 4af01ac1c94f339ca3f65f692d91f74da751806d..e66d840e4d01d79abe9844e9277bcd6604e55381 100644 (file)
@@ -3,7 +3,8 @@
 
    WINS replication testing
 
-   Copyright (C) Andrew Tridgell 2005
+   Copyright (C) Andrew Tridgell       2005
+   Copyright (C) Stefan Metzmacher     2005
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 */
 
 #include "includes.h"
-#include "libcli/nbt/libnbt.h"
 #include "libcli/wrepl/winsrepl.h"
 #include "lib/events/events.h"
 #include "lib/socket/socket.h"
-#include "system/time.h"
+#include "libcli/resolve/resolve.h"
+#include "system/network.h"
+#include "netif/netif.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "torture/torture.h"
 
 #define CHECK_STATUS(status, correct) do { \
        if (!NT_STATUS_EQUAL(status, correct)) { \
@@ -46,7 +50,7 @@
 #define CHECK_VALUE_UINT64(v, correct) do { \
        if ((v) != (correct)) { \
                printf("(%s) Incorrect value %s=%llu - should be %llu\n", \
-                      __location__, #v, v, correct); \
+                      __location__, #v, (long long)v, (long long)correct); \
                ret = False; \
                goto done; \
        }} while (0)
@@ -102,6 +106,8 @@ static BOOL test_assoc_ctx1(TALLOC_CTX *mem_ctx, const char *address)
        struct wrepl_socket *wrepl_socket2;
        struct wrepl_associate associate2;
        struct wrepl_pull_table pull_table;
+       struct wrepl_packet packet;
+       struct wrepl_send_ctrl ctrl;
        struct wrepl_packet *rep_packet;
        struct wrepl_associate_stop assoc_stop;
        NTSTATUS status;
@@ -136,9 +142,14 @@ static BOOL test_assoc_ctx1(TALLOC_CTX *mem_ctx, const char *address)
        printf("association context (conn2): 0x%x\n", associate2.out.assoc_ctx);
 
        printf("Send a replication table query, with assoc 1 (conn2), the anwser should be on conn1\n");
-       pull_table.in.assoc_ctx = associate1.out.assoc_ctx;
-       req = wrepl_pull_table_send(wrepl_socket2, &pull_table);
-       req->send_only = True;
+       ZERO_STRUCT(packet);
+       packet.opcode                      = WREPL_OPCODE_BITS;
+       packet.assoc_ctx                   = associate1.out.assoc_ctx;
+       packet.mess_type                   = WREPL_REPLICATION;
+       packet.message.replication.command = WREPL_REPL_TABLE_QUERY;
+       ZERO_STRUCT(ctrl);
+       ctrl.send_only = True;
+       req = wrepl_request_send(wrepl_socket2, &packet, &ctrl);
        status = wrepl_request_recv(req, mem_ctx, &rep_packet);
        CHECK_STATUS(status, NT_STATUS_OK);
 
@@ -229,7 +240,7 @@ static void display_entry(TALLOC_CTX *mem_ctx, struct wrepl_name *name)
 
        printf("%s\n", nbt_name_string(mem_ctx, &name->name));
        printf("\tTYPE:%u STATE:%u NODE:%u STATIC:%u VERSION_ID: %llu\n",
-               name->type, name->state, name->node, name->is_static, name->version_id);
+               name->type, name->state, name->node, name->is_static, (long long)name->version_id);
        printf("\tRAW_FLAGS: 0x%08X OWNER: %-15s\n",
                name->raw_flags, name->owner);
        for (i=0;i<name->num_addresses;i++) {
@@ -280,7 +291,7 @@ static BOOL test_wins_replication(TALLOC_CTX *mem_ctx, const char *address)
                packet.mess_type                   = WREPL_STOP_ASSOCIATION;
                packet.message.stop.reason         = 0;
 
-               req = wrepl_request_send(wrepl_socket, &packet);
+               req = wrepl_request_send(wrepl_socket, &packet, NULL);
                talloc_free(req);
 
                printf("failed - We are not a valid pull partner for the server\n");
@@ -295,8 +306,8 @@ static BOOL test_wins_replication(TALLOC_CTX *mem_ctx, const char *address)
                struct wrepl_wins_owner *partner = &pull_table.out.partners[i];
                printf("%s   max_version=%6llu   min_version=%6llu type=%d\n",
                       partner->address, 
-                      partner->max_version, 
-                      partner->min_version, 
+                      (long long)partner->max_version, 
+                      (long long)partner->min_version, 
                       partner->type);
 
                pull_names.in.assoc_ctx = associate.out.assoc_ctx;
@@ -327,11 +338,13 @@ struct test_wrepl_conflict_conn {
 #define TEST_ADDRESS_A_PREFIX "127.0.65"
 #define TEST_OWNER_B_ADDRESS "127.66.66.1"
 #define TEST_ADDRESS_B_PREFIX "127.0.66"
+#define TEST_OWNER_X_ADDRESS "127.88.88.1"
+#define TEST_ADDRESS_X_PREFIX "127.0.88"
 
-       struct wrepl_wins_owner a, b, c;
+       struct wrepl_wins_owner a, b, c, x;
 
-       const char *myaddr;
-       const char *myaddr2;
+       struct socket_address *myaddr;
+       struct socket_address *myaddr2;
        struct nbt_name_socket *nbtsock;
        struct nbt_name_socket *nbtsock2;
 
@@ -373,6 +386,89 @@ static const struct wrepl_ip addresses_A_3_4[] = {
        .ip     = TEST_ADDRESS_A_PREFIX".4"
        }
 };
+static const struct wrepl_ip addresses_A_3_4_X_3_4[] = {
+       {
+       .owner  = TEST_OWNER_A_ADDRESS,
+       .ip     = TEST_ADDRESS_A_PREFIX".3"
+       },
+       {
+       .owner  = TEST_OWNER_A_ADDRESS,
+       .ip     = TEST_ADDRESS_A_PREFIX".4"
+       },
+       {
+       .owner  = TEST_OWNER_X_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".3"
+       },
+       {
+       .owner  = TEST_OWNER_X_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".4"
+       }
+};
+static const struct wrepl_ip addresses_A_3_4_B_3_4[] = {
+       {
+       .owner  = TEST_OWNER_A_ADDRESS,
+       .ip     = TEST_ADDRESS_A_PREFIX".3"
+       },
+       {
+       .owner  = TEST_OWNER_A_ADDRESS,
+       .ip     = TEST_ADDRESS_A_PREFIX".4"
+       },
+       {
+       .owner  = TEST_OWNER_B_ADDRESS,
+       .ip     = TEST_ADDRESS_B_PREFIX".3"
+       },
+       {
+       .owner  = TEST_OWNER_B_ADDRESS,
+       .ip     = TEST_ADDRESS_B_PREFIX".4"
+       }
+};
+static const struct wrepl_ip addresses_A_3_4_OWNER_B[] = {
+       {
+       .owner  = TEST_OWNER_B_ADDRESS,
+       .ip     = TEST_ADDRESS_A_PREFIX".3"
+       },
+       {
+       .owner  = TEST_OWNER_B_ADDRESS,
+       .ip     = TEST_ADDRESS_A_PREFIX".4"
+       }
+};
+static const struct wrepl_ip addresses_A_3_4_X_3_4_OWNER_B[] = {
+       {
+       .owner  = TEST_OWNER_B_ADDRESS,
+       .ip     = TEST_ADDRESS_A_PREFIX".3"
+       },
+       {
+       .owner  = TEST_OWNER_B_ADDRESS,
+       .ip     = TEST_ADDRESS_A_PREFIX".4"
+       },
+       {
+       .owner  = TEST_OWNER_B_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".3"
+       },
+       {
+       .owner  = TEST_OWNER_B_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".4"
+       }
+};
+
+static const struct wrepl_ip addresses_A_3_4_X_1_2[] = {
+       {
+       .owner  = TEST_OWNER_A_ADDRESS,
+       .ip     = TEST_ADDRESS_A_PREFIX".3"
+       },
+       {
+       .owner  = TEST_OWNER_A_ADDRESS,
+       .ip     = TEST_ADDRESS_A_PREFIX".4"
+       },
+       {
+       .owner  = TEST_OWNER_X_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".1"
+       },
+       {
+       .owner  = TEST_OWNER_X_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".2"
+       }
+};
 
 static const struct wrepl_ip addresses_B_1[] = {
        {
@@ -396,6 +492,63 @@ static const struct wrepl_ip addresses_B_3_4[] = {
        .ip     = TEST_ADDRESS_B_PREFIX".4"
        }
 };
+static const struct wrepl_ip addresses_B_3_4_X_3_4[] = {
+       {
+       .owner  = TEST_OWNER_B_ADDRESS,
+       .ip     = TEST_ADDRESS_B_PREFIX".3"
+       },
+       {
+       .owner  = TEST_OWNER_B_ADDRESS,
+       .ip     = TEST_ADDRESS_B_PREFIX".4"
+       },
+       {
+       .owner  = TEST_OWNER_X_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".3"
+       },
+       {
+       .owner  = TEST_OWNER_X_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".4"
+       }
+};
+static const struct wrepl_ip addresses_B_3_4_X_1_2[] = {
+       {
+       .owner  = TEST_OWNER_B_ADDRESS,
+       .ip     = TEST_ADDRESS_B_PREFIX".3"
+       },
+       {
+       .owner  = TEST_OWNER_B_ADDRESS,
+       .ip     = TEST_ADDRESS_B_PREFIX".4"
+       },
+       {
+       .owner  = TEST_OWNER_X_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".1"
+       },
+       {
+       .owner  = TEST_OWNER_X_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".2"
+       }
+};
+
+static const struct wrepl_ip addresses_X_1_2[] = {
+       {
+       .owner  = TEST_OWNER_X_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".1"
+       },
+       {
+       .owner  = TEST_OWNER_X_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".2"
+       }
+};
+static const struct wrepl_ip addresses_X_3_4[] = {
+       {
+       .owner  = TEST_OWNER_X_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".3"
+       },
+       {
+       .owner  = TEST_OWNER_X_ADDRESS,
+       .ip     = TEST_ADDRESS_X_PREFIX".4"
+       }
+};
 
 static struct test_wrepl_conflict_conn *test_create_conflict_ctx(TALLOC_CTX *mem_ctx,
                                                                 const char *address)
@@ -403,6 +556,7 @@ static struct test_wrepl_conflict_conn *test_create_conflict_ctx(TALLOC_CTX *mem
        struct test_wrepl_conflict_conn *ctx;
        struct wrepl_associate associate;
        struct wrepl_pull_table pull_table;
+       struct socket_address *nbt_srv_addr;
        NTSTATUS status;
        uint32_t i;
 
@@ -432,6 +586,11 @@ static struct test_wrepl_conflict_conn *test_create_conflict_ctx(TALLOC_CTX *mem
        ctx->b.min_version      = 0;
        ctx->b.type             = 1;
 
+       ctx->x.address          = TEST_OWNER_X_ADDRESS;
+       ctx->x.max_version      = 0;
+       ctx->x.min_version      = 0;
+       ctx->x.type             = 1;
+
        ctx->c.address          = address;
        ctx->c.max_version      = 0;
        ctx->c.min_version      = 0;
@@ -450,6 +609,10 @@ static struct test_wrepl_conflict_conn *test_create_conflict_ctx(TALLOC_CTX *mem
                        ctx->b.max_version      = pull_table.out.partners[i].max_version;
                        ctx->b.min_version      = pull_table.out.partners[i].min_version;
                }
+               if (strcmp(TEST_OWNER_X_ADDRESS,pull_table.out.partners[i].address)==0) {
+                       ctx->x.max_version      = pull_table.out.partners[i].max_version;
+                       ctx->x.min_version      = pull_table.out.partners[i].min_version;
+               }
                if (strcmp(address,pull_table.out.partners[i].address)==0) {
                        ctx->c.max_version      = pull_table.out.partners[i].max_version;
                        ctx->c.min_version      = pull_table.out.partners[i].min_version;
@@ -458,43 +621,59 @@ static struct test_wrepl_conflict_conn *test_create_conflict_ctx(TALLOC_CTX *mem
 
        talloc_free(pull_table.out.partners);
 
-       ctx->myaddr = talloc_strdup(mem_ctx, iface_best_ip(address));
+       ctx->nbtsock = nbt_name_socket_init(ctx, NULL);
+       if (!ctx->nbtsock) return NULL;
+
+       ctx->myaddr = socket_address_from_strings(mem_ctx, ctx->nbtsock->sock->backend_name, iface_best_ip(address), 0);
        if (!ctx->myaddr) return NULL;
 
        for (i = 0; i < iface_count(); i++) {
-               if (strcmp(ctx->myaddr, iface_n_ip(i)) == 0) continue;
-               ctx->myaddr2 = talloc_strdup(mem_ctx, iface_n_ip(i));
+               if (strcmp(ctx->myaddr->addr, iface_n_ip(i)) == 0) continue;
+               ctx->myaddr2 = socket_address_from_strings(mem_ctx, ctx->nbtsock->sock->backend_name, iface_n_ip(i), 0);
                if (!ctx->myaddr2) return NULL;
                break;
        }
 
-       ctx->nbtsock = nbt_name_socket_init(ctx, NULL);
-       if (!ctx->nbtsock) return NULL;
-
-       status = socket_listen(ctx->nbtsock->sock, ctx->myaddr, 0, 0, 0);
+       status = socket_listen(ctx->nbtsock->sock, ctx->myaddr, 0, 0);
        if (!NT_STATUS_IS_OK(status)) return NULL;
 
        ctx->nbtsock_srv = nbt_name_socket_init(ctx, NULL);
        if (!ctx->nbtsock_srv) return NULL;
 
-       status = socket_listen(ctx->nbtsock_srv->sock, ctx->myaddr, lp_nbt_port(), 0, 0);
+       /* Make a port 137 version of ctx->myaddr */
+       nbt_srv_addr = socket_address_from_strings(mem_ctx, ctx->nbtsock_srv->sock->backend_name, ctx->myaddr->addr, lp_nbt_port());
+       if (!nbt_srv_addr) return NULL;
+
+       /* And if possible, bind to it.  This won't work unless we are root or in sockewrapper */
+       status = socket_listen(ctx->nbtsock_srv->sock, nbt_srv_addr, 0, 0);
+       talloc_free(nbt_srv_addr);
        if (!NT_STATUS_IS_OK(status)) {
+               /* this isn't fatal */
                talloc_free(ctx->nbtsock_srv);
                ctx->nbtsock_srv = NULL;
        }
 
-       if (ctx->myaddr2) {
+       if (ctx->myaddr2 && ctx->nbtsock_srv) {
                ctx->nbtsock2 = nbt_name_socket_init(ctx, NULL);
                if (!ctx->nbtsock2) return NULL;
 
-               status = socket_listen(ctx->nbtsock2->sock, ctx->myaddr2, 0, 0, 0);
+               status = socket_listen(ctx->nbtsock2->sock, ctx->myaddr2, 0, 0);
                if (!NT_STATUS_IS_OK(status)) return NULL;
 
                ctx->nbtsock_srv2 = nbt_name_socket_init(ctx, ctx->nbtsock_srv->event_ctx);
                if (!ctx->nbtsock_srv2) return NULL;
 
-               status = socket_listen(ctx->nbtsock_srv2->sock, ctx->myaddr2, lp_nbt_port(), 0, 0);
+               /* Make a port 137 version of ctx->myaddr2 */
+               nbt_srv_addr = socket_address_from_strings(mem_ctx, 
+                                                          ctx->nbtsock_srv->sock->backend_name, 
+                                                          ctx->myaddr2->addr, lp_nbt_port());
+               if (!nbt_srv_addr) return NULL;
+
+               /* And if possible, bind to it.  This won't work unless we are root or in sockewrapper */
+               status = socket_listen(ctx->nbtsock_srv2->sock, ctx->myaddr2, 0, 0);
+               talloc_free(nbt_srv_addr);
                if (!NT_STATUS_IS_OK(status)) {
+                       /* this isn't fatal */
                        talloc_free(ctx->nbtsock_srv2);
                        ctx->nbtsock_srv2 = NULL;
                }
@@ -504,7 +683,7 @@ static struct test_wrepl_conflict_conn *test_create_conflict_ctx(TALLOC_CTX *mem
        ctx->addresses_best = talloc_array(ctx, struct wrepl_ip, ctx->addresses_best_num);
        if (!ctx->addresses_best) return NULL;
        ctx->addresses_best[0].owner    = ctx->b.address;
-       ctx->addresses_best[0].ip       = ctx->myaddr;
+       ctx->addresses_best[0].ip       = ctx->myaddr->addr;
 
        ctx->addresses_all_num = iface_count();
        ctx->addresses_all = talloc_array(ctx, struct wrepl_ip, ctx->addresses_all_num);
@@ -520,15 +699,15 @@ static struct test_wrepl_conflict_conn *test_create_conflict_ctx(TALLOC_CTX *mem
                ctx->addresses_best2 = talloc_array(ctx, struct wrepl_ip, ctx->addresses_best2_num);
                if (!ctx->addresses_best2) return NULL;
                ctx->addresses_best2[0].owner   = ctx->b.address;
-               ctx->addresses_best2[0].ip      = ctx->myaddr2;
+               ctx->addresses_best2[0].ip      = ctx->myaddr2->addr;
 
                ctx->addresses_mhomed_num = 2;
                ctx->addresses_mhomed = talloc_array(ctx, struct wrepl_ip, ctx->addresses_mhomed_num);
                if (!ctx->addresses_mhomed) return NULL;
                ctx->addresses_mhomed[0].owner  = ctx->b.address;
-               ctx->addresses_mhomed[0].ip     = ctx->myaddr;
+               ctx->addresses_mhomed[0].ip     = ctx->myaddr->addr;
                ctx->addresses_mhomed[1].owner  = ctx->b.address;
-               ctx->addresses_mhomed[1].ip     = ctx->myaddr2;
+               ctx->addresses_mhomed[1].ip     = ctx->myaddr2->addr;
        }
 
        return ctx;
@@ -604,80 +783,6 @@ done:
        return ret;
 }
 
-#if 0
-static BOOL test_wrepl_update_two(struct test_wrepl_conflict_conn *ctx,
-                                 const struct wrepl_wins_owner *owner,
-                                 const struct wrepl_wins_name *name1,
-                                 const struct wrepl_wins_name *name2)
-{
-       BOOL ret = True;
-       struct wrepl_socket *wrepl_socket;
-       struct wrepl_associate associate;
-       struct wrepl_packet update_packet, repl_send;
-       struct wrepl_table *update;
-       struct wrepl_wins_owner wrepl_wins_owners[1];
-       struct wrepl_packet *repl_recv;
-       struct wrepl_wins_owner *send_request;
-       struct wrepl_send_reply *send_reply;
-       struct wrepl_wins_name wrepl_wins_names[2];
-       uint32_t assoc_ctx;
-       NTSTATUS status;
-
-       wrepl_socket = wrepl_socket_init(ctx, NULL);
-
-       status = wrepl_connect(wrepl_socket, NULL, ctx->address);
-       CHECK_STATUS(status, NT_STATUS_OK);
-
-       status = wrepl_associate(wrepl_socket, &associate);
-       CHECK_STATUS(status, NT_STATUS_OK);
-       assoc_ctx = associate.out.assoc_ctx;
-
-       /* now send a WREPL_REPL_UPDATE message */
-       ZERO_STRUCT(update_packet);
-       update_packet.opcode                    = WREPL_OPCODE_BITS;
-       update_packet.assoc_ctx                 = assoc_ctx;
-       update_packet.mess_type                 = WREPL_REPLICATION;
-       update_packet.message.replication.command       = WREPL_REPL_UPDATE;
-       update  = &update_packet.message.replication.info.table;
-
-       update->partner_count   = ARRAY_SIZE(wrepl_wins_owners);
-       update->partners        = wrepl_wins_owners;
-       update->initiator       = "0.0.0.0";
-
-       wrepl_wins_owners[0]    = *owner;
-
-       status = wrepl_request(wrepl_socket, wrepl_socket,
-                              &update_packet, &repl_recv);
-       CHECK_STATUS(status, NT_STATUS_OK);
-       CHECK_VALUE(repl_recv->mess_type, WREPL_REPLICATION);
-       CHECK_VALUE(repl_recv->message.replication.command, WREPL_REPL_SEND_REQUEST);
-       send_request = &repl_recv->message.replication.info.owner;
-
-       ZERO_STRUCT(repl_send);
-       repl_send.opcode                        = WREPL_OPCODE_BITS;
-       repl_send.assoc_ctx                     = assoc_ctx;
-       repl_send.mess_type                     = WREPL_REPLICATION;
-       repl_send.message.replication.command   = WREPL_REPL_SEND_REPLY;
-       send_reply = &repl_send.message.replication.info.reply;
-
-       send_reply->num_names   = ARRAY_SIZE(wrepl_wins_names);
-       send_reply->names       = wrepl_wins_names;
-
-       wrepl_wins_names[0]     = *name1;
-       wrepl_wins_names[1]     = *name2;
-
-       status = wrepl_request(wrepl_socket, wrepl_socket,
-                              &repl_send, &repl_recv);
-       CHECK_STATUS(status, NT_STATUS_OK);
-       CHECK_VALUE(repl_recv->mess_type, WREPL_STOP_ASSOCIATION);
-       CHECK_VALUE(repl_recv->message.stop.reason, 0);
-
-done:
-       talloc_free(wrepl_socket);
-       return ret;
-}
-#endif
-
 static BOOL test_wrepl_is_applied(struct test_wrepl_conflict_conn *ctx,
                                  const struct wrepl_wins_owner *owner,
                                  const struct wrepl_wins_name *name,
@@ -801,44 +906,114 @@ done:
        return ret;
 }
 
-static BOOL test_wrepl_is_merged(struct test_wrepl_conflict_conn *ctx,
-                                const struct wrepl_wins_name *name1,
-                                const struct wrepl_wins_name *name2)
+static BOOL test_wrepl_sgroup_merged(struct test_wrepl_conflict_conn *ctx,
+                                    struct wrepl_wins_owner *merge_owner,
+                                    struct wrepl_wins_owner *owner1,
+                                    uint32_t num_ips1, const struct wrepl_ip *ips1,
+                                    struct wrepl_wins_owner *owner2,
+                                    uint32_t num_ips2, const struct wrepl_ip *ips2,
+                                    const struct wrepl_wins_name *name2)
 {
-       return True;
-#if 0
        BOOL ret = True;
        NTSTATUS status;
        struct wrepl_pull_names pull_names;
        struct wrepl_name *names;
-       uint32_t num_ips;
+       struct wrepl_name *name = NULL;
+       uint32_t flags;
+       uint32_t i, j;
+       uint32_t num_ips = num_ips1 + num_ips2;
+
+       if (!merge_owner) {
+               merge_owner = &ctx->c;
+       }
+
+       for (i = 0; i < num_ips1; i++) {
+               if (owner1 != &ctx->c && strcmp(ips1[i].owner,owner2->address) == 0) {
+                       num_ips--;
+                       continue;
+               }
+               for (j = 0; j < num_ips2; j++) {
+                       if (strcmp(ips1[i].ip,ips2[j].ip) == 0) {
+                               num_ips--;
+                               break;
+                       }
+               }
+       }
+
 
        pull_names.in.assoc_ctx = ctx->pull_assoc;
-       pull_names.in.partner   = ctx->c;
-       pull_names.in.partner.min_version = ctx->c.max_version-1;
+       pull_names.in.partner   = *merge_owner;
+       pull_names.in.partner.min_version = pull_names.in.partner.max_version;
+       pull_names.in.partner.max_version = 0;
 
        status = wrepl_pull_names(ctx->pull, ctx->pull, &pull_names);
        CHECK_STATUS(status, NT_STATUS_OK);
-       CHECK_VALUE(pull_names.out.num_names, 1);
 
        names = pull_names.out.names;
+       
+       for (i = 0; i < pull_names.out.num_names; i++) {
+               if (names[i].name.type != name2->name->type)    continue;
+               if (!names[i].name.name) continue;
+               if (strcmp(names[i].name.name, name2->name->name) != 0) continue;
+               if (names[i].name.scope) continue;
+
+               name = &names[i];
+       }
+
+       if (pull_names.out.num_names > 0) {
+               merge_owner->max_version        = names[pull_names.out.num_names-1].version_id;
+       }
+
+       if (!name) {
+               printf("%s: Name '%s' not found\n", __location__, nbt_name_string(ctx, name2->name));
+               return False;
+       }
+
+       flags = WREPL_NAME_FLAGS(name->type,
+                                name->state,
+                                name->node,
+                                name->is_static);
+       CHECK_VALUE(name->name.type, name2->name->type);
+       CHECK_VALUE_STRING(name->name.name, name2->name->name);
+       CHECK_VALUE_STRING(name->name.scope, name2->name->scope);
+       CHECK_VALUE(flags, name2->flags);
+
+       CHECK_VALUE(name->num_addresses, num_ips);
+
+       for (i = 0; i < name->num_addresses; i++) {
+               const char *addr = name->addresses[i].address; 
+               const char *owner = name->addresses[i].owner;
+               BOOL found = False;
+
+               for (j = 0; j < num_ips2; j++) {
+                       if (strcmp(addr, ips2[j].ip) == 0) {
+                               found = True;
+                               CHECK_VALUE_STRING(owner, ips2[j].owner);
+                               break;
+                       }
+               }
+
+               if (found) continue;
 
-       num_ips = name1->addresses.addresses.num_ips + name2->addresses.addresses.num_ips;
+               for (j = 0; j < num_ips1; j++) {
+                       if (strcmp(addr, ips1[j].ip) == 0) {
+                               found = True;
+                               if (owner1 == &ctx->c) {
+                                       CHECK_VALUE_STRING(owner, owner1->address);
+                               } else {
+                                       CHECK_VALUE_STRING(owner, ips1[j].owner);
+                               }
+                               break;
+                       }
+               }
 
-       CHECK_VALUE(names[0].name.type, name1->name->type);
-       CHECK_VALUE_STRING(names[0].name.name, name1->name->name);
-       CHECK_VALUE_STRING(names[0].name.scope, name1->name->scope);
-       CHECK_VALUE(names[0].type, WREPL_TYPE_SGROUP);
-       CHECK_VALUE(names[0].state, (num_ips>0?WREPL_STATE_ACTIVE:WREPL_STATE_RELEASED));
-       CHECK_VALUE_UINT64(names[0].version_id, ctx->c.max_version);
+               if (found) continue;
 
-       CHECK_VALUE(names[0].num_addresses,
-                   name1->addresses.addresses.num_ips+
-                   name2->addresses.addresses.num_ips);
+               CHECK_VALUE_STRING(addr, "not found in address list");
+       }
 done:
        talloc_free(pull_names.out.names);
        return ret;
-#endif
 }
 
 static BOOL test_conflict_same_owner(struct test_wrepl_conflict_conn *ctx)
@@ -948,8 +1123,6 @@ static BOOL test_conflict_same_owner(struct test_wrepl_conflict_conn *ctx)
                }
        };
 
-       if (!ctx) return False;
-
        name.name       = "_SAME_OWNER_A";
        name.type       = 0;
        name.scope      = NULL;
@@ -1025,6 +1198,7 @@ static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
        struct {
                const char *line; /* just better debugging */
                struct nbt_name name;
+               const char *comment;
                BOOL extra; /* not the worst case, this is an extra test */
                BOOL cleanup;
                struct {
@@ -1036,7 +1210,9 @@ static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
                        uint32_t num_ips;
                        const struct wrepl_ip *ips;
                        BOOL apply_expected;
-                       BOOL merge_expected;
+                       BOOL sgroup_merge;
+                       struct wrepl_wins_owner *merge_owner;
+                       BOOL sgroup_cleanup;
                } r1, r2;
        } records[] = {
        /* 
@@ -2842,11 +3018,11 @@ static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
        },
 
 /*
- * special groups vs multi homed section,
+ * special groups (not active) vs special group section,
  */
        /* 
-        * sgroup,active vs. mhomed,active
-        * => should NOT be replaced
+        * sgroup,released vs. sgroup,active
+        * => should be replaced
         */
        {
                .line   = __location__,
@@ -2854,34 +3030,153 @@ static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
                .r1     = {
                        .owner          = &ctx->a,
                        .type           = WREPL_TYPE_SGROUP,
-                       .state          = WREPL_STATE_ACTIVE,
+                       .state          = WREPL_STATE_RELEASED,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
                        .num_ips        = ARRAY_SIZE(addresses_A_1),
                        .ips            = addresses_A_1,
-                       .apply_expected = True
+                       .apply_expected = False
                },
                .r2     = {
                        .owner          = &ctx->b,
-                       .type           = WREPL_TYPE_MHOMED,
+                       .type           = WREPL_TYPE_SGROUP,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_A_1),
-                       .ips            = addresses_A_1,
-                       .apply_expected = False
+                       .num_ips        = ARRAY_SIZE(addresses_B_1),
+                       .ips            = addresses_B_1,
+                       .apply_expected = True
                }
        },
 
        /* 
-        * sgroup,active vs. mhomed,tombstone
-        * => should NOT be replaced
+        * sgroup,released vs. sgroup,tombstone
+        * => should be replaced
         */
        {
                .line   = __location__,
                .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
                .r1     = {
-                       .owner          = &ctx->a,
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_RELEASED,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_1),
+                       .ips            = addresses_B_1,
+                       .apply_expected = False
+               },
+               .r2     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_1),
+                       .ips            = addresses_A_1,
+                       .apply_expected = True
+               }
+       },
+
+       /* 
+        * sgroup,tombstone vs. sgroup,active
+        * => should NOT be replaced
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_1),
+                       .ips            = addresses_A_1,
+                       .apply_expected = True
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_1),
+                       .ips            = addresses_B_1,
+                       .apply_expected = True
+               }
+       },
+
+       /* 
+        * sgroup,tombstone vs. sgroup,tombstone
+        * => should NOT be replaced
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .r1     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_1),
+                       .ips            = addresses_B_1,
+                       .apply_expected = True
+               },
+               .r2     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_1),
+                       .ips            = addresses_A_1,
+                       .apply_expected = True
+               }
+       },
+
+/*
+ * special groups vs multi homed section,
+ */
+       /* 
+        * sgroup,active vs. mhomed,active
+        * => should NOT be replaced
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_1),
+                       .ips            = addresses_A_1,
+                       .apply_expected = True
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_MHOMED,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_1),
+                       .ips            = addresses_A_1,
+                       .apply_expected = False
+               }
+       },
+
+       /* 
+        * sgroup,active vs. mhomed,tombstone
+        * => should NOT be replaced
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .r1     = {
+                       .owner          = &ctx->a,
                        .type           = WREPL_TYPE_SGROUP,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
@@ -3725,18 +4020,73 @@ static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
                        .apply_expected = True
                }
        },
-
-#if 0
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .cleanup= True,
+               .r1     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_UNIQUE,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_1),
+                       .ips            = addresses_B_1,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_UNIQUE,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_1),
+                       .ips            = addresses_A_1,
+                       .apply_expected = True,
+               }
+       },
 /*
  * special group vs special group section,
  */
        /* 
-        * sgroup,active vs. sgroup,active
-        * => should be merged
+        * sgroup,active vs. sgroup,active same addresses
+        * => should be NOT replaced
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:A_3_4 vs. B:A_3_4",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4),
+                       .ips            = addresses_A_3_4,
+                       .apply_expected = True
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4),
+                       .ips            = addresses_A_3_4,
+                       .apply_expected = False,
+                       .sgroup_cleanup = True
+               }
+       },
+       /* 
+        * sgroup,active vs. sgroup,active same addresses
+        * => should be NOT replaced
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_DIFF_OWNER_SG", 0x00, NULL),
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:A_3_4 vs. B:NULL",
                .extra  = True,
                .r1     = {
                        .owner          = &ctx->a,
@@ -3746,6 +4096,37 @@ static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
                        .is_static      = False,
                        .num_ips        = ARRAY_SIZE(addresses_A_3_4),
                        .ips            = addresses_A_3_4,
+                       .apply_expected = True
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = 0,
+                       .ips            = NULL,
+                       .apply_expected = False,
+                       .sgroup_cleanup = True
+               }
+       },
+       /* 
+        * sgroup,active vs. sgroup,active subset addresses, special case...
+        * => should NOT be replaced
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:A_3_4_X_3_4 vs. B:A_3_4",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4_X_3_4),
+                       .ips            = addresses_A_3_4_X_3_4,
                        .apply_expected = True,
                },
                .r2     = {
@@ -3754,15 +4135,14 @@ static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
-                       .ips            = addresses_B_3_4,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4),
+                       .ips            = addresses_A_3_4,
                        .apply_expected = False,
-                       .merge_expected = True
                }
        },
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_DIFF_OWNER_SG", 0x00, NULL),
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
                .cleanup= True,
                .r1     = {
                        .owner          = &ctx->a,
@@ -3772,10 +4152,10 @@ static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
                        .is_static      = False,
                        .num_ips        = 0,
                        .ips            = NULL,
-                       .apply_expected = False
+                       .apply_expected = False,
                },
                .r2     = {
-                       .owner          = &ctx->b,
+                       .owner          = &ctx->x,
                        .type           = WREPL_TYPE_SGROUP,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
@@ -3783,75 +4163,631 @@ static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
                        .num_ips        = 0,
                        .ips            = NULL,
                        .apply_expected = False,
-                       .merge_expected = False
                }
        },
+       /* 
+        * sgroup,active vs. sgroup,active different addresses, but owner changed
+        * => should be replaced
+        */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_DIFF_OWNER_SG", 0x00, NULL),
-               .cleanup= True,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:B_3_4 vs. B:A_3_4",
+               .extra  = True,
                .r1     = {
                        .owner          = &ctx->a,
                        .type           = WREPL_TYPE_SGROUP,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_A_1),
-                       .ips            = addresses_A_1,
-                       .apply_expected = True
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
+                       .ips            = addresses_B_3_4,
+                       .apply_expected = True,
                },
                .r2     = {
-                       .owner          = &ctx->a,
-                       .type           = WREPL_TYPE_UNIQUE,
-                       .state          = WREPL_STATE_TOMBSTONE,
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_A_1),
-                       .ips            = addresses_A_1,
-                       .apply_expected = True
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4),
+                       .ips            = addresses_A_3_4,
+                       .apply_expected = True,
+                       .sgroup_cleanup = True
                }
        },
-#endif
        /* 
-        * This should be the last record in this array,
-        * we need to make sure the we leave a tombstoned unique entry
-        * owned by OWNER_A
+        * sgroup,active vs. sgroup,active different addresses, but owner changed
+        * => should be replaced
         */
        {
                .line   = __location__,
                .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
-               .cleanup= True,
+               .comment= "A:A_3_4 vs. B:A_3_4_OWNER_B",
+               .extra  = True,
                .r1     = {
-                       .owner          = &ctx->b,
-                       .type           = WREPL_TYPE_UNIQUE,
-                       .state          = WREPL_STATE_TOMBSTONE,
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_A_1),
-                       .ips            = addresses_A_1,
-                       .apply_expected = True
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4),
+                       .ips            = addresses_A_3_4,
+                       .apply_expected = True,
                },
                .r2     = {
-                       .owner          = &ctx->a,
-                       .type           = WREPL_TYPE_UNIQUE,
-                       .state          = WREPL_STATE_TOMBSTONE,
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_A_1),
-                       .ips            = addresses_A_1,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4_OWNER_B),
+                       .ips            = addresses_A_3_4_OWNER_B,
+                       .apply_expected = True,
+                       .sgroup_cleanup = True
+               }
+       },
+       /* 
+        * sgroup,active vs. sgroup,active different addresses, but owner changed
+        * => should be replaced
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:A_3_4_OWNER_B vs. B:A_3_4",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4_OWNER_B),
+                       .ips            = addresses_A_3_4_OWNER_B,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4),
+                       .ips            = addresses_A_3_4,
+                       .apply_expected = True,
+                       .sgroup_cleanup = True
+               }
+       },
+       /* 
+        * sgroup,active vs. sgroup,active different addresses
+        * => should be merged
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4),
+                       .ips            = addresses_A_3_4,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
+                       .ips            = addresses_B_3_4,
+                       .sgroup_merge   = True,
+                       .sgroup_cleanup = True,
+               }
+       },
+       /* 
+        * sgroup,active vs. sgroup,active different addresses, special case...
+        * => should be merged
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4_X_3_4",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+                       .ips            = addresses_B_3_4_X_3_4,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4),
+                       .ips            = addresses_A_3_4,
+                       .sgroup_merge   = True,
+                       .merge_owner    = &ctx->b,
+                       .sgroup_cleanup = False
+               }
+       },
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .cleanup= True,
+               .r1     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4_X_3_4_OWNER_B),
+                       .ips            = addresses_A_3_4_X_3_4_OWNER_B,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = 0,
+                       .ips            = NULL,
+                       .apply_expected = False,
+               }
+       },
+       /* 
+        * sgroup,active vs. sgroup,active different addresses, special case...
+        * => should be merged
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_X_3_4),
+                       .ips            = addresses_X_3_4,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4),
+                       .ips            = addresses_A_3_4,
+                       .sgroup_merge   = True,
+                       .sgroup_cleanup = False
+               }
+       },
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .cleanup= True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = 0,
+                       .ips            = NULL,
+                       .apply_expected = False,
+               },
+               .r2     = {
+                       .owner          = &ctx->x,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = 0,
+                       .ips            = NULL,
+                       .apply_expected = False,
+               }
+       },
+       /* 
+        * sgroup,active vs. sgroup,active different addresses, special case...
+        * => should be merged
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:A_3_4_X_3_4 vs. B:A_3_4_OWNER_B => B:A_3_4_OWNER_B_X_3_4",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4_X_3_4),
+                       .ips            = addresses_A_3_4_X_3_4,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4_OWNER_B),
+                       .ips            = addresses_A_3_4_OWNER_B,
+                       .sgroup_merge   = True,
+                       .merge_owner    = &ctx->b,
+               }
+       },
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .cleanup= True,
+               .r1     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = 0,
+                       .ips            = NULL,
+                       .apply_expected = False,
+               },
+               .r2     = {
+                       .owner          = &ctx->x,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = 0,
+                       .ips            = NULL,
+                       .apply_expected = False,
+               }
+       },
+       /* 
+        * sgroup,active vs. sgroup,active partly different addresses, special case...
+        * => should be merged
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:B_3_4_X_3_4 vs. B:B_3_4_X_1_2 => C:B_3_4_X_1_2_3_4",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+                       .ips            = addresses_B_3_4_X_3_4,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4_X_1_2),
+                       .ips            = addresses_B_3_4_X_1_2,
+                       .sgroup_merge   = True,
+                       .sgroup_cleanup = False
+               }
+       },
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .cleanup= True,
+               .r1     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = 0,
+                       .ips            = NULL,
+                       .apply_expected = False,
+               },
+               .r2     = {
+                       .owner          = &ctx->x,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = 0,
+                       .ips            = NULL,
+                       .apply_expected = False,
+               }
+       },
+       /* 
+        * sgroup,active vs. sgroup,active different addresses, special case...
+        * => should be merged
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:A_3_4_B_3_4 vs. B:NULL => B:A_3_4",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4_B_3_4),
+                       .ips            = addresses_A_3_4_B_3_4,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = 0,
+                       .ips            = NULL,
+                       .sgroup_merge   = True,
+                       .merge_owner    = &ctx->b,
+                       .sgroup_cleanup = True
+               }
+       },
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .cleanup= True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = 0,
+                       .ips            = NULL,
+                       .apply_expected = False,
+               },
+               .r2     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_UNIQUE,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_1),
+                       .ips            = addresses_A_1,
+                       .apply_expected = True,
+               }
+       },
+       /* 
+        * sgroup,active vs. sgroup,active different addresses, special case...
+        * => should be merged
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+                       .ips            = addresses_B_3_4_X_3_4,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = 0,
+                       .ips            = NULL,
+                       .sgroup_merge   = True,
+                       .merge_owner    = &ctx->b,
+                       .sgroup_cleanup = True
+               }
+       },
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .cleanup= True,
+               .r1     = {
+                       .owner          = &ctx->x,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = 0,
+                       .ips            = NULL,
+                       .apply_expected = False,
+               },
+               .r2     = {
+                       .owner          = &ctx->x,
+                       .type           = WREPL_TYPE_UNIQUE,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_1),
+                       .ips            = addresses_A_1,
+                       .apply_expected = True,
+               }
+       },
+
+       /* 
+        * sgroup,active vs. sgroup,tombstone different no addresses, special
+        * => should be replaced
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:B_3_4_X_3_4 vs. B:NULL => B:NULL",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+                       .ips            = addresses_B_3_4_X_3_4,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = 0,
+                       .ips            = NULL,
+                       .apply_expected = True,
+               }
+       },
+       /* 
+        * sgroup,active vs. sgroup,tombstone different addresses
+        * => should be replaced
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+                       .ips            = addresses_B_3_4_X_3_4,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4),
+                       .ips            = addresses_A_3_4,
+                       .apply_expected = True,
+               }
+       },
+       /* 
+        * sgroup,active vs. sgroup,tombstone subset addresses
+        * => should be replaced
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:B_3_4_X_3_4 vs. B:B_3_4 => B:B_3_4",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+                       .ips            = addresses_B_3_4_X_3_4,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
+                       .ips            = addresses_B_3_4,
+                       .apply_expected = True,
+               }
+       },
+       /* 
+        * sgroup,active vs. sgroup,active same addresses
+        * => should be replaced
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .comment= "A:B_3_4_X_3_4 vs. B:B_3_4_X_3_4 => B:B_3_4_X_3_4",
+               .extra  = True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+                       .ips            = addresses_B_3_4_X_3_4,
+                       .apply_expected = True,
+               },
+               .r2     = {
+                       .owner          = &ctx->b,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+                       .ips            = addresses_B_3_4_X_3_4,
+                       .apply_expected = True,
+               }
+       },
+
+       /* 
+        * This should be the last record in this array,
+        * we need to make sure the we leave a tombstoned unique entry
+        * owned by OWNER_A
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+               .cleanup= True,
+               .r1     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_UNIQUE,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_1),
+                       .ips            = addresses_A_1,
+                       .apply_expected = True
+               },
+               .r2     = {
+                       .owner          = &ctx->a,
+                       .type           = WREPL_TYPE_UNIQUE,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_A_1),
+                       .ips            = addresses_A_1,
                        .apply_expected = True
                }
        }}; /* do not add entries here, this should be the last record! */
 
-       if (!ctx) return False;
-
        wins_name_r1    = &wins_name1;
        wins_name_r2    = &wins_name2;
 
        printf("Test Replica Conflicts with different owners\n");
 
        for(i=0; ret && i < ARRAY_SIZE(records); i++) {
-       
+
                if (!records[i].extra && !records[i].cleanup) {
                        /* we should test the worst cases */
                        if (records[i].r2.apply_expected && records[i].r1.ips==records[i].r2.ips) {
@@ -3869,8 +4805,8 @@ static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
                        const char *expected;
                        const char *ips;
 
-                       if (records[i].r2.merge_expected) {
-                               expected = "MERGE";
+                       if (records[i].r2.sgroup_merge) {
+                               expected = "SGROUP_MERGE";
                        } else if (records[i].r2.apply_expected) {
                                expected = "REPLACE";
                        } else {
@@ -3878,21 +4814,22 @@ static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
                        }
 
                        if (!records[i].r1.ips && !records[i].r2.ips) {
-                               ips = "no";
+                               ips = "with no ip(s)";
                        } else if (records[i].r1.ips==records[i].r2.ips) {
-                               ips = "same";
+                               ips = "with same ip(s)";
                        } else {
-                               ips = "different";
+                               ips = "with different ip(s)";
                        }
 
-                       printf("%s,%s%s vs. %s,%s%s with %s ip(s) => %s\n",
+                       printf("%s,%s%s vs. %s,%s%s %s => %s\n",
                                wrepl_name_type_string(records[i].r1.type),
                                wrepl_name_state_string(records[i].r1.state),
                                (records[i].r1.is_static?",static":""),
                                wrepl_name_type_string(records[i].r2.type),
                                wrepl_name_state_string(records[i].r2.state),
                                (records[i].r2.is_static?",static":""),
-                               ips, expected);
+                               (records[i].comment?records[i].comment:ips),
+                               expected);
                }
 
                /*
@@ -3939,8 +4876,13 @@ static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
                if (records[i].r1.state == WREPL_STATE_RELEASED) {
                        ret &= test_wrepl_is_applied(ctx, records[i].r1.owner,
                                                     wins_name_r1, False);
-               } else if (records[i].r2.merge_expected) {
-                       ret &= test_wrepl_is_merged(ctx, wins_name_r1, wins_name_r2);           
+               } else if (records[i].r2.sgroup_merge) {
+                       ret &= test_wrepl_sgroup_merged(ctx, records[i].r2.merge_owner,
+                                                       records[i].r1.owner,
+                                                       records[i].r1.num_ips, records[i].r1.ips,
+                                                       records[i].r2.owner,
+                                                       records[i].r2.num_ips, records[i].r2.ips,
+                                                       wins_name_r2);
                } else if (records[i].r1.owner != records[i].r2.owner) {
                        BOOL _expected;
                        _expected = (records[i].r1.apply_expected && !records[i].r2.apply_expected);
@@ -3950,11 +4892,79 @@ static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
                if (records[i].r2.state == WREPL_STATE_RELEASED) {
                        ret &= test_wrepl_is_applied(ctx, records[i].r2.owner,
                                                     wins_name_r2, False);
-               } else if (!records[i].r2.merge_expected) {
+               } else if (!records[i].r2.sgroup_merge) {
                        ret &= test_wrepl_is_applied(ctx, records[i].r2.owner,
                                                     wins_name_r2, records[i].r2.apply_expected);
                }
 
+               if (records[i].r2.sgroup_cleanup) {
+                       if (!ret) {
+                               printf("failed before sgroup_cleanup record[%u]: %s\n", i, records[i].line);
+                               return ret;
+                       }
+
+                       /* clean up the SGROUP record */
+                       wins_name_r1->name      = &records[i].name;
+                       wins_name_r1->flags     = WREPL_NAME_FLAGS(WREPL_TYPE_SGROUP,
+                                                                  WREPL_STATE_ACTIVE,
+                                                                  WREPL_NODE_B, False);
+                       wins_name_r1->id        = ++records[i].r1.owner->max_version;
+                       wins_name_r1->addresses.addresses.num_ips = 0;
+                       wins_name_r1->addresses.addresses.ips     = NULL;
+                       wins_name_r1->unknown   = "255.255.255.255";
+                       ret &= test_wrepl_update_one(ctx, records[i].r1.owner, wins_name_r1);
+
+                       /* here we test how names from an owner are deleted */
+                       if (records[i].r2.sgroup_merge && records[i].r2.num_ips) {
+                               ret &= test_wrepl_sgroup_merged(ctx, NULL,
+                                                               records[i].r2.owner,
+                                                               records[i].r2.num_ips, records[i].r2.ips,
+                                                               records[i].r1.owner,
+                                                               0, NULL,
+                                                               wins_name_r2);
+                       }
+
+                       /* clean up the SGROUP record */
+                       wins_name_r2->name      = &records[i].name;
+                       wins_name_r2->flags     = WREPL_NAME_FLAGS(WREPL_TYPE_SGROUP,
+                                                                  WREPL_STATE_ACTIVE,
+                                                                  WREPL_NODE_B, False);
+                       wins_name_r2->id        = ++records[i].r2.owner->max_version;
+                       wins_name_r2->addresses.addresses.num_ips = 0;
+                       wins_name_r2->addresses.addresses.ips     = NULL;
+                       wins_name_r2->unknown   = "255.255.255.255";
+                       ret &= test_wrepl_update_one(ctx, records[i].r2.owner, wins_name_r2);
+
+                       /* take ownership of the SGROUP record */
+                       wins_name_r2->name      = &records[i].name;
+                       wins_name_r2->flags     = WREPL_NAME_FLAGS(WREPL_TYPE_SGROUP,
+                                                                  WREPL_STATE_ACTIVE,
+                                                                  WREPL_NODE_B, False);
+                       wins_name_r2->id        = ++records[i].r2.owner->max_version;
+                       wins_name_r2->addresses.addresses.num_ips = ARRAY_SIZE(addresses_B_1);
+                       wins_name_r2->addresses.addresses.ips     = discard_const(addresses_B_1);
+                       wins_name_r2->unknown   = "255.255.255.255";
+                       ret &= test_wrepl_update_one(ctx, records[i].r2.owner, wins_name_r2);
+                       ret &= test_wrepl_is_applied(ctx, records[i].r2.owner, wins_name_r2, True);
+
+                       /* overwrite the SGROUP record with unique,tombstone */
+                       wins_name_r2->name      = &records[i].name;
+                       wins_name_r2->flags     = WREPL_NAME_FLAGS(WREPL_TYPE_SGROUP,
+                                                                  WREPL_STATE_TOMBSTONE,
+                                                                  WREPL_NODE_B, False);
+                       wins_name_r2->id        = ++records[i].r2.owner->max_version;
+                       wins_name_r2->addresses.addresses.num_ips = ARRAY_SIZE(addresses_B_1);
+                       wins_name_r2->addresses.addresses.ips     = discard_const(addresses_B_1);
+                       wins_name_r2->unknown   = "255.255.255.255";
+                       ret &= test_wrepl_update_one(ctx, records[i].r2.owner, wins_name_r2);
+                       ret &= test_wrepl_is_applied(ctx, records[i].r2.owner, wins_name_r2, True);
+
+                       if (!ret) {
+                               printf("failed in sgroup_cleanup record[%u]: %s\n", i, records[i].line);
+                               return ret;
+                       }
+               }
+
                /* the first one is a cleanup run */
                if (!ret && i == 0) ret = True;
 
@@ -5520,8 +6530,6 @@ static BOOL test_conflict_owned_released_vs_replica(struct test_wrepl_conflict_c
        },
        };
 
-       if (!ctx) return False;
-
        printf("Test Replica records vs. owned released records\n");
 
        for(i=0; ret && i < ARRAY_SIZE(records); i++) {
@@ -5647,6 +6655,7 @@ struct test_conflict_owned_active_vs_replica_struct {
        const char *line; /* just better debugging */
        const char *section; /* just better debugging */
        struct nbt_name name;
+       const char *comment;
        BOOL skip;
        struct {
                uint32_t nb_flags;
@@ -5674,12 +6683,13 @@ struct test_conflict_owned_active_vs_replica_struct {
                const struct wrepl_ip *ips;
                BOOL apply_expected;
                BOOL mhomed_merge;
+               BOOL sgroup_merge;
        } replica;
 };
 
 static void test_conflict_owned_active_vs_replica_handler(struct nbt_name_socket *nbtsock, 
                                                          struct nbt_name_packet *req_packet, 
-                                                         const struct nbt_peer_socket *src);
+                                                         struct socket_address *src);
 
 static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_conn *ctx)
 {
@@ -7209,11 +8219,202 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                },
        },
        /*
-        * mhomed,active vs. group,active with different ip(s), release expected
+        * mhomed,active vs. group,active with different ip(s), release expected
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_MA_GA_DI_R", 0x00, NULL),
+               .wins   = {
+                       .nb_flags       = 0,
+                       .mhomed         = True,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
+                       .apply_expected = True
+               },
+               .defend = {
+                       .timeout        = 10,
+                       .expect_release = True,
+               },
+               .replica= {
+                       .type           = WREPL_TYPE_GROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_1),
+                       .ips            = addresses_B_1,
+                       .apply_expected = True
+               },
+       },
+       /*
+        * mhomed,active vs. group,tombstone with same ip(s), unchecked
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_MA_GT_SI_U", 0x00, NULL),
+               .wins   = {
+                       .nb_flags       = 0,
+                       .mhomed         = True,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
+                       .apply_expected = True
+               },
+               .defend = {
+                       .timeout        = 0,
+               },
+               .replica= {
+                       .type           = WREPL_TYPE_GROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
+                       .apply_expected = False
+               },
+       },
+       /*
+        * mhomed,active vs. group,tombstone with different ip(s), unchecked
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_MA_GT_DI_U", 0x00, NULL),
+               .wins   = {
+                       .nb_flags       = 0,
+                       .mhomed         = True,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
+                       .apply_expected = True
+               },
+               .defend = {
+                       .timeout        = 0,
+               },
+               .replica= {
+                       .type           = WREPL_TYPE_GROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_1),
+                       .ips            = addresses_B_1,
+                       .apply_expected = False
+               },
+       },
+/* 
+ * multi homed vs. special group section
+ */
+       /*
+        * mhomed,active vs. sgroup,active with same ip(s), release expected
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_MA_SA_SI_R", 0x00, NULL),
+               .wins   = {
+                       .nb_flags       = 0,
+                       .mhomed         = True,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
+                       .apply_expected = True
+               },
+               .defend = {
+                       .timeout        = 10,
+                       .expect_release = True,
+               },
+               .replica= {
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
+                       .apply_expected = True
+               },
+       },
+       /*
+        * mhomed,active vs. group,active with different ip(s), release expected
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_MA_SA_DI_R", 0x00, NULL),
+               .wins   = {
+                       .nb_flags       = 0,
+                       .mhomed         = True,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
+                       .apply_expected = True
+               },
+               .defend = {
+                       .timeout        = 10,
+                       .expect_release = True,
+               },
+               .replica= {
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_1),
+                       .ips            = addresses_B_1,
+                       .apply_expected = True
+               },
+       },
+       /*
+        * mhomed,active vs. sgroup,tombstone with same ip(s), unchecked
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_MA_ST_SI_U", 0x00, NULL),
+               .wins   = {
+                       .nb_flags       = 0,
+                       .mhomed         = True,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
+                       .apply_expected = True
+               },
+               .defend = {
+                       .timeout        = 0,
+               },
+               .replica= {
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
+                       .apply_expected = False
+               },
+       },
+       /*
+        * mhomed,active vs. sgroup,tombstone with different ip(s), unchecked
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_MA_ST_DI_U", 0x00, NULL),
+               .wins   = {
+                       .nb_flags       = 0,
+                       .mhomed         = True,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
+                       .apply_expected = True
+               },
+               .defend = {
+                       .timeout        = 0,
+               },
+               .replica= {
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
+                       .num_ips        = ARRAY_SIZE(addresses_B_1),
+                       .ips            = addresses_B_1,
+                       .apply_expected = False
+               },
+       },
+/* 
+ * multi homed vs. multi homed section
+ */
+       /*
+        * mhomed,active vs. mhomed,active with same ip(s), unchecked
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_GA_DI_R", 0x00, NULL),
+               .name   = _NBT_NAME("_MA_MA_SI_U", 0x00, NULL),
                .wins   = {
                        .nb_flags       = 0,
                        .mhomed         = True,
@@ -7222,25 +8423,24 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 10,
-                       .expect_release = True,
+                       .timeout        = 0,
                },
                .replica= {
-                       .type           = WREPL_TYPE_GROUP,
+                       .type           = WREPL_TYPE_MHOMED,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_B_1),
-                       .ips            = addresses_B_1,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
                        .apply_expected = True
                },
        },
        /*
-        * mhomed,active vs. group,tombstone with same ip(s), unchecked
+        * mhomed,active vs. mhomed,active with superset ip(s), unchecked
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_GT_SI_U", 0x00, NULL),
+               .name   = _NBT_NAME("_MA_MA_SP_U", 0x00, NULL),
                .wins   = {
                        .nb_flags       = 0,
                        .mhomed         = True,
@@ -7252,21 +8452,21 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                        .timeout        = 0,
                },
                .replica= {
-                       .type           = WREPL_TYPE_GROUP,
-                       .state          = WREPL_STATE_TOMBSTONE,
+                       .type           = WREPL_TYPE_MHOMED,
+                       .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
-                       .apply_expected = False
+                       .num_ips        = ctx->addresses_all_num,
+                       .ips            = ctx->addresses_all,
+                       .apply_expected = True
                },
        },
        /*
-        * mhomed,active vs. group,tombstone with different ip(s), unchecked
+        * mhomed,active vs. mhomed,active with different ip(s), positive response
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_GT_DI_U", 0x00, NULL),
+               .name   = _NBT_NAME("_MA_MA_DI_P", 0x00, NULL),
                .wins   = {
                        .nb_flags       = 0,
                        .mhomed         = True,
@@ -7275,27 +8475,25 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 0,
+                       .timeout        = 10,
+                       .positive       = True,
                },
                .replica= {
-                       .type           = WREPL_TYPE_GROUP,
-                       .state          = WREPL_STATE_TOMBSTONE,
+                       .type           = WREPL_TYPE_MHOMED,
+                       .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_B_1),
-                       .ips            = addresses_B_1,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
+                       .ips            = addresses_B_3_4,
                        .apply_expected = False
                },
        },
-/* 
- * multi homed vs. special group section
- */
        /*
-        * mhomed,active vs. sgroup,active with same ip(s), release expected
+        * mhomed,active vs. mhomed,active with different ip(s), positive response other ips
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_SA_SI_R", 0x00, NULL),
+               .name   = _NBT_NAME("_MA_MA_DI_O", 0x00, NULL),
                .wins   = {
                        .nb_flags       = 0,
                        .mhomed         = True,
@@ -7305,24 +8503,26 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                },
                .defend = {
                        .timeout        = 10,
-                       .expect_release = True,
+                       .positive       = True,
+                       .num_ips        = ARRAY_SIZE(addresses_A_3_4),
+                       .ips            = addresses_A_3_4,
                },
                .replica= {
-                       .type           = WREPL_TYPE_SGROUP,
+                       .type           = WREPL_TYPE_MHOMED,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
-                       .apply_expected = True
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
+                       .ips            = addresses_B_3_4,
+                       .apply_expected = False
                },
        },
        /*
-        * mhomed,active vs. group,active with different ip(s), release expected
+        * mhomed,active vs. mhomed,active with different ip(s), negative response
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_SA_DI_R", 0x00, NULL),
+               .name   = _NBT_NAME("_MA_MA_DI_N", 0x00, NULL),
                .wins   = {
                        .nb_flags       = 0,
                        .mhomed         = True,
@@ -7332,24 +8532,24 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                },
                .defend = {
                        .timeout        = 10,
-                       .expect_release = True,
+                       .positive       = False,
                },
                .replica= {
-                       .type           = WREPL_TYPE_SGROUP,
+                       .type           = WREPL_TYPE_MHOMED,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_B_1),
-                       .ips            = addresses_B_1,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
+                       .ips            = addresses_B_3_4,
                        .apply_expected = True
                },
        },
        /*
-        * mhomed,active vs. sgroup,tombstone with same ip(s), unchecked
+        * mhomed,active vs. mhomed,tombstone with same ip(s), unchecked
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_ST_SI_U", 0x00, NULL),
+               .name   = _NBT_NAME("_MA_MT_SI_U", 0x00, NULL),
                .wins   = {
                        .nb_flags       = 0,
                        .mhomed         = True,
@@ -7361,7 +8561,7 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                        .timeout        = 0,
                },
                .replica= {
-                       .type           = WREPL_TYPE_SGROUP,
+                       .type           = WREPL_TYPE_MHOMED,
                        .state          = WREPL_STATE_TOMBSTONE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
@@ -7371,11 +8571,11 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                },
        },
        /*
-        * mhomed,active vs. sgroup,tombstone with different ip(s), unchecked
+        * mhomed,active vs. mhomed,tombstone with different ip(s), unchecked
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_ST_DI_U", 0x00, NULL),
+               .name   = _NBT_NAME("_MA_MT_DI_U", 0x00, NULL),
                .wins   = {
                        .nb_flags       = 0,
                        .mhomed         = True,
@@ -7387,29 +8587,32 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                        .timeout        = 0,
                },
                .replica= {
-                       .type           = WREPL_TYPE_SGROUP,
+                       .type           = WREPL_TYPE_MHOMED,
                        .state          = WREPL_STATE_TOMBSTONE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_B_1),
-                       .ips            = addresses_B_1,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
+                       .ips            = addresses_B_3_4,
                        .apply_expected = False
                },
        },
-/* 
- * multi homed vs. multi homed section
+/*
+ * some more multi homed test, including merging
  */
        /*
-        * mhomed,active vs. mhomed,active with same ip(s), unchecked
+        * mhomed,active vs. mhomed,active with superset ip(s), unchecked
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_MA_SI_U", 0x00, NULL),
+               .section= "Test Replica vs. owned active: some more MHOMED combinations",
+               .name   = _NBT_NAME("_MA_MA_SP_U", 0x00, NULL),
+               .comment= "C:MHOMED vs. B:ALL => B:ALL",
+               .skip   = (ctx->addresses_all_num < 3),
                .wins   = {
                        .nb_flags       = 0,
                        .mhomed         = True,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
+                       .num_ips        = ctx->addresses_mhomed_num,
+                       .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
@@ -7420,22 +8623,24 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
+                       .num_ips        = ctx->addresses_all_num,
+                       .ips            = ctx->addresses_all,
                        .apply_expected = True
                },
        },
        /*
-        * mhomed,active vs. mhomed,active with superset ip(s), unchecked
+        * mhomed,active vs. mhomed,active with same ips, unchecked
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_MA_SP_U", 0x00, NULL),
+               .name   = _NBT_NAME("_MA_MA_SM_U", 0x00, NULL),
+               .comment= "C:MHOMED vs. B:MHOMED => B:MHOMED",
+               .skip   = (ctx->addresses_mhomed_num < 2),
                .wins   = {
                        .nb_flags       = 0,
                        .mhomed         = True,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
+                       .num_ips        = ctx->addresses_mhomed_num,
+                       .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
@@ -7446,450 +8651,516 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ctx->addresses_all_num,
-                       .ips            = ctx->addresses_all,
+                       .num_ips        = ctx->addresses_mhomed_num,
+                       .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
        },
        /*
-        * mhomed,active vs. mhomed,active with different ip(s), positive response
+        * mhomed,active vs. mhomed,active with subset ip(s), positive response
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_MA_DI_P", 0x00, NULL),
+               .name   = _NBT_NAME("_MA_MA_SB_P", 0x00, NULL),
+               .comment= "C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED",
+               .skip   = (ctx->addresses_mhomed_num < 2),
                .wins   = {
                        .nb_flags       = 0,
                        .mhomed         = True,
+                       .num_ips        = ctx->addresses_mhomed_num,
+                       .ips            = ctx->addresses_mhomed,
+                       .apply_expected = True
+               },
+               .defend = {
+                       .timeout        = 10,
+                       .positive       = True
+               },
+               .replica= {
+                       .type           = WREPL_TYPE_MHOMED,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
                        .num_ips        = ctx->addresses_best_num,
                        .ips            = ctx->addresses_best,
+                       .mhomed_merge   = True
+               },
+       },
+       /*
+        * mhomed,active vs. mhomed,active with subset ip(s), positive response, with all addresses
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_MA_MA_SB_A", 0x00, NULL),
+               .comment= "C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED",
+               .skip   = (ctx->addresses_all_num < 3),
+               .wins   = {
+                       .nb_flags       = 0,
+                       .mhomed         = True,
+                       .num_ips        = ctx->addresses_mhomed_num,
+                       .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
                        .timeout        = 10,
                        .positive       = True,
+                       .num_ips        = ctx->addresses_all_num,
+                       .ips            = ctx->addresses_all,
                },
                .replica= {
                        .type           = WREPL_TYPE_MHOMED,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
-                       .ips            = addresses_B_3_4,
-                       .apply_expected = False
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
+                       .mhomed_merge   = True
                },
        },
        /*
-        * mhomed,active vs. mhomed,active with different ip(s), positive response other ips
+        * mhomed,active vs. mhomed,active with subset ip(s), positive response, with replicas addresses
+        * TODO: check why the server sends a name release demand for one address?
+        *       the release demand has no effect to the database record...
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_MA_DI_O", 0x00, NULL),
+               .name   = _NBT_NAME("_MA_MA_SB_PRA", 0x00, NULL),
+               .comment= "C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED",
+               .skip   = (ctx->addresses_all_num < 2),
                .wins   = {
                        .nb_flags       = 0,
                        .mhomed         = True,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
+                       .num_ips        = ctx->addresses_mhomed_num,
+                       .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
                        .timeout        = 10,
                        .positive       = True,
-                       .num_ips        = ARRAY_SIZE(addresses_A_3_4),
-                       .ips            = addresses_A_3_4,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
+                       .late_release   = True
                },
                .replica= {
                        .type           = WREPL_TYPE_MHOMED,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
-                       .ips            = addresses_B_3_4,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
                        .apply_expected = False
                },
        },
        /*
-        * mhomed,active vs. mhomed,active with different ip(s), negative response
+        * mhomed,active vs. mhomed,active with subset ip(s), positive response, with other addresses
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_MA_DI_N", 0x00, NULL),
+               .name   = _NBT_NAME("_MA_MA_SB_O", 0x00, NULL),
+               .comment= "C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED",
+               .skip   = (ctx->addresses_all_num < 2),
                .wins   = {
                        .nb_flags       = 0,
                        .mhomed         = True,
+                       .num_ips        = ctx->addresses_mhomed_num,
+                       .ips            = ctx->addresses_mhomed,
+                       .apply_expected = True
+               },
+               .defend = {
+                       .timeout        = 10,
+                       .positive       = True,
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
+                       .ips            = addresses_B_3_4,
+               },
+               .replica= {
+                       .type           = WREPL_TYPE_MHOMED,
+                       .state          = WREPL_STATE_ACTIVE,
+                       .node           = WREPL_NODE_B,
+                       .is_static      = False,
                        .num_ips        = ctx->addresses_best_num,
                        .ips            = ctx->addresses_best,
+                       .apply_expected = False
+               },
+       },
+       /*
+        * mhomed,active vs. mhomed,active with subset ip(s), negative response
+        */
+       {
+               .line   = __location__,
+               .name   = _NBT_NAME("_MA_MA_SB_N", 0x00, NULL),
+               .comment= "C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST",
+               .skip   = (ctx->addresses_mhomed_num < 2),
+               .wins   = {
+                       .nb_flags       = 0,
+                       .mhomed         = True,
+                       .num_ips        = ctx->addresses_mhomed_num,
+                       .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
                        .timeout        = 10,
-                       .positive       = False,
+                       .positive       = False
                },
                .replica= {
                        .type           = WREPL_TYPE_MHOMED,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
-                       .ips            = addresses_B_3_4,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
                        .apply_expected = True
                },
        },
+/*
+ * some more multi homed and unique test, including merging
+ */
        /*
-        * mhomed,active vs. mhomed,tombstone with same ip(s), unchecked
+        * mhomed,active vs. unique,active with subset ip(s), positive response
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_MT_SI_U", 0x00, NULL),
+               .section= "Test Replica vs. owned active: some more UNIQUE,MHOMED combinations",
+               .name   = _NBT_NAME("_MA_UA_SB_P", 0x00, NULL),
+               .comment= "C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED",
+               .skip   = (ctx->addresses_all_num < 2),
                .wins   = {
                        .nb_flags       = 0,
                        .mhomed         = True,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
+                       .num_ips        = ctx->addresses_mhomed_num,
+                       .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 0,
+                       .timeout        = 10,
+                       .positive       = True,
                },
                .replica= {
-                       .type           = WREPL_TYPE_MHOMED,
-                       .state          = WREPL_STATE_TOMBSTONE,
+                       .type           = WREPL_TYPE_UNIQUE,
+                       .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
                        .num_ips        = ctx->addresses_best_num,
                        .ips            = ctx->addresses_best,
-                       .apply_expected = False
+                       .mhomed_merge   = True
                },
        },
        /*
-        * mhomed,active vs. mhomed,tombstone with different ip(s), unchecked
+        * unique,active vs. unique,active with different ip(s), positive response, with replicas address
+        * TODO: check why the server sends a name release demand for one address?
+        *       the release demand has no effect to the database record...
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_MT_DI_U", 0x00, NULL),
+               .name   = _NBT_NAME("_UA_UA_DI_PRA", 0x00, NULL),
+               .comment= "C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST",
+               .skip   = (ctx->addresses_all_num < 2),
                .wins   = {
                        .nb_flags       = 0,
-                       .mhomed         = True,
+                       .mhomed         = False,
                        .num_ips        = ctx->addresses_best_num,
                        .ips            = ctx->addresses_best,
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 0,
+                       .timeout        = 10,
+                       .positive       = True,
+                       .num_ips        = ctx->addresses_best2_num,
+                       .ips            = ctx->addresses_best2,
+                       .late_release   = True
                },
                .replica= {
-                       .type           = WREPL_TYPE_MHOMED,
-                       .state          = WREPL_STATE_TOMBSTONE,
+                       .type           = WREPL_TYPE_UNIQUE,
+                       .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
-                       .is_static      = False,
-                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
-                       .ips            = addresses_B_3_4,
-                       .apply_expected = False
+                       .is_static      = False,
+                       .num_ips        = ctx->addresses_best2_num,
+                       .ips            = ctx->addresses_best2,
+                       .apply_expected = False,
                },
        },
-/*
- * some more multi homed test, including merging
- */
        /*
-        * mhomed,active vs. mhomed,active with superset ip(s), unchecked
+        * unique,active vs. unique,active with different ip(s), positive response, with all addresses
         */
        {
                .line   = __location__,
-               .section= "Test Replica vs. owned active: some more MHOMED combinations",
-               .name   = _NBT_NAME("_MA_MA_SP_U", 0x00, NULL),
+               .name   = _NBT_NAME("_UA_UA_DI_A", 0x00, NULL),
+               .comment= "C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED",
                .skip   = (ctx->addresses_all_num < 3),
                .wins   = {
                        .nb_flags       = 0,
-                       .mhomed         = True,
-                       .num_ips        = ctx->addresses_mhomed_num,
-                       .ips            = ctx->addresses_mhomed,
+                       .mhomed         = False,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 0,
+                       .timeout        = 10,
+                       .positive       = True,
+                       .num_ips        = ctx->addresses_all_num,
+                       .ips            = ctx->addresses_all,
                },
                .replica= {
-                       .type           = WREPL_TYPE_MHOMED,
+                       .type           = WREPL_TYPE_UNIQUE,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ctx->addresses_all_num,
-                       .ips            = ctx->addresses_all,
-                       .apply_expected = True
+                       .num_ips        = ctx->addresses_best2_num,
+                       .ips            = ctx->addresses_best2,
+                       .mhomed_merge   = True,
                },
        },
        /*
-        * mhomed,active vs. mhomed,active with same ips, unchecked
+        * unique,active vs. mhomed,active with different ip(s), positive response, with all addresses
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_MA_SM_U", 0x00, NULL),
-               .skip   = (ctx->addresses_mhomed_num != 2),
+               .name   = _NBT_NAME("_UA_MA_DI_A", 0x00, NULL),
+               .comment= "C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED",
+               .skip   = (ctx->addresses_all_num < 3),
                .wins   = {
                        .nb_flags       = 0,
-                       .mhomed         = True,
-                       .num_ips        = ctx->addresses_mhomed_num,
-                       .ips            = ctx->addresses_mhomed,
+                       .mhomed         = False,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 0,
+                       .timeout        = 10,
+                       .positive       = True,
+                       .num_ips        = ctx->addresses_all_num,
+                       .ips            = ctx->addresses_all,
                },
                .replica= {
                        .type           = WREPL_TYPE_MHOMED,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ctx->addresses_mhomed_num,
-                       .ips            = ctx->addresses_mhomed,
-                       .apply_expected = True
+                       .num_ips        = ctx->addresses_best2_num,
+                       .ips            = ctx->addresses_best2,
+                       .mhomed_merge   = True,
                },
        },
+/*
+ * special group vs. special group merging section
+ */
        /*
-        * mhomed,active vs. mhomed,active with subset ip(s), positive response
+        * sgroup,active vs. sgroup,active with different ip(s)
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_MA_SB_P", 0x00, NULL),
-               .skip   = (ctx->addresses_mhomed_num != 2),
+               .section= "Test Replica vs. owned active: SGROUP vs. SGROUP tests",
+               .name   = _NBT_NAME("_SA_SA_DI_U", 0x1C, NULL),
+               .skip   = (ctx->addresses_all_num < 3),
                .wins   = {
-                       .nb_flags       = 0,
-                       .mhomed         = True,
+                       .nb_flags       = NBT_NM_GROUP,
+                       .mhomed         = False,
                        .num_ips        = ctx->addresses_mhomed_num,
                        .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 10,
-                       .positive       = True
+                       .timeout        = 0,
                },
                .replica= {
-                       .type           = WREPL_TYPE_MHOMED,
+                       .type           = WREPL_TYPE_SGROUP,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
-                       .mhomed_merge   = True
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
+                       .ips            = addresses_B_3_4,
+                       .sgroup_merge   = True
                },
        },
        /*
-        * mhomed,active vs. mhomed,active with subset ip(s), positive response, with all addresses
+        * sgroup,active vs. sgroup,active with same ip(s)
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_MA_SB_A", 0x00, NULL),
+               .name   = _NBT_NAME("_SA_SA_SI_U", 0x1C, NULL),
                .skip   = (ctx->addresses_all_num < 3),
                .wins   = {
-                       .nb_flags       = 0,
-                       .mhomed         = True,
+                       .nb_flags       = NBT_NM_GROUP,
+                       .mhomed         = False,
                        .num_ips        = ctx->addresses_mhomed_num,
                        .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 10,
-                       .positive       = True,
-                       .num_ips        = ctx->addresses_all_num,
-                       .ips            = ctx->addresses_all,
+                       .timeout        = 0,
                },
                .replica= {
-                       .type           = WREPL_TYPE_MHOMED,
+                       .type           = WREPL_TYPE_SGROUP,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
-                       .mhomed_merge   = True
+                       .num_ips        = ctx->addresses_mhomed_num,
+                       .ips            = ctx->addresses_mhomed,
+                       .sgroup_merge   = True
                },
        },
        /*
-        * mhomed,active vs. mhomed,active with subset ip(s), positive response, with replicas addresses
-        * TODO: check why the server sends a name release demand for one address?
-        *       the release demand has no effect to the database record...
+        * sgroup,active vs. sgroup,active with superset ip(s)
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_MA_SB_C", 0x00, NULL),
+               .name   = _NBT_NAME("_SA_SA_SP_U", 0x1C, NULL),
                .skip   = (ctx->addresses_all_num < 3),
                .wins   = {
-                       .nb_flags       = 0,
-                       .mhomed         = True,
+                       .nb_flags       = NBT_NM_GROUP,
+                       .mhomed         = False,
                        .num_ips        = ctx->addresses_mhomed_num,
                        .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 10,
-                       .positive       = True,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
-                       .late_release   = True
+                       .timeout        = 0,
                },
                .replica= {
-                       .type           = WREPL_TYPE_MHOMED,
+                       .type           = WREPL_TYPE_SGROUP,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
-                       .apply_expected = False
+                       .num_ips        = ctx->addresses_all_num,
+                       .ips            = ctx->addresses_all,
+                       .sgroup_merge   = True
                },
        },
        /*
-        * mhomed,active vs. mhomed,active with subset ip(s), positive response, with other addresses
+        * sgroup,active vs. sgroup,active with subset ip(s)
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_MA_SB_O", 0x00, NULL),
-
+               .name   = _NBT_NAME("_SA_SA_SB_U", 0x1C, NULL),
                .skip   = (ctx->addresses_all_num < 3),
                .wins   = {
-                       .nb_flags       = 0,
-                       .mhomed         = True,
+                       .nb_flags       = NBT_NM_GROUP,
+                       .mhomed         = False,
                        .num_ips        = ctx->addresses_mhomed_num,
                        .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 10,
-                       .positive       = True,
-                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
-                       .ips            = addresses_B_3_4,
+                       .timeout        = 0,
                },
                .replica= {
-                       .type           = WREPL_TYPE_MHOMED,
+                       .type           = WREPL_TYPE_SGROUP,
                        .state          = WREPL_STATE_ACTIVE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
                        .num_ips        = ctx->addresses_best_num,
                        .ips            = ctx->addresses_best,
-                       .apply_expected = False
+                       .sgroup_merge   = True
                },
        },
        /*
-        * mhomed,active vs. mhomed,active with subset ip(s), negative response
+        * sgroup,active vs. sgroup,tombstone with different ip(s)
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_MA_MA_SB_N", 0x00, NULL),
-               .skip   = (ctx->addresses_mhomed_num != 2),
+               .name   = _NBT_NAME("_SA_ST_DI_U", 0x1C, NULL),
+               .skip   = (ctx->addresses_all_num < 3),
                .wins   = {
-                       .nb_flags       = 0,
-                       .mhomed         = True,
+                       .nb_flags       = NBT_NM_GROUP,
+                       .mhomed         = False,
                        .num_ips        = ctx->addresses_mhomed_num,
                        .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 10,
-                       .positive       = False
+                       .timeout        = 0,
                },
                .replica= {
-                       .type           = WREPL_TYPE_MHOMED,
-                       .state          = WREPL_STATE_ACTIVE,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
-                       .apply_expected = True
+                       .num_ips        = ARRAY_SIZE(addresses_B_3_4),
+                       .ips            = addresses_B_3_4,
+                       .apply_expected = False
                },
        },
-/*
- * some more multi homed and unique test, including merging
- */
        /*
-        * mhomed,active vs. unique,active with subset ip(s), positive response
+        * sgroup,active vs. sgroup,tombstone with same ip(s)
         */
        {
                .line   = __location__,
-               .section= "Test Replica vs. owned active: some more UNIQUE,MHOMED combinations",
-               .name   = _NBT_NAME("_MA_UA_SB_A", 0x00, NULL),
+               .name   = _NBT_NAME("_SA_ST_SI_U", 0x1C, NULL),
                .skip   = (ctx->addresses_all_num < 3),
                .wins   = {
-                       .nb_flags       = 0,
-                       .mhomed         = True,
+                       .nb_flags       = NBT_NM_GROUP,
+                       .mhomed         = False,
                        .num_ips        = ctx->addresses_mhomed_num,
                        .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 10,
-                       .positive       = True,
+                       .timeout        = 0,
                },
                .replica= {
-                       .type           = WREPL_TYPE_UNIQUE,
-                       .state          = WREPL_STATE_ACTIVE,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
-                       .mhomed_merge   = True
+                       .num_ips        = ctx->addresses_mhomed_num,
+                       .ips            = ctx->addresses_mhomed,
+                       .apply_expected = False
                },
        },
        /*
-        * unique,active vs. unique,active with different ip(s), positive response, with all addresses
+        * sgroup,active vs. sgroup,tombstone with superset ip(s)
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_UA_UA_DI_A", 0x00, NULL),
+               .name   = _NBT_NAME("_SA_ST_SP_U", 0x1C, NULL),
                .skip   = (ctx->addresses_all_num < 3),
                .wins   = {
-                       .nb_flags       = 0,
+                       .nb_flags       = NBT_NM_GROUP,
                        .mhomed         = False,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
+                       .num_ips        = ctx->addresses_mhomed_num,
+                       .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 10,
-                       .positive       = True,
-                       .num_ips        = ctx->addresses_all_num,
-                       .ips            = ctx->addresses_all,
+                       .timeout        = 0,
                },
                .replica= {
-                       .type           = WREPL_TYPE_UNIQUE,
-                       .state          = WREPL_STATE_ACTIVE,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ctx->addresses_best2_num,
-                       .ips            = ctx->addresses_best2,
-                       .mhomed_merge   = True,
+                       .num_ips        = ctx->addresses_all_num,
+                       .ips            = ctx->addresses_all,
+                       .apply_expected = False
                },
        },
        /*
-        * unique,active vs. mhomed,active with different ip(s), positive response, with all addresses
+        * sgroup,active vs. sgroup,tombstone with subset ip(s)
         */
        {
                .line   = __location__,
-               .name   = _NBT_NAME("_UA_MA_DI_A", 0x00, NULL),
+               .name   = _NBT_NAME("_SA_ST_SB_U", 0x1C, NULL),
                .skip   = (ctx->addresses_all_num < 3),
                .wins   = {
-                       .nb_flags       = 0,
+                       .nb_flags       = NBT_NM_GROUP,
                        .mhomed         = False,
-                       .num_ips        = ctx->addresses_best_num,
-                       .ips            = ctx->addresses_best,
+                       .num_ips        = ctx->addresses_mhomed_num,
+                       .ips            = ctx->addresses_mhomed,
                        .apply_expected = True
                },
                .defend = {
-                       .timeout        = 10,
-                       .positive       = True,
-                       .num_ips        = ctx->addresses_all_num,
-                       .ips            = ctx->addresses_all,
+                       .timeout        = 0,
                },
                .replica= {
-                       .type           = WREPL_TYPE_MHOMED,
-                       .state          = WREPL_STATE_ACTIVE,
+                       .type           = WREPL_TYPE_SGROUP,
+                       .state          = WREPL_STATE_TOMBSTONE,
                        .node           = WREPL_NODE_B,
                        .is_static      = False,
-                       .num_ips        = ctx->addresses_best2_num,
-                       .ips            = ctx->addresses_best2,
-                       .mhomed_merge   = True,
+                       .num_ips        = ctx->addresses_best_num,
+                       .ips            = ctx->addresses_best,
+                       .apply_expected = False
                },
        },
        };
 
-       if (!ctx) return False;
-
        if (!ctx->nbtsock_srv) {
                printf("SKIP: Test Replica records vs. owned active records: not bound to port[%d]\n",
                        lp_nbt_port());
@@ -7904,7 +9175,7 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                uint32_t j, count = 1;
                const char *action;
 
-               if (records[i].wins.mhomed) {
+               if (records[i].wins.mhomed || records[i].name.type == 0x1C) {
                        count = records[i].wins.num_ips;
                }
 
@@ -7919,13 +9190,19 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
 
                if (records[i].replica.mhomed_merge) {
                        action = "MHOMED_MERGE";
+               } else if (records[i].replica.sgroup_merge) {
+                       action = "SGROUP_MERGE";
                } else if (records[i].replica.apply_expected) {
                        action = "REPLACE";
                } else {
                        action = "NOT REPLACE";
                }
 
-               printf("%s => %s\n", nbt_name_string(ctx, &records[i].name), action);
+               printf("%s%s%s => %s\n",
+                       nbt_name_string(ctx, &records[i].name),
+                       (records[i].comment?": ":""),
+                       (records[i].comment?records[i].comment:""),
+                       action);
 
                /* Prepare for multi homed registration */
                ZERO_STRUCT(records[i].defend);
@@ -7967,7 +9244,7 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                         * the server will do name queries to see if the old addresses
                         * are still alive
                         */
-                       if (j > 0) {
+                       if (records[i].wins.mhomed && j > 0) {
                                end = timeval_current_ofs(records[i].defend.timeout,0);
                                records[i].defend.ret = True;
                                while (records[i].defend.timeout > 0) {
@@ -8059,6 +9336,13 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                                                        &ctx->b,
                                                        records[i].replica.num_ips, records[i].replica.ips,
                                                        wins_name);
+               } else if (records[i].replica.sgroup_merge) {
+                       ret &= test_wrepl_sgroup_merged(ctx, NULL,
+                                                       &ctx->c,
+                                                       records[i].wins.num_ips, records[i].wins.ips,
+                                                       &ctx->b,
+                                                       records[i].replica.num_ips, records[i].replica.ips,
+                                                       wins_name);
                } else {
                        ret &= test_wrepl_is_applied(ctx, &ctx->b, wins_name,
                                                     records[i].replica.apply_expected);
@@ -8080,7 +9364,7 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                        for (j=0; j < count; j++) {
                                struct nbt_name_socket *nbtsock = ctx->nbtsock;
 
-                               if (ctx->myaddr && strcmp(records[i].wins.ips[j].ip, ctx->myaddr2) == 0) {
+                               if (ctx->myaddr2 && strcmp(records[i].wins.ips[j].ip, ctx->myaddr2->addr) == 0) {
                                        nbtsock = ctx->nbtsock2;
                                }
 
@@ -8104,6 +9388,42 @@ static BOOL test_conflict_owned_active_vs_replica(struct test_wrepl_conflict_con
                                }
                                CHECK_VALUE(release->out.rcode, 0);
                        }
+
+                       if (records[i].replica.sgroup_merge) {
+                               /* clean up the SGROUP record */
+                               wins_name->name         = &records[i].name;
+                               wins_name->flags        = WREPL_NAME_FLAGS(WREPL_TYPE_SGROUP,
+                                                                          WREPL_STATE_ACTIVE,
+                                                                          WREPL_NODE_B, False);
+                               wins_name->id           = ++ctx->b.max_version;
+                               wins_name->addresses.addresses.num_ips = 0;
+                               wins_name->addresses.addresses.ips     = NULL;
+                               wins_name->unknown      = "255.255.255.255";
+                               ret &= test_wrepl_update_one(ctx, &ctx->b, wins_name);
+
+                               /* take ownership of the SGROUP record */
+                               wins_name->name         = &records[i].name;
+                               wins_name->flags        = WREPL_NAME_FLAGS(WREPL_TYPE_SGROUP,
+                                                                          WREPL_STATE_ACTIVE,
+                                                                          WREPL_NODE_B, False);
+                               wins_name->id           = ++ctx->b.max_version;
+                               wins_name->addresses.addresses.num_ips = ARRAY_SIZE(addresses_B_1);
+                               wins_name->addresses.addresses.ips     = discard_const(addresses_B_1);
+                               wins_name->unknown      = "255.255.255.255";
+                               ret &= test_wrepl_update_one(ctx, &ctx->b, wins_name);
+                               ret &= test_wrepl_is_applied(ctx, &ctx->b, wins_name, True);
+
+                               /* overwrite the SGROUP record with unique,tombstone */
+                               wins_name->name         = &records[i].name;
+                               wins_name->flags        = WREPL_NAME_FLAGS(WREPL_TYPE_UNIQUE,
+                                                                          WREPL_STATE_TOMBSTONE,
+                                                                          WREPL_NODE_B, False);
+                               wins_name->id           = ++ctx->b.max_version;
+                               wins_name->addresses.ip = addresses_A_1[0].ip;
+                               wins_name->unknown      = "255.255.255.255";
+                               ret &= test_wrepl_update_one(ctx, &ctx->b, wins_name);
+                               ret &= test_wrepl_is_applied(ctx, &ctx->b, wins_name, True);
+                       }
                }
 
 done:
@@ -8136,7 +9456,7 @@ done:
 
 static void test_conflict_owned_active_vs_replica_handler_query(struct nbt_name_socket *nbtsock, 
                                                                struct nbt_name_packet *req_packet, 
-                                                               const struct nbt_peer_socket *src)
+                                                               struct socket_address *src)
 {
        struct nbt_name *name;
        struct nbt_name_packet *rep_packet;
@@ -8223,6 +9543,7 @@ static void test_conflict_owned_active_vs_replica_handler_query(struct nbt_name_
 
        /* make sure we push the reply to the wire */
        event_loop_once(nbtsock->event_ctx);
+       msleep(1000);
 
        rec->defend.timeout     = 0;
        rec->defend.ret         = True;
@@ -8230,7 +9551,7 @@ static void test_conflict_owned_active_vs_replica_handler_query(struct nbt_name_
 
 static void test_conflict_owned_active_vs_replica_handler_release(struct nbt_name_socket *nbtsock, 
                                                                  struct nbt_name_packet *req_packet, 
-                                                                 const struct nbt_peer_socket *src)
+                                                                 struct socket_address *src)
 {
        struct nbt_name *name;
        struct nbt_name_packet *rep_packet;
@@ -8275,6 +9596,7 @@ static void test_conflict_owned_active_vs_replica_handler_release(struct nbt_nam
 
        /* make sure we push the reply to the wire */
        event_loop_once(nbtsock->event_ctx);
+       msleep(1000);
 
        rec->defend.timeout     = 0;
        rec->defend.ret         = True;
@@ -8282,7 +9604,7 @@ static void test_conflict_owned_active_vs_replica_handler_release(struct nbt_nam
 
 static void test_conflict_owned_active_vs_replica_handler(struct nbt_name_socket *nbtsock, 
                                                          struct nbt_name_packet *req_packet, 
-                                                         const struct nbt_peer_socket *src)
+                                                         struct socket_address *src)
 {
        struct test_conflict_owned_active_vs_replica_struct *rec = nbtsock->incoming.private;
 
@@ -8302,9 +9624,9 @@ static void test_conflict_owned_active_vs_replica_handler(struct nbt_name_socket
 }
 
 /*
-  test WINS replication operations
+  test simple WINS replication operations
 */
-BOOL torture_nbt_winsreplication_quick(void)
+BOOL torture_nbt_winsreplication_simple(struct torture_context *torture)
 {
        const char *address;
        struct nbt_name name;
@@ -8334,9 +9656,9 @@ BOOL torture_nbt_winsreplication_quick(void)
 }
 
 /*
-  test WINS replication operations
+  test WINS replication replica conflicts operations
 */
-BOOL torture_nbt_winsreplication(void)
+BOOL torture_nbt_winsreplication_replica(struct torture_context *torture)
 {
        const char *address;
        struct nbt_name name;
@@ -8356,15 +9678,43 @@ BOOL torture_nbt_winsreplication(void)
                return False;
        }
 
-       ret &= test_assoc_ctx1(mem_ctx, address);
-       ret &= test_assoc_ctx2(mem_ctx, address);
-
-       ret &= test_wins_replication(mem_ctx, address);
-
        ctx = test_create_conflict_ctx(mem_ctx, address);
+       if (!ctx) return False;
 
        ret &= test_conflict_same_owner(ctx);
        ret &= test_conflict_different_owner(ctx);
+
+       talloc_free(mem_ctx);
+
+       return ret;
+}
+
+/*
+  test WINS replication owned conflicts operations
+*/
+BOOL torture_nbt_winsreplication_owned(struct torture_context *torture)
+{
+       const char *address;
+       struct nbt_name name;
+       TALLOC_CTX *mem_ctx = talloc_new(NULL);
+       NTSTATUS status;
+       BOOL ret = True;
+       struct test_wrepl_conflict_conn *ctx;
+
+       make_nbt_name_server(&name, lp_parm_string(-1, "torture", "host"));
+
+       /* do an initial name resolution to find its IP */
+       status = resolve_name(&name, mem_ctx, &address, NULL);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("Failed to resolve %s - %s\n",
+                      name.name, nt_errstr(status));
+               talloc_free(mem_ctx);
+               return False;
+       }
+
+       ctx = test_create_conflict_ctx(mem_ctx, address);
+       if (!ctx) return False;
+
        ret &= test_conflict_owned_released_vs_replica(ctx);
        ret &= test_conflict_owned_active_vs_replica(ctx);