github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/raft/raftflag/flag_test.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package raftflag_test
     5  
     6  import (
     7  	coreraft "github.com/hashicorp/raft"
     8  	jc "github.com/juju/testing/checkers"
     9  	gc "gopkg.in/check.v1"
    10  	"gopkg.in/juju/worker.v1"
    11  	"gopkg.in/juju/worker.v1/workertest"
    12  
    13  	"github.com/juju/juju/cmd/jujud/agent/engine"
    14  	coretesting "github.com/juju/juju/testing"
    15  	"github.com/juju/juju/worker/raft"
    16  	"github.com/juju/juju/worker/raft/raftflag"
    17  	"github.com/juju/juju/worker/raft/rafttest"
    18  )
    19  
    20  type workerFixture struct {
    21  	rafttest.RaftFixture
    22  	config raftflag.Config
    23  }
    24  
    25  func (s *workerFixture) SetUpTest(c *gc.C) {
    26  	s.FSM = &raft.SimpleFSM{}
    27  	s.RaftFixture.SetUpTest(c)
    28  	s.config = raftflag.Config{
    29  		Raft: s.Raft,
    30  	}
    31  }
    32  
    33  type WorkerValidationSuite struct {
    34  	workerFixture
    35  }
    36  
    37  var _ = gc.Suite(&WorkerValidationSuite{})
    38  
    39  func (s *WorkerValidationSuite) TestValidateErrors(c *gc.C) {
    40  	type test struct {
    41  		f      func(*raftflag.Config)
    42  		expect string
    43  	}
    44  	tests := []test{{
    45  		func(cfg *raftflag.Config) { cfg.Raft = nil },
    46  		"nil Raft not valid",
    47  	}}
    48  	for i, test := range tests {
    49  		c.Logf("test #%d (%s)", i, test.expect)
    50  		s.testValidateError(c, test.f, test.expect)
    51  	}
    52  }
    53  
    54  func (s *WorkerValidationSuite) testValidateError(c *gc.C, f func(*raftflag.Config), expect string) {
    55  	config := s.config
    56  	f(&config)
    57  	w, err := raftflag.NewWorker(config)
    58  	if !c.Check(err, gc.NotNil) {
    59  		workertest.DirtyKill(c, w)
    60  		return
    61  	}
    62  	c.Check(w, gc.IsNil)
    63  	c.Check(err, gc.ErrorMatches, expect)
    64  }
    65  
    66  type WorkerSuite struct {
    67  	workerFixture
    68  	worker worker.Worker
    69  	flag   engine.Flag
    70  }
    71  
    72  var _ = gc.Suite(&WorkerSuite{})
    73  
    74  func (s *WorkerSuite) SetUpTest(c *gc.C) {
    75  	s.workerFixture.SetUpTest(c)
    76  	worker, err := raftflag.NewWorker(s.config)
    77  	c.Assert(err, jc.ErrorIsNil)
    78  	s.AddCleanup(func(c *gc.C) {
    79  		workertest.DirtyKill(c, worker)
    80  	})
    81  	s.worker = worker
    82  	s.flag = worker.(engine.Flag)
    83  }
    84  
    85  func (s *WorkerSuite) TestCleanKill(c *gc.C) {
    86  	workertest.CleanKill(c, s.worker)
    87  }
    88  
    89  func (s *WorkerSuite) TestCheckLeader(c *gc.C) {
    90  	c.Assert(s.Raft.VerifyLeader().Error(), jc.ErrorIsNil)
    91  	c.Assert(s.flag.Check(), jc.IsTrue)
    92  }
    93  
    94  func (s *WorkerSuite) TestErrRefresh(c *gc.C) {
    95  	raft1, _, transport1, _, _ := s.NewRaft(c, "1", &raft.SimpleFSM{})
    96  	raft2, _, transport2, _, _ := s.NewRaft(c, "2", &raft.SimpleFSM{})
    97  	transports := []coreraft.LoopbackTransport{s.Transport, transport1, transport2}
    98  	for _, t1 := range transports {
    99  		for _, t2 := range transports {
   100  			t1.Connect(t2.LocalAddr(), t2)
   101  		}
   102  	}
   103  	var f coreraft.Future = s.Raft.AddVoter("1", transport1.LocalAddr(), 0, 0)
   104  	c.Assert(f.Error(), jc.ErrorIsNil)
   105  	f = s.Raft.AddVoter("2", transport2.LocalAddr(), 0, 0)
   106  	c.Assert(f.Error(), jc.ErrorIsNil)
   107  
   108  	// Start a new raftflag worker for the second raft.
   109  	newFlagWorker := func(r *coreraft.Raft) (worker.Worker, bool) {
   110  		config := s.config
   111  		config.Raft = r
   112  		worker, err := raftflag.NewWorker(config)
   113  		c.Assert(err, jc.ErrorIsNil)
   114  		s.AddCleanup(func(c *gc.C) {
   115  			workertest.DirtyKill(c, worker)
   116  		})
   117  		return worker, worker.(engine.Flag).Check()
   118  	}
   119  	worker1, flag1 := newFlagWorker(raft1)
   120  	worker2, flag2 := newFlagWorker(raft2)
   121  	c.Assert(flag1, jc.IsFalse)
   122  	c.Assert(flag2, jc.IsFalse)
   123  
   124  	// Shutdown the original node, causing one of the other
   125  	// two nodes to become the leader.
   126  	f = s.Raft.Shutdown()
   127  	c.Assert(f.Error(), jc.ErrorIsNil)
   128  
   129  	// When the raft node toggles between leader/follower,
   130  	// then the worker will exit with ErrRefresh.
   131  	err := workertest.CheckKilled(c, s.worker)
   132  	c.Assert(err, gc.Equals, raftflag.ErrRefresh)
   133  
   134  	for a := coretesting.LongAttempt.Start(); a.Next(); {
   135  		if raft1.State() == coreraft.Leader || raft2.State() == coreraft.Leader {
   136  			break
   137  		}
   138  	}
   139  	var leaderWorker, followerWorker worker.Worker
   140  	switch {
   141  	case raft1.State() == coreraft.Leader:
   142  		c.Assert(raft2.State(), gc.Equals, coreraft.Follower)
   143  		leaderWorker, followerWorker = worker1, worker2
   144  	case raft2.State() == coreraft.Leader:
   145  		c.Assert(raft1.State(), gc.Equals, coreraft.Follower)
   146  		leaderWorker, followerWorker = worker2, worker1
   147  	}
   148  	err = workertest.CheckKilled(c, leaderWorker)
   149  	c.Assert(err, gc.Equals, raftflag.ErrRefresh)
   150  	workertest.CheckAlive(c, followerWorker)
   151  }