1 /*
2  * Copyright (C) 2009-2020 Codership Oy <info@codership.com>
3  */
4 
5 #include "check_gcomm.hpp"
6 
7 #include "pc_message.hpp"
8 #include "pc_proto.hpp"
9 #include "evs_proto.hpp"
10 
11 #include "check_templ.hpp"
12 #include "check_trace.hpp"
13 #include "gcomm/conf.hpp"
14 #include "gu_errno.h"
15 
16 #include "gu_asio.hpp" // gu::ssl_register_params()
17 
18 #include <check.h>
19 
20 #include <list>
21 #include <cstdlib>
22 #include <vector>
23 
24 using namespace std;
25 using namespace std::rel_ops;
26 using namespace gu::datetime;
27 using namespace gcomm;
28 using namespace gcomm::pc;
29 using gu::byte_t;
30 using gu::Buffer;
31 using gu::Exception;
32 using gu::URI;
33 using gu::DeleteObject;
34 
START_TEST(test_pc_messages)35 START_TEST(test_pc_messages)
36 {
37     StateMessage pcs(0);
38     pc::NodeMap& sim(pcs.node_map());
39 
40     sim.insert(std::make_pair(UUID(0,0),
41                               pc::Node(true, false, false, 6,
42                                        ViewId(V_PRIM,
43                                               UUID(0, 0), 9),
44                                        42, -1)));
45     sim.insert(std::make_pair(UUID(0,0),
46                               pc::Node(false, true, false, 88, ViewId(V_PRIM,
47                                                          UUID(0, 0), 3),
48                                        472, 0)));
49     sim.insert(std::make_pair(UUID(0,0),
50                               pc::Node(true, false, true, 78, ViewId(V_PRIM,
51                                                         UUID(0, 0), 87),
52                                        52, 1)));
53 
54     size_t expt_size = 4 // hdr
55         + 4              // seq
56         + 4 + 3*(UUID::serial_size() + sizeof(uint32_t) + 4 + 20 + 8); // NodeMap
57     check_serialization(pcs, expt_size, StateMessage(-1));
58 
59     InstallMessage pci(0);
60     pc::NodeMap& iim = pci.node_map();
61 
62     iim.insert(std::make_pair(UUID(0,0),
63                               pc::Node(true, true, true, 6, ViewId(V_PRIM,
64                                                              UUID(0, 0), 9), 42, -1)));
65     iim.insert(std::make_pair(UUID(0,0),
66                               pc::Node(false, false, false, 88, ViewId(V_NON_PRIM,
67                                                          UUID(0, 0), 3), 472, 0)));
68     iim.insert(std::make_pair(UUID(0,0),
69                               pc::Node(true, false, false, 78, ViewId(V_PRIM,
70                                                         UUID(0, 0), 87), 52, 1)));
71     iim.insert(std::make_pair(UUID(0,0),
72                               pc::Node(false, true, true, 457, ViewId(V_NON_PRIM,
73                                                           UUID(0, 0), 37), 56, 0xff)));
74 
75     expt_size = 4 // hdr
76         + 4              // seq
77         + 4 + 4*(UUID::serial_size() + sizeof(uint32_t) + 4 + 20 + 8); // NodeMap
78     check_serialization(pci, expt_size, InstallMessage(-1));
79 
80     UserMessage pcu(0, 7);
81     pcu.checksum(0xfefe, true);
82 
83     expt_size = 4 + 4;
84     check_serialization(pcu, expt_size, UserMessage(-1, -1U));
85     ck_assert(pcu.serial_size() % 4 == 0);
86 }
87 END_TEST
88 
89 class PCUser : public Toplay
90 {
91 public:
PCUser(gu::Config & conf,const UUID & uuid,DummyTransport * tp,Proto * pc)92     PCUser(gu::Config& conf, const UUID& uuid,
93            DummyTransport *tp, Proto* pc) :
94         Toplay(conf),
95         views_(),
96         uuid_(uuid),
97         tp_(tp),
98         pc_(pc)
99     {
100         gcomm::connect(tp_, pc_);
101         gcomm::connect(pc_, this);
102     }
103 
uuid() const104     const UUID& uuid() const { return uuid_; }
tp()105     DummyTransport* tp() { return tp_; }
pc()106     Proto* pc() { return pc_; }
107 
handle_up(const void * cid,const Datagram & rb,const ProtoUpMeta & um)108     void handle_up(const void* cid, const Datagram& rb,
109                    const ProtoUpMeta& um)
110     {
111         if (um.has_view() == true)
112         {
113             const View& view(um.view());
114             log_info << view;
115             ck_assert(view.type() == V_PRIM ||
116                         view.type() == V_NON_PRIM);
117             views_.push_back(View(view));
118         }
119     }
120 
send()121     void send()
122     {
123         byte_t pl[4] = {1, 2, 3, 4};
124         Buffer buf(pl, pl + sizeof(pl));
125         Datagram dg(buf);
126         ck_assert(send_down(dg, ProtoDownMeta()) == 0);
127     }
128 private:
129 
130     PCUser(const PCUser&);
131     void operator=(const PCUser&);
132 
133     list<View> views_;
134     UUID uuid_;
135     DummyTransport* tp_;
136     Proto* pc_;
137 };
138 
get_msg(Datagram * rb,Message * msg,bool release=true)139 void get_msg(Datagram* rb, Message* msg, bool release = true)
140 {
141     assert(msg != 0);
142     if (rb == 0)
143     {
144         log_info << "get_msg: (null)";
145     }
146     else
147     {
148         // assert(rb->get_header().size() == 0 && rb->get_offset() == 0);
149         const byte_t* begin(gcomm::begin(*rb));
150         const size_t available(gcomm::available(*rb));
151         ck_assert(msg->unserialize(begin,
152                                      available, 0) != 0);
153         log_info << "get_msg: " << msg->to_string();
154         if (release)
155             delete rb;
156     }
157 
158 }
159 
single_boot(int version,PCUser * pu1)160 void single_boot(int version, PCUser* pu1)
161 {
162 
163     ProtoUpMeta sum1(pu1->uuid());
164 
165     View vt0(version, ViewId(V_TRANS, pu1->uuid(), 0));
166     vt0.add_member(pu1->uuid(), 0);
167     ProtoUpMeta um1(UUID::nil(), ViewId(), &vt0);
168     pu1->pc()->connect(true);
169     // pu1->pc()->shift_to(Proto::S_JOINING);
170     pu1->pc()->handle_up(0, Datagram(), um1);
171     ck_assert(pu1->pc()->state() == Proto::S_TRANS);
172 
173     View vr1(version, ViewId(V_REG, pu1->uuid(), 1));
174     vr1.add_member(pu1->uuid(), 0);
175     ProtoUpMeta um2(UUID::nil(), ViewId(), &vr1);
176     pu1->pc()->handle_up(0, Datagram(), um2);
177     ck_assert(pu1->pc()->state() == Proto::S_STATES_EXCH);
178 
179     Datagram* rb = pu1->tp()->out();
180     ck_assert(rb != 0);
181     Message sm1;
182     get_msg(rb, &sm1);
183     ck_assert(sm1.type() == Message::PC_T_STATE);
184     ck_assert(sm1.node_map().size() == 1);
185     {
186         const pc::Node& pi1 = pc::NodeMap::value(sm1.node_map().begin());
187         ck_assert(pi1.prim() == true);
188         ck_assert(pi1.last_prim() == ViewId(V_PRIM, pu1->uuid(), 0));
189     }
190     pu1->pc()->handle_msg(sm1, Datagram(), sum1);
191     ck_assert(pu1->pc()->state() == Proto::S_INSTALL);
192 
193     rb = pu1->tp()->out();
194     ck_assert(rb != 0);
195     Message im1;
196     get_msg(rb, &im1);
197     ck_assert(im1.type() == Message::PC_T_INSTALL);
198     ck_assert(im1.node_map().size() == 1);
199     {
200         const pc::Node& pi1 = pc::NodeMap::value(im1.node_map().begin());
201         ck_assert(pi1.prim() == true);
202         ck_assert(pi1.last_prim() == ViewId(V_PRIM, pu1->uuid(), 0));
203     }
204     pu1->pc()->handle_msg(im1, Datagram(), sum1);
205     ck_assert(pu1->pc()->state() == Proto::S_PRIM);
206 }
207 
START_TEST(test_pc_view_changes_single)208 START_TEST(test_pc_view_changes_single)
209 {
210     log_info << "START (test_pc_view_changes_single)";
211     gu::Config conf;
212     gu::ssl_register_params(conf);
213     gcomm::Conf::register_params(conf);
214     UUID uuid1(0, 0);
215     Proto pc1(conf, uuid1, 0);
216     DummyTransport tp1;
217     PCUser pu1(conf, uuid1, &tp1, &pc1);
218     single_boot(0, &pu1);
219 
220 }
221 END_TEST
222 
223 
double_boot(int version,PCUser * pu1,PCUser * pu2)224 static void double_boot(int version, PCUser* pu1, PCUser* pu2)
225 {
226     ProtoUpMeta pum1(pu1->uuid());
227     ProtoUpMeta pum2(pu2->uuid());
228 
229     View t11(version, ViewId(V_TRANS, pu1->pc()->current_view().id()));
230     t11.add_member(pu1->uuid(), 0);
231     pu1->pc()->handle_view(t11);
232     ck_assert(pu1->pc()->state() == Proto::S_TRANS);
233 
234     View t12(version, ViewId(V_TRANS, pu2->uuid(), 0));
235     t12.add_member(pu2->uuid(), 0);
236     // pu2->pc()->shift_to(Proto::S_JOINING);
237     pu2->pc()->connect(false);
238     pu2->pc()->handle_view(t12);
239     ck_assert(pu2->pc()->state() == Proto::S_TRANS);
240 
241     View r1(version, ViewId(V_REG,
242                    pu1->uuid(),
243                    pu1->pc()->current_view().id().seq() + 1));
244     r1.add_member(pu1->uuid(), 0);
245     r1.add_member(pu2->uuid(), 0);
246     pu1->pc()->handle_view(r1);
247     ck_assert(pu1->pc()->state() == Proto::S_STATES_EXCH);
248 
249     pu2->pc()->handle_view(r1);
250     ck_assert(pu2->pc()->state() == Proto::S_STATES_EXCH);
251 
252     Datagram* rb = pu1->tp()->out();
253     ck_assert(rb != 0);
254     Message sm1;
255     get_msg(rb, &sm1);
256     ck_assert(sm1.type() == Message::PC_T_STATE);
257 
258     rb = pu2->tp()->out();
259     ck_assert(rb != 0);
260     Message sm2;
261     get_msg(rb, &sm2);
262     ck_assert(sm2.type() == Message::PC_T_STATE);
263 
264     rb = pu1->tp()->out();
265     ck_assert(rb == 0);
266     rb = pu2->tp()->out();
267     ck_assert(rb == 0);
268 
269     pu1->pc()->handle_msg(sm1, Datagram(), pum1);
270     rb = pu1->tp()->out();
271     ck_assert(rb == 0);
272     ck_assert(pu1->pc()->state() == Proto::S_STATES_EXCH);
273     pu1->pc()->handle_msg(sm2, Datagram(), pum2);
274     ck_assert(pu1->pc()->state() == Proto::S_INSTALL);
275 
276     pu2->pc()->handle_msg(sm1, Datagram(), pum1);
277     rb = pu2->tp()->out();
278     ck_assert(rb == 0);
279     ck_assert(pu2->pc()->state() == Proto::S_STATES_EXCH);
280     pu2->pc()->handle_msg(sm2, Datagram(), pum2);
281     ck_assert(pu2->pc()->state() == Proto::S_INSTALL);
282 
283     Message im1;
284     UUID imsrc;
285     if (pu1->uuid() < pu2->uuid())
286     {
287         rb = pu1->tp()->out();
288         imsrc = pu1->uuid();
289     }
290     else
291     {
292         rb = pu2->tp()->out();
293         imsrc = pu2->uuid();
294     }
295 
296     ck_assert(rb != 0);
297     get_msg(rb, &im1);
298     ck_assert(im1.type() == Message::PC_T_INSTALL);
299 
300     ck_assert(pu1->tp()->out() == 0);
301     ck_assert(pu2->tp()->out() == 0);
302 
303     ProtoUpMeta ipum(imsrc);
304     pu1->pc()->handle_msg(im1, Datagram(), ipum);
305     ck_assert(pu1->pc()->state() == Proto::S_PRIM);
306 
307     pu2->pc()->handle_msg(im1, Datagram(), ipum);
308     ck_assert(pu2->pc()->state() == Proto::S_PRIM);
309 }
310 
311 // Form PC for three instances.
triple_boot(int version,PCUser * pu1,PCUser * pu2,PCUser * pu3)312 static void triple_boot(int version, PCUser* pu1, PCUser* pu2, PCUser* pu3)
313 {
314     ck_assert(pu1->uuid() < pu2->uuid() && pu2->uuid() < pu3->uuid());
315 
316     // trans views
317     {
318         View tr12(version, ViewId(V_TRANS, pu1->pc()->current_view().id()));
319         tr12.add_member(pu1->uuid(), 0);
320         tr12.add_member(pu2->uuid(), 0);
321 
322         ProtoUpMeta trum12(UUID::nil(), ViewId(), &tr12);
323         pu1->pc()->handle_up(0, Datagram(), trum12);
324         pu2->pc()->handle_up(0, Datagram(), trum12);
325 
326         ck_assert(pu1->pc()->state() == Proto::S_TRANS);
327         ck_assert(pu2->pc()->state() == Proto::S_TRANS);
328 
329         pu3->pc()->connect(false);
330         View tr3(version, ViewId(V_TRANS, pu3->uuid(), 0));
331         tr3.add_member(pu3->uuid(), 0);
332         ProtoUpMeta trum3(UUID::nil(), ViewId(), &tr3);
333         pu3->pc()->handle_up(0, Datagram(), trum3);
334 
335         ck_assert(pu3->pc()->state() == Proto::S_TRANS);
336     }
337 
338     // reg view
339     {
340         View reg(version,
341             ViewId(V_REG,
342                    pu1->uuid(), pu1->pc()->current_view().id().seq() + 1));
343         reg.add_member(pu1->uuid(), 0);
344         reg.add_member(pu2->uuid(), 0);
345         reg.add_member(pu3->uuid(), 0);
346 
347         ProtoUpMeta pum(UUID::nil(), ViewId(), &reg);
348         pu1->pc()->handle_up(0, Datagram(), pum);
349         pu2->pc()->handle_up(0, Datagram(), pum);
350         pu3->pc()->handle_up(0, Datagram(), pum);
351 
352         ck_assert(pu1->pc()->state() == Proto::S_STATES_EXCH);
353         ck_assert(pu2->pc()->state() == Proto::S_STATES_EXCH);
354         ck_assert(pu3->pc()->state() == Proto::S_STATES_EXCH);
355 
356     }
357 
358     // states exch
359     {
360         Datagram* dg(pu1->tp()->out());
361         ck_assert(dg != 0);
362         pu1->pc()->handle_up(0, *dg, ProtoUpMeta(pu1->uuid()));
363         pu2->pc()->handle_up(0, *dg, ProtoUpMeta(pu1->uuid()));
364         pu3->pc()->handle_up(0, *dg, ProtoUpMeta(pu1->uuid()));
365         delete dg;
366 
367         dg = pu2->tp()->out();
368         ck_assert(dg != 0);
369         pu1->pc()->handle_up(0, *dg, ProtoUpMeta(pu2->uuid()));
370         pu2->pc()->handle_up(0, *dg, ProtoUpMeta(pu2->uuid()));
371         pu3->pc()->handle_up(0, *dg, ProtoUpMeta(pu2->uuid()));
372         delete dg;
373 
374         dg = pu3->tp()->out();
375         ck_assert(dg != 0);
376         pu1->pc()->handle_up(0, *dg, ProtoUpMeta(pu3->uuid()));
377         pu2->pc()->handle_up(0, *dg, ProtoUpMeta(pu3->uuid()));
378         pu3->pc()->handle_up(0, *dg, ProtoUpMeta(pu3->uuid()));
379         delete dg;
380 
381         ck_assert(pu1->pc()->state() == Proto::S_INSTALL);
382         ck_assert(pu2->pc()->state() == Proto::S_INSTALL);
383         ck_assert(pu3->pc()->state() == Proto::S_INSTALL);
384     }
385 
386     // install
387     {
388         Datagram* dg(pu1->tp()->out());
389         ck_assert(dg != 0);
390         pu1->pc()->handle_up(0, *dg, ProtoUpMeta(pu1->uuid()));
391         pu2->pc()->handle_up(0, *dg, ProtoUpMeta(pu1->uuid()));
392         pu3->pc()->handle_up(0, *dg, ProtoUpMeta(pu1->uuid()));
393         delete dg;
394 
395         ck_assert(pu1->pc()->state() == Proto::S_PRIM);
396         ck_assert(pu2->pc()->state() == Proto::S_PRIM);
397         ck_assert(pu3->pc()->state() == Proto::S_PRIM);
398     }
399 }
400 
401 
START_TEST(test_pc_view_changes_double)402 START_TEST(test_pc_view_changes_double)
403 {
404     log_info << "START (test_pc_view_changes_double)";
405     gu::Config conf;
406     gu::ssl_register_params(conf);
407     gcomm::Conf::register_params(conf);
408     UUID uuid1(1);
409     ProtoUpMeta pum1(uuid1);
410     Proto pc1(conf, uuid1, 0);
411     DummyTransport tp1;
412     PCUser pu1(conf, uuid1, &tp1, &pc1);
413     single_boot(0, &pu1);
414 
415     UUID uuid2(2);
416     ProtoUpMeta pum2(uuid2);
417     Proto pc2(conf, uuid2, 0);
418     DummyTransport tp2;
419     PCUser pu2(conf, uuid2, &tp2, &pc2);
420 
421     double_boot(0, &pu1, &pu2);
422 
423     Datagram* rb;
424 
425     View tnp(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
426     tnp.add_member(uuid1, 0);
427     pu1.pc()->handle_view(tnp);
428     ck_assert(pu1.pc()->state() == Proto::S_TRANS);
429     View reg(0, ViewId(V_REG, uuid1,
430                     pu1.pc()->current_view().id().seq() + 1));
431     reg.add_member(uuid1, 0);
432     pu1.pc()->handle_view(reg);
433     ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
434     rb = pu1.tp()->out();
435     ck_assert(rb != 0);
436     pu1.pc()->handle_up(0, *rb, ProtoUpMeta(uuid1));
437     ck_assert(pu1.pc()->state() == Proto::S_NON_PRIM);
438     delete rb;
439 
440     View tpv2(0, ViewId(V_TRANS, pu2.pc()->current_view().id()));
441     tpv2.add_member(uuid2, 0);
442     tpv2.add_left(uuid1, 0);
443     pu2.pc()->handle_view(tpv2);
444     ck_assert(pu2.pc()->state() == Proto::S_TRANS);
445     ck_assert(pu2.tp()->out() == 0);
446 
447     View rp2(0, ViewId(V_REG, uuid2,
448                        pu1.pc()->current_view().id().seq() + 1));
449     rp2.add_member(uuid2, 0);
450     rp2.add_left(uuid1, 0);
451     pu2.pc()->handle_view(rp2);
452     ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
453     rb = pu2.tp()->out();
454     ck_assert(rb != 0);
455     Message sm2;
456     get_msg(rb, &sm2);
457     ck_assert(sm2.type() == Message::PC_T_STATE);
458     ck_assert(pu2.tp()->out() == 0);
459     pu2.pc()->handle_msg(sm2, Datagram(), pum2);
460     ck_assert(pu2.pc()->state() == Proto::S_INSTALL);
461     rb = pu2.tp()->out();
462     ck_assert(rb != 0);
463     Message im2;
464     get_msg(rb, &im2);
465     ck_assert(im2.type() == Message::PC_T_INSTALL);
466     pu2.pc()->handle_msg(im2, Datagram(), pum2);
467     ck_assert(pu2.pc()->state() == Proto::S_PRIM);
468 
469 }
470 END_TEST
471 
472 /* Test that UUID ordering does not matter when starting nodes */
START_TEST(test_pc_view_changes_reverse)473 START_TEST(test_pc_view_changes_reverse)
474 {
475     log_info << "START (test_pc_view_changes_reverse)";
476     gu::Config conf;
477     gu::ssl_register_params(conf);
478     gcomm::Conf::register_params(conf);
479     UUID uuid1(1);
480     ProtoUpMeta pum1(uuid1);
481     Proto pc1(conf, uuid1, 0);
482     DummyTransport tp1;
483     PCUser pu1(conf, uuid1, &tp1, &pc1);
484 
485 
486     UUID uuid2(2);
487     ProtoUpMeta pum2(uuid2);
488     Proto pc2(conf, uuid2, 0);
489     DummyTransport tp2;
490     PCUser pu2(conf, uuid2, &tp2, &pc2);
491 
492     single_boot(0, &pu2);
493     double_boot(0, &pu2, &pu1);
494 }
495 END_TEST
496 
497 
498 
START_TEST(test_pc_state1)499 START_TEST(test_pc_state1)
500 {
501     log_info << "START (test_pc_state1)";
502     gu::Config conf;
503     gu::ssl_register_params(conf);
504     gcomm::Conf::register_params(conf);
505     UUID uuid1(1);
506     ProtoUpMeta pum1(uuid1);
507     Proto pc1(conf, uuid1, 0);
508     DummyTransport tp1;
509     PCUser pu1(conf, uuid1, &tp1, &pc1);
510     single_boot(0, &pu1);
511 
512     UUID uuid2(2);
513     ProtoUpMeta pum2(uuid2);
514     Proto pc2(conf, uuid2, 0);
515     DummyTransport tp2;
516     PCUser pu2(conf, uuid2, &tp2, &pc2);
517 
518     // n1: PRIM -> TRANS -> STATES_EXCH -> RTR -> PRIM
519     // n2: JOINING -> STATES_EXCH -> RTR -> PRIM
520     double_boot(0, &pu1, &pu2);
521 
522     ck_assert(pu1.pc()->state() == Proto::S_PRIM);
523     ck_assert(pu2.pc()->state() == Proto::S_PRIM);
524 
525     // PRIM -> TRANS -> STATES_EXCH -> RTR -> TRANS -> STATES_EXCH -> RTR ->PRIM
526     View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
527     tr1.add_member(uuid1, 0);
528     tr1.add_member(uuid2, 0);
529     pu1.pc()->handle_view(tr1);
530     pu2.pc()->handle_view(tr1);
531 
532     ck_assert(pu1.pc()->state() == Proto::S_TRANS);
533     ck_assert(pu2.pc()->state() == Proto::S_TRANS);
534 
535     ck_assert(pu1.tp()->out() == 0);
536     ck_assert(pu2.tp()->out() == 0);
537 
538     View reg2(0, ViewId(V_REG, uuid1,
539                      pu1.pc()->current_view().id().seq() + 1));
540     reg2.add_member(uuid1, 0);
541     reg2.add_member(uuid2, 0);
542     pu1.pc()->handle_view(reg2);
543     pu2.pc()->handle_view(reg2);
544 
545     ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
546     ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
547 
548     Message msg;
549     get_msg(pu1.tp()->out(), &msg);
550     pu1.pc()->handle_msg(msg, Datagram(), pum1);
551     pu2.pc()->handle_msg(msg, Datagram(), pum1);
552 
553     ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
554     ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
555 
556     get_msg(pu2.tp()->out(), &msg);
557     pu1.pc()->handle_msg(msg, Datagram(), pum2);
558     pu2.pc()->handle_msg(msg, Datagram(), pum2);
559 
560     ck_assert(pu1.pc()->state() == Proto::S_INSTALL);
561     ck_assert(pu2.pc()->state() == Proto::S_INSTALL);
562 
563     View tr2(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
564     tr2.add_member(uuid1, 0);
565     tr2.add_member(uuid2, 0);
566 
567     pu1.pc()->handle_view(tr2);
568     pu2.pc()->handle_view(tr2);
569 
570 
571     ck_assert(pu1.pc()->state() == Proto::S_TRANS);
572     ck_assert(pu2.pc()->state() == Proto::S_TRANS);
573 
574     Message im;
575 
576     if (uuid1 < uuid2)
577     {
578         get_msg(pu1.tp()->out(), &im);
579         pu1.pc()->handle_msg(im, Datagram(), pum1);
580         pu2.pc()->handle_msg(im, Datagram(), pum1);
581     }
582     else
583     {
584         get_msg(pu2.tp()->out(), &im);
585         pu1.pc()->handle_msg(im, Datagram(), pum2);
586         pu2.pc()->handle_msg(im, Datagram(), pum2);
587     }
588 
589 
590     ck_assert(pu1.pc()->state() == Proto::S_TRANS);
591     ck_assert(pu2.pc()->state() == Proto::S_TRANS);
592 
593 
594     View reg3(0, ViewId(V_REG, uuid1,
595                         pu1.pc()->current_view().id().seq() + 1));
596 
597     reg3.add_member(uuid1, 0);
598     reg3.add_member(uuid2, 0);
599 
600     pu1.pc()->handle_view(reg3);
601     pu2.pc()->handle_view(reg3);
602 
603     ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
604     ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
605 
606     get_msg(pu1.tp()->out(), &msg);
607     pu1.pc()->handle_msg(msg, Datagram(), pum1);
608     pu2.pc()->handle_msg(msg, Datagram(), pum1);
609 
610     ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
611     ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
612 
613     get_msg(pu2.tp()->out(), &msg);
614     pu1.pc()->handle_msg(msg, Datagram(), pum2);
615     pu2.pc()->handle_msg(msg, Datagram(), pum2);
616 
617     ck_assert(pu1.pc()->state() == Proto::S_INSTALL);
618     ck_assert(pu2.pc()->state() == Proto::S_INSTALL);
619 
620     if (uuid1 < uuid2)
621     {
622         get_msg(pu1.tp()->out(), &im);
623         pu1.pc()->handle_msg(im, Datagram(), pum1);
624         pu2.pc()->handle_msg(im, Datagram(), pum1);
625     }
626     else
627     {
628         get_msg(pu2.tp()->out(), &im);
629         pu1.pc()->handle_msg(im, Datagram(), pum2);
630         pu2.pc()->handle_msg(im, Datagram(), pum2);
631     }
632 
633     ck_assert(pu1.pc()->state() == Proto::S_PRIM);
634     ck_assert(pu2.pc()->state() == Proto::S_PRIM);
635 
636 }
637 END_TEST
638 
START_TEST(test_pc_state2)639 START_TEST(test_pc_state2)
640 {
641     log_info << "START (test_pc_state2)";
642     gu::Config conf;
643     gu::ssl_register_params(conf);
644     gcomm::Conf::register_params(conf);
645     UUID uuid1(1);
646     ProtoUpMeta pum1(uuid1);
647     Proto pc1(conf, uuid1, 0);
648     DummyTransport tp1;
649     PCUser pu1(conf, uuid1, &tp1, &pc1);
650     single_boot(0, &pu1);
651 
652     UUID uuid2(2);
653     ProtoUpMeta pum2(uuid2);
654     Proto pc2(conf, uuid2, 0);
655     DummyTransport tp2;
656     PCUser pu2(conf, uuid2, &tp2, &pc2);
657 
658     // n1: PRIM -> TRANS -> STATES_EXCH -> RTR -> PRIM
659     // n2: JOINING -> STATES_EXCH -> RTR -> PRIM
660     double_boot(0, &pu1, &pu2);
661 
662     ck_assert(pu1.pc()->state() == Proto::S_PRIM);
663     ck_assert(pu2.pc()->state() == Proto::S_PRIM);
664 
665     // PRIM -> TRANS -> STATES_EXCH -> TRANS -> STATES_EXCH -> RTR -> PRIM
666     View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
667     tr1.add_member(uuid1, 0);
668     tr1.add_member(uuid2, 0);
669     pu1.pc()->handle_view(tr1);
670     pu2.pc()->handle_view(tr1);
671 
672     ck_assert(pu1.pc()->state() == Proto::S_TRANS);
673     ck_assert(pu2.pc()->state() == Proto::S_TRANS);
674 
675     ck_assert(pu1.tp()->out() == 0);
676     ck_assert(pu2.tp()->out() == 0);
677 
678     View reg2(0, ViewId(V_REG, uuid1,
679                         pu1.pc()->current_view().id().seq() + 1));
680     reg2.add_member(uuid1, 0);
681     reg2.add_member(uuid2, 0);
682     pu1.pc()->handle_view(reg2);
683     pu2.pc()->handle_view(reg2);
684 
685     ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
686     ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
687 
688 
689 
690     View tr2(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
691     tr2.add_member(uuid1, 0);
692     tr2.add_member(uuid2, 0);
693 
694     pu1.pc()->handle_view(tr2);
695     pu2.pc()->handle_view(tr2);
696 
697 
698     ck_assert(pu1.pc()->state() == Proto::S_TRANS);
699     ck_assert(pu2.pc()->state() == Proto::S_TRANS);
700 
701     Message msg;
702     get_msg(pu1.tp()->out(), &msg);
703     pu1.pc()->handle_msg(msg, Datagram(), pum1);
704     pu2.pc()->handle_msg(msg, Datagram(), pum1);
705 
706     ck_assert(pu1.pc()->state() == Proto::S_TRANS);
707     ck_assert(pu2.pc()->state() == Proto::S_TRANS);
708 
709     get_msg(pu2.tp()->out(), &msg);
710     pu1.pc()->handle_msg(msg, Datagram(), pum2);
711     pu2.pc()->handle_msg(msg, Datagram(), pum2);
712 
713     ck_assert(pu1.pc()->state() == Proto::S_TRANS);
714     ck_assert(pu2.pc()->state() == Proto::S_TRANS);
715 
716 
717     View reg3(0, ViewId(V_REG, uuid1,
718                         pu1.pc()->current_view().id().seq() + 1));
719 
720     reg3.add_member(uuid1, 0);
721     reg3.add_member(uuid2, 0);
722 
723     pu1.pc()->handle_view(reg3);
724     pu2.pc()->handle_view(reg3);
725 
726     ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
727     ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
728 
729     get_msg(pu1.tp()->out(), &msg);
730     pu1.pc()->handle_msg(msg, Datagram(), pum1);
731     pu2.pc()->handle_msg(msg, Datagram(), pum1);
732 
733     ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
734     ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
735 
736     get_msg(pu2.tp()->out(), &msg);
737     pu1.pc()->handle_msg(msg, Datagram(), pum2);
738     pu2.pc()->handle_msg(msg, Datagram(), pum2);
739 
740     ck_assert(pu1.pc()->state() == Proto::S_INSTALL);
741     ck_assert(pu2.pc()->state() == Proto::S_INSTALL);
742 
743     Message im;
744     if (uuid1 < uuid2)
745     {
746         get_msg(pu1.tp()->out(), &im);
747         pu1.pc()->handle_msg(im, Datagram(), pum1);
748         pu2.pc()->handle_msg(im, Datagram(), pum1);
749     }
750     else
751     {
752         get_msg(pu2.tp()->out(), &im);
753         pu1.pc()->handle_msg(im, Datagram(), pum2);
754         pu2.pc()->handle_msg(im, Datagram(), pum2);
755     }
756 
757     ck_assert(pu1.pc()->state() == Proto::S_PRIM);
758     ck_assert(pu2.pc()->state() == Proto::S_PRIM);
759 
760 }
761 END_TEST
762 
START_TEST(test_pc_state3)763 START_TEST(test_pc_state3)
764 {
765     log_info << "START (test_pc_state3)";
766     gu::Config conf;
767     gu::ssl_register_params(conf);
768     gcomm::Conf::register_params(conf);
769     UUID uuid1(1);
770     ProtoUpMeta pum1(uuid1);
771     Proto pc1(conf, uuid1, 0);
772     DummyTransport tp1;
773     PCUser pu1(conf, uuid1, &tp1, &pc1);
774     single_boot(0, &pu1);
775 
776     UUID uuid2(2);
777     ProtoUpMeta pum2(uuid2);
778     Proto pc2(conf, uuid2, 0);
779     DummyTransport tp2;
780     PCUser pu2(conf, uuid2, &tp2, &pc2);
781 
782     // n1: PRIM -> TRANS -> STATES_EXCH -> RTR -> PRIM
783     // n2: JOINING -> STATES_EXCH -> RTR -> PRIM
784     double_boot(0, &pu1, &pu2);
785 
786     ck_assert(pu1.pc()->state() == Proto::S_PRIM);
787     ck_assert(pu2.pc()->state() == Proto::S_PRIM);
788 
789     // PRIM -> NON_PRIM -> STATES_EXCH -> RTR -> NON_PRIM -> STATES_EXCH -> ...
790     //      -> NON_PRIM -> STATES_EXCH -> RTR -> NON_PRIM
791     View tr11(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
792     tr11.add_member(uuid1, 0);
793     pu1.pc()->handle_view(tr11);
794 
795     View tr12(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
796     tr12.add_member(uuid2, 0);
797     pu2.pc()->handle_view(tr12);
798 
799     ck_assert(pu1.pc()->state() == Proto::S_TRANS);
800     ck_assert(pu2.pc()->state() == Proto::S_TRANS);
801 
802     ck_assert(pu1.tp()->out() == 0);
803     ck_assert(pu2.tp()->out() == 0);
804 
805     View reg21(0, ViewId(V_REG, uuid1,
806                          pu1.pc()->current_view().id().seq() + 1));
807     reg21.add_member(uuid1, 0);
808     pu1.pc()->handle_view(reg21);
809     ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
810 
811     View reg22(0, ViewId(V_REG, uuid2,
812                          pu2.pc()->current_view().id().seq() + 1));
813     reg22.add_member(uuid2, 0);
814     pu2.pc()->handle_view(reg22);
815     ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
816 
817 
818     Message msg;
819     get_msg(pu1.tp()->out(), &msg);
820     pu1.pc()->handle_msg(msg, Datagram(), pum1);
821 
822     get_msg(pu2.tp()->out(), &msg);
823     pu2.pc()->handle_msg(msg, Datagram(), pum2);
824 
825     ck_assert(pu1.pc()->state() == Proto::S_NON_PRIM);
826     ck_assert(pu2.pc()->state() == Proto::S_NON_PRIM);
827 
828 
829 
830     View tr21(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
831     tr21.add_member(uuid1, 0);
832     pu1.pc()->handle_view(tr21);
833 
834     View tr22(0, ViewId(V_TRANS, pu2.pc()->current_view().id()));
835     tr22.add_member(uuid2, 0);
836     pu2.pc()->handle_view(tr22);
837 
838     ck_assert(pu1.pc()->state() == Proto::S_TRANS);
839     ck_assert(pu2.pc()->state() == Proto::S_TRANS);
840 
841     ck_assert(pu1.tp()->out() == 0);
842     ck_assert(pu2.tp()->out() == 0);
843 
844     View reg3(0, ViewId(V_REG, uuid1,
845                         pu1.pc()->current_view().id().seq() + 1));
846     reg3.add_member(uuid1, 0);
847     reg3.add_member(uuid2, 0);
848 
849     pu1.pc()->handle_view(reg3);
850     pu2.pc()->handle_view(reg3);
851 
852     ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
853     ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
854 
855     get_msg(pu1.tp()->out(), &msg);
856     pu1.pc()->handle_msg(msg, Datagram(), pum1);
857     pu2.pc()->handle_msg(msg, Datagram(), pum1);
858 
859     ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
860     ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
861 
862     get_msg(pu2.tp()->out(), &msg);
863     pu1.pc()->handle_msg(msg, Datagram(), pum2);
864     pu2.pc()->handle_msg(msg, Datagram(), pum2);
865 
866     ck_assert(pu1.pc()->state() == Proto::S_INSTALL);
867     ck_assert(pu2.pc()->state() == Proto::S_INSTALL);
868 
869     Message im;
870     if (uuid1 < uuid2)
871     {
872         get_msg(pu1.tp()->out(), &im);
873         pu1.pc()->handle_msg(im, Datagram(), pum1);
874         pu2.pc()->handle_msg(im, Datagram(), pum1);
875     }
876     else
877     {
878         get_msg(pu2.tp()->out(), &im);
879         pu1.pc()->handle_msg(im, Datagram(), pum2);
880         pu2.pc()->handle_msg(im, Datagram(), pum2);
881     }
882 
883     ck_assert(pu1.pc()->state() == Proto::S_PRIM);
884     ck_assert(pu2.pc()->state() == Proto::S_PRIM);
885 
886 }
887 END_TEST
888 
START_TEST(test_pc_conflicting_prims)889 START_TEST(test_pc_conflicting_prims)
890 {
891     log_info << "START (test_pc_conflicting_prims)";
892     gu::Config conf;
893     gu::ssl_register_params(conf);
894     gcomm::Conf::register_params(conf);
895     UUID uuid1(1);
896     ProtoUpMeta pum1(uuid1);
897     Proto pc1(conf, uuid1, 0);
898     DummyTransport tp1;
899     PCUser pu1(conf, uuid1, &tp1, &pc1);
900     single_boot(0, &pu1);
901 
902     UUID uuid2(2);
903     ProtoUpMeta pum2(uuid2);
904     Proto pc2(conf, uuid2, 0);
905     DummyTransport tp2;
906     PCUser pu2(conf, uuid2, &tp2, &pc2);
907     single_boot(0, &pu2);
908 
909     View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
910     tr1.add_member(uuid1, 0);
911     pu1.pc()->handle_view(tr1);
912     View tr2(0, ViewId(V_TRANS, pu2.pc()->current_view().id()));
913     tr2.add_member(uuid2, 0);
914     pu2.pc()->handle_view(tr2);
915 
916     View reg(0, ViewId(V_REG, uuid1, tr1.id().seq() + 1));
917     reg.add_member(uuid1, 0);
918     reg.add_member(uuid2, 0);
919     pu1.pc()->handle_view(reg);
920     pu2.pc()->handle_view(reg);
921 
922     Message msg1, msg2;
923 
924     /* First node must discard msg2 and stay in states exch waiting for
925      * trans view */
926     get_msg(pu1.tp()->out(), &msg1);
927     get_msg(pu2.tp()->out(), &msg2);
928     ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
929 
930     pu1.pc()->handle_msg(msg1, Datagram(), pum1);
931     pu1.pc()->handle_msg(msg2, Datagram(), pum2);
932 
933     /* Second node must abort */
934     try
935     {
936         pu2.pc()->handle_msg(msg1, Datagram(), pum1);
937         ck_abort_msg("not aborted");
938     }
939     catch (Exception& e)
940     {
941         log_info << e.what();
942     }
943 
944     ck_assert(pu1.tp()->out() == 0);
945 
946     View tr3(0, ViewId(V_TRANS, reg.id()));
947     tr3.add_member(uuid1, 0);
948     pu1.pc()->handle_view(tr3);
949     View reg3(0, ViewId(V_REG, uuid1, tr3.id().seq() + 1));
950     reg3.add_member(uuid1, 0);
951     pu1.pc()->handle_view(reg3);
952 
953     get_msg(pu1.tp()->out(), &msg1);
954     pu1.pc()->handle_msg(msg1, Datagram(), pum1);
955 
956     get_msg(pu1.tp()->out(), &msg1);
957     pu1.pc()->handle_msg(msg1, Datagram(), pum1);
958 
959     ck_assert(pu1.pc()->state() == Proto::S_PRIM);
960 
961 }
962 END_TEST
963 
START_TEST(test_pc_conflicting_prims_npvo)964 START_TEST(test_pc_conflicting_prims_npvo)
965 {
966     log_info << "START (test_pc_conflicting_npvo)";
967     gu::Config conf;
968     gu::ssl_register_params(conf);
969     gcomm::Conf::register_params(conf);
970     UUID uuid1(1);
971     ProtoUpMeta pum1(uuid1);
972     Proto pc1(conf, uuid1, 0, URI("pc://?pc.npvo=true"));
973     DummyTransport tp1;
974     PCUser pu1(conf, uuid1, &tp1, &pc1);
975     single_boot(0, &pu1);
976 
977     UUID uuid2(2);
978     ProtoUpMeta pum2(uuid2);
979     Proto pc2(conf, uuid2, 0, URI("pc://?pc.npvo=true"));
980     DummyTransport tp2;
981     PCUser pu2(conf, uuid2, &tp2, &pc2);
982     single_boot(0, &pu2);
983 
984     View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
985     tr1.add_member(uuid1, 0);
986     pu1.pc()->handle_view(tr1);
987     View tr2(0, ViewId(V_TRANS, pu2.pc()->current_view().id()));
988     tr2.add_member(uuid2, 0);
989     pu2.pc()->handle_view(tr2);
990 
991     View reg(0, ViewId(V_REG, uuid1, tr1.id().seq() + 1));
992     reg.add_member(uuid1, 0);
993     reg.add_member(uuid2, 0);
994     pu1.pc()->handle_view(reg);
995     pu2.pc()->handle_view(reg);
996 
997     Message msg1, msg2;
998 
999     /* First node must discard msg2 and stay in states exch waiting for
1000      * trans view */
1001     get_msg(pu1.tp()->out(), &msg1);
1002     get_msg(pu2.tp()->out(), &msg2);
1003     ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
1004 
1005     pu1.pc()->handle_msg(msg1, Datagram(), pum1);
1006     pu2.pc()->handle_msg(msg1, Datagram(), pum1);
1007 
1008     /* First node must abort */
1009     try
1010     {
1011         pu1.pc()->handle_msg(msg2, Datagram(), pum2);
1012         ck_abort_msg("not aborted");
1013     }
1014     catch (Exception& e)
1015     {
1016         log_info << e.what();
1017     }
1018 
1019     ck_assert(pu2.tp()->out() == 0);
1020 
1021     View tr3(0, ViewId(V_TRANS, reg.id()));
1022     tr3.add_member(uuid2, 0);
1023     pu2.pc()->handle_view(tr3);
1024     View reg3(0, ViewId(V_REG, uuid2, tr3.id().seq() + 1));
1025     reg3.add_member(uuid2, 0);
1026     pu2.pc()->handle_view(reg3);
1027 
1028     get_msg(pu2.tp()->out(), &msg2);
1029     pu2.pc()->handle_msg(msg2, Datagram(), pum2);
1030 
1031     get_msg(pu2.tp()->out(), &msg2);
1032     pu2.pc()->handle_msg(msg2, Datagram(), pum2);
1033 
1034     ck_assert(pu2.pc()->state() == Proto::S_PRIM);
1035 
1036 }
1037 END_TEST
1038 
1039 
join_node(PropagationMatrix * p,DummyNode * n,bool first)1040 static void join_node(PropagationMatrix* p,
1041                       DummyNode* n, bool first)
1042 {
1043     log_info << first;
1044     gu_trace(p->insert_tp(n));
1045     gu_trace(n->connect(first));
1046 }
1047 
send_n(DummyNode * node,const size_t n)1048 static void send_n(DummyNode* node, const size_t n)
1049 {
1050     for (size_t i = 0; i < n; ++i)
1051     {
1052         gu_trace(node->send());
1053     }
1054 }
1055 
set_cvi(vector<DummyNode * > & nvec,size_t i_begin,size_t i_end,size_t seq,ViewType type)1056 static void set_cvi(vector<DummyNode*>& nvec, size_t i_begin, size_t i_end,
1057                     size_t seq, ViewType type)
1058 {
1059     for (size_t i = i_begin; i <= i_end; ++i)
1060     {
1061         nvec[i]->set_cvi(ViewId(type,
1062                                 type == V_NON_PRIM ?
1063                                 nvec[0]->uuid() :
1064                                 nvec[i_begin]->uuid(),
1065                                 static_cast<uint32_t>(type == V_NON_PRIM ? seq - 1 : seq)));
1066     }
1067 }
1068 
1069 struct InitGuConf
1070 {
InitGuConfInitGuConf1071     explicit InitGuConf(gu::Config& conf) { gcomm::Conf::register_params(conf); }
1072 };
1073 
1074 static gu::Config&
static_gu_conf()1075 static_gu_conf()
1076 {
1077     static gu::Config conf;
1078     static InitGuConf init(conf);
1079 
1080     return conf;
1081 }
1082 
create_dummy_node(size_t idx,int version,const string & suspect_timeout="PT1H",const string & inactive_timeout="PT1H",const string & retrans_period="PT20M",int weight=1)1083 static DummyNode* create_dummy_node(size_t idx,
1084                                     int version,
1085                                     const string& suspect_timeout = "PT1H",
1086                                     const string& inactive_timeout = "PT1H",
1087                                     const string& retrans_period = "PT20M",
1088                                     int weight = 1)
1089 {
1090     gu::Config& gu_conf(static_gu_conf());
1091     gu::ssl_register_params(gu_conf);
1092     gcomm::Conf::register_params(gu_conf);
1093     const string conf = "evs://?" + Conf::EvsViewForgetTimeout + "=PT1H&"
1094         + Conf::EvsInactiveCheckPeriod + "=" + to_string(Period(suspect_timeout)/3) + "&"
1095         + Conf::EvsSuspectTimeout + "=" + suspect_timeout + "&"
1096         + Conf::EvsInactiveTimeout + "=" + inactive_timeout + "&"
1097         + Conf::EvsKeepalivePeriod + "=" + retrans_period + "&"
1098         + Conf::EvsJoinRetransPeriod + "=" + retrans_period + "&"
1099         + Conf::EvsInstallTimeout + "=" + inactive_timeout + "&"
1100         + Conf::PcWeight + "=" + gu::to_string(weight) + "&"
1101         + Conf::EvsVersion + "=" + gu::to_string<int>(version) + "&"
1102         + Conf::EvsInfoLogMask + "=" + "0x3";
1103     list<Protolay*> protos;
1104 
1105     UUID uuid(static_cast<int32_t>(idx));
1106     protos.push_back(new DummyTransport(uuid, false));
1107     protos.push_back(new evs::Proto(gu_conf, uuid, 0, conf));
1108     protos.push_back(new Proto(gu_conf, uuid, 0, conf));
1109     return new DummyNode(gu_conf, idx, gcomm::UUID(idx), protos);
1110 }
1111 
1112 namespace
1113 {
pc_from_dummy(DummyNode * dn)1114     gcomm::pc::Proto* pc_from_dummy(DummyNode* dn)
1115     {
1116         return reinterpret_cast<Proto*>(dn->protos().back());
1117     }
1118 }
1119 
1120 
view_type(const size_t i_begin,const size_t i_end,const size_t n_nodes)1121 static ViewType view_type(const size_t i_begin, const size_t i_end,
1122                           const size_t n_nodes)
1123 {
1124 
1125     return (((i_end - i_begin + 1)*2 > n_nodes) ? V_PRIM : V_NON_PRIM);
1126 }
1127 
START_TEST(test_pc_split_merge)1128 START_TEST(test_pc_split_merge)
1129 {
1130     log_info << "START (test_pc_split_merge)";
1131     size_t n_nodes(5);
1132     vector<DummyNode*> dn;
1133     PropagationMatrix prop;
1134     const string suspect_timeout("PT0.35S");
1135     const string inactive_timeout("PT0.7S");
1136     const string retrans_period("PT0.1S");
1137     uint32_t view_seq = 0;
1138 
1139     mark_point();
1140 
1141     for (size_t i = 0; i < n_nodes; ++i)
1142     {
1143         dn.push_back(create_dummy_node(i + 1, 0, suspect_timeout,
1144                                        inactive_timeout, retrans_period));
1145         gu_trace(join_node(&prop, dn[i], i == 0));
1146         set_cvi(dn, 0, i, ++view_seq, V_PRIM);
1147         gu_trace(prop.propagate_until_cvi(false));
1148     }
1149 
1150     mark_point();
1151 
1152     for (size_t i = 1; i < n_nodes; ++i)
1153     {
1154 
1155         for (size_t j = 0; j < i; ++j)
1156         {
1157             for (size_t k = i; k < n_nodes; ++k)
1158             {
1159                 prop.split(j + 1, k + 1);
1160             }
1161         }
1162 
1163         ++view_seq;
1164         log_info << "split " << i << " view seq " << view_seq;
1165         set_cvi(dn, 0, i - 1, view_seq, view_type(0, i - 1, n_nodes));
1166         set_cvi(dn, i, n_nodes - 1, view_seq, view_type(i,n_nodes - 1,n_nodes));
1167         gu_trace(prop.propagate_until_cvi(true));
1168 
1169         for (size_t j = 0; j < i; ++j)
1170         {
1171             for (size_t k = i; k < n_nodes; ++k)
1172             {
1173                 prop.merge(j + 1, k + 1);
1174             }
1175         }
1176         ++view_seq;
1177         log_info << "merge " << i << " view seq " << view_seq;
1178         set_cvi(dn, 0, n_nodes - 1, view_seq, V_PRIM);
1179         gu_trace(prop.propagate_until_cvi(true));
1180     }
1181 
1182     mark_point();
1183 
1184     check_trace(dn);
1185     for_each(dn.begin(), dn.end(), DeleteObject());
1186 }
1187 END_TEST
1188 
1189 
1190 
START_TEST(test_pc_split_merge_w_user_msg)1191 START_TEST(test_pc_split_merge_w_user_msg)
1192 {
1193     log_info << "START (test_pc_split_merge_w_user_msg)";
1194     size_t n_nodes(5);
1195     vector<DummyNode*> dn;
1196     PropagationMatrix prop;
1197     const string suspect_timeout("PT0.35S");
1198     const string inactive_timeout("PT0.7S");
1199     const string retrans_period("PT0.1S");
1200     uint32_t view_seq = 0;
1201 
1202     for (size_t i = 0; i < n_nodes; ++i)
1203     {
1204         dn.push_back(create_dummy_node(i + 1, 0, suspect_timeout,
1205                                        inactive_timeout, retrans_period));
1206         gu_trace(join_node(&prop, dn[i], i == 0));
1207         set_cvi(dn, 0, i, ++view_seq, V_PRIM);
1208         gu_trace(prop.propagate_until_cvi(false));
1209     }
1210 
1211     for (size_t i = 1; i < n_nodes; ++i)
1212     {
1213         for (size_t j = 0; j < n_nodes; ++j)
1214         {
1215             send_n(dn[j], ::rand() % 5);
1216         }
1217         for (size_t j = 0; j < i; ++j)
1218         {
1219             for (size_t k = i; k < n_nodes; ++k)
1220             {
1221                 prop.split(j + 1, k + 1);
1222             }
1223         }
1224         ++view_seq;
1225         log_info << "split " << i << " view seq " << view_seq;
1226         set_cvi(dn, 0, i - 1, view_seq, view_type(0, i - 1, n_nodes));
1227         set_cvi(dn, i, n_nodes - 1, view_seq, view_type(i, n_nodes - 1, n_nodes));
1228         gu_trace(prop.propagate_until_cvi(true));
1229 
1230         for (size_t j = 0; j < n_nodes; ++j)
1231         {
1232             send_n(dn[j], ::rand() % 5);
1233         }
1234         for (size_t j = 0; j < i; ++j)
1235         {
1236             for (size_t k = i; k < n_nodes; ++k)
1237             {
1238                 prop.merge(j + 1, k + 1);
1239             }
1240         }
1241         ++view_seq;
1242         log_info << "merge " << i << " view seq " << view_seq;
1243         set_cvi(dn, 0, n_nodes - 1, view_seq, V_PRIM);
1244         gu_trace(prop.propagate_until_cvi(true));
1245     }
1246     check_trace(dn);
1247     for_each(dn.begin(), dn.end(), DeleteObject());
1248 }
1249 END_TEST
1250 
1251 
START_TEST(test_pc_complete_split_merge)1252 START_TEST(test_pc_complete_split_merge)
1253 {
1254     log_info << "START (test_pc_complete_split_merge)";
1255     size_t n_nodes(5);
1256     vector<DummyNode*> dn;
1257     PropagationMatrix prop;
1258     const string suspect_timeout("PT0.35S");
1259     const string inactive_timeout("PT0.31S");
1260     const string retrans_period("PT0.1S");
1261     uint32_t view_seq = 0;
1262 
1263     for (size_t i = 0; i < n_nodes; ++i)
1264     {
1265         dn.push_back(create_dummy_node(i + 1, 0, suspect_timeout,
1266                                        inactive_timeout, retrans_period));
1267         log_info << "i " << i;
1268         gu_trace(join_node(&prop, dn[i], i == 0));
1269         set_cvi(dn, 0, i, ++view_seq, V_PRIM);
1270         gu_trace(prop.propagate_until_cvi(false));
1271     }
1272 
1273     for (size_t i = 0; i < 5; ++i)
1274     {
1275 
1276         for (size_t j = 0; j < n_nodes; ++j)
1277         {
1278             send_n(dn[j], ::rand() % 5);
1279         }
1280 
1281 
1282         prop.propagate_n(9 + ::rand() % 5);
1283 
1284         for (size_t j = 0; j < n_nodes; ++j)
1285         {
1286             for (size_t k = 0; k < n_nodes; ++k)
1287             {
1288                 if (j != k)
1289                 {
1290                     prop.split(j + 1, k + 1);
1291                 }
1292             }
1293         }
1294 
1295         ++view_seq;
1296         log_info << "split " << i << " view seq " << view_seq;
1297         set_cvi(dn, 0, n_nodes - 1, view_seq, V_NON_PRIM);
1298         gu_trace(prop.propagate_until_cvi(true));
1299 
1300         for (size_t j = 0; j < n_nodes; ++j)
1301         {
1302             for (size_t k = 0; k < n_nodes; ++k)
1303             {
1304                 if (j != k)
1305                 {
1306                     prop.merge(j + 1, k + 1);
1307                 }
1308             }
1309         }
1310         ++view_seq;
1311         log_info << "merge " << i << " view seq " << view_seq;
1312         set_cvi(dn, 0, n_nodes - 1, view_seq, V_PRIM);
1313         gu_trace(prop.propagate_until_cvi(true));
1314     }
1315     check_trace(dn);
1316     for_each(dn.begin(), dn.end(), DeleteObject());
1317 }
1318 END_TEST
1319 
1320 
START_TEST(test_pc_protocol_upgrade)1321 START_TEST(test_pc_protocol_upgrade)
1322 {
1323     log_info << "START (test_pc_protocol_upgrade)";
1324     vector<DummyNode*> dn;
1325     PropagationMatrix prop;
1326     uint32_t view_seq(0);
1327 
1328     for (int i(0); i <= GCOMM_PROTOCOL_MAX_VERSION; ++i)
1329     {
1330         dn.push_back(create_dummy_node(i + 1, i));
1331         gu_trace(join_node(&prop, dn[i], i == 0));
1332         set_cvi(dn, 0, i, view_seq, V_PRIM);
1333         gu_trace(prop.propagate_until_cvi(false));
1334         ++view_seq;
1335         for (int j(0); j <= i; ++j)
1336         {
1337             ck_assert(pc_from_dummy(dn[j])->current_view().version() == 0);
1338             gu_trace(send_n(dn[j], 5 + ::rand() % 4));
1339         }
1340     }
1341 
1342     for (int i(0); i < GCOMM_PROTOCOL_MAX_VERSION; ++i)
1343     {
1344         for (int j(i); j <= GCOMM_PROTOCOL_MAX_VERSION; ++j)
1345         {
1346             gu_trace(send_n(dn[j], 5 + ::rand() % 4));
1347         }
1348         dn[i]->close();
1349         dn[i]->set_cvi(V_NON_PRIM);
1350         set_cvi(dn, i + 1, GCOMM_PROTOCOL_MAX_VERSION, view_seq, V_PRIM);
1351         gu_trace(prop.propagate_until_cvi(true));
1352         ++view_seq;
1353         for (int j(i + 1); j <= GCOMM_PROTOCOL_MAX_VERSION; ++j)
1354         {
1355             gu_trace(send_n(dn[j], 5 + ::rand() % 4));
1356         }
1357         gu_trace(prop.propagate_until_empty());
1358     }
1359     ck_assert(pc_from_dummy(dn[GCOMM_PROTOCOL_MAX_VERSION])->current_view().version() == GCOMM_PROTOCOL_MAX_VERSION);
1360     check_trace(dn);
1361     for_each(dn.begin(), dn.end(), DeleteObject());
1362 }
1363 END_TEST
1364 
1365 
1366 
START_TEST(test_trac_191)1367 START_TEST(test_trac_191)
1368 {
1369     log_info << "START (test_trac_191)";
1370     gu::Config conf;
1371     gu::ssl_register_params(conf);
1372     gcomm::Conf::register_params(conf);
1373     UUID uuid1(1), uuid2(2), uuid3(3), uuid4(4);
1374     Proto p(conf, uuid4, 0);
1375     DummyTransport tp(uuid4, true);
1376     // gcomm::connect(&tp, &p);
1377     PCUser pu(conf, uuid4, &tp, &p);
1378 
1379     p.shift_to(Proto::S_NON_PRIM);
1380     View t0(0, ViewId(V_TRANS, uuid4, 0));
1381     t0.add_member(uuid4, 0);
1382     p.handle_view(t0);
1383 
1384     View r5(0, ViewId(V_REG, uuid2, 5));
1385     r5.add_member(uuid3, 0);
1386     r5.add_member(uuid4, 0);
1387 
1388     p.handle_view(r5);
1389 
1390     Datagram* dg = tp.out();
1391     ck_assert(dg != 0);
1392     Message sm4;
1393     get_msg(dg, &sm4);
1394     ck_assert(sm4.type() == Message::PC_T_STATE);
1395 
1396     // Handle first sm from uuid3
1397 
1398     StateMessage sm3(0);
1399     pc::NodeMap& im3(sm3.node_map());
1400     im3.insert_unique(make_pair(uuid1,
1401                                 pc::Node(true, false, false, 254, ViewId(V_PRIM, uuid1, 3), 20)));
1402     im3.insert_unique(make_pair(uuid2,
1403                                 pc::Node(true, false, false, 254, ViewId(V_PRIM, uuid1, 3), 20)));
1404     im3.insert_unique(make_pair(uuid3,
1405                                 pc::Node(false, false, false, 254, ViewId(V_PRIM, uuid1, 3), 25)));
1406     p.handle_msg(sm3, Datagram(), ProtoUpMeta(uuid3));
1407     p.handle_msg(sm4, Datagram(), ProtoUpMeta(uuid4));
1408 }
1409 END_TEST
1410 
START_TEST(test_trac_413)1411 START_TEST(test_trac_413)
1412 {
1413     log_info << "START (test_trac_413)";
1414 
1415     class TN : gcomm::Toplay // test node
1416     {
1417     public:
1418         TN(gu::Config conf, const UUID& uuid)
1419             :
1420             Toplay(conf),
1421             p_(conf, uuid, 0),
1422             tp_(uuid, true)
1423         {
1424             gcomm::connect(&tp_, &p_);
1425             gcomm::connect(&p_, this);
1426         }
1427         const UUID& uuid() const { return p_.uuid(); }
1428         gcomm::pc::Proto& p() { return p_; }
1429         DummyTransport& tp() { return tp_; }
1430         void handle_up(const void* id, const Datagram& dg,
1431                        const gcomm::ProtoUpMeta& um)
1432         {
1433             // void
1434         }
1435     private:
1436         pc::Proto p_;
1437         DummyTransport tp_;
1438     };
1439 
1440     gu::Config conf;
1441     gu::ssl_register_params(conf);
1442     gcomm::Conf::register_params(conf);
1443 
1444     TN n1(conf, 1), n2(conf, 2), n3(conf, 3);
1445 
1446 
1447     // boot to first prim
1448     {
1449         gcomm::View tr(0, ViewId(V_TRANS, n1.uuid(), 0));
1450         tr.members().insert_unique(std::make_pair(n1.uuid(), 0));
1451         n1.p().connect(true);
1452         n1.p().handle_view(tr);
1453         Datagram* dg(n1.tp().out());
1454         ck_assert(dg == 0 && n1.p().state() == gcomm::pc::Proto::S_TRANS);
1455         gcomm::View reg(0, ViewId(V_REG, n1.uuid(), 1));
1456         reg.members().insert_unique(std::make_pair(n1.uuid(), 0));
1457         n1.p().handle_view(reg);
1458         dg = n1.tp().out();
1459         ck_assert(dg != 0 &&
1460                     n1.p().state() == gcomm::pc::Proto::S_STATES_EXCH);
1461         n1.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid()));
1462         delete dg;
1463         dg = n1.tp().out();
1464         ck_assert(dg != 0 &&
1465                     n1.p().state() == gcomm::pc::Proto::S_INSTALL);
1466         n1.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid()));
1467         delete dg;
1468         dg = n1.tp().out();
1469         ck_assert(dg == 0 && n1.p().state() == gcomm::pc::Proto::S_PRIM);
1470     }
1471 
1472     // add remaining nodes
1473     {
1474         gcomm::View tr(0, ViewId(V_TRANS, n1.uuid(), 1));
1475         tr.members().insert_unique(std::make_pair(n1.uuid(), 0));
1476         n1.p().handle_view(tr);
1477     }
1478     {
1479         gcomm::View tr(0, ViewId(V_TRANS, n2.uuid(), 0));
1480         tr.members().insert_unique(std::make_pair(n2.uuid(), 0));
1481         n2.p().connect(false);
1482         n2.p().handle_view(tr);
1483     }
1484     {
1485         gcomm::View tr(0, ViewId(V_TRANS, n3.uuid(), 0));
1486         tr.members().insert_unique(std::make_pair(n3.uuid(), 0));
1487         n3.p().connect(false);
1488         n3.p().handle_view(tr);
1489     }
1490 
1491     {
1492         gcomm::View reg(0, ViewId(V_REG, n1.uuid(), 2));
1493         reg.members().insert_unique(std::make_pair(n1.uuid(), 0));
1494         reg.members().insert_unique(std::make_pair(n2.uuid(), 0));
1495         reg.members().insert_unique(std::make_pair(n3.uuid(), 0));
1496         n1.p().handle_view(reg);
1497         n2.p().handle_view(reg);
1498         n3.p().handle_view(reg);
1499 
1500         Datagram* dg(n1.tp().out());
1501         ck_assert(dg != 0);
1502         n1.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid()));
1503         n2.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid()));
1504         n3.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid()));
1505         delete dg;
1506 
1507         dg = n2.tp().out();
1508         ck_assert(dg != 0);
1509         n1.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n2.uuid()));
1510         n2.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n2.uuid()));
1511         n3.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n2.uuid()));
1512         delete dg;
1513 
1514         dg = n3.tp().out();
1515         ck_assert(dg != 0);
1516         n1.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n3.uuid()));
1517         n2.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n3.uuid()));
1518         n3.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n3.uuid()));
1519         delete dg;
1520 
1521         dg = n1.tp().out();
1522         ck_assert(dg != 0);
1523         n1.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid()));
1524         n2.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid()));
1525         n3.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid()));
1526         delete dg;
1527 
1528         ck_assert(n1.tp().out() == 0 &&
1529                     n1.p().state() == gcomm::pc::Proto::S_PRIM);
1530         ck_assert(n2.tp().out() == 0 &&
1531                     n2.p().state() == gcomm::pc::Proto::S_PRIM);
1532         ck_assert(n3.tp().out() == 0 &&
1533                     n3.p().state() == gcomm::pc::Proto::S_PRIM);
1534     }
1535 
1536     mark_point();
1537     // drop n1 from view and deliver only state messages in
1538     // the following reg view
1539     {
1540         gcomm::View tr(0, gcomm::ViewId(V_TRANS, n1.uuid(), 2));
1541         tr.members().insert_unique(std::make_pair(n2.uuid(), 0));
1542         tr.members().insert_unique(std::make_pair(n3.uuid(), 0));
1543 
1544         n2.p().handle_view(tr);
1545         n3.p().handle_view(tr);
1546 
1547         gcomm::View reg(0, gcomm::ViewId(V_REG, n2.uuid(), 3));
1548         reg.members().insert_unique(std::make_pair(n2.uuid(), 0));
1549         reg.members().insert_unique(std::make_pair(n3.uuid(), 0));
1550         n2.p().handle_view(reg);
1551         n3.p().handle_view(reg);
1552 
1553 
1554         Datagram* dg(n2.tp().out());
1555         n2.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n2.uuid()));
1556         n3.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n2.uuid()));
1557         delete dg;
1558 
1559         dg = n3.tp().out();
1560         n2.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n3.uuid()));
1561         n3.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n3.uuid()));
1562         delete dg;
1563         // Clean up n2 out queue
1564         dg = n2.tp().out();
1565         delete dg;
1566     }
1567 
1568     mark_point();
1569     // drop n2 from view and make sure that n3 ends in non-prim
1570     {
1571         gcomm::View tr(0, gcomm::ViewId(V_TRANS, n2.uuid(), 3));
1572         tr.members().insert_unique(std::make_pair(n3.uuid(), 0));
1573         n3.p().handle_view(tr);
1574         ck_assert(n3.tp().out() == 0 &&
1575                     n3.p().state() == gcomm::pc::Proto::S_TRANS);
1576 
1577         gcomm::View reg(0, gcomm::ViewId(V_REG, n3.uuid(), 4));
1578         reg.members().insert_unique(std::make_pair(n3.uuid(), 0));
1579         n3.p().handle_view(reg);
1580 
1581         ck_assert(n3.p().state() == gcomm::pc::Proto::S_STATES_EXCH);
1582 
1583         Datagram* dg(n3.tp().out());
1584         ck_assert(dg != 0);
1585         n3.p().handle_up(0, *dg, ProtoUpMeta(n3.uuid()));
1586         delete dg;
1587         dg = n3.tp().out();
1588         ck_assert_msg(dg == 0 &&
1589                       n3.p().state() == gcomm::pc::Proto::S_NON_PRIM,
1590                       "%p %d", dg, n3.p().state());
1591     }
1592 
1593 }
1594 END_TEST
1595 
1596 
START_TEST(test_fifo_violation)1597 START_TEST(test_fifo_violation)
1598 {
1599     log_info << "START (test_fifo_violation)";
1600     gu::Config conf;
1601     gu::ssl_register_params(conf);
1602     gcomm::Conf::register_params(conf);
1603     UUID uuid1(1);
1604     ProtoUpMeta pum1(uuid1);
1605     Proto pc1(conf, uuid1, 0);
1606     DummyTransport tp1;
1607     PCUser pu1(conf, uuid1, &tp1, &pc1);
1608     single_boot(0, &pu1);
1609 
1610     assert(pc1.state() == Proto::S_PRIM);
1611     pu1.send();
1612     pu1.send();
1613     Datagram* dg1(tp1.out());
1614     ck_assert(dg1 != 0);
1615     Datagram* dg2(tp1.out());
1616     ck_assert(dg2 != 0);
1617 
1618     try
1619     {
1620         pc1.handle_up(0, *dg2, ProtoUpMeta(uuid1, ViewId(), 0, 0xff, O_SAFE));
1621         ck_abort_msg("Exception not thrown");
1622     }
1623     catch (Exception& e)
1624     {
1625         ck_assert(e.get_errno() == ENOTRECOVERABLE);
1626     }
1627     delete dg1;
1628     delete dg2;
1629 }
1630 END_TEST
1631 
START_TEST(test_checksum)1632 START_TEST(test_checksum)
1633 {
1634     log_info << "START (test_checksum)";
1635     gu::Config conf;
1636     gu::ssl_register_params(conf);
1637     gcomm::Conf::register_params(conf);
1638     conf.set(Conf::PcChecksum, gu::to_string(true));
1639     UUID uuid1(1);
1640     ProtoUpMeta pum1(uuid1);
1641     Proto pc1(conf, uuid1, 0);
1642     DummyTransport tp1;
1643     PCUser pu1(conf, uuid1, &tp1, &pc1);
1644     single_boot(0, &pu1);
1645 
1646     assert(pc1.state() == Proto::S_PRIM);
1647     pu1.send();
1648     Datagram* dg(tp1.out());
1649     ck_assert(dg != 0);
1650     dg->normalize();
1651     pc1.handle_up(0, *dg, ProtoUpMeta(uuid1));
1652     delete dg;
1653 
1654     pu1.send();
1655     dg = tp1.out();
1656     ck_assert(dg != 0);
1657     dg->normalize();
1658     *(&dg->payload()[0] + dg->payload().size() - 1) ^= 0x10;
1659     try
1660     {
1661         pc1.handle_up(0, *dg, ProtoUpMeta(uuid1));
1662         ck_abort_msg("Exception not thrown");
1663     }
1664     catch (Exception& e)
1665     {
1666         ck_assert(e.get_errno() == ENOTRECOVERABLE);
1667     }
1668     delete dg;
1669 }
1670 END_TEST
1671 
1672 
1673 
1674 
1675 
START_TEST(test_trac_277)1676 START_TEST(test_trac_277)
1677 {
1678     log_info << "START (test_trac_277)";
1679     size_t n_nodes(3);
1680     vector<DummyNode*> dn;
1681     PropagationMatrix prop;
1682     const string suspect_timeout("PT0.35S");
1683     const string inactive_timeout("PT0.7S");
1684     const string retrans_period("PT0.1S");
1685     uint32_t view_seq = 0;
1686 
1687     for (size_t i = 0; i < n_nodes; ++i)
1688     {
1689         dn.push_back(create_dummy_node(i + 1, 0, suspect_timeout,
1690                                        inactive_timeout, retrans_period));
1691         gu_trace(join_node(&prop, dn[i], i == 0));
1692         set_cvi(dn, 0, i, ++view_seq, V_PRIM);
1693         gu_trace(prop.propagate_until_cvi(false));
1694     }
1695 
1696     log_info << "generate messages";
1697     send_n(dn[0], 1);
1698     send_n(dn[1], 1);
1699     send_n(dn[2], 1);
1700     gu_trace(prop.propagate_until_empty());
1701 
1702     log_info << "isolate 3";
1703     prop.split(1, 3);
1704     prop.split(2, 3);
1705     ++view_seq;
1706     set_cvi(dn, 0, 1, view_seq, V_PRIM);
1707     set_cvi(dn, 2, 2, view_seq, V_NON_PRIM);
1708     gu_trace(prop.propagate_until_cvi(true));
1709 
1710     log_info << "isolate 1 and 2";
1711     ++view_seq;
1712     prop.split(1, 2);
1713     set_cvi(dn, 0, 1, view_seq, V_NON_PRIM);
1714     gu_trace(prop.propagate_until_cvi(true));
1715 
1716     log_info << "merge 1 and 2";
1717     ++view_seq;
1718     prop.merge(1, 2);
1719     set_cvi(dn, 0, 1, view_seq, V_PRIM);
1720     gu_trace(prop.propagate_until_cvi(true));
1721 
1722 
1723 
1724     log_info << "merge 3";
1725     ++view_seq;
1726     prop.merge(1, 3);
1727     prop.merge(2, 3);
1728     set_cvi(dn, 0, 2, view_seq, V_PRIM);
1729     gu_trace(prop.propagate_until_cvi(true));
1730 
1731     check_trace(dn);
1732     for_each(dn.begin(), dn.end(), DeleteObject());
1733 }
1734 END_TEST
1735 
1736 
1737 // This test checks the case when another node of two node cluster
1738 // crashes or becomes completely isolated and prim view of cluster
1739 // is established by starting third instance directly in prim mode.
START_TEST(test_trac_622_638)1740 START_TEST(test_trac_622_638)
1741 {
1742     log_info << "START (test_trac_622_638)";
1743     vector<DummyNode*> dn;
1744     PropagationMatrix prop;
1745     const string suspect_timeout("PT0.35S");
1746     const string inactive_timeout("PT0.7S");
1747     const string retrans_period("PT0.1S");
1748     uint32_t view_seq = 0;
1749 
1750     // Create two node cluster and make it split. First node is
1751     // considered crashed after split (stay isolated in non-prim).
1752     dn.push_back(create_dummy_node(1, 0, suspect_timeout,
1753                                    inactive_timeout, retrans_period));
1754     gu_trace(join_node(&prop, dn[0], true));
1755     set_cvi(dn, 0, 0, ++view_seq, V_PRIM);
1756     gu_trace(prop.propagate_until_cvi(false));
1757 
1758     dn.push_back(create_dummy_node(2, 0, suspect_timeout,
1759                                    inactive_timeout, retrans_period));
1760     gu_trace(join_node(&prop, dn[1], false));
1761     set_cvi(dn, 0, 1, ++view_seq, V_PRIM);
1762     gu_trace(prop.propagate_until_cvi(false));
1763 
1764     log_info << "generate messages";
1765     send_n(dn[0], 1);
1766     send_n(dn[1], 1);
1767     gu_trace(prop.propagate_until_empty());
1768 
1769     log_info << "isolate 1 and 2";
1770     prop.split(1, 2);
1771     ++view_seq;
1772     set_cvi(dn, 0, 0, view_seq, V_NON_PRIM);
1773     set_cvi(dn, 1, 1, view_seq, V_NON_PRIM);
1774     gu_trace(prop.propagate_until_cvi(true));
1775 
1776     // Add third node which will be connected with node 2. This will
1777     // be started with prim status.
1778     dn.push_back(create_dummy_node(3, 0, suspect_timeout,
1779                                    inactive_timeout, retrans_period));
1780     gu_trace(join_node(&prop, dn[2], true));
1781     prop.split(1, 3); // avoid 1 <-> 3 communication
1782     ++view_seq;
1783     set_cvi(dn, 1, 2, view_seq, V_PRIM);
1784     gu_trace(prop.propagate_until_cvi(false));
1785 
1786     check_trace(dn);
1787     for_each(dn.begin(), dn.end(), DeleteObject());
1788 }
1789 END_TEST
1790 
START_TEST(test_weighted_quorum)1791 START_TEST(test_weighted_quorum)
1792 {
1793     log_info << "START (test_weighted_quorum)";
1794     size_t n_nodes(3);
1795     vector<DummyNode*> dn;
1796     PropagationMatrix prop;
1797     const string suspect_timeout("PT0.35S");
1798     const string inactive_timeout("PT0.7S");
1799     const string retrans_period("PT0.1S");
1800     uint32_t view_seq = 0;
1801 
1802     for (size_t i = 0; i < n_nodes; ++i)
1803     {
1804         dn.push_back(create_dummy_node(i + 1, 0, suspect_timeout,
1805                                        inactive_timeout,
1806                                        retrans_period, i));
1807         gu_trace(join_node(&prop, dn[i], i == 0));
1808         set_cvi(dn, 0, i, ++view_seq, V_PRIM);
1809         gu_trace(prop.propagate_until_cvi(false));
1810     }
1811 
1812     for (size_t i(0); i < n_nodes; ++i)
1813     {
1814         int weight(pc_from_dummy(dn[i])->cluster_weight());
1815         ck_assert_msg(weight == 3,
1816                       "index: %zu weight: %d", i, weight);
1817     }
1818     // split node 3 (weight 2) out, node 3 should remain in prim while
1819     // nodes 1 and 2 (weights 0 + 1 = 1) should end up in non-prim
1820     prop.split(1, 3);
1821     prop.split(2, 3);
1822     ++view_seq;
1823     set_cvi(dn, 0, 1, view_seq, V_NON_PRIM);
1824     set_cvi(dn, 2, 2, view_seq, V_PRIM);
1825     gu_trace(prop.propagate_until_cvi(true));
1826 
1827     ck_assert(pc_from_dummy(dn[0])->cluster_weight() == 0);
1828     ck_assert(pc_from_dummy(dn[1])->cluster_weight() == 0);
1829     ck_assert(pc_from_dummy(dn[2])->cluster_weight() == 2);
1830     std::for_each(dn.begin(), dn.end(), gu::DeleteObject());
1831 }
1832 END_TEST
1833 
1834 
1835 //
1836 // The scenario is the following (before fix):
1837 //
1838 // - Two nodes 2 and 3 started with weights 1
1839 // - Third node 1 with weight 3 is brought in the cluster
1840 //   (becomes representative)
1841 // - Partitioning to (1) and (2, 3) happens so that INSTALL message is
1842 //   delivered on 2 and 3 in TRANS and on 1 in REG
1843 // - Node 1 forms PC
1844 // - Nodes 2 and 3 renegotiate and form PC too because node 1 was not present
1845 //   in the previous PC
1846 //
1847 // What should happen is that nodes 2 and 3 recompute quorum on handling
1848 // install message and shift to non-PC
1849 //
START_TEST(test_weighted_partitioning_1)1850 START_TEST(test_weighted_partitioning_1)
1851 {
1852     log_info << "START (test_weighted_partitioning_1)";
1853     gu::Config conf3;
1854     gu::ssl_register_params(conf3);
1855     gcomm::Conf::register_params(conf3);
1856     conf3.set("pc.weight", "1");
1857     UUID uuid3(3);
1858     ProtoUpMeta pum3(uuid3);
1859     Proto pc3(conf3, uuid3, 0);
1860     DummyTransport tp3;
1861     PCUser pu3(conf3, uuid3, &tp3, &pc3);
1862     single_boot(0, &pu3);
1863 
1864     gu::Config conf2;
1865     gu::ssl_register_params(conf2);
1866     gcomm::Conf::register_params(conf2);
1867     conf2.set("pc.weight", "1");
1868     UUID uuid2(2);
1869     ProtoUpMeta pum2(uuid2);
1870     Proto pc2(conf2, uuid2, 0);
1871     DummyTransport tp2;
1872     PCUser pu2(conf2, uuid2, &tp2, &pc2);
1873 
1874     double_boot(0, &pu3, &pu2);
1875 
1876     gu::Config conf1;
1877     gu::ssl_register_params(conf1);
1878     gcomm::Conf::register_params(conf1);
1879     conf1.set("pc.weight", "3");
1880     UUID uuid1(1);
1881     ProtoUpMeta pum1(uuid1);
1882     Proto pc1(conf1, uuid1, 0);
1883     DummyTransport tp1;
1884     PCUser pu1(conf1, uuid1, &tp1, &pc1);
1885 
1886     // trans views
1887     {
1888         View tr1(0, ViewId(V_TRANS, uuid1, 0));
1889         tr1.add_member(uuid1, 0);
1890         pu1.pc()->connect(false);
1891         ProtoUpMeta um1(UUID::nil(), ViewId(), &tr1);
1892         pu1.pc()->handle_up(0, Datagram(), um1);
1893 
1894         View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id()));
1895         tr23.add_member(uuid2, 0);
1896         tr23.add_member(uuid3, 0);
1897         ProtoUpMeta um23(UUID::nil(), ViewId(), &tr23);
1898         pu2.pc()->handle_up(0, Datagram(), um23);
1899         pu3.pc()->handle_up(0, Datagram(), um23);
1900     }
1901 
1902 
1903     // reg view
1904     {
1905         View reg(0,
1906                  ViewId(V_REG, uuid1, pu2.pc()->current_view().id().seq() + 1));
1907         reg.add_member(uuid1, 0);
1908         reg.add_member(uuid2, 0);
1909         reg.add_member(uuid3, 0);
1910         ProtoUpMeta um(UUID::nil(), ViewId(), &reg);
1911         pu1.pc()->handle_up(0, Datagram(), um);
1912         pu2.pc()->handle_up(0, Datagram(), um);
1913         pu3.pc()->handle_up(0, Datagram(), um);
1914     }
1915 
1916     // states exch
1917     {
1918         Datagram* dg(pu1.tp()->out());
1919         ck_assert(dg != 0);
1920         pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1));
1921         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1));
1922         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1));
1923         delete dg;
1924 
1925         dg = pu2.tp()->out();
1926         ck_assert(dg != 0);
1927         pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2));
1928         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2));
1929         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2));
1930         delete dg;
1931 
1932         dg = pu3.tp()->out();
1933         ck_assert(dg != 0);
1934         pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3));
1935         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3));
1936         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3));
1937         delete dg;
1938 
1939         ck_assert(pu2.tp()->out() == 0);
1940         ck_assert(pu3.tp()->out() == 0);
1941     }
1942 
1943     // install msg
1944     {
1945         Datagram* dg(pu1.tp()->out());
1946         ck_assert(dg != 0);
1947 
1948         pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1));
1949         ck_assert(pu1.pc()->state() == Proto::S_PRIM);
1950 
1951         // trans view for 2 and 3
1952         View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id()));
1953         tr23.add_member(uuid2, 0);
1954         tr23.add_member(uuid3, 0);
1955         tr23.add_partitioned(uuid1, 0);
1956 
1957         ProtoUpMeta trum23(UUID::nil(), ViewId(), &tr23);
1958         pu2.pc()->handle_up(0, Datagram(), trum23);
1959         pu3.pc()->handle_up(0, Datagram(), trum23);
1960 
1961         // 2 and 3 handle install
1962         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1));
1963         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1));
1964         delete dg;
1965 
1966         // reg view for 2 and 3
1967         View reg23(0, ViewId(V_REG, uuid2, pu2.pc()->current_view().id().seq() + 1));
1968         reg23.add_member(uuid2, 0);
1969         reg23.add_member(uuid3, 0);
1970         ProtoUpMeta rum23(UUID::nil(), ViewId(), &reg23);
1971         pu2.pc()->handle_up(0, Datagram(), rum23);
1972         pu3.pc()->handle_up(0, Datagram(), rum23);
1973 
1974         // states exch
1975 
1976         dg = pu2.tp()->out();
1977         ck_assert(dg != 0);
1978         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2));
1979         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2));
1980         delete dg;
1981 
1982         dg = pu3.tp()->out();
1983         ck_assert(dg != 0);
1984         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3));
1985         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3));
1986         delete dg;
1987 
1988         // 2 and 3 should end up in non prim
1989         ck_assert_msg(pu2.pc()->state() == Proto::S_NON_PRIM,
1990                       "state: %s", Proto::to_string(pu2.pc()->state()).c_str());
1991         ck_assert_msg(pu3.pc()->state() == Proto::S_NON_PRIM,
1992                       "state: %s", Proto::to_string(pu3.pc()->state()).c_str());
1993     }
1994 
1995 
1996 }
1997 END_TEST
1998 
1999 //
2000 // - Two nodes 2 and 3 started with weights 1
2001 // - Third node 1 with weight 3 is brought in the cluster
2002 //   (becomes representative)
2003 // - Partitioning to (1) and (2, 3) happens so that INSTALL message is
2004 //   delivered in trans view on all nodes
2005 // - All nodes should end up in non-prim, nodes 2 and 3 because they don't know
2006 //   if node 1 ended up in prim (see test_weighted_partitioning_1 above),
2007 //   node 1 because it hasn't been in primary before and fails to deliver
2008 //   install message in reg view
2009 //
START_TEST(test_weighted_partitioning_2)2010 START_TEST(test_weighted_partitioning_2)
2011 {
2012     log_info << "START (test_weighted_partitioning_2)";
2013     gu::Config conf3;
2014     gu::ssl_register_params(conf3);
2015     gcomm::Conf::register_params(conf3);
2016     conf3.set("pc.weight", "1");
2017     UUID uuid3(3);
2018     ProtoUpMeta pum3(uuid3);
2019     Proto pc3(conf3, uuid3, 0);
2020     DummyTransport tp3;
2021     PCUser pu3(conf3, uuid3, &tp3, &pc3);
2022     single_boot(0, &pu3);
2023 
2024     gu::Config conf2;
2025     gu::ssl_register_params(conf2);
2026     gcomm::Conf::register_params(conf2);
2027     conf2.set("pc.weight", "1");
2028     UUID uuid2(2);
2029     ProtoUpMeta pum2(uuid2);
2030     Proto pc2(conf2, uuid2, 0);
2031     DummyTransport tp2;
2032     PCUser pu2(conf2, uuid2, &tp2, &pc2);
2033 
2034     double_boot(0, &pu3, &pu2);
2035 
2036     gu::Config conf1;
2037     gu::ssl_register_params(conf1);
2038     gcomm::Conf::register_params(conf1);
2039     conf1.set("pc.weight", "3");
2040     UUID uuid1(1);
2041     ProtoUpMeta pum1(uuid1);
2042     Proto pc1(conf1, uuid1, 0);
2043     DummyTransport tp1;
2044     PCUser pu1(conf1, uuid1, &tp1, &pc1);
2045 
2046     // trans views
2047     {
2048         View tr1(0, ViewId(V_TRANS, uuid1, 0));
2049         tr1.add_member(uuid1, 0);
2050         pu1.pc()->connect(false);
2051         ProtoUpMeta um1(UUID::nil(), ViewId(), &tr1);
2052         pu1.pc()->handle_up(0, Datagram(), um1);
2053 
2054         View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id()));
2055         tr23.add_member(uuid2, 0);
2056         tr23.add_member(uuid3, 0);
2057         ProtoUpMeta um23(UUID::nil(), ViewId(), &tr23);
2058         pu2.pc()->handle_up(0, Datagram(), um23);
2059         pu3.pc()->handle_up(0, Datagram(), um23);
2060     }
2061 
2062 
2063     // reg view
2064     {
2065         View reg(0,
2066                  ViewId(V_REG, uuid1, pu2.pc()->current_view().id().seq() + 1));
2067         reg.add_member(uuid1, 0);
2068         reg.add_member(uuid2, 0);
2069         reg.add_member(uuid3, 0);
2070         ProtoUpMeta um(UUID::nil(), ViewId(), &reg);
2071         pu1.pc()->handle_up(0, Datagram(), um);
2072         pu2.pc()->handle_up(0, Datagram(), um);
2073         pu3.pc()->handle_up(0, Datagram(), um);
2074     }
2075 
2076     // states exch
2077     {
2078         Datagram* dg(pu1.tp()->out());
2079         ck_assert(dg != 0);
2080         pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1));
2081         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1));
2082         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1));
2083         delete dg;
2084 
2085         dg = pu2.tp()->out();
2086         ck_assert(dg != 0);
2087         pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2));
2088         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2));
2089         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2));
2090         delete dg;
2091 
2092         dg = pu3.tp()->out();
2093         ck_assert(dg != 0);
2094         pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3));
2095         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3));
2096         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3));
2097         delete dg;
2098 
2099         ck_assert(pu2.tp()->out() == 0);
2100         ck_assert(pu3.tp()->out() == 0);
2101     }
2102 
2103     // install msg
2104     {
2105         Datagram* dg(pu1.tp()->out());
2106         ck_assert(dg != 0);
2107 
2108         // trans view for 1
2109         View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
2110         tr1.add_member(uuid1, 0);
2111         tr1.add_partitioned(uuid2, 0);
2112         tr1.add_partitioned(uuid3, 0);
2113         ProtoUpMeta trum1(UUID::nil(), ViewId(), &tr1);
2114         pu1.pc()->handle_up(0, Datagram(), trum1);
2115         ck_assert(pu1.pc()->state() == Proto::S_TRANS);
2116 
2117         // 1 handle install
2118         pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1));
2119         ck_assert(pu1.pc()->state() == Proto::S_TRANS);
2120 
2121 
2122         // trans view for 2 and 3
2123         View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id()));
2124         tr23.add_member(uuid2, 0);
2125         tr23.add_member(uuid3, 0);
2126         tr23.add_partitioned(uuid1, 0);
2127         ProtoUpMeta trum23(UUID::nil(), ViewId(), &tr23);
2128         pu2.pc()->handle_up(0, Datagram(), trum23);
2129         pu3.pc()->handle_up(0, Datagram(), trum23);
2130         ck_assert(pu2.pc()->state() == Proto::S_TRANS);
2131         ck_assert(pu3.pc()->state() == Proto::S_TRANS);
2132 
2133         // 2 and 3 handle install
2134         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1));
2135         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1));
2136         ck_assert(pu2.pc()->state() == Proto::S_TRANS);
2137         ck_assert(pu3.pc()->state() == Proto::S_TRANS);
2138 
2139         delete dg;
2140 
2141         // reg view for 1
2142         View reg1(0, ViewId(V_REG, uuid1, pu1.pc()->current_view().id().seq() + 1));
2143         reg1.add_member(uuid1, 0);
2144         ProtoUpMeta rum1(UUID::nil(), ViewId(), &reg1);
2145         pu1.pc()->handle_up(0, Datagram(), rum1);
2146         ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
2147 
2148         // reg view for 2 and 3
2149         View reg23(0, ViewId(V_REG, uuid2, pu2.pc()->current_view().id().seq() + 1));
2150         reg23.add_member(uuid2, 0);
2151         reg23.add_member(uuid3, 0);
2152         ProtoUpMeta rum23(UUID::nil(), ViewId(), &reg23);
2153         pu2.pc()->handle_up(0, Datagram(), rum23);
2154         pu3.pc()->handle_up(0, Datagram(), rum23);
2155         ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
2156         ck_assert(pu3.pc()->state() == Proto::S_STATES_EXCH);
2157 
2158 
2159         // states exch
2160 
2161         dg = pu1.tp()->out();
2162         ck_assert(dg != 0);
2163         pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1));
2164         ck_assert_msg(pu1.pc()->state() == Proto::S_NON_PRIM,
2165                       "state: %s", Proto::to_string(pu1.pc()->state()).c_str());
2166         delete dg;
2167 
2168         dg = pu2.tp()->out();
2169         ck_assert(dg != 0);
2170         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2));
2171         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2));
2172         delete dg;
2173 
2174         dg = pu3.tp()->out();
2175         ck_assert(dg != 0);
2176         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3));
2177         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3));
2178         delete dg;
2179 
2180 
2181         ck_assert_msg(pu2.pc()->state() == Proto::S_NON_PRIM,
2182                       "state: %s", Proto::to_string(pu2.pc()->state()).c_str());
2183         ck_assert_msg(pu3.pc()->state() == Proto::S_NON_PRIM,
2184                       "state: %s", Proto::to_string(pu3.pc()->state()).c_str());
2185     }
2186 
2187 
2188 }
2189 END_TEST
2190 
2191 
2192 //
2193 // - Nodes 1-3 started with equal weights
2194 // - Weight for node 1 is changed to 3
2195 // - Group splits to (1), (2, 3)
2196 // - Weigh changing message is delivered in reg view in (1) and in
2197 //   trans in (2, 3)
2198 // - Expected outcome: 1 stays in prim, 2 and 3 end up in non-prim
2199 //
START_TEST(test_weight_change_partitioning_1)2200 START_TEST(test_weight_change_partitioning_1)
2201 {
2202     log_info << "START (test_weight_change_partitioning_1)";
2203     gu::Config conf1;
2204     gu::ssl_register_params(conf1);
2205     gcomm::Conf::register_params(conf1);
2206     conf1.set("pc.weight", "1");
2207     UUID uuid1(1);
2208     ProtoUpMeta pum1(uuid1);
2209     Proto pc1(conf1, uuid1, 0);
2210     DummyTransport tp1;
2211     PCUser pu1(conf1, uuid1, &tp1, &pc1);
2212     single_boot(0, &pu1);
2213 
2214     gu::Config conf2;
2215     gu::ssl_register_params(conf2);
2216     gcomm::Conf::register_params(conf2);
2217     conf2.set("pc.weight", "1");
2218     UUID uuid2(2);
2219     ProtoUpMeta pum2(uuid2);
2220     Proto pc2(conf2, uuid2, 0);
2221     DummyTransport tp2;
2222     PCUser pu2(conf2, uuid2, &tp2, &pc2);
2223 
2224     double_boot(0, &pu1, &pu2);
2225 
2226     gu::Config conf3;
2227     gu::ssl_register_params(conf3);
2228     gcomm::Conf::register_params(conf3);
2229     conf3.set("pc.weight", "1");
2230     UUID uuid3(3);
2231     ProtoUpMeta pum3(uuid3);
2232     Proto pc3(conf3, uuid3, 0);
2233     DummyTransport tp3;
2234     PCUser pu3(conf3, uuid3, &tp3, &pc3);
2235 
2236     triple_boot(0, &pu1, &pu2, &pu3);
2237 
2238     // weight change
2239     {
2240         Protolay::sync_param_cb_t sync_param_cb;
2241         pu1.pc()->set_param("pc.weight", "3", sync_param_cb);
2242         ck_assert(sync_param_cb.empty() == false);
2243         Datagram* install_dg(pu1.tp()->out());
2244         ck_assert(install_dg != 0);
2245 
2246         // node 1 handle weight change install, proceed to singleton prim
2247         pu1.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid()));
2248 
2249         View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
2250         tr1.add_member(pu1.uuid(), 0);
2251         tr1.add_partitioned(pu2.uuid(), 0);
2252         tr1.add_partitioned(pu3.uuid(), 0);
2253 
2254         pu1.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1));
2255         ck_assert(pu1.pc()->state() == Proto::S_TRANS);
2256 
2257         View reg1(0, ViewId(V_REG, pu1.uuid(),
2258                             pu1.pc()->current_view().id().seq() + 1));
2259         reg1.add_member(pu1.uuid(), 0);
2260         pu1.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg1));
2261         ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
2262 
2263         Datagram* dg(pu1.tp()->out());
2264         ck_assert(dg != 0);
2265         pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid()));
2266         delete dg;
2267         ck_assert(pu1.pc()->state() == Proto::S_INSTALL);
2268 
2269         dg = pu1.tp()->out();
2270         ck_assert(dg != 0);
2271         pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid()));
2272         delete dg;
2273         ck_assert(pu1.pc()->state() == Proto::S_PRIM);
2274 
2275         // nodes 2 and 3 go to trans, handle install
2276         View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id()));
2277         tr23.add_member(pu2.uuid(), 0);
2278         tr23.add_member(pu3.uuid(), 0);
2279         tr23.add_partitioned(pu1.uuid(), 0);
2280 
2281         pu2.pc()->handle_up(0, Datagram(),
2282                             ProtoUpMeta(UUID::nil(), ViewId(), &tr23));
2283         pu3.pc()->handle_up(0, Datagram(),
2284                             ProtoUpMeta(UUID::nil(), ViewId(), &tr23));
2285         ck_assert(pu2.pc()->state() == Proto::S_TRANS);
2286         ck_assert(pu3.pc()->state() == Proto::S_TRANS);
2287 
2288         pu2.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid()));
2289         pu3.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid()));
2290 
2291         View reg23(0, ViewId(V_REG, pu2.uuid(),
2292                              pu2.pc()->current_view().id().seq() + 1));
2293         reg23.add_member(pu2.uuid(), 0);
2294         reg23.add_member(pu3.uuid(), 0);
2295 
2296         pu2.pc()->handle_up(0, Datagram(),
2297                             ProtoUpMeta(UUID::nil(), ViewId(), &reg23));
2298         pu3.pc()->handle_up(0, Datagram(),
2299                             ProtoUpMeta(UUID::nil(), ViewId(), &reg23));
2300         ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
2301         ck_assert(pu3.pc()->state() == Proto::S_STATES_EXCH);
2302 
2303         dg = pu2.tp()->out();
2304         ck_assert(dg != 0);
2305         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid()));
2306         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid()));
2307         delete dg;
2308 
2309         dg = pu3.tp()->out();
2310         ck_assert(dg != 0);
2311         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid()));
2312         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid()));
2313         delete dg;
2314 
2315         ck_assert(pu2.pc()->state() == Proto::S_NON_PRIM);
2316         ck_assert(pu3.pc()->state() == Proto::S_NON_PRIM);
2317 
2318         delete install_dg;
2319     }
2320 
2321 }
2322 END_TEST
2323 
2324 
2325 //
2326 // - Nodes 2 and 3 start with weight 1, node 1 with weight 3
2327 // - Weight for node 1 is changed to 1
2328 // - Group splits to (1), (2, 3)
2329 // - Weigh changing message is delivered in reg view in (1) and in
2330 //   trans in (2, 3)
2331 // - Expected outcome: all nodes go non-prim
2332 //
START_TEST(test_weight_change_partitioning_2)2333 START_TEST(test_weight_change_partitioning_2)
2334 {
2335     log_info << "START (test_weight_change_partitioning_2)";
2336     gu::Config conf1;
2337     gu::ssl_register_params(conf1);
2338     gcomm::Conf::register_params(conf1);
2339     conf1.set("pc.weight", "3");
2340     UUID uuid1(1);
2341     ProtoUpMeta pum1(uuid1);
2342     Proto pc1(conf1, uuid1, 0);
2343     DummyTransport tp1;
2344     PCUser pu1(conf1, uuid1, &tp1, &pc1);
2345     single_boot(0, &pu1);
2346 
2347     gu::Config conf2;
2348     gu::ssl_register_params(conf2);
2349     gcomm::Conf::register_params(conf2);
2350     conf2.set("pc.weight", "1");
2351     UUID uuid2(2);
2352     ProtoUpMeta pum2(uuid2);
2353     Proto pc2(conf2, uuid2, 0);
2354     DummyTransport tp2;
2355     PCUser pu2(conf2, uuid2, &tp2, &pc2);
2356 
2357     double_boot(0, &pu1, &pu2);
2358 
2359     gu::Config conf3;
2360     gu::ssl_register_params(conf3);
2361     gcomm::Conf::register_params(conf3);
2362     conf3.set("pc.weight", "1");
2363     UUID uuid3(3);
2364     ProtoUpMeta pum3(uuid3);
2365     Proto pc3(conf3, uuid3, 0);
2366     DummyTransport tp3;
2367     PCUser pu3(conf3, uuid3, &tp3, &pc3);
2368 
2369     triple_boot(0, &pu1, &pu2, &pu3);
2370 
2371     // weight change
2372     {
2373         Protolay::sync_param_cb_t sync_param_cb;
2374         pu1.pc()->set_param("pc.weight", "1", sync_param_cb);
2375         ck_assert(sync_param_cb.empty() == false);
2376         Datagram* install_dg(pu1.tp()->out());
2377         ck_assert(install_dg != 0);
2378 
2379         // node 1 handle weight change install, proceed to singleton prim
2380         pu1.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid()));
2381 
2382         View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
2383         tr1.add_member(pu1.uuid(), 0);
2384         tr1.add_partitioned(pu2.uuid(), 0);
2385         tr1.add_partitioned(pu3.uuid(), 0);
2386 
2387         pu1.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1));
2388         ck_assert(pu1.pc()->state() == Proto::S_TRANS);
2389 
2390         View reg1(0, ViewId(V_REG, pu1.uuid(),
2391                             pu1.pc()->current_view().id().seq() + 1));
2392         reg1.add_member(pu1.uuid(), 0);
2393         pu1.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg1));
2394         ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
2395 
2396         Datagram* dg(pu1.tp()->out());
2397         ck_assert(dg != 0);
2398         pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid()));
2399         delete dg;
2400         ck_assert(pu1.pc()->state() == Proto::S_NON_PRIM);
2401 
2402         // nodes 2 and 3 go to trans, handle install
2403         View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id()));
2404         tr23.add_member(pu2.uuid(), 0);
2405         tr23.add_member(pu3.uuid(), 0);
2406         tr23.add_partitioned(pu1.uuid(), 0);
2407 
2408         pu2.pc()->handle_up(0, Datagram(),
2409                             ProtoUpMeta(UUID::nil(), ViewId(), &tr23));
2410         pu3.pc()->handle_up(0, Datagram(),
2411                             ProtoUpMeta(UUID::nil(), ViewId(), &tr23));
2412         ck_assert(pu2.pc()->state() == Proto::S_TRANS);
2413         ck_assert(pu3.pc()->state() == Proto::S_TRANS);
2414 
2415         pu2.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid()));
2416         pu3.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid()));
2417 
2418         View reg23(0, ViewId(V_REG, pu2.uuid(),
2419                              pu2.pc()->current_view().id().seq() + 1));
2420         reg23.add_member(pu2.uuid(), 0);
2421         reg23.add_member(pu3.uuid(), 0);
2422 
2423         pu2.pc()->handle_up(0, Datagram(),
2424                             ProtoUpMeta(UUID::nil(), ViewId(), &reg23));
2425         pu3.pc()->handle_up(0, Datagram(),
2426                             ProtoUpMeta(UUID::nil(), ViewId(), &reg23));
2427         ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
2428         ck_assert(pu3.pc()->state() == Proto::S_STATES_EXCH);
2429 
2430         dg = pu2.tp()->out();
2431         ck_assert(dg != 0);
2432         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid()));
2433         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid()));
2434         delete dg;
2435 
2436         dg = pu3.tp()->out();
2437         ck_assert(dg != 0);
2438         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid()));
2439         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid()));
2440         delete dg;
2441 
2442         ck_assert(pu2.pc()->state() == Proto::S_NON_PRIM);
2443         ck_assert(pu3.pc()->state() == Proto::S_NON_PRIM);
2444 
2445         delete install_dg;
2446     }
2447 
2448 }
2449 END_TEST
2450 
2451 
2452 //
2453 // Weight changing message is delivered in transitional view when new node is
2454 // joining. All nodes should end up in prim.
2455 //
START_TEST(test_weight_change_joining)2456 START_TEST(test_weight_change_joining)
2457 {
2458     log_info << "START (test_weight_change_joining)";
2459     gu::Config conf1;
2460     gu::ssl_register_params(conf1);
2461     gcomm::Conf::register_params(conf1);
2462     conf1.set("pc.weight", "1");
2463     UUID uuid1(1);
2464     ProtoUpMeta pum1(uuid1);
2465     Proto pc1(conf1, uuid1, 0);
2466     DummyTransport tp1;
2467     PCUser pu1(conf1, uuid1, &tp1, &pc1);
2468     single_boot(0, &pu1);
2469 
2470     gu::Config conf2;
2471     gu::ssl_register_params(conf2);
2472     gcomm::Conf::register_params(conf2);
2473     conf2.set("pc.weight", "1");
2474     UUID uuid2(2);
2475     ProtoUpMeta pum2(uuid2);
2476     Proto pc2(conf2, uuid2, 0);
2477     DummyTransport tp2;
2478     PCUser pu2(conf2, uuid2, &tp2, &pc2);
2479 
2480     double_boot(0, &pu1, &pu2);
2481 
2482     gu::Config conf3;
2483     gu::ssl_register_params(conf3);
2484     gcomm::Conf::register_params(conf3);
2485     conf3.set("pc.weight", "1");
2486     UUID uuid3(3);
2487     ProtoUpMeta pum3(uuid3);
2488     Proto pc3(conf3, uuid3, 0);
2489     DummyTransport tp3;
2490     PCUser pu3(conf3, uuid3, &tp3, &pc3);
2491 
2492     // weight change
2493     {
2494         Protolay::sync_param_cb_t sync_param_cb;
2495         pu1.pc()->set_param("pc.weight", "1", sync_param_cb);
2496         ck_assert(sync_param_cb.empty() == false);
2497         Datagram* install_dg(pu1.tp()->out());
2498         ck_assert(install_dg != 0);
2499 
2500         // trans views
2501         {
2502             View tr12(0, ViewId(V_TRANS, pu1.pc()->current_view().id()));
2503             tr12.add_member(pu1.uuid(), 0);
2504             tr12.add_member(pu2.uuid(), 0);
2505 
2506             ProtoUpMeta trum12(UUID::nil(), ViewId(), &tr12);
2507             pu1.pc()->handle_up(0, Datagram(), trum12);
2508             pu2.pc()->handle_up(0, Datagram(), trum12);
2509 
2510             ck_assert(pu1.pc()->state() == Proto::S_TRANS);
2511             ck_assert(pu2.pc()->state() == Proto::S_TRANS);
2512 
2513             // deliver weight change install in trans view
2514             pu1.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid()));
2515             pu2.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid()));
2516 
2517             pu3.pc()->connect(false);
2518             View tr3(0, ViewId(V_TRANS, pu3.uuid(), 0));
2519             tr3.add_member(pu3.uuid(), 0);
2520             ProtoUpMeta trum3(UUID::nil(), ViewId(), &tr3);
2521             pu3.pc()->handle_up(0, Datagram(), trum3);
2522 
2523             ck_assert(pu3.pc()->state() == Proto::S_TRANS);
2524         }
2525 
2526         // reg view
2527         {
2528             View reg(0,
2529                      ViewId(V_REG,
2530                             pu1.uuid(), pu1.pc()->current_view().id().seq() + 1));
2531             reg.add_member(pu1.uuid(), 0);
2532             reg.add_member(pu2.uuid(), 0);
2533             reg.add_member(pu3.uuid(), 0);
2534 
2535             ProtoUpMeta pum(UUID::nil(), ViewId(), &reg);
2536             pu1.pc()->handle_up(0, Datagram(), pum);
2537             pu2.pc()->handle_up(0, Datagram(), pum);
2538             pu3.pc()->handle_up(0, Datagram(), pum);
2539 
2540             ck_assert(pu1.pc()->state() == Proto::S_STATES_EXCH);
2541             ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
2542             ck_assert(pu3.pc()->state() == Proto::S_STATES_EXCH);
2543 
2544         }
2545 
2546         // states exch
2547         {
2548             Datagram* dg(pu1.tp()->out());
2549             ck_assert(dg != 0);
2550             pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid()));
2551             pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid()));
2552             pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid()));
2553             delete dg;
2554 
2555             dg = pu2.tp()->out();
2556             ck_assert(dg != 0);
2557             pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid()));
2558             pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid()));
2559             pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid()));
2560             delete dg;
2561 
2562             dg = pu3.tp()->out();
2563             ck_assert(dg != 0);
2564             pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid()));
2565             pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid()));
2566             pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid()));
2567             delete dg;
2568 
2569             ck_assert(pu1.pc()->state() == Proto::S_INSTALL);
2570             ck_assert(pu2.pc()->state() == Proto::S_INSTALL);
2571             ck_assert(pu3.pc()->state() == Proto::S_INSTALL);
2572         }
2573 
2574         // install
2575         {
2576             Datagram* dg(pu1.tp()->out());
2577             ck_assert(dg != 0);
2578             pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid()));
2579             pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid()));
2580             pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid()));
2581             delete dg;
2582 
2583             ck_assert(pu1.pc()->state() == Proto::S_PRIM);
2584             ck_assert(pu2.pc()->state() == Proto::S_PRIM);
2585             ck_assert(pu3.pc()->state() == Proto::S_PRIM);
2586         }
2587         delete install_dg;
2588     }
2589 }
2590 END_TEST
2591 
2592 
2593 //
2594 // One of the nodes leaves gracefully from group and weight change message
2595 // is delivered in trans view. Remaining nodes must not enter non-prim.
2596 //
START_TEST(test_weight_change_leaving)2597 START_TEST(test_weight_change_leaving)
2598 {
2599     log_info << "START (test_weight_change_leaving)";
2600     gu::Config conf1;
2601     gu::ssl_register_params(conf1);
2602     gcomm::Conf::register_params(conf1);
2603     conf1.set("pc.weight", "3");
2604     UUID uuid1(1);
2605     ProtoUpMeta pum1(uuid1);
2606     Proto pc1(conf1, uuid1, 0);
2607     DummyTransport tp1;
2608     PCUser pu1(conf1, uuid1, &tp1, &pc1);
2609     single_boot(0, &pu1);
2610 
2611     gu::Config conf2;
2612     gu::ssl_register_params(conf2);
2613     gcomm::Conf::register_params(conf2);
2614     conf2.set("pc.weight", "2");
2615     UUID uuid2(2);
2616     ProtoUpMeta pum2(uuid2);
2617     Proto pc2(conf2, uuid2, 0);
2618     DummyTransport tp2;
2619     PCUser pu2(conf2, uuid2, &tp2, &pc2);
2620 
2621     double_boot(0, &pu1, &pu2);
2622 
2623     gu::Config conf3;
2624     gu::ssl_register_params(conf3);
2625     gcomm::Conf::register_params(conf3);
2626     conf3.set("pc.weight", "1");
2627     UUID uuid3(3);
2628     ProtoUpMeta pum3(uuid3);
2629     Proto pc3(conf3, uuid3, 0);
2630     DummyTransport tp3;
2631     PCUser pu3(conf3, uuid3, &tp3, &pc3);
2632 
2633     triple_boot(0, &pu1, &pu2, &pu3);
2634 
2635     // weight change
2636     {
2637         Protolay::sync_param_cb_t sync_param_cb;
2638         // change weight for node 2 while node 1 leaves the group gracefully
2639         pu2.pc()->set_param("pc.weight", "1", sync_param_cb);
2640         ck_assert(sync_param_cb.empty() == false);
2641         Datagram* install_dg(pu2.tp()->out());
2642         ck_assert(install_dg != 0);
2643 
2644         // nodes 2 and 3 go to trans, handle install
2645         View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id()));
2646         tr23.add_member(pu2.uuid(), 0);
2647         tr23.add_member(pu3.uuid(), 0);
2648         tr23.add_left(pu1.uuid(), 0);
2649 
2650         pu2.pc()->handle_up(0, Datagram(),
2651                             ProtoUpMeta(UUID::nil(), ViewId(), &tr23));
2652         pu3.pc()->handle_up(0, Datagram(),
2653                             ProtoUpMeta(UUID::nil(), ViewId(), &tr23));
2654         ck_assert(pu2.pc()->state() == Proto::S_TRANS);
2655         ck_assert(pu3.pc()->state() == Proto::S_TRANS);
2656 
2657         pu2.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid()));
2658         pu3.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid()));
2659 
2660         View reg23(0, ViewId(V_REG, pu2.uuid(),
2661                              pu2.pc()->current_view().id().seq() + 1));
2662         reg23.add_member(pu2.uuid(), 0);
2663         reg23.add_member(pu3.uuid(), 0);
2664 
2665         pu2.pc()->handle_up(0, Datagram(),
2666                             ProtoUpMeta(UUID::nil(), ViewId(), &reg23));
2667         pu3.pc()->handle_up(0, Datagram(),
2668                             ProtoUpMeta(UUID::nil(), ViewId(), &reg23));
2669         ck_assert(pu2.pc()->state() == Proto::S_STATES_EXCH);
2670         ck_assert(pu3.pc()->state() == Proto::S_STATES_EXCH);
2671 
2672         Datagram* dg(pu2.tp()->out());
2673         ck_assert(dg != 0);
2674         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid()));
2675         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid()));
2676         delete dg;
2677 
2678         dg = pu3.tp()->out();
2679         ck_assert(dg != 0);
2680         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid()));
2681         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid()));
2682         delete dg;
2683 
2684         ck_assert(pu2.pc()->state() == Proto::S_INSTALL);
2685         ck_assert(pu3.pc()->state() == Proto::S_INSTALL);
2686 
2687         dg = pu2.tp()->out();
2688         ck_assert(dg != 0);
2689         pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid()));
2690         pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid()));
2691         delete dg;
2692 
2693         ck_assert(pu2.pc()->state() == Proto::S_PRIM);
2694         ck_assert(pu3.pc()->state() == Proto::S_PRIM);
2695 
2696         delete install_dg;
2697     }
2698 
2699 }
2700 END_TEST
2701 
2702 // node1 and node2 are a cluster.
2703 // before node3 joins, node2 lost connection to node1 and node3.
2704 // after node1 and node3 merged, node2 joins.
2705 // we expect all nodes are a cluster, and they are all in prim state.
_test_join_split_cluster(const UUID & uuid1,const UUID & uuid2,const UUID & uuid3)2706 static void _test_join_split_cluster(
2707     const UUID& uuid1, const UUID& uuid2, const UUID& uuid3)
2708 {
2709     // construct restored view.
2710     const UUID& prim_uuid = uuid1 < uuid2 ? uuid1 : uuid2;
2711     View rst_view(0, ViewId(V_PRIM, prim_uuid, 0));
2712     rst_view.add_member(uuid1, 0);
2713     rst_view.add_member(uuid2, 0);
2714 
2715     gu::Config conf1;
2716     gu::ssl_register_params(conf1);
2717     gcomm::Conf::register_params(conf1);
2718     ProtoUpMeta pum1(uuid1);
2719     Proto pc1(conf1, uuid1, 0);
2720     pc1.set_restored_view(&rst_view);
2721     DummyTransport tp1;
2722     PCUser pu1(conf1, uuid1, &tp1, &pc1);
2723     single_boot(0, &pu1);
2724 
2725     gu::Config conf2;
2726     gu::ssl_register_params(conf2);
2727     gcomm::Conf::register_params(conf2);
2728     ProtoUpMeta pum2(uuid2);
2729     Proto pc2(conf2, uuid2, 0);
2730     pc2.set_restored_view(&rst_view);
2731     DummyTransport tp2;
2732     PCUser pu2(conf2, uuid2, &tp2, &pc2);
2733 
2734     double_boot(0, &pu1, &pu2);
2735 
2736     gu::Config conf3;
2737     gu::ssl_register_params(conf3);
2738     gcomm::Conf::register_params(conf3);
2739     ProtoUpMeta pum3(uuid3);
2740     Proto pc3(conf3, uuid3, 0);
2741     DummyTransport tp3;
2742     PCUser pu3(conf3, uuid3, &tp3, &pc3);
2743     // assume previous cluster is node1 and node3.
2744     const UUID& prim_uuid2 = uuid1 < uuid3 ? uuid1 : uuid3;
2745     View rst_view2(0, ViewId(V_PRIM, prim_uuid2, 0));
2746     rst_view2.add_member(uuid1, 0);
2747     rst_view2.add_member(uuid3, 0);
2748     pc3.set_restored_view(&rst_view2);
2749 
2750 
2751     {
2752         uint32_t seq = pc1.current_view().id().seq();
2753         const UUID& reg_uuid = pu1.uuid() < pu3.uuid()
2754                                             ? pu1.uuid() : pu3.uuid();
2755 
2756         // node1
2757         View tr1(0, ViewId(V_TRANS, pc1.current_view().id()));
2758         tr1.add_member(pu1.uuid(), 0);
2759         tr1.add_partitioned(pu2.uuid(), 0);
2760         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1));
2761         ck_assert(pc1.state() == Proto::S_TRANS);
2762 
2763         View reg1(0, ViewId(V_REG, reg_uuid, seq + 1));
2764         reg1.add_member(pu1.uuid(), 0);
2765         reg1.add_member(pu3.uuid(), 0);
2766         reg1.add_joined(pu3.uuid(), 0);
2767         reg1.add_partitioned(pu2.uuid(), 0);
2768         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg1));
2769         ck_assert(pc1.state() == Proto::S_STATES_EXCH);
2770 
2771         // node3
2772         View tr3(0, ViewId(V_TRANS, pc3.current_view().id()));
2773         tr3.add_member(pu3.uuid(), 0);
2774         pc3.connect(false);
2775         pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr3));
2776         ck_assert(pc3.state() == Proto::S_TRANS);
2777 
2778         View reg3(0, ViewId(V_REG, reg_uuid, seq + 1));
2779         reg3.add_member(pu1.uuid(), 0);
2780         reg3.add_member(pu3.uuid(), 0);
2781         reg3.add_joined(pu1.uuid(), 0);
2782         pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg3));
2783         ck_assert(pc3.state() == Proto::S_STATES_EXCH);
2784 
2785         Datagram* dg1(pu1.tp()->out());
2786         ck_assert(dg1 != 0);
2787         Datagram* dg3(pu3.tp()->out());
2788         ck_assert(dg3 != 0);
2789 
2790         pc1.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid()));
2791         pc1.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid()));
2792         ck_assert(pc1.state() == Proto::S_NON_PRIM);
2793         pc3.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid()));
2794         pc3.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid()));
2795         ck_assert(pc3.state() == Proto::S_NON_PRIM);
2796 
2797         delete dg1;
2798         delete dg3;
2799     }
2800     {
2801         // node2
2802         uint32_t seq = pc2.current_view().id().seq();
2803         View tr2(0, ViewId(V_TRANS, pc2.current_view().id()));
2804         tr2.add_member(pu2.uuid(), 0);
2805         tr2.add_partitioned(pu1.uuid(), 0);
2806         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr2));
2807         ck_assert(pc2.state() == Proto::S_TRANS);
2808 
2809         View reg2(0, ViewId(V_REG, pc2.uuid(), seq + 1));
2810         reg2.add_member(pu2.uuid(), 0);
2811         reg2.add_partitioned(pu1.uuid(), 0);
2812         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg2));
2813         ck_assert(pc2.state() == Proto::S_STATES_EXCH);
2814 
2815         Datagram* dg2(pu2.tp()->out());
2816         ck_assert(dg2 != 0);
2817         pc2.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid()));
2818         ck_assert(pc2.state() == Proto::S_NON_PRIM);
2819         delete dg2;
2820     }
2821     {
2822         View tr1(0, ViewId(V_TRANS, pc1.current_view().id()));
2823         tr1.add_member(pu1.uuid(), 0);
2824         tr1.add_member(pu3.uuid(), 0);
2825         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1));
2826         ck_assert(pc1.state() == Proto::S_TRANS);
2827 
2828         View tr2(0, ViewId(V_TRANS, pc2.current_view().id()));
2829         tr2.add_member(pu2.uuid(), 0);
2830         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr2));
2831         ck_assert(pc2.state() == Proto::S_TRANS);
2832 
2833         View tr3(0, ViewId(V_TRANS, pc3.current_view().id()));
2834         tr3.add_member(pu1.uuid(), 0);
2835         tr3.add_member(pu3.uuid(), 0);
2836         pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr3));
2837         ck_assert(pc3.state() == Proto::S_TRANS);
2838 
2839         int seq = pc1.current_view().id().seq();
2840         const UUID& reg_uuid1 = pu1.uuid() < pu2.uuid() ? pu1.uuid() : pu2.uuid();
2841         const UUID& reg_uuid = reg_uuid1 < pu3.uuid() ? reg_uuid1 : pu3.uuid();
2842         View reg1(0, ViewId(V_REG, reg_uuid, seq + 1));
2843         reg1.add_member(pu1.uuid(), 0);
2844         reg1.add_member(pu2.uuid(), 0);
2845         reg1.add_member(pu3.uuid(), 0);
2846         reg1.add_joined(pu2.uuid(), 0);
2847         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg1));
2848         ck_assert(pc1.state() == Proto::S_STATES_EXCH);
2849         pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg1));
2850         ck_assert(pc3.state() == Proto::S_STATES_EXCH);
2851 
2852         View reg2(0, ViewId(V_REG, reg_uuid, seq + 1));
2853         reg2.add_member(pu1.uuid(), 0);
2854         reg2.add_member(pu2.uuid(), 0);
2855         reg2.add_member(pu3.uuid(), 0);
2856         reg2.add_joined(pu1.uuid(), 0);
2857         reg2.add_joined(pu3.uuid(), 0);
2858         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg2));
2859         ck_assert(pc2.state() == Proto::S_STATES_EXCH);
2860 
2861         Datagram* dg1(pu1.tp()->out());
2862         Datagram* dg2(pu2.tp()->out());
2863         Datagram* dg3(pu3.tp()->out());
2864         pc1.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid()));
2865         pc1.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid()));
2866         pc1.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid()));
2867         ck_assert(pc1.state() == Proto::S_INSTALL);
2868         pc2.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid()));
2869         pc2.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid()));
2870         pc2.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid()));
2871         ck_assert(pc2.state() == Proto::S_INSTALL);
2872         pc3.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid()));
2873         pc3.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid()));
2874         pc3.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid()));
2875         ck_assert(pc3.state() == Proto::S_INSTALL);
2876         delete dg1;
2877         delete dg2;
2878         delete dg3;
2879 
2880         Datagram* dg = 0;
2881         PCUser* pcs[3] = {&pu1, &pu2, &pu3};
2882         for (int i=0; i<3; i++) {
2883             if (pcs[i]->uuid() == reg_uuid) {
2884                 dg = pcs[i]->tp()->out();
2885                 ck_assert(dg != 0);
2886             } else {
2887                 ck_assert(!pcs[i]->tp()->out());
2888             }
2889         }
2890         pc1.handle_up(0, *dg, ProtoUpMeta(reg_uuid));
2891         pc2.handle_up(0, *dg, ProtoUpMeta(reg_uuid));
2892         pc3.handle_up(0, *dg, ProtoUpMeta(reg_uuid));
2893         ck_assert(pc1.state() == Proto::S_PRIM);
2894         ck_assert(pc2.state() == Proto::S_PRIM);
2895         ck_assert(pc3.state() == Proto::S_PRIM);
2896         delete dg;
2897     }
2898 }
START_TEST(test_join_split_cluster)2899 START_TEST(test_join_split_cluster)
2900 {
2901     log_info << "START (test_join_split_cluster)";
2902     gu_conf_debug_on();
2903     UUID uuid1(1);
2904     UUID uuid2(2);
2905     UUID uuid3(3);
2906     _test_join_split_cluster(uuid1, uuid2, uuid3);
2907     _test_join_split_cluster(uuid2, uuid1, uuid3);
2908     _test_join_split_cluster(uuid2, uuid3, uuid1);
2909 }
2910 END_TEST
2911 
START_TEST(test_trac_762)2912 START_TEST(test_trac_762)
2913 {
2914     log_info << "START (trac_762)";
2915     size_t n_nodes(3);
2916     vector<DummyNode*> dn;
2917     PropagationMatrix prop;
2918     const string suspect_timeout("PT0.35S");
2919     const string inactive_timeout("PT0.7S");
2920     const string retrans_period("PT0.1S");
2921     uint32_t view_seq = 0;
2922 
2923     for (size_t i = 0; i < n_nodes; ++i)
2924     {
2925         dn.push_back(create_dummy_node(i + 1, 0,
2926                                        suspect_timeout,
2927                                        inactive_timeout,
2928                                        retrans_period));
2929         gu_trace(join_node(&prop, dn[i], i == 0));
2930         set_cvi(dn, 0, i, ++view_seq, V_PRIM);
2931         gu_trace(prop.propagate_until_cvi(false));
2932     }
2933 
2934     log_info << "split 1";
2935     // split group so that node 3 becomes isolated
2936     prop.split(1, 3);
2937     prop.split(2, 3);
2938     ++view_seq;
2939     set_cvi(dn, 0, 1, view_seq, V_PRIM);
2940     set_cvi(dn, 2, 2, view_seq, V_NON_PRIM);
2941     gu_trace(prop.propagate_until_cvi(true));
2942 
2943     mark_point();
2944     log_info << "remerge 1";
2945 
2946     // detach PC layer from EVS and lower layers, attach to DummyTransport
2947     for (size_t i(0); i < n_nodes; ++i)
2948     {
2949         std::list<Protolay*>::iterator li0(dn[i]->protos().begin());
2950         std::list<Protolay*>::iterator li1(li0);
2951         ++li1;
2952         assert(li1 != dn[i]->protos().end());
2953         std::list<Protolay*>::iterator li2(li1);
2954         ++li2;
2955         assert(li2 != dn[i]->protos().end());
2956         gcomm::disconnect(*li0, *li1);
2957         gcomm::disconnect(*li1, *li2);
2958         delete *li0;
2959         delete *li1;
2960         dn[i]->protos().pop_front();
2961         dn[i]->protos().pop_front();
2962 
2963         DummyTransport* tp(new DummyTransport(dn[i]->uuid(), true));
2964         dn[i]->protos().push_front(tp);
2965         gcomm::connect(tp, *li2);
2966     }
2967 
2968     Proto* pc1(pc_from_dummy(dn[0]));
2969     DummyTransport* tp1(reinterpret_cast<DummyTransport*>(
2970                             dn[0]->protos().front()));
2971     Proto* pc2(pc_from_dummy(dn[1]));
2972     DummyTransport* tp2(reinterpret_cast<DummyTransport*>(
2973                             dn[1]->protos().front()));
2974     Proto* pc3(pc_from_dummy(dn[2]));
2975     DummyTransport* tp3(reinterpret_cast<DummyTransport*>(
2976                             dn[2]->protos().front()));
2977 
2978 
2979     // remerge group, process event by event so that nodes 1 and 2 handle
2980     // install message in reg view and reach prim view, node 3 partitions and
2981     // handles install in trans view and marks nodes 1 and 2 to have un state
2982     {
2983         View tr1(0, ViewId(V_TRANS, tp1->uuid(), view_seq));
2984         tr1.add_member(tp1->uuid(), 0);
2985         tr1.add_member(tp2->uuid(), 0);
2986         pc1->handle_view(tr1);
2987         pc2->handle_view(tr1);
2988 
2989         View tr2(0, ViewId(V_TRANS, tp3->uuid(), view_seq));
2990         tr2.add_member(tp3->uuid(), 0);
2991         pc3->handle_view(tr2);
2992 
2993         ++view_seq;
2994         View reg(0, ViewId(V_REG, tp1->uuid(), view_seq));
2995         reg.add_member(tp1->uuid(), 0);
2996         reg.add_member(tp2->uuid(), 0);
2997         reg.add_member(tp3->uuid(), 0);
2998 
2999         pc1->handle_view(reg);
3000         pc2->handle_view(reg);
3001         pc3->handle_view(reg);
3002 
3003         // states exch
3004         Datagram* dg(tp1->out());
3005         ck_assert(dg != 0);
3006         pc1->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3007         pc2->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3008         pc3->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3009         delete dg;
3010 
3011         dg = tp2->out();
3012         ck_assert(dg != 0);
3013         pc1->handle_up(0, *dg, ProtoUpMeta(tp2->uuid()));
3014         pc2->handle_up(0, *dg, ProtoUpMeta(tp2->uuid()));
3015         pc3->handle_up(0, *dg, ProtoUpMeta(tp2->uuid()));
3016         delete dg;
3017 
3018         dg = tp3->out();
3019         ck_assert(dg != 0);
3020         pc1->handle_up(0, *dg, ProtoUpMeta(tp3->uuid()));
3021         pc2->handle_up(0, *dg, ProtoUpMeta(tp3->uuid()));
3022         pc3->handle_up(0, *dg, ProtoUpMeta(tp3->uuid()));
3023         delete dg;
3024 
3025         // install message
3026         dg = tp1->out();
3027         ck_assert(dg != 0);
3028         pc1->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3029         pc2->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3030 
3031         View tr3(0, ViewId(V_TRANS, tp1->uuid(), view_seq));
3032         tr3.add_member(tp1->uuid(), 0);
3033         tr3.add_member(tp2->uuid(), 0);
3034         tr3.add_partitioned(tp3->uuid(), 0);
3035 
3036         pc1->handle_view(tr3);
3037         pc2->handle_view(tr3);
3038 
3039         View tr4(0, ViewId(V_TRANS, tp1->uuid(), view_seq));
3040         tr4.add_member(tp3->uuid(), 0);
3041         tr4.add_partitioned(tp1->uuid(), 0);
3042         tr4.add_partitioned(tp2->uuid(), 0);
3043         pc3->handle_view(tr4);
3044         pc3->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3045         delete dg;
3046     }
3047 
3048     ++view_seq;
3049     // ... intermediate reg/trans views
3050     // 1 and 2
3051     {
3052 
3053         View reg(0, ViewId(V_REG, tp1->uuid(), view_seq));
3054         reg.add_member(tp1->uuid(), 0);
3055         reg.add_member(tp2->uuid(), 0);
3056         pc1->handle_view(reg);
3057         pc2->handle_view(reg);
3058 
3059         View tr(0, ViewId(V_TRANS, tp1->uuid(), view_seq));
3060         tr.add_member(tp1->uuid(), 0);
3061         tr.add_member(tp2->uuid(), 0);
3062         pc1->handle_view(tr);
3063         pc2->handle_view(tr);
3064 
3065         Datagram* dg(tp1->out());
3066         ck_assert(dg != 0);
3067         pc1->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3068         pc2->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3069         delete dg;
3070 
3071         dg = tp2->out();
3072         ck_assert(dg != 0);
3073         pc1->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3074         pc2->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3075         delete dg;
3076     }
3077     // 3
3078     {
3079         View reg(0, ViewId(V_REG, tp3->uuid(), view_seq));
3080         reg.add_member(tp3->uuid(), 0);
3081         pc3->handle_view(reg);
3082 
3083         Datagram* dg(tp3->out());
3084         ck_assert(dg != 0);
3085         pc3->handle_up(0, *dg, ProtoUpMeta(tp3->uuid()));
3086         delete dg;
3087 
3088         View tr(0, ViewId(V_TRANS, tp3->uuid(), view_seq));
3089         tr.add_member(tp3->uuid(), 0);
3090         pc3->handle_view(tr);
3091     }
3092 
3093     // Remerge and PC crash should occur if bug is present.
3094     ++view_seq;
3095     {
3096         View reg(0, ViewId(V_REG, tp1->uuid(), view_seq));
3097         reg.add_member(tp1->uuid(), 0);
3098         reg.add_member(tp2->uuid(), 0);
3099         reg.add_member(tp3->uuid(), 0);
3100 
3101         pc1->handle_view(reg);
3102         pc2->handle_view(reg);
3103         pc3->handle_view(reg);
3104 
3105         // State msgs
3106         Datagram* dg(tp1->out());
3107         ck_assert(dg != 0);
3108         pc1->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3109         pc2->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3110         pc3->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3111         delete dg;
3112 
3113         dg = tp2->out();
3114         ck_assert(dg != 0);
3115         pc1->handle_up(0, *dg, ProtoUpMeta(tp2->uuid()));
3116         pc2->handle_up(0, *dg, ProtoUpMeta(tp2->uuid()));
3117         pc3->handle_up(0, *dg, ProtoUpMeta(tp2->uuid()));
3118         delete dg;
3119 
3120         dg = tp3->out();
3121         ck_assert(dg != 0);
3122         pc1->handle_up(0, *dg, ProtoUpMeta(tp3->uuid()));
3123         pc2->handle_up(0, *dg, ProtoUpMeta(tp3->uuid()));
3124         pc3->handle_up(0, *dg, ProtoUpMeta(tp3->uuid()));
3125         delete dg;
3126 
3127         // Install msg
3128         dg = tp1->out();
3129         ck_assert(dg != 0);
3130         pc1->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3131         pc2->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3132         pc3->handle_up(0, *dg, ProtoUpMeta(tp1->uuid()));
3133 
3134         ck_assert(tp1->out() == 0);
3135         ck_assert(tp2->out() == 0);
3136         ck_assert(tp3->out() == 0);
3137         delete dg;
3138     }
3139     std::for_each(dn.begin(), dn.end(), gu::DeleteObject());
3140 }
3141 END_TEST
3142 
START_TEST(test_gh_92)3143 START_TEST(test_gh_92)
3144 {
3145     UUID uuid1(1), uuid2(2), uuid3(3);
3146     gu::Config conf1;
3147     gu::ssl_register_params(conf1);
3148     gcomm::Conf::register_params(conf1);
3149     ProtoUpMeta pum1(uuid1);
3150     Proto pc1(conf1, uuid1, 0);
3151     DummyTransport tp1;
3152     PCUser pu1(conf1, uuid1, &tp1, &pc1);
3153     single_boot(0, &pu1);
3154 
3155     gu::Config conf2;
3156     gu::ssl_register_params(conf2);
3157     gcomm::Conf::register_params(conf2);
3158     ProtoUpMeta pum2(uuid2);
3159     Proto pc2(conf2, uuid2, 0);
3160     DummyTransport tp2;
3161     PCUser pu2(conf2, uuid2, &tp2, &pc2);
3162     double_boot(0, &pu1, &pu2);
3163 
3164     gu::Config conf3;
3165     gu::ssl_register_params(conf3);
3166     gcomm::Conf::register_params(conf3);
3167     ProtoUpMeta pum3(uuid3);
3168     Proto pc3(conf3, uuid3, 0);
3169     DummyTransport tp3;
3170     PCUser pu3(conf3, uuid3, &tp3, &pc3);
3171     triple_boot(0, &pu1, &pu2, &pu3);
3172 
3173     uint32_t seq = pc1.current_view().id().seq();
3174     Datagram* im = 0;
3175     Datagram* dg = 0;
3176 
3177     // they split into three parts.
3178     {
3179         View tr1(0, ViewId(V_TRANS, pc1.current_view().id()));
3180         tr1.add_member(pu1.uuid(), 0);
3181         tr1.add_partitioned(pu2.uuid(), 0);
3182         tr1.add_partitioned(pu3.uuid(), 0);
3183         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1));
3184         ck_assert(pc1.state() == Proto::S_TRANS);
3185 
3186         View reg1(0, ViewId(V_REG, uuid1, seq + 1));
3187         reg1.add_member(pu1.uuid(), 0);
3188         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg1));
3189         ck_assert(pc1.state() == Proto::S_STATES_EXCH);
3190         dg = pu1.tp()->out();
3191         pc1.handle_up(0, *dg, ProtoUpMeta(pu1.uuid()));
3192         ck_assert(pc1.state() == Proto::S_NON_PRIM);
3193 
3194         View tr2(0, ViewId(V_TRANS, pc2.current_view().id()));
3195         tr2.add_member(pu2.uuid(), 0);
3196         tr2.add_partitioned(pu1.uuid(), 0);
3197         tr2.add_partitioned(pu3.uuid(), 0);
3198         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr2));
3199         ck_assert(pc2.state() == Proto::S_TRANS);
3200 
3201         View reg2(0, ViewId(V_REG, uuid2, seq + 1));
3202         reg2.add_member(pu2.uuid(), 0);
3203         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg2));
3204         ck_assert(pc2.state() == Proto::S_STATES_EXCH);
3205         delete dg;
3206         dg = pu2.tp()->out();
3207         pc2.handle_up(0, *dg, ProtoUpMeta(pu2.uuid()));
3208         ck_assert(pc2.state() == Proto::S_NON_PRIM);
3209 
3210         View tr3(0, ViewId(V_TRANS, pc3.current_view().id()));
3211         tr3.add_member(pu3.uuid(), 0);
3212         tr3.add_partitioned(pu1.uuid(), 0);
3213         tr3.add_partitioned(pu2.uuid(), 0);
3214         pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr3));
3215         ck_assert(pc3.state() == Proto::S_TRANS);
3216 
3217         View reg3(0, ViewId(V_REG, uuid3, seq + 1));
3218         reg3.add_member(pu3.uuid(), 0);
3219         pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg3));
3220         ck_assert(pc3.state() == Proto::S_STATES_EXCH);
3221         delete dg;
3222         dg = pu3.tp()->out();
3223         pc3.handle_up(0, *dg, ProtoUpMeta(pu3.uuid()));
3224         ck_assert(pc3.state() == Proto::S_NON_PRIM);
3225         delete dg;
3226         dg = 0;
3227     }
3228     seq += 1;
3229 
3230     // they try to merge into a primary component, but fails when sending install message.
3231     {
3232         View tr1(0, ViewId(V_TRANS, pc1.current_view().id()));
3233         tr1.add_member(pu1.uuid(), 0);
3234         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1));
3235         ck_assert(pc1.state() == Proto::S_TRANS);
3236 
3237         View reg1(0, ViewId(V_REG, uuid1, seq + 1));
3238         reg1.add_member(pu1.uuid(), 0);
3239         reg1.add_member(pu2.uuid(), 0);
3240         reg1.add_member(pu3.uuid(), 0);
3241         reg1.add_joined(pu2.uuid(), 0);
3242         reg1.add_joined(pu3.uuid(), 0);
3243         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg1));
3244         ck_assert(pc1.state() == Proto::S_STATES_EXCH);
3245 
3246         View tr2(0, ViewId(V_TRANS, pc2.current_view().id()));
3247         tr2.add_member(pu2.uuid(), 0);
3248         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr2));
3249         ck_assert(pc2.state() == Proto::S_TRANS);
3250 
3251         View reg2(0, ViewId(V_REG, uuid1, seq + 1));
3252         reg2.add_member(pu1.uuid(), 0);
3253         reg2.add_member(pu2.uuid(), 0);
3254         reg2.add_member(pu3.uuid(), 0);
3255         reg2.add_joined(pu1.uuid(), 0);
3256         reg2.add_joined(pu3.uuid(), 0);
3257         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg2));
3258         ck_assert(pc2.state() == Proto::S_STATES_EXCH);
3259 
3260         View tr3(0, ViewId(V_TRANS, pc3.current_view().id()));
3261         tr3.add_member(pu3.uuid(), 0);
3262         pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr3));
3263         ck_assert(pc3.state() == Proto::S_TRANS);
3264 
3265         View reg3(0, ViewId(V_REG, uuid1, seq + 1));
3266         reg3.add_member(pu1.uuid(), 0);
3267         reg3.add_member(pu2.uuid(), 0);
3268         reg3.add_member(pu3.uuid(), 0);
3269         reg3.add_joined(pu1.uuid(), 0);
3270         reg3.add_joined(pu2.uuid(), 0);
3271         pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg3));
3272         ck_assert(pc3.state() == Proto::S_STATES_EXCH);
3273 
3274         Datagram* dg1(pu1.tp()->out());
3275         Datagram* dg2(pu2.tp()->out());
3276         Datagram* dg3(pu3.tp()->out());
3277         ck_assert(dg1 != 0);
3278         ck_assert(dg2 != 0);
3279         ck_assert(dg3 != 0);
3280         pc1.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid()));
3281         pc1.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid()));
3282         pc1.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid()));
3283         pc2.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid()));
3284         pc2.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid()));
3285         pc2.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid()));
3286         pc3.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid()));
3287         pc3.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid()));
3288         pc3.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid()));
3289         delete dg1; delete dg2; delete dg3;
3290         ck_assert(pc1.state() == Proto::S_INSTALL);
3291         ck_assert(pc2.state() == Proto::S_INSTALL);
3292         ck_assert(pc3.state() == Proto::S_INSTALL);
3293 
3294         im = pu1.tp()->out();
3295         ck_assert(im != 0);
3296         ck_assert(pu2.tp()->out() == 0);
3297         ck_assert(pu3.tp()->out() == 0);
3298     }
3299     seq += 1;
3300 
3301     // node3 is separate from node1 and node2.
3302     // they get the stale install message when they get transient view.
3303     {
3304         View tr1(0, ViewId(V_TRANS, pc1.current_view().id()));
3305         tr1.add_member(pu1.uuid(), 0);
3306         tr1.add_member(pu2.uuid(), 0);
3307         tr1.add_partitioned(pu3.uuid(), 0);
3308         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1));
3309         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1));
3310         ck_assert(pc1.state() == Proto::S_TRANS);
3311         ck_assert(pc2.state() == Proto::S_TRANS);
3312         pc1.handle_up(0, *im, ProtoUpMeta(pu1.uuid()));
3313         pc2.handle_up(0, *im, ProtoUpMeta(pu1.uuid()));
3314         ck_assert(pc1.state() == Proto::S_TRANS);
3315         ck_assert(pc2.state() == Proto::S_TRANS);
3316 
3317         View reg1(0, ViewId(V_REG, uuid1, seq + 1));
3318         reg1.add_member(pu1.uuid(), 0);
3319         reg1.add_member(pu2.uuid(), 0);
3320         reg1.add_partitioned(pu3.uuid(), 0);
3321         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg1));
3322         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg1));
3323         ck_assert(pc1.state() == Proto::S_STATES_EXCH);
3324         ck_assert(pc2.state() == Proto::S_STATES_EXCH);
3325         Datagram* dg1(pu1.tp()->out());
3326         Datagram* dg2(pu2.tp()->out());
3327         ck_assert(dg1 != 0);
3328         ck_assert(dg2 != 0);
3329         pc1.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid()));
3330         pc1.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid()));
3331         pc2.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid()));
3332         pc2.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid()));
3333         ck_assert(pc1.state() == Proto::S_NON_PRIM);
3334         ck_assert(pc2.state() == Proto::S_NON_PRIM);
3335 
3336         View tr3(0, ViewId(V_TRANS, pc3.current_view().id()));
3337         tr3.add_member(pu3.uuid(), 0);
3338         tr3.add_partitioned(pu1.uuid(), 0);
3339         tr3.add_partitioned(pu2.uuid(), 0);
3340         pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr3));
3341         ck_assert(pc3.state() == Proto::S_TRANS);
3342         pc3.handle_up(0, *im, ProtoUpMeta(pu1.uuid()));
3343         ck_assert(pc3.state() == Proto::S_TRANS);
3344 
3345         View reg3(0, ViewId(V_REG, uuid3, seq + 1));
3346         reg3.add_member(pu3.uuid(), 0);
3347         reg3.add_partitioned(pu1.uuid(), 0);
3348         reg3.add_partitioned(pu2.uuid(), 0);
3349         pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg3));
3350         ck_assert(pc3.state() == Proto::S_STATES_EXCH);
3351         Datagram* dg3(pu3.tp()->out());
3352         ck_assert(dg3 != 0);
3353         pc3.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid()));
3354         ck_assert(pc3.state() == Proto::S_NON_PRIM);
3355 
3356         delete dg1; delete dg2; delete dg3;
3357     }
3358     seq += 1;
3359 
3360     // then they try to merge into a primary component again.
3361     {
3362         View tr1(0, ViewId(V_TRANS, pc1.current_view().id()));
3363         tr1.add_member(pu1.uuid(), 0);
3364         tr1.add_member(pu2.uuid(), 0);
3365         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1));
3366         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1));
3367         ck_assert(pc1.state() == Proto::S_TRANS);
3368         ck_assert(pc2.state() == Proto::S_TRANS);
3369 
3370         View reg1(0, ViewId(V_REG, uuid1, seq + 1));
3371         reg1.add_member(pu1.uuid(), 0);
3372         reg1.add_member(pu2.uuid(), 0);
3373         reg1.add_member(pu3.uuid(), 0);
3374         reg1.add_joined(pu3.uuid(), 0);
3375         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg1));
3376         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg1));
3377         ck_assert(pc1.state() == Proto::S_STATES_EXCH);
3378         ck_assert(pc2.state() == Proto::S_STATES_EXCH);
3379 
3380         View tr3(0, ViewId(V_TRANS, pc3.current_view().id()));
3381         tr3.add_member(pu3.uuid(), 0);
3382         pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr3));
3383         ck_assert(pc3.state() == Proto::S_TRANS);
3384 
3385         View reg3(0, ViewId(V_REG, uuid1, seq + 1));
3386         reg3.add_member(pu1.uuid(), 0);
3387         reg3.add_member(pu2.uuid(), 0);
3388         reg3.add_member(pu3.uuid(), 0);
3389         reg3.add_joined(pu1.uuid(), 0);
3390         reg3.add_joined(pu2.uuid(), 0);
3391         pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg3));
3392         ck_assert(pc3.state() == Proto::S_STATES_EXCH);
3393 
3394         Datagram* dg1(pu1.tp()->out());
3395         Datagram* dg2(pu2.tp()->out());
3396         Datagram* dg3(pu3.tp()->out());
3397         ck_assert(dg1 != 0);
3398         ck_assert(dg2 != 0);
3399         ck_assert(dg3 != 0);
3400         pc1.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid()));
3401         pc1.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid()));
3402         pc1.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid()));
3403         pc2.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid()));
3404         pc2.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid()));
3405         pc2.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid()));
3406         pc3.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid()));
3407         pc3.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid()));
3408         pc3.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid()));
3409         delete dg1; delete dg2; delete dg3;
3410         ck_assert(pc1.state() == Proto::S_INSTALL);
3411         ck_assert(pc2.state() == Proto::S_INSTALL);
3412         ck_assert(pc3.state() == Proto::S_INSTALL);
3413 
3414         delete im;
3415         im = pu1.tp()->out();
3416         ck_assert(im != 0);
3417         ck_assert(pu2.tp()->out() == 0);
3418         ck_assert(pu3.tp()->out() == 0);
3419         pc1.handle_up(0, *im, ProtoUpMeta(pu1.uuid()));
3420         pc2.handle_up(0, *im, ProtoUpMeta(pu1.uuid()));
3421         pc3.handle_up(0, *im, ProtoUpMeta(pu1.uuid()));
3422         ck_assert(pc1.state() == Proto::S_PRIM);
3423         ck_assert(pc2.state() == Proto::S_PRIM);
3424         ck_assert(pc3.state() == Proto::S_PRIM);
3425         delete im;
3426     }
3427 }
3428 END_TEST
3429 
3430 // Nodes 1, 2, 3. Node 3 will be evicted from group while group is
3431 // fully partitioned. After remerging 1 and 2 they should reach
3432 // primary component.
START_TEST(test_prim_after_evict)3433 START_TEST(test_prim_after_evict)
3434 {
3435     log_info << "START(test_prim_after_evict)";
3436     UUID uuid1(1), uuid2(2), uuid3(3);
3437     gu::Config conf1;
3438     gu::ssl_register_params(conf1);
3439     gcomm::Conf::register_params(conf1);
3440     ProtoUpMeta pum1(uuid1);
3441     Proto pc1(conf1, uuid1, 0);
3442     DummyTransport tp1;
3443     PCUser pu1(conf1, uuid1, &tp1, &pc1);
3444     single_boot(1, &pu1);
3445 
3446     gu::Config conf2;
3447     gu::ssl_register_params(conf2);
3448     gcomm::Conf::register_params(conf2);
3449     ProtoUpMeta pum2(uuid2);
3450     Proto pc2(conf2, uuid2, 0);
3451     DummyTransport tp2;
3452     PCUser pu2(conf2, uuid2, &tp2, &pc2);
3453     double_boot(1, &pu1, &pu2);
3454 
3455     gu::Config conf3;
3456     gu::ssl_register_params(conf3);
3457     gcomm::Conf::register_params(conf3);
3458     ProtoUpMeta pum3(uuid3);
3459     Proto pc3(conf3, uuid3, 0);
3460     DummyTransport tp3;
3461     PCUser pu3(conf3, uuid3, &tp3, &pc3);
3462     triple_boot(1, &pu1, &pu2, &pu3);
3463 
3464     // Node 1 partitions
3465     {
3466         // Trans view
3467         View tr1(1, ViewId(V_TRANS, pc1.current_view().id()));
3468         tr1.add_member(pc1.uuid(), 0);
3469         tr1.add_partitioned(pc2.uuid(), 0);
3470         tr1.add_partitioned(pc3.uuid(), 0);
3471         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1));
3472         // Reg view
3473         View reg1(1, ViewId(V_REG, pc1.uuid(), tr1.id().seq() + 1));
3474         reg1.add_member(pc1.uuid(), 0);
3475         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg1));
3476         // States exch
3477         Datagram* dg(tp1.out());
3478         ck_assert(dg != 0);
3479         pc1.handle_up(0, *dg, ProtoUpMeta(pc1.uuid()));
3480         delete dg;
3481         // Non-prim
3482         dg = tp1.out();
3483         ck_assert(dg == 0);
3484         ck_assert(pc1.state() == Proto::S_NON_PRIM);
3485     }
3486 
3487     // Node 2 partitions
3488     {
3489         // Trans view
3490         View tr2(1, ViewId(V_TRANS, pc2.current_view().id()));
3491         tr2.add_member(pc2.uuid(), 0);
3492         tr2.add_partitioned(pc1.uuid(), 0);
3493         tr2.add_partitioned(pc3.uuid(), 0);
3494         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr2));
3495         // Reg view
3496         View reg2(1, ViewId(V_REG, pc2.uuid(), tr2.id().seq() + 1));
3497         reg2.add_member(pc2.uuid(), 0);
3498         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg2));
3499         // States exch
3500         Datagram* dg(tp2.out());
3501         ck_assert(dg != 0);
3502         pc2.handle_up(0, *dg, ProtoUpMeta(pc2.uuid()));
3503         delete dg;
3504         // Non-prim
3505         dg = tp2.out();
3506         ck_assert(dg == 0);
3507         ck_assert(pc2.state() == Proto::S_NON_PRIM);
3508     }
3509 
3510     // Just forget about node3, it is gone forever
3511     // Nodes 1 and 2 set node3 evicted
3512 
3513     pc1.evict(pc3.uuid());
3514     pc2.evict(pc3.uuid());
3515 
3516     // Nodes 1 and 2 merge and should reach Prim
3517 
3518     {
3519         // Trans view for node 1
3520         View tr1(1, ViewId(V_TRANS, pc1.current_view().id()));
3521         tr1.add_member(pc1.uuid(), 0);
3522         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1));
3523         Datagram *dg(tp1.out());
3524         ck_assert(dg == 0);
3525         ck_assert(pc1.state() == Proto::S_TRANS);
3526 
3527         // Trans view for node 2
3528         View tr2(1, ViewId(V_TRANS, pc2.current_view().id()));
3529         tr2.add_member(pc2.uuid(), 0);
3530         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr2));
3531         dg = tp2.out();
3532         ck_assert(dg == 0);
3533         ck_assert(pc2.state() == Proto::S_TRANS);
3534 
3535         // Reg view for nodes 1 and 2
3536         View reg(1, ViewId(V_REG, pc1.uuid(), tr1.id().seq() + 1));
3537         reg.add_member(pc1.uuid(), 0);
3538         reg.add_member(pc2.uuid(), 0);
3539         pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg));
3540         pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &reg));
3541 
3542         // States exchange
3543         ck_assert(pc1.state() == Proto::S_STATES_EXCH);
3544         ck_assert(pc2.state() == Proto::S_STATES_EXCH);
3545 
3546         // State message from node 1
3547         dg = tp1.out();
3548         ck_assert(dg != 0);
3549         pc1.handle_up(0, *dg, ProtoUpMeta(pc1.uuid()));
3550         pc2.handle_up(0, *dg, ProtoUpMeta(pc1.uuid()));
3551         delete dg;
3552         dg = tp1.out();
3553         ck_assert(dg == 0);
3554 
3555         // State message from node 2
3556         dg = tp2.out();
3557         ck_assert(dg != 0);
3558         pc1.handle_up(0, *dg, ProtoUpMeta(pc2.uuid()));
3559         pc2.handle_up(0, *dg, ProtoUpMeta(pc2.uuid()));
3560         delete dg;
3561         dg = tp2.out();
3562         ck_assert(dg == 0);
3563 
3564         // Install
3565         ck_assert_msg(pc1.state() == Proto::S_INSTALL, "state is %s",
3566                       Proto::to_string(pc1.state()).c_str());
3567         ck_assert_msg(pc2.state() == Proto::S_INSTALL, "state is %s",
3568                       Proto::to_string(pc2.state()).c_str());
3569 
3570         // Install message from node 1
3571         dg = tp1.out();
3572         ck_assert(dg != 0);
3573         pc1.handle_up(0, *dg, ProtoUpMeta(pc1.uuid()));
3574         pc2.handle_up(0, *dg, ProtoUpMeta(pc1.uuid()));
3575         delete dg;
3576 
3577         // Prim
3578         dg = tp1.out();
3579         ck_assert(dg == 0);
3580         dg = tp2.out();
3581         ck_assert(dg == 0);
3582         ck_assert(pc1.state() == Proto::S_PRIM);
3583         ck_assert(pc2.state() == Proto::S_PRIM);
3584     }
3585 
3586 
3587 }
3588 END_TEST
3589 
3590 class DummyEvs : public gcomm::Bottomlay
3591 {
3592 public:
DummyEvs(gu::Config & conf)3593     DummyEvs(gu::Config& conf) : gcomm::Bottomlay(conf) { }
handle_down(Datagram &,const ProtoDownMeta &)3594     int handle_down(Datagram&, const ProtoDownMeta&) { return 0; }
3595 };
3596 
3597 class DummyTop : public gcomm::Toplay
3598 {
3599 public:
DummyTop(gu::Config & conf)3600     DummyTop(gu::Config& conf) : gcomm::Toplay(conf) { }
handle_up(const void *,const gcomm::Datagram &,const gcomm::ProtoUpMeta &)3601     void handle_up(const void*, const gcomm::Datagram&,
3602                    const gcomm::ProtoUpMeta&) { }
3603 };
3604 
3605 // Test outline:
3606 // * Three node cluster, nodes n1, n2, n3
3607 // * Current primary view is (n1, n2), view number 2
3608 // * Group is merging, current EVS view is (n1, n2, n3),
3609 //   view number 3
3610 // * State messages have been delivered, but group partitioned again when
3611 //   install message was being sent.
3612 // * Underlying EVS membership changes so that the transitional view
3613 //   ends up in (n1, n3), paritioned (n2)
3614 // * It is expected that the n1 ends up in non-primary component.
START_TEST(test_quorum_2_to_2_in_3_node_cluster)3615 START_TEST(test_quorum_2_to_2_in_3_node_cluster)
3616 {
3617     gu_log_max_level = GU_LOG_DEBUG;
3618     gcomm::pc::ProtoBuilder builder;
3619     gu::Config conf;
3620     gu::ssl_register_params(conf);
3621     gcomm::Conf::register_params(conf);
3622 
3623     // Current view is EVS view (n1, n2, n3), view number 3
3624     gcomm::View current_view(0, gcomm::ViewId(V_REG, gcomm::UUID(1), 3));
3625     current_view.add_member(gcomm::UUID(1), 0);
3626     current_view.add_member(gcomm::UUID(2), 0);
3627     current_view.add_member(gcomm::UUID(3), 0);
3628 
3629     // Primary component view (n1, n2), view number 2
3630     gcomm::View pc_view(0, gcomm::ViewId(V_PRIM, gcomm::UUID(1), 2));
3631     pc_view.add_member(gcomm::UUID(1), 0);
3632     pc_view.add_member(gcomm::UUID(2), 0);
3633 
3634     // Known instances according to state messages.
3635     gcomm::pc::Node node1(true, false, false, 0,
3636                           gcomm::ViewId(V_PRIM, gcomm::UUID(1), 2),
3637                           0, 1, 0);
3638     gcomm::pc::Node node2(true, false, false, 0,
3639                           gcomm::ViewId(V_PRIM, gcomm::UUID(1), 2),
3640                           0, 1, 0);
3641     gcomm::pc::Node node3(false, false, false, 0,
3642                           gcomm::ViewId(V_PRIM, gcomm::UUID(1), 1),
3643                           0, 1, 0);
3644     gcomm::pc::NodeMap instances;
3645     instances.insert(std::make_pair(gcomm::UUID(1), node1));
3646     instances.insert(std::make_pair(gcomm::UUID(2), node2));
3647     instances.insert(std::make_pair(gcomm::UUID(3), node3));
3648 
3649     // State messages for all nodes.
3650     // * Nodes n1, n2 report previous prim view (n1, n2), view number 2.
3651     // * Node 3 reports previous prim view (n1, n2, n3), view number 1.
3652     gcomm::pc::Proto::SMMap state_msgs;
3653     {
3654         // Node n1
3655         gcomm::pc::NodeMap nm;
3656         nm.insert(std::make_pair(gcomm::UUID(1), node1));
3657         nm.insert(std::make_pair(gcomm::UUID(2), node2));
3658         gcomm::pc::Message msg(1, gcomm::pc::Message::PC_T_STATE, 0, nm);
3659         state_msgs.insert(std::make_pair(gcomm::UUID(1), msg));
3660     }
3661     {
3662         // Node n2
3663         gcomm::pc::NodeMap nm;
3664         nm.insert(std::make_pair(gcomm::UUID(1), node1));
3665         nm.insert(std::make_pair(gcomm::UUID(2), node2));
3666         gcomm::pc::Message msg(1, gcomm::pc::Message::PC_T_STATE, 0, nm);
3667         state_msgs.insert(std::make_pair(gcomm::UUID(2), msg));
3668     }
3669     {
3670         // Node3
3671         gcomm::pc::NodeMap nm;
3672         // Nodes n1 and n2 have previously been seen in prim view number 1
3673         nm.insert(std::make_pair(gcomm::UUID(1),
3674                                  gcomm::pc::Node(
3675                                      false, false, false, 0,
3676                                      gcomm::ViewId(V_PRIM, gcomm::UUID(1), 1),
3677                                      0, 1, 0)));
3678         nm.insert(std::make_pair(gcomm::UUID(2),
3679                                  gcomm::pc::Node(
3680                                      false, false, false, 0,
3681                                      gcomm::ViewId(V_PRIM, gcomm::UUID(1), 1),
3682                                      0, 1, 0)));
3683         nm.insert(std::make_pair(gcomm::UUID(3), node3));
3684         gcomm::pc::Message msg(1, gcomm::pc::Message::PC_T_STATE, 0, nm);
3685         state_msgs.insert(std::make_pair(gcomm::UUID(3), msg));
3686     }
3687 
3688     // Build n1 state in S_INSTALL.
3689     builder
3690         .conf(conf)
3691         .uuid(gcomm::UUID(1))
3692         .state_msgs(state_msgs)
3693         .current_view(current_view)
3694         .pc_view(pc_view)
3695         .instances(instances)
3696         .state(gcomm::pc::Proto::S_INSTALL);
3697     std::unique_ptr<gcomm::pc::Proto> p(builder.make_proto());
3698     DummyEvs devs(conf);
3699     DummyTop dtop(conf);
3700     gcomm::connect(&devs, p.get());
3701     gcomm::connect(p.get(), &dtop);
3702 
3703     // Deliver transitional EVS view where members are n1, n3 and
3704     // partitioned n2. After handling transitional view n1 is
3705     // expected to end up in non-primary.
3706     gcomm::View trans_view(0, gcomm::ViewId(V_TRANS, gcomm::UUID(1), 3));
3707     trans_view.add_member(gcomm::UUID(1), 0);
3708     trans_view.add_partitioned(gcomm::UUID(2), 0);
3709     trans_view.add_member(gcomm::UUID(3), 0);
3710 
3711     p->handle_view(trans_view);
3712 
3713     ck_assert(p->state() == gcomm::pc::Proto::S_TRANS);
3714     ck_assert(not p->prim());
3715 }
3716 END_TEST
3717 
pc_suite()3718 Suite* pc_suite()
3719 {
3720     Suite* s = suite_create("gcomm::pc");
3721     TCase* tc;
3722 
3723     tc = tcase_create("test_pc_messages");
3724     tcase_add_test(tc, test_pc_messages);
3725     suite_add_tcase(s, tc);
3726 
3727     tc = tcase_create("test_pc_view_changes_single");
3728     tcase_add_test(tc, test_pc_view_changes_single);
3729     suite_add_tcase(s, tc);
3730 
3731     tc = tcase_create("test_pc_view_changes_double");
3732     tcase_add_test(tc, test_pc_view_changes_double);
3733     suite_add_tcase(s, tc);
3734 
3735     tc = tcase_create("test_pc_view_changes_reverse");
3736     tcase_add_test(tc, test_pc_view_changes_reverse);
3737     suite_add_tcase(s, tc);
3738 
3739     tc = tcase_create("test_pc_state1");
3740     tcase_add_test(tc, test_pc_state1);
3741     suite_add_tcase(s, tc);
3742 
3743     tc = tcase_create("test_pc_state2");
3744     tcase_add_test(tc, test_pc_state2);
3745     suite_add_tcase(s, tc);
3746 
3747     tc = tcase_create("test_pc_state3");
3748     tcase_add_test(tc, test_pc_state3);
3749     suite_add_tcase(s, tc);
3750 
3751     tc = tcase_create("test_pc_conflicting_prims");
3752     tcase_add_test(tc, test_pc_conflicting_prims);
3753     suite_add_tcase(s, tc);
3754 
3755     tc = tcase_create("test_pc_conflicting_prims_npvo");
3756     tcase_add_test(tc, test_pc_conflicting_prims_npvo);
3757     suite_add_tcase(s, tc);
3758 
3759     tc = tcase_create("test_pc_split_merge");
3760     tcase_add_test(tc, test_pc_split_merge);
3761     tcase_set_timeout(tc, 15);
3762     suite_add_tcase(s, tc);
3763 
3764     tc = tcase_create("test_pc_split_merge_w_user_msg");
3765     tcase_add_test(tc, test_pc_split_merge_w_user_msg);
3766     tcase_set_timeout(tc, 15);
3767     suite_add_tcase(s, tc);
3768 
3769     tc = tcase_create("test_pc_complete_split_merge");
3770     tcase_add_test(tc, test_pc_complete_split_merge);
3771     tcase_set_timeout(tc, 25);
3772     suite_add_tcase(s, tc);
3773 
3774     tc = tcase_create("test_pc_protocol_upgrade");
3775     tcase_add_test(tc, test_pc_protocol_upgrade);
3776     tcase_set_timeout(tc, 25);
3777     suite_add_tcase(s, tc);
3778 
3779     tc = tcase_create("test_trac_191");
3780     tcase_add_test(tc, test_trac_191);
3781     suite_add_tcase(s, tc);
3782 
3783     tc = tcase_create("test_trac_413");
3784     tcase_add_test(tc, test_trac_413);
3785     suite_add_tcase(s, tc);
3786 
3787     tc = tcase_create("test_fifo_violation");
3788     tcase_add_test(tc, test_fifo_violation);
3789     suite_add_tcase(s, tc);
3790 
3791     tc = tcase_create("test_checksum");
3792     tcase_add_test(tc, test_checksum);
3793     suite_add_tcase(s, tc);
3794 
3795     tc = tcase_create("test_trac_277");
3796     tcase_add_test(tc, test_trac_277);
3797     suite_add_tcase(s, tc);
3798 
3799     tc = tcase_create("test_trac_622_638");
3800     tcase_add_test(tc, test_trac_622_638);
3801     suite_add_tcase(s, tc);
3802 
3803     tc = tcase_create("test_weighted_quorum");
3804     tcase_add_test(tc, test_weighted_quorum);
3805     suite_add_tcase(s, tc);
3806 
3807     tc = tcase_create("test_weighted_partitioning_1");
3808     tcase_add_test(tc, test_weighted_partitioning_1);
3809     suite_add_tcase(s, tc);
3810 
3811     tc = tcase_create("test_weighted_partitioning_2");
3812     tcase_add_test(tc, test_weighted_partitioning_2);
3813     suite_add_tcase(s, tc);
3814 
3815     tc = tcase_create("test_weight_change_partitioning_1");
3816     tcase_add_test(tc, test_weight_change_partitioning_1);
3817     suite_add_tcase(s, tc);
3818 
3819     tc = tcase_create("test_weight_change_partitioning_2");
3820     tcase_add_test(tc, test_weight_change_partitioning_2);
3821     suite_add_tcase(s, tc);
3822 
3823     tc = tcase_create("test_weight_change_joining");
3824     tcase_add_test(tc, test_weight_change_joining);
3825     suite_add_tcase(s, tc);
3826 
3827     tc = tcase_create("test_weight_change_leaving");
3828     tcase_add_test(tc, test_weight_change_leaving);
3829     suite_add_tcase(s, tc);
3830 
3831     tc = tcase_create("test_trac_762");
3832     tcase_add_test(tc, test_trac_762);
3833     tcase_set_timeout(tc, 15);
3834     suite_add_tcase(s, tc);
3835 
3836     tc = tcase_create("test_join_split_cluster");
3837     tcase_add_test(tc, test_join_split_cluster);
3838     suite_add_tcase(s, tc);
3839 
3840     tc = tcase_create("test_gh_92");
3841     tcase_add_test(tc, test_gh_92);
3842     suite_add_tcase(s, tc);
3843 
3844     tc = tcase_create("test_prim_after_evict");
3845     tcase_add_test(tc, test_prim_after_evict);
3846     suite_add_tcase(s, tc);
3847 
3848     tc = tcase_create("test_quorum_2_to_2_in_3_node_cluster");
3849     tcase_add_test(tc, test_quorum_2_to_2_in_3_node_cluster);
3850     suite_add_tcase(s, tc);
3851 
3852     return s;
3853 }
3854