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  }