github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/export_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "path/filepath" 10 "time" 11 12 "github.com/juju/errors" 13 "github.com/juju/loggo" 14 "github.com/juju/names" 15 jc "github.com/juju/testing/checkers" 16 jujutxn "github.com/juju/txn" 17 txntesting "github.com/juju/txn/testing" 18 gc "gopkg.in/check.v1" 19 "gopkg.in/juju/charm.v6-unstable" 20 "gopkg.in/mgo.v2" 21 "gopkg.in/mgo.v2/bson" 22 "gopkg.in/mgo.v2/txn" 23 24 "github.com/juju/juju/core/lease" 25 "github.com/juju/juju/mongo" 26 "github.com/juju/juju/network" 27 "github.com/juju/juju/testcharms" 28 ) 29 30 const ( 31 InstanceDataC = instanceDataC 32 MachinesC = machinesC 33 ServicesC = servicesC 34 EndpointBindingsC = endpointBindingsC 35 SettingsC = settingsC 36 UnitsC = unitsC 37 UsersC = usersC 38 BlockDevicesC = blockDevicesC 39 StorageInstancesC = storageInstancesC 40 StatusesHistoryC = statusesHistoryC 41 GUISettingsC = guisettingsC 42 ) 43 44 var ( 45 BinarystorageNew = &binarystorageNew 46 ImageStorageNewStorage = &imageStorageNewStorage 47 MachineIdLessThan = machineIdLessThan 48 ControllerAvailable = &controllerAvailable 49 GetOrCreatePorts = getOrCreatePorts 50 GetPorts = getPorts 51 PortsGlobalKey = portsGlobalKey 52 CurrentUpgradeId = currentUpgradeId 53 NowToTheSecond = nowToTheSecond 54 PickAddress = &pickAddress 55 AddVolumeOps = (*State).addVolumeOps 56 CombineMeterStatus = combineMeterStatus 57 ServiceGlobalKey = serviceGlobalKey 58 MergeBindings = mergeBindings 59 UpgradeInProgressError = errUpgradeInProgress 60 ) 61 62 type ( 63 CharmDoc charmDoc 64 MachineDoc machineDoc 65 RelationDoc relationDoc 66 ServiceDoc serviceDoc 67 UnitDoc unitDoc 68 BlockDevicesDoc blockDevicesDoc 69 ) 70 71 func SetTestHooks(c *gc.C, st *State, hooks ...jujutxn.TestHook) txntesting.TransactionChecker { 72 return txntesting.SetTestHooks(c, newRunnerForHooks(st), hooks...) 73 } 74 75 func SetBeforeHooks(c *gc.C, st *State, fs ...func()) txntesting.TransactionChecker { 76 return txntesting.SetBeforeHooks(c, newRunnerForHooks(st), fs...) 77 } 78 79 func SetAfterHooks(c *gc.C, st *State, fs ...func()) txntesting.TransactionChecker { 80 return txntesting.SetAfterHooks(c, newRunnerForHooks(st), fs...) 81 } 82 83 func SetRetryHooks(c *gc.C, st *State, block, check func()) txntesting.TransactionChecker { 84 return txntesting.SetRetryHooks(c, newRunnerForHooks(st), block, check) 85 } 86 87 func newRunnerForHooks(st *State) jujutxn.Runner { 88 db := st.database.(*database) 89 runner := jujutxn.NewRunner(jujutxn.RunnerParams{Database: db.raw}) 90 db.runner = runner 91 return runner 92 } 93 94 // SetPolicy updates the State's policy field to the 95 // given Policy, and returns the old value. 96 func SetPolicy(st *State, p Policy) Policy { 97 old := st.policy 98 st.policy = p 99 return old 100 } 101 102 func (doc *MachineDoc) String() string { 103 m := &Machine{doc: machineDoc(*doc)} 104 return m.String() 105 } 106 107 func ServiceSettingsRefCount(st *State, serviceName string, curl *charm.URL) (int, error) { 108 settingsRefsCollection, closer := st.getCollection(settingsrefsC) 109 defer closer() 110 111 key := serviceSettingsKey(serviceName, curl) 112 var doc settingsRefsDoc 113 if err := settingsRefsCollection.FindId(key).One(&doc); err == nil { 114 return doc.RefCount, nil 115 } 116 return 0, mgo.ErrNotFound 117 } 118 119 func AddTestingCharm(c *gc.C, st *State, name string) *Charm { 120 return addCharm(c, st, "quantal", testcharms.Repo.CharmDir(name)) 121 } 122 123 func AddTestingCharmForSeries(c *gc.C, st *State, series, name string) *Charm { 124 return addCharm(c, st, series, testcharms.Repo.CharmDir(name)) 125 } 126 127 func AddTestingCharmMultiSeries(c *gc.C, st *State, name string) *Charm { 128 ch := testcharms.Repo.CharmDir(name) 129 ident := fmt.Sprintf("%s-%d", ch.Meta().Name, ch.Revision()) 130 curl := charm.MustParseURL("cs:" + ident) 131 info := CharmInfo{ 132 Charm: ch, 133 ID: curl, 134 StoragePath: "dummy-path", 135 SHA256: ident + "-sha256", 136 } 137 sch, err := st.AddCharm(info) 138 c.Assert(err, jc.ErrorIsNil) 139 return sch 140 } 141 142 func AddTestingService(c *gc.C, st *State, name string, ch *Charm, owner names.UserTag) *Service { 143 return addTestingService(c, st, "", name, ch, owner, nil, nil) 144 } 145 146 func AddTestingServiceForSeries(c *gc.C, st *State, series, name string, ch *Charm, owner names.UserTag) *Service { 147 return addTestingService(c, st, series, name, ch, owner, nil, nil) 148 } 149 150 func AddTestingServiceWithStorage(c *gc.C, st *State, name string, ch *Charm, owner names.UserTag, storage map[string]StorageConstraints) *Service { 151 return addTestingService(c, st, "", name, ch, owner, nil, storage) 152 } 153 154 func AddTestingServiceWithBindings(c *gc.C, st *State, name string, ch *Charm, owner names.UserTag, bindings map[string]string) *Service { 155 return addTestingService(c, st, "", name, ch, owner, bindings, nil) 156 } 157 158 func addTestingService(c *gc.C, st *State, series, name string, ch *Charm, owner names.UserTag, bindings map[string]string, storage map[string]StorageConstraints) *Service { 159 c.Assert(ch, gc.NotNil) 160 service, err := st.AddService(AddServiceArgs{ 161 Name: name, 162 Series: series, 163 Owner: owner.String(), 164 Charm: ch, 165 EndpointBindings: bindings, 166 Storage: storage, 167 }) 168 c.Assert(err, jc.ErrorIsNil) 169 return service 170 } 171 172 func AddCustomCharm(c *gc.C, st *State, name, filename, content, series string, revision int) *Charm { 173 path := testcharms.Repo.ClonedDirPath(c.MkDir(), name) 174 if filename != "" { 175 config := filepath.Join(path, filename) 176 err := ioutil.WriteFile(config, []byte(content), 0644) 177 c.Assert(err, jc.ErrorIsNil) 178 } 179 ch, err := charm.ReadCharmDir(path) 180 c.Assert(err, jc.ErrorIsNil) 181 if revision != -1 { 182 ch.SetRevision(revision) 183 } 184 return addCharm(c, st, series, ch) 185 } 186 187 func addCharm(c *gc.C, st *State, series string, ch charm.Charm) *Charm { 188 ident := fmt.Sprintf("%s-%s-%d", series, ch.Meta().Name, ch.Revision()) 189 url := "local:" + series + "/" + ident 190 if series == "" { 191 ident = fmt.Sprintf("%s-%d", ch.Meta().Name, ch.Revision()) 192 url = "local:" + ident 193 } 194 curl := charm.MustParseURL(url) 195 info := CharmInfo{ 196 Charm: ch, 197 ID: curl, 198 StoragePath: "dummy-path", 199 SHA256: ident + "-sha256", 200 } 201 sch, err := st.AddCharm(info) 202 c.Assert(err, jc.ErrorIsNil) 203 return sch 204 } 205 206 // SetCharmBundleURL sets the deprecated bundleurl field in the 207 // charm document for the charm with the specified URL. 208 func SetCharmBundleURL(c *gc.C, st *State, curl *charm.URL, bundleURL string) { 209 ops := []txn.Op{{ 210 C: charmsC, 211 Id: st.docID(curl.String()), 212 Assert: txn.DocExists, 213 Update: bson.D{{"$set", bson.D{{"bundleurl", bundleURL}}}}, 214 }} 215 err := st.runTransaction(ops) 216 c.Assert(err, jc.ErrorIsNil) 217 } 218 219 // SCHEMACHANGE 220 // This method is used to reset the ownertag attribute 221 func SetServiceOwnerTag(s *Service, ownerTag string) { 222 s.doc.OwnerTag = ownerTag 223 } 224 225 // SCHEMACHANGE 226 // Get the owner directly 227 func GetServiceOwnerTag(s *Service) string { 228 return s.doc.OwnerTag 229 } 230 231 func SetPasswordHash(e Authenticator, passwordHash string) error { 232 type hasSetPasswordHash interface { 233 setPasswordHash(string) error 234 } 235 return e.(hasSetPasswordHash).setPasswordHash(passwordHash) 236 } 237 238 // Return the underlying PasswordHash stored in the database. Used by the test 239 // suite to check that the PasswordHash gets properly updated to new values 240 // when compatibility mode is detected. 241 func GetPasswordHash(e Authenticator) string { 242 type hasGetPasswordHash interface { 243 getPasswordHash() string 244 } 245 return e.(hasGetPasswordHash).getPasswordHash() 246 } 247 248 func init() { 249 txnLogSize = txnLogSizeTests 250 } 251 252 // TxnRevno returns the txn-revno field of the document 253 // associated with the given Id in the given collection. 254 func TxnRevno(st *State, collName string, id interface{}) (int64, error) { 255 var doc struct { 256 TxnRevno int64 `bson:"txn-revno"` 257 } 258 coll, closer := st.getCollection(collName) 259 defer closer() 260 err := coll.FindId(id).One(&doc) 261 if err != nil { 262 return 0, err 263 } 264 return doc.TxnRevno, nil 265 } 266 267 // MinUnitsRevno returns the Revno of the minUnits document 268 // associated with the given service name. 269 func MinUnitsRevno(st *State, serviceName string) (int, error) { 270 minUnitsCollection, closer := st.getCollection(minUnitsC) 271 defer closer() 272 var doc minUnitsDoc 273 if err := minUnitsCollection.FindId(serviceName).One(&doc); err != nil { 274 return 0, err 275 } 276 return doc.Revno, nil 277 } 278 279 func ConvertTagToCollectionNameAndId(st *State, tag names.Tag) (string, interface{}, error) { 280 return st.tagToCollectionAndId(tag) 281 } 282 283 func RunTransaction(st *State, ops []txn.Op) error { 284 return st.runTransaction(ops) 285 } 286 287 // Return the PasswordSalt that goes along with the PasswordHash 288 func GetUserPasswordSaltAndHash(u *User) (string, string) { 289 return u.doc.PasswordSalt, u.doc.PasswordHash 290 } 291 292 func CheckUserExists(st *State, name string) (bool, error) { 293 return st.checkUserExists(name) 294 } 295 296 func WatcherMergeIds(st *State, changeset *[]string, updates map[interface{}]bool, idconv func(string) string) error { 297 return mergeIds(st, changeset, updates, idconv) 298 } 299 300 func WatcherEnsureSuffixFn(marker string) func(string) string { 301 return ensureSuffixFn(marker) 302 } 303 304 func WatcherMakeIdFilter(st *State, marker string, receivers ...ActionReceiver) func(interface{}) bool { 305 return makeIdFilter(st, marker, receivers...) 306 } 307 308 func NewActionStatusWatcher(st *State, receivers []ActionReceiver, statuses ...ActionStatus) StringsWatcher { 309 return newActionStatusWatcher(st, receivers, statuses...) 310 } 311 312 func GetAllUpgradeInfos(st *State) ([]*UpgradeInfo, error) { 313 upgradeInfos, closer := st.getCollection(upgradeInfoC) 314 defer closer() 315 316 var out []*UpgradeInfo 317 var doc upgradeInfoDoc 318 iter := upgradeInfos.Find(nil).Iter() 319 defer iter.Close() 320 for iter.Next(&doc) { 321 out = append(out, &UpgradeInfo{st: st, doc: doc}) 322 } 323 if err := iter.Err(); err != nil { 324 return nil, err 325 } 326 return out, nil 327 } 328 329 func UserModelNameIndex(username, modelName string) string { 330 return userModelNameIndex(username, modelName) 331 } 332 333 func DocID(st *State, id string) string { 334 return st.docID(id) 335 } 336 337 func LocalID(st *State, id string) string { 338 return st.localID(id) 339 } 340 341 func StrictLocalID(st *State, id string) (string, error) { 342 return st.strictLocalID(id) 343 } 344 345 func GetUnitModelUUID(unit *Unit) string { 346 return unit.doc.ModelUUID 347 } 348 349 func GetCollection(st *State, name string) (mongo.Collection, func()) { 350 return st.getCollection(name) 351 } 352 353 func GetRawCollection(st *State, name string) (*mgo.Collection, func()) { 354 return st.getRawCollection(name) 355 } 356 357 func HasRawAccess(collectionName string) bool { 358 return allCollections()[collectionName].rawAccess 359 } 360 361 func MultiEnvCollections() []string { 362 var result []string 363 for name, info := range allCollections() { 364 if !info.global { 365 result = append(result, name) 366 } 367 } 368 return result 369 } 370 371 func Sequence(st *State, name string) (int, error) { 372 return st.sequence(name) 373 } 374 375 func SetModelLifeDead(st *State, modelUUID string) error { 376 ops := []txn.Op{{ 377 C: modelsC, 378 Id: modelUUID, 379 Update: bson.D{{"$set", bson.D{{"life", Dead}}}}, 380 }} 381 return st.runTransaction(ops) 382 } 383 384 func HostedModelCount(c *gc.C, st *State) int { 385 count, err := hostedModelCount(st) 386 c.Assert(err, jc.ErrorIsNil) 387 return count 388 } 389 390 type MockGlobalEntity struct { 391 } 392 393 func (m MockGlobalEntity) globalKey() string { 394 return "globalKey" 395 } 396 func (m MockGlobalEntity) Tag() names.Tag { 397 return names.NewMachineTag("42") 398 } 399 400 var ( 401 _ GlobalEntity = (*MockGlobalEntity)(nil) 402 TagToCollectionAndId = (*State).tagToCollectionAndId 403 ) 404 405 func AssertAddressConversion(c *gc.C, netAddr network.Address) { 406 addr := fromNetworkAddress(netAddr, OriginUnknown) 407 newNetAddr := addr.networkAddress() 408 c.Assert(netAddr, gc.DeepEquals, newNetAddr) 409 410 size := 5 411 netAddrs := make([]network.Address, size) 412 for i := 0; i < size; i++ { 413 netAddrs[i] = netAddr 414 } 415 addrs := fromNetworkAddresses(netAddrs, OriginUnknown) 416 newNetAddrs := networkAddresses(addrs) 417 c.Assert(netAddrs, gc.DeepEquals, newNetAddrs) 418 } 419 420 func AssertHostPortConversion(c *gc.C, netHostPort network.HostPort) { 421 hostPort := fromNetworkHostPort(netHostPort) 422 newNetHostPort := hostPort.networkHostPort() 423 c.Assert(netHostPort, gc.DeepEquals, newNetHostPort) 424 425 size := 5 426 netHostsPorts := make([][]network.HostPort, size) 427 for i := 0; i < size; i++ { 428 netHostsPorts[i] = make([]network.HostPort, size) 429 for j := 0; j < size; j++ { 430 netHostsPorts[i][j] = netHostPort 431 } 432 } 433 hostsPorts := fromNetworkHostsPorts(netHostsPorts) 434 newNetHostsPorts := networkHostsPorts(hostsPorts) 435 c.Assert(netHostsPorts, gc.DeepEquals, newNetHostsPorts) 436 } 437 438 // MakeLogDoc creates a database document for a single log message. 439 func MakeLogDoc( 440 modelUUID string, 441 entity names.Tag, 442 t time.Time, 443 module string, 444 location string, 445 level loggo.Level, 446 msg string, 447 ) *logDoc { 448 return &logDoc{ 449 Id: bson.NewObjectId(), 450 Time: t, 451 ModelUUID: modelUUID, 452 Entity: entity.String(), 453 Module: module, 454 Location: location, 455 Level: level, 456 Message: msg, 457 } 458 } 459 460 func SpaceDoc(s *Space) spaceDoc { 461 return s.doc 462 } 463 464 func ForceDestroyMachineOps(m *Machine) ([]txn.Op, error) { 465 return m.forceDestroyOps() 466 } 467 468 func IsManagerMachineError(err error) bool { 469 return errors.Cause(err) == managerMachineError 470 } 471 472 var ActionNotificationIdToActionId = actionNotificationIdToActionId 473 474 func UpdateModelUserLastConnection(e *ModelUser, when time.Time) error { 475 return e.updateLastConnection(when) 476 } 477 478 func RemoveEndpointBindingsForService(c *gc.C, service *Service) { 479 globalKey := service.globalKey() 480 removeOp := removeEndpointBindingsOp(globalKey) 481 482 txnError := service.st.runTransaction([]txn.Op{removeOp}) 483 err := onAbort(txnError, nil) // ignore ErrAborted as it asserts DocExists 484 c.Assert(err, jc.ErrorIsNil) 485 } 486 487 func RelationCount(service *Service) int { 488 return service.doc.RelationCount 489 } 490 491 func AssertEndpointBindingsNotFoundForService(c *gc.C, service *Service) { 492 globalKey := service.globalKey() 493 storedBindings, _, err := readEndpointBindings(service.st, globalKey) 494 c.Assert(storedBindings, gc.IsNil) 495 c.Assert(err, gc.ErrorMatches, fmt.Sprintf("endpoint bindings for %q not found", globalKey)) 496 c.Assert(err, jc.Satisfies, errors.IsNotFound) 497 } 498 499 func LeadershipLeases(st *State) map[string]lease.Info { 500 return st.leadershipClient.Leases() 501 }