github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/sequence_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "sort" 8 9 "github.com/juju/mgo/v3/bson" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/state" 14 ) 15 16 var _ = gc.Suite(&sequenceSuite{}) 17 18 type sequenceSuite struct { 19 ConnSuite 20 } 21 22 func (s *sequenceSuite) TestSequence(c *gc.C) { 23 s.incAndCheck(c, s.State, "foo", 0) 24 s.checkDocCount(c, 1) 25 s.checkDoc(c, s.State.ModelUUID(), "foo", 1) 26 27 s.incAndCheck(c, s.State, "foo", 1) 28 s.checkDocCount(c, 1) 29 s.checkDoc(c, s.State.ModelUUID(), "foo", 2) 30 } 31 32 func (s *sequenceSuite) TestMultipleSequences(c *gc.C) { 33 s.incAndCheck(c, s.State, "foo", 0) 34 s.incAndCheck(c, s.State, "bar", 0) 35 s.incAndCheck(c, s.State, "bar", 1) 36 s.incAndCheck(c, s.State, "foo", 1) 37 s.incAndCheck(c, s.State, "bar", 2) 38 39 s.checkDocCount(c, 2) 40 s.checkDoc(c, s.State.ModelUUID(), "foo", 2) 41 s.checkDoc(c, s.State.ModelUUID(), "bar", 3) 42 } 43 44 func (s *sequenceSuite) TestSequenceWithMultipleModels(c *gc.C) { 45 state1 := s.State 46 state2 := s.Factory.MakeModel(c, nil) 47 defer state2.Close() 48 49 s.incAndCheck(c, state1, "foo", 0) 50 s.incAndCheck(c, state2, "foo", 0) 51 s.incAndCheck(c, state1, "foo", 1) 52 s.incAndCheck(c, state2, "foo", 1) 53 s.incAndCheck(c, state1, "foo", 2) 54 55 s.checkDocCount(c, 2) 56 s.checkDoc(c, state1.ModelUUID(), "foo", 3) 57 s.checkDoc(c, state2.ModelUUID(), "foo", 2) 58 } 59 60 func (s *sequenceSuite) TestSequences(c *gc.C) { 61 state1 := s.State 62 state2 := s.Factory.MakeModel(c, nil) 63 defer state2.Close() 64 65 s.incAndCheck(c, state1, "foo", 0) 66 s.incAndCheck(c, state2, "foo", 0) 67 s.incAndCheck(c, state1, "foo", 1) 68 s.incAndCheck(c, state2, "foo", 1) 69 s.incAndCheck(c, state1, "foo", 2) 70 s.incAndCheck(c, state1, "bar", 0) 71 s.incAndCheck(c, state2, "baz", 0) 72 73 sequences, err := state1.Sequences() 74 c.Assert(err, jc.ErrorIsNil) 75 c.Assert(sequences, jc.DeepEquals, map[string]int{ 76 "foo": 3, "bar": 1, 77 }) 78 } 79 80 func (s *sequenceSuite) TestSequenceWithMin(c *gc.C) { 81 st := s.State 82 modelUUID := st.ModelUUID() 83 const name = "foo" 84 85 value, err := state.SequenceWithMin(st, name, 3) 86 c.Assert(err, jc.ErrorIsNil) 87 c.Check(value, gc.Equals, 3) 88 s.checkDoc(c, modelUUID, name, 4) 89 90 value, err = state.SequenceWithMin(st, name, 3) 91 c.Assert(err, jc.ErrorIsNil) 92 c.Check(value, gc.Equals, 4) 93 s.checkDoc(c, modelUUID, name, 5) 94 95 value, err = state.SequenceWithMin(st, name, 3) 96 c.Assert(err, jc.ErrorIsNil) 97 c.Check(value, gc.Equals, 5) 98 s.checkDoc(c, modelUUID, name, 6) 99 100 value, err = state.SequenceWithMin(st, name, 10) 101 c.Assert(err, jc.ErrorIsNil) 102 c.Check(value, gc.Equals, 10) 103 s.checkDoc(c, modelUUID, name, 11) 104 } 105 106 func (s *sequenceSuite) TestMultipleSequenceWithMin(c *gc.C) { 107 st := s.State 108 109 value, err := state.SequenceWithMin(st, "foo", 3) 110 c.Assert(err, jc.ErrorIsNil) 111 c.Check(value, gc.Equals, 3) 112 113 value, err = state.SequenceWithMin(st, "bar", 2) 114 c.Assert(err, jc.ErrorIsNil) 115 c.Check(value, gc.Equals, 2) 116 117 value, err = state.SequenceWithMin(st, "foo", 3) 118 c.Assert(err, jc.ErrorIsNil) 119 c.Check(value, gc.Equals, 4) 120 121 value, err = state.SequenceWithMin(st, "bar", 2) 122 c.Assert(err, jc.ErrorIsNil) 123 c.Check(value, gc.Equals, 3) 124 } 125 126 func (s *sequenceSuite) TestMigrationSequenceWithMin(c *gc.C) { 127 // Test local charm migration where incoming charms may have 128 // the same curl with non-sequential revisions. 129 st := s.State 130 131 value, err := state.SequenceWithMin(st, "foo", 0) 132 c.Assert(err, jc.ErrorIsNil) 133 c.Check(value, gc.Equals, 0) 134 135 value, err = state.SequenceWithMin(st, "foo", 2) 136 c.Assert(err, jc.ErrorIsNil) 137 c.Check(value, gc.Equals, 2) 138 139 found, err := state.Sequence(st, "foo") 140 c.Assert(err, jc.ErrorIsNil) 141 c.Check(found, gc.Equals, 3) 142 } 143 144 func (s *sequenceSuite) TestContention(c *gc.C) { 145 const name = "foo" 146 const goroutines = 2 147 const iterations = 10 148 st := s.State 149 150 type results struct { 151 values []int 152 numErrs int 153 } 154 resultsCh := make(chan results) 155 156 workFunc := func(nextSeq func() (int, error)) { 157 var r results 158 for i := 0; i < iterations; i++ { 159 v, err := nextSeq() 160 if err != nil { 161 c.Logf("sequence increment failed: %v", err) 162 r.numErrs++ 163 } 164 r.values = append(r.values, v) 165 } 166 resultsCh <- r 167 } 168 169 go workFunc(func() (int, error) { 170 return state.Sequence(st, name) 171 }) 172 173 go workFunc(func() (int, error) { 174 return state.SequenceWithMin(st, name, 0) 175 }) 176 177 var seenValues sort.IntSlice 178 var seenErrs int 179 for i := 0; i < goroutines; i++ { 180 r := <-resultsCh 181 seenValues = append(seenValues, r.values...) 182 seenErrs += r.numErrs 183 } 184 c.Assert(seenErrs, gc.Equals, 0) 185 186 numExpected := goroutines * iterations 187 c.Assert(len(seenValues), gc.Equals, numExpected) 188 seenValues.Sort() 189 for i := 0; i < numExpected; i++ { 190 c.Assert(seenValues[i], gc.Equals, i, gc.Commentf("index %d", i)) 191 } 192 } 193 194 func (s *sequenceSuite) TestEnsureCreate(c *gc.C) { 195 err := state.SequenceEnsure(s.State, "foo", 3) 196 c.Assert(err, jc.ErrorIsNil) 197 s.incAndCheck(c, s.State, "foo", 3) 198 } 199 200 func (s *sequenceSuite) TestEnsureSet(c *gc.C) { 201 s.incAndCheck(c, s.State, "foo", 0) 202 err := state.SequenceEnsure(s.State, "foo", 5) 203 c.Assert(err, jc.ErrorIsNil) 204 s.incAndCheck(c, s.State, "foo", 5) 205 } 206 207 func (s *sequenceSuite) TestEnsureBackwards(c *gc.C) { 208 s.incAndCheck(c, s.State, "foo", 0) 209 s.incAndCheck(c, s.State, "foo", 1) 210 s.incAndCheck(c, s.State, "foo", 2) 211 212 err := state.SequenceEnsure(s.State, "foo", 1) 213 c.Assert(err, jc.ErrorIsNil) 214 215 s.incAndCheck(c, s.State, "foo", 3) 216 } 217 218 func (s *sequenceSuite) TestResetSequence(c *gc.C) { 219 err := state.SequenceEnsure(s.State, "foo", 3) 220 c.Assert(err, jc.ErrorIsNil) 221 s.incAndCheck(c, s.State, "foo", 3) 222 223 err = state.ResetSequence(s.State, "foo") 224 c.Assert(err, jc.ErrorIsNil) 225 226 s.incAndCheck(c, s.State, "foo", 0) 227 } 228 func (s *sequenceSuite) incAndCheck(c *gc.C, st *state.State, name string, expectedCount int) { 229 value, err := state.Sequence(st, name) 230 c.Assert(err, jc.ErrorIsNil) 231 c.Check(value, gc.Equals, expectedCount) 232 } 233 234 func (s *sequenceSuite) checkDocCount(c *gc.C, expectedCount int) { 235 coll, closer := state.GetRawCollection(s.State, "sequence") 236 defer closer() 237 count, err := coll.Count() 238 c.Assert(err, jc.ErrorIsNil) 239 c.Check(count, gc.Equals, expectedCount) 240 } 241 242 func (s *sequenceSuite) checkDoc(c *gc.C, modelUUID, name string, value int) { 243 coll, closer := state.GetRawCollection(s.State, "sequence") 244 defer closer() 245 246 docID := modelUUID + ":" + name 247 var doc bson.M 248 err := coll.FindId(docID).One(&doc) 249 c.Assert(err, jc.ErrorIsNil) 250 c.Check(doc["_id"], gc.Equals, docID) 251 c.Check(doc["name"], gc.Equals, name) 252 c.Check(doc["model-uuid"], gc.Equals, modelUUID) 253 c.Check(doc["counter"], gc.Equals, value) 254 }