github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/charmrevision/worker_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package charmrevision_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/clock/testclock"
    10  	"github.com/juju/errors"
    11  	"github.com/juju/testing"
    12  	jc "github.com/juju/testing/checkers"
    13  	"github.com/juju/worker/v3"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	coretesting "github.com/juju/juju/testing"
    17  	"github.com/juju/juju/worker/charmrevision"
    18  )
    19  
    20  type WorkerSuite struct {
    21  	testing.IsolationSuite
    22  }
    23  
    24  var _ = gc.Suite(&WorkerSuite{})
    25  
    26  func (s *WorkerSuite) TestNoMoreUpdatesUntilPeriod(c *gc.C) {
    27  	fix := newFixture(time.Minute)
    28  	fix.cleanTest(c, func(_ worker.Worker) {
    29  		fix.clock.Advance(time.Minute - time.Nanosecond)
    30  		fix.waitNoCall(c)
    31  	})
    32  }
    33  
    34  func (s *WorkerSuite) TestUpdatesAfterPeriod(c *gc.C) {
    35  	fix := newFixture(time.Minute)
    36  	fix.cleanTest(c, func(_ worker.Worker) {
    37  		if err := fix.clock.WaitAdvance(time.Minute*2, testing.LongWait, 1); err != nil {
    38  			c.Fatal(err)
    39  		}
    40  		fix.waitCall(c)
    41  		fix.waitNoCall(c)
    42  	})
    43  	fix.revisionUpdater.stub.CheckCallNames(c, "UpdateLatestRevisions")
    44  }
    45  
    46  func (s *WorkerSuite) TestDelayedUpdateError(c *gc.C) {
    47  	fix := newFixture(time.Minute)
    48  	fix.revisionUpdater.stub.SetErrors(
    49  		errors.New("no more updates for you"),
    50  	)
    51  	fix.dirtyTest(c, func(w worker.Worker) {
    52  		if err := fix.clock.WaitAdvance(time.Minute*2, testing.LongWait, 1); err != nil {
    53  			c.Fatal(err)
    54  		}
    55  		fix.waitCall(c)
    56  		c.Check(w.Wait(), gc.ErrorMatches, "no more updates for you")
    57  		fix.waitNoCall(c)
    58  	})
    59  	fix.revisionUpdater.stub.CheckCallNames(c, "UpdateLatestRevisions")
    60  }
    61  
    62  // workerFixture isolates a charmrevision worker for testing.
    63  type workerFixture struct {
    64  	revisionUpdater mockRevisionUpdater
    65  	clock           *testclock.Clock
    66  	period          time.Duration
    67  }
    68  
    69  func newFixture(period time.Duration) workerFixture {
    70  	return workerFixture{
    71  		revisionUpdater: newMockRevisionUpdater(),
    72  		clock:           testclock.NewClock(coretesting.ZeroTime()),
    73  		period:          period,
    74  	}
    75  }
    76  
    77  type testFunc func(worker.Worker)
    78  
    79  func (fix workerFixture) cleanTest(c *gc.C, test testFunc) {
    80  	fix.runTest(c, test, true)
    81  }
    82  
    83  func (fix workerFixture) dirtyTest(c *gc.C, test testFunc) {
    84  	fix.runTest(c, test, false)
    85  }
    86  
    87  func (fix workerFixture) runTest(c *gc.C, test testFunc, checkWaitErr bool) {
    88  	w, err := charmrevision.NewWorker(charmrevision.Config{
    89  		RevisionUpdater: fix.revisionUpdater,
    90  		Clock:           fix.clock,
    91  		Period:          fix.period,
    92  		Logger:          coretesting.NoopLogger{},
    93  	})
    94  	c.Assert(err, jc.ErrorIsNil)
    95  	defer func() {
    96  		err := worker.Stop(w)
    97  		if checkWaitErr {
    98  			c.Check(err, jc.ErrorIsNil)
    99  		}
   100  	}()
   101  	test(w)
   102  }
   103  
   104  func (fix workerFixture) waitCall(c *gc.C) {
   105  	select {
   106  	case <-fix.revisionUpdater.calls:
   107  	case <-time.After(coretesting.LongWait):
   108  		c.Fatalf("timed out")
   109  	}
   110  }
   111  
   112  func (fix workerFixture) waitNoCall(c *gc.C) {
   113  	select {
   114  	case <-fix.revisionUpdater.calls:
   115  		c.Fatalf("unexpected revisionUpdater call")
   116  	case <-time.After(coretesting.ShortWait):
   117  	}
   118  }
   119  
   120  // mockRevisionUpdater records (and notifies of) calls made to UpdateLatestRevisions.
   121  type mockRevisionUpdater struct {
   122  	stub  *testing.Stub
   123  	calls chan struct{}
   124  }
   125  
   126  func newMockRevisionUpdater() mockRevisionUpdater {
   127  	return mockRevisionUpdater{
   128  		stub:  &testing.Stub{},
   129  		calls: make(chan struct{}, 1000),
   130  	}
   131  }
   132  
   133  func (mock mockRevisionUpdater) UpdateLatestRevisions() error {
   134  	mock.stub.AddCall("UpdateLatestRevisions")
   135  	mock.calls <- struct{}{}
   136  	return mock.stub.NextErr()
   137  }