func (s *modelInfoSuite) TestModelInfo(c *gc.C) { s.st.model.users[1].SetErrors( nil, state.NeverConnectedError("never connected"), ) info := s.getModelInfo(c) c.Assert(info, jc.DeepEquals, params.ModelInfo{ Name: "testenv", UUID: s.st.model.cfg.UUID(), ControllerUUID: coretesting.ModelTag.Id(), OwnerTag: "user-bob@local", ProviderType: "someprovider", DefaultSeries: series.LatestLts(), Life: params.Dying, Status: params.EntityStatus{ Status: status.StatusDestroying, Since: &time.Time{}, }, Users: []params.ModelUserInfo{{ UserName: "******", LastConnection: &time.Time{}, Access: params.ModelWriteAccess, }, { UserName: "******", DisplayName: "Bob", LastConnection: nil, // never connected Access: params.ModelReadAccess, }, { UserName: "******", DisplayName: "Charlotte", LastConnection: &time.Time{}, Access: params.ModelReadAccess, }}, }) s.st.CheckCalls(c, []gitjujutesting.StubCall{ {"IsControllerAdministrator", []interface{}{names.NewUserTag("admin@local")}}, {"ModelUUID", nil}, {"ForModel", []interface{}{names.NewModelTag(s.st.model.cfg.UUID())}}, {"Model", nil}, {"Close", nil}, }) s.st.model.CheckCalls(c, []gitjujutesting.StubCall{ {"Config", nil}, {"Users", nil}, {"Status", nil}, {"Owner", nil}, {"Life", nil}, }) }
// LastLogin implements loginEntity.LastLogin. func (u *modelUserEntity) LastLogin() (time.Time, error) { // The last connection for the model takes precedence over // the local user last login time. var err error var t time.Time if !permission.IsEmptyUserAccess(u.modelUser) { t, err = u.st.LastModelConnection(u.modelUser.UserTag) } else { err = state.NeverConnectedError("controller user") } if state.IsNeverConnectedError(err) || permission.IsEmptyUserAccess(u.modelUser) { if u.user != nil { // There's a global user, so use that login time instead. return u.user.LastLogin() } // Since we're implementing LastLogin, we need // to implement LastLogin error semantics too. err = state.NeverLoggedInError(err.Error()) } return t, errors.Trace(err) }