github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/lease/manager_cross_test.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package lease_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/clock/testclock"
    10  	"github.com/juju/errors"
    11  	"github.com/juju/loggo"
    12  	"github.com/juju/testing"
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	corelease "github.com/juju/juju/core/lease"
    17  	"github.com/juju/juju/worker/lease"
    18  )
    19  
    20  // Tests that check the manager handles leases across namespaces and
    21  // models correctly.
    22  
    23  type CrossSuite struct {
    24  	testing.IsolationSuite
    25  }
    26  
    27  var _ = gc.Suite(&CrossSuite{})
    28  
    29  func (s *CrossSuite) testClaims(c *gc.C, lease1, lease2 corelease.Key) {
    30  	fix := Fixture{
    31  		expectCalls: []call{{
    32  			method: "ClaimLease",
    33  			args: []interface{}{
    34  				lease1,
    35  				corelease.Request{"sgt-howie", time.Minute},
    36  			},
    37  			callback: func(leases map[corelease.Key]corelease.Info) {
    38  				leases[lease1] = corelease.Info{
    39  					Holder: "sgt-howie",
    40  					Expiry: offset(time.Second),
    41  				}
    42  			},
    43  		}, {
    44  			method: "ClaimLease",
    45  			args: []interface{}{
    46  				lease2,
    47  				corelease.Request{"rowan", time.Minute},
    48  			},
    49  			callback: func(leases map[corelease.Key]corelease.Info) {
    50  				leases[lease2] = corelease.Info{
    51  					Holder: "rowan",
    52  					Expiry: offset(time.Second),
    53  				}
    54  			},
    55  		}},
    56  	}
    57  	fix.RunTest(c, func(manager *lease.Manager, _ *testclock.Clock) {
    58  		claimer1, err := manager.Claimer(lease1.Namespace, lease1.ModelUUID)
    59  		c.Assert(err, jc.ErrorIsNil)
    60  		claimer2, err := manager.Claimer(lease2.Namespace, lease2.ModelUUID)
    61  		c.Assert(err, jc.ErrorIsNil)
    62  
    63  		err = claimer1.Claim(lease1.Lease, "sgt-howie", time.Minute)
    64  		c.Assert(err, jc.ErrorIsNil)
    65  		err = claimer2.Claim(lease2.Lease, "rowan", time.Minute)
    66  		c.Assert(err, jc.ErrorIsNil)
    67  
    68  		err = claimer1.Claim(lease1.Lease, "lord-summerisle", time.Minute)
    69  		c.Assert(err, gc.Equals, corelease.ErrClaimDenied)
    70  	})
    71  }
    72  
    73  func (s *CrossSuite) TestClaimAcrossNamespaces(c *gc.C) {
    74  	s.testClaims(c,
    75  		key("ns1", "model", "summerisle"),
    76  		key("ns2", "model", "summerisle"),
    77  	)
    78  }
    79  
    80  func (s *CrossSuite) TestClaimAcrossModels(c *gc.C) {
    81  	s.testClaims(c,
    82  		key("ns", "model1", "summerisle"),
    83  		key("ns", "model2", "summerisle"),
    84  	)
    85  }
    86  
    87  func (s *CrossSuite) testWaits(c *gc.C, lease1, lease2 corelease.Key) {
    88  	fix := Fixture{
    89  		leases: map[corelease.Key]corelease.Info{
    90  			lease1: {
    91  				Holder: "sgt-howie",
    92  				Expiry: offset(time.Second),
    93  			},
    94  			lease2: {
    95  				Holder: "willow",
    96  				Expiry: offset(time.Minute),
    97  			},
    98  		},
    99  		expectCalls: []call{{
   100  			method: "Refresh",
   101  		}, {
   102  			method: "ExpireLease",
   103  			args:   []interface{}{lease1},
   104  			callback: func(leases map[corelease.Key]corelease.Info) {
   105  				delete(leases, lease1)
   106  			},
   107  		}},
   108  	}
   109  	fix.RunTest(c, func(manager *lease.Manager, clock *testclock.Clock) {
   110  		b1 := newBlockTest(c, manager, lease1)
   111  		b2 := newBlockTest(c, manager, lease2)
   112  
   113  		b1.assertBlocked(c)
   114  		b2.assertBlocked(c)
   115  
   116  		clock.Advance(time.Second)
   117  
   118  		err := b1.assertUnblocked(c)
   119  		c.Assert(err, jc.ErrorIsNil)
   120  		b2.assertBlocked(c)
   121  	})
   122  }
   123  
   124  func (s *CrossSuite) TestWaitAcrossNamespaces(c *gc.C) {
   125  	s.testWaits(c,
   126  		key("ns1", "model", "summerisle"),
   127  		key("ns2", "model", "summerisle"),
   128  	)
   129  }
   130  
   131  func (s *CrossSuite) TestWaitAcrossModels(c *gc.C) {
   132  	s.testWaits(c,
   133  		key("ns", "model1", "summerisle"),
   134  		key("ns", "model2", "summerisle"),
   135  	)
   136  }
   137  
   138  func (s *CrossSuite) testChecks(c *gc.C, lease1, lease2 corelease.Key) {
   139  	fix := Fixture{
   140  		leases: map[corelease.Key]corelease.Info{
   141  			lease1: {
   142  				Holder:   "sgt-howie",
   143  				Expiry:   offset(time.Second),
   144  				Trapdoor: corelease.LockedTrapdoor,
   145  			},
   146  		},
   147  		expectCalls: []call{{
   148  			method: "Refresh",
   149  		}},
   150  	}
   151  	fix.RunTest(c, func(manager *lease.Manager, _ *testclock.Clock) {
   152  		checker1, err := manager.Checker(lease1.Namespace, lease1.ModelUUID)
   153  		c.Assert(err, jc.ErrorIsNil)
   154  		checker2, err := manager.Checker(lease2.Namespace, lease2.ModelUUID)
   155  		c.Assert(err, jc.ErrorIsNil)
   156  
   157  		t1 := checker1.Token(lease1.Lease, "sgt-howie")
   158  		c.Assert(t1.Check(0, nil), gc.Equals, nil)
   159  
   160  		t2 := checker2.Token(lease2.Lease, "sgt-howie")
   161  		err = t2.Check(0, nil)
   162  		c.Assert(errors.Cause(err), gc.Equals, corelease.ErrNotHeld)
   163  	})
   164  }
   165  
   166  func (s *CrossSuite) TestCheckAcrossNamespaces(c *gc.C) {
   167  	s.testChecks(c,
   168  		key("ns1", "model", "summerisle"),
   169  		key("ns2", "model", "summerisle"),
   170  	)
   171  }
   172  
   173  func (s *CrossSuite) TestCheckAcrossModels(c *gc.C) {
   174  	s.testChecks(c,
   175  		key("ns", "model1", "summerisle"),
   176  		key("ns", "model2", "summerisle"),
   177  	)
   178  }
   179  
   180  func (s *CrossSuite) TestDifferentNamespaceValidation(c *gc.C) {
   181  	clock := testclock.NewClock(defaultClockStart)
   182  	store := NewStore(false, nil, nil)
   183  	manager, err := lease.NewManager(lease.ManagerConfig{
   184  		Clock: clock,
   185  		Store: store,
   186  		Secretary: func(namespace string) (lease.Secretary, error) {
   187  			switch namespace {
   188  			case "ns1":
   189  				return Secretary{}, nil
   190  			case "ns2":
   191  				return OtherSecretary{}, nil
   192  			default:
   193  				return nil, errors.Errorf("bad namespace!")
   194  			}
   195  		},
   196  		MaxSleep:             defaultMaxSleep,
   197  		Logger:               loggo.GetLogger("lease_test"),
   198  		PrometheusRegisterer: noopRegisterer{},
   199  	})
   200  	c.Assert(err, jc.ErrorIsNil)
   201  	defer func() {
   202  		manager.Kill()
   203  		err := manager.Wait()
   204  		c.Check(err, jc.ErrorIsNil)
   205  	}()
   206  	defer store.Wait(c)
   207  
   208  	_, err = manager.Claimer("something-else", "model")
   209  	c.Assert(err, gc.ErrorMatches, "bad namespace!")
   210  
   211  	c1, err := manager.Claimer("ns1", "model")
   212  	c.Assert(err, jc.ErrorIsNil)
   213  	err = c1.Claim("INVALID", "sgt-howie", time.Minute)
   214  	c.Assert(err, gc.ErrorMatches, `cannot claim lease "INVALID": name not valid`)
   215  
   216  	c2, err := manager.Claimer("ns2", "model")
   217  	c.Assert(err, jc.ErrorIsNil)
   218  	err = c2.Claim("INVALID", "sgt-howie", time.Minute)
   219  	c.Assert(err, gc.ErrorMatches, `cannot claim lease "INVALID": lease name not valid`)
   220  }
   221  
   222  type OtherSecretary struct{}
   223  
   224  // CheckLease is part of the lease.Secretary interface.
   225  func (OtherSecretary) CheckLease(key corelease.Key) error {
   226  	return errors.NotValidf("lease name")
   227  }
   228  
   229  // CheckHolder is part of the lease.Secretary interface.
   230  func (OtherSecretary) CheckHolder(name string) error {
   231  	return errors.NotValidf("holder name")
   232  }
   233  
   234  // CheckDuration is part of the lease.Secretary interface.
   235  func (OtherSecretary) CheckDuration(duration time.Duration) error {
   236  	if duration != time.Hour {
   237  		return errors.NotValidf("time")
   238  	}
   239  	return nil
   240  }