github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/overlord/devicestate/devicestate_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016-2019 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package devicestate_test 21 22 import ( 23 "errors" 24 "fmt" 25 "os" 26 "testing" 27 "time" 28 29 . "gopkg.in/check.v1" 30 "gopkg.in/tomb.v2" 31 32 "github.com/snapcore/snapd/asserts" 33 "github.com/snapcore/snapd/asserts/assertstest" 34 "github.com/snapcore/snapd/asserts/sysdb" 35 "github.com/snapcore/snapd/boot" 36 "github.com/snapcore/snapd/bootloader" 37 "github.com/snapcore/snapd/bootloader/bootloadertest" 38 "github.com/snapcore/snapd/dirs" 39 "github.com/snapcore/snapd/interfaces" 40 "github.com/snapcore/snapd/interfaces/builtin" 41 "github.com/snapcore/snapd/overlord" 42 "github.com/snapcore/snapd/overlord/assertstate" 43 "github.com/snapcore/snapd/overlord/assertstate/assertstatetest" 44 "github.com/snapcore/snapd/overlord/auth" 45 "github.com/snapcore/snapd/overlord/configstate/config" 46 "github.com/snapcore/snapd/overlord/devicestate" 47 "github.com/snapcore/snapd/overlord/devicestate/devicestatetest" 48 "github.com/snapcore/snapd/overlord/hookstate" 49 "github.com/snapcore/snapd/overlord/ifacestate/ifacerepo" 50 "github.com/snapcore/snapd/overlord/snapstate" 51 "github.com/snapcore/snapd/overlord/snapstate/snapstatetest" 52 "github.com/snapcore/snapd/overlord/state" 53 "github.com/snapcore/snapd/overlord/storecontext" 54 "github.com/snapcore/snapd/release" 55 "github.com/snapcore/snapd/snap" 56 "github.com/snapcore/snapd/snap/snaptest" 57 "github.com/snapcore/snapd/snapdenv" 58 "github.com/snapcore/snapd/store/storetest" 59 "github.com/snapcore/snapd/sysconfig" 60 "github.com/snapcore/snapd/testutil" 61 "github.com/snapcore/snapd/timings" 62 ) 63 64 var ( 65 settleTimeout = testutil.HostScaledTimeout(15 * time.Second) 66 ) 67 68 func TestDeviceManager(t *testing.T) { TestingT(t) } 69 70 type deviceMgrBaseSuite struct { 71 testutil.BaseTest 72 73 o *overlord.Overlord 74 state *state.State 75 se *overlord.StateEngine 76 hookMgr *hookstate.HookManager 77 mgr *devicestate.DeviceManager 78 db *asserts.Database 79 80 bootloader *bootloadertest.MockBootloader 81 82 storeSigning *assertstest.StoreStack 83 brands *assertstest.SigningAccounts 84 85 ancillary []asserts.Assertion 86 87 restartRequests []state.RestartType 88 89 newFakeStore func(storecontext.DeviceBackend) snapstate.StoreService 90 91 // saved so that if a derived suite wants to undo the cloud-init mocking to 92 // test the actual functions, it can just call this in it's SetUpTest, see 93 // devicestate_cloudinit_test.go for details 94 restoreCloudInitStatusRestore func() 95 } 96 97 type deviceMgrSuite struct { 98 deviceMgrBaseSuite 99 } 100 101 var _ = Suite(&deviceMgrSuite{}) 102 103 type fakeStore struct { 104 storetest.Store 105 106 state *state.State 107 db asserts.RODatabase 108 } 109 110 func (sto *fakeStore) pokeStateLock() { 111 // the store should be called without the state lock held. Try 112 // to acquire it. 113 sto.state.Lock() 114 sto.state.Unlock() 115 } 116 117 func (sto *fakeStore) Assertion(assertType *asserts.AssertionType, key []string, _ *auth.UserState) (asserts.Assertion, error) { 118 sto.pokeStateLock() 119 ref := &asserts.Ref{Type: assertType, PrimaryKey: key} 120 return ref.Resolve(sto.db.Find) 121 } 122 123 var ( 124 brandPrivKey, _ = assertstest.GenerateKey(752) 125 brandPrivKey2, _ = assertstest.GenerateKey(752) 126 brandPrivKey3, _ = assertstest.GenerateKey(752) 127 ) 128 129 func (s *deviceMgrBaseSuite) SetUpTest(c *C) { 130 s.BaseTest.SetUpTest(c) 131 132 dirs.SetRootDir(c.MkDir()) 133 s.AddCleanup(func() { dirs.SetRootDir("") }) 134 os.MkdirAll(dirs.SnapRunDir, 0755) 135 136 s.restartRequests = nil 137 138 s.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {})) 139 140 s.bootloader = bootloadertest.Mock("mock", c.MkDir()) 141 bootloader.Force(s.bootloader) 142 s.AddCleanup(func() { bootloader.Force(nil) }) 143 144 s.AddCleanup(release.MockOnClassic(false)) 145 146 s.storeSigning = assertstest.NewStoreStack("canonical", nil) 147 s.o = overlord.MockWithStateAndRestartHandler(nil, func(req state.RestartType) { 148 s.restartRequests = append(s.restartRequests, req) 149 }) 150 s.state = s.o.State() 151 s.state.Lock() 152 s.state.VerifyReboot("boot-id-0") 153 s.state.Unlock() 154 s.se = s.o.StateEngine() 155 156 s.AddCleanup(sysdb.MockGenericClassicModel(s.storeSigning.GenericClassicModel)) 157 158 s.brands = assertstest.NewSigningAccounts(s.storeSigning) 159 s.brands.Register("my-brand", brandPrivKey, map[string]interface{}{ 160 "display-name": "fancy model publisher", 161 "validation": "certified", 162 }) 163 s.brands.Register("rereg-brand", brandPrivKey2, nil) 164 165 db, err := asserts.OpenDatabase(&asserts.DatabaseConfig{ 166 Backstore: asserts.NewMemoryBackstore(), 167 Trusted: s.storeSigning.Trusted, 168 OtherPredefined: s.storeSigning.Generic, 169 }) 170 c.Assert(err, IsNil) 171 172 s.state.Lock() 173 assertstate.ReplaceDB(s.state, db) 174 s.state.Unlock() 175 s.AddCleanup(func() { 176 s.state.Lock() 177 assertstate.ReplaceDB(s.state, nil) 178 s.state.Unlock() 179 }) 180 181 err = db.Add(s.storeSigning.StoreAccountKey("")) 182 c.Assert(err, IsNil) 183 184 hookMgr, err := hookstate.Manager(s.state, s.o.TaskRunner()) 185 c.Assert(err, IsNil) 186 mgr, err := devicestate.Manager(s.state, hookMgr, s.o.TaskRunner(), s.newStore) 187 c.Assert(err, IsNil) 188 189 s.db = db 190 s.hookMgr = hookMgr 191 s.o.AddManager(s.hookMgr) 192 s.mgr = mgr 193 s.o.AddManager(s.mgr) 194 s.o.AddManager(s.o.TaskRunner()) 195 196 // For triggering errors 197 erroringHandler := func(task *state.Task, _ *tomb.Tomb) error { 198 return errors.New("error out") 199 } 200 s.o.TaskRunner().AddHandler("error-trigger", erroringHandler, nil) 201 202 c.Assert(s.o.StartUp(), IsNil) 203 204 s.state.Lock() 205 snapstate.ReplaceStore(s.state, &fakeStore{ 206 state: s.state, 207 db: s.storeSigning, 208 }) 209 s.state.Unlock() 210 211 s.restoreCloudInitStatusRestore = devicestate.MockCloudInitStatus(func() (sysconfig.CloudInitState, error) { 212 return sysconfig.CloudInitRestrictedBySnapd, nil 213 }) 214 s.AddCleanup(s.restoreCloudInitStatusRestore) 215 216 s.AddCleanup(func() { s.ancillary = nil }) 217 } 218 219 func (s *deviceMgrBaseSuite) newStore(devBE storecontext.DeviceBackend) snapstate.StoreService { 220 return s.newFakeStore(devBE) 221 } 222 223 func (s *deviceMgrBaseSuite) settle(c *C) { 224 err := s.o.Settle(settleTimeout) 225 c.Assert(err, IsNil) 226 } 227 228 // seeding avoids triggering a real full seeding, it simulates having it in process instead 229 func (s *deviceMgrBaseSuite) seeding() { 230 chg := s.state.NewChange("seed", "Seed system") 231 chg.SetStatus(state.DoingStatus) 232 } 233 234 func (s *deviceMgrSuite) TestDeviceManagerSetTimeOnce(c *C) { 235 s.state.Lock() 236 defer s.state.Unlock() 237 238 // set first time 239 now := time.Now() 240 err := devicestate.SetTimeOnce(s.mgr, "key-name", now) 241 c.Assert(err, IsNil) 242 243 later := now.Add(1 * time.Minute) 244 // setting again doesn't change value 245 err = devicestate.SetTimeOnce(s.mgr, "key-name", later) 246 c.Assert(err, IsNil) 247 248 var t time.Time 249 s.state.Get("key-name", &t) 250 251 c.Assert(t.Equal(now), Equals, true) 252 } 253 254 func (s *deviceMgrSuite) TestDeviceManagerEnsureSeededAlreadySeeded(c *C) { 255 s.state.Lock() 256 s.state.Set("seeded", true) 257 s.state.Unlock() 258 259 called := false 260 restore := devicestate.MockPopulateStateFromSeed(func(*state.State, *devicestate.PopulateStateFromSeedOptions, timings.Measurer) ([]*state.TaskSet, error) { 261 called = true 262 return nil, nil 263 }) 264 defer restore() 265 266 err := devicestate.EnsureSeeded(s.mgr) 267 c.Assert(err, IsNil) 268 c.Assert(called, Equals, false) 269 } 270 271 func (s *deviceMgrSuite) TestDeviceManagerEnsureSeededChangeInFlight(c *C) { 272 s.state.Lock() 273 chg := s.state.NewChange("seed", "just for testing") 274 chg.AddTask(s.state.NewTask("test-task", "the change needs a task")) 275 s.state.Unlock() 276 277 called := false 278 restore := devicestate.MockPopulateStateFromSeed(func(*state.State, *devicestate.PopulateStateFromSeedOptions, timings.Measurer) ([]*state.TaskSet, error) { 279 called = true 280 return nil, nil 281 }) 282 defer restore() 283 284 err := devicestate.EnsureSeeded(s.mgr) 285 c.Assert(err, IsNil) 286 c.Assert(called, Equals, false) 287 } 288 289 func (s *deviceMgrSuite) TestDeviceManagerEnsureSeededAlsoOnClassic(c *C) { 290 release.OnClassic = true 291 292 called := false 293 restore := devicestate.MockPopulateStateFromSeed(func(st *state.State, opts *devicestate.PopulateStateFromSeedOptions, tm timings.Measurer) ([]*state.TaskSet, error) { 294 called = true 295 c.Check(opts, IsNil) 296 return nil, nil 297 }) 298 defer restore() 299 300 err := devicestate.EnsureSeeded(s.mgr) 301 c.Assert(err, IsNil) 302 c.Assert(called, Equals, true) 303 } 304 305 func (s *deviceMgrSuite) TestDeviceManagerEnsureSeededHappy(c *C) { 306 restore := devicestate.MockPopulateStateFromSeed(func(st *state.State, opts *devicestate.PopulateStateFromSeedOptions, tm timings.Measurer) (ts []*state.TaskSet, err error) { 307 c.Assert(opts, IsNil) 308 t := s.state.NewTask("test-task", "a random task") 309 ts = append(ts, state.NewTaskSet(t)) 310 return ts, nil 311 }) 312 defer restore() 313 314 err := devicestate.EnsureSeeded(s.mgr) 315 c.Assert(err, IsNil) 316 317 s.state.Lock() 318 defer s.state.Unlock() 319 320 c.Check(s.state.Changes(), HasLen, 1) 321 322 var seedStartTime time.Time 323 c.Assert(s.state.Get("seed-start-time", &seedStartTime), IsNil) 324 c.Check(seedStartTime.Equal(devicestate.StartTime()), Equals, true) 325 } 326 327 func (s *deviceMgrSuite) TestDeviceManagerEnsureBootOkSkippedOnClassic(c *C) { 328 s.bootloader.GetErr = fmt.Errorf("should not be called") 329 release.OnClassic = true 330 331 err := devicestate.EnsureBootOk(s.mgr) 332 c.Assert(err, IsNil) 333 } 334 335 func (s *deviceMgrSuite) TestDeviceManagerEnsureBootOkSkippedOnNonRunModes(c *C) { 336 s.bootloader.GetErr = fmt.Errorf("should not be called") 337 devicestate.SetSystemMode(s.mgr, "install") 338 339 err := devicestate.EnsureBootOk(s.mgr) 340 c.Assert(err, IsNil) 341 } 342 343 func (s *deviceMgrSuite) TestDeviceManagerEnsureSeededHappyWithModeenv(c *C) { 344 n := 0 345 restore := devicestate.MockPopulateStateFromSeed(func(st *state.State, opts *devicestate.PopulateStateFromSeedOptions, tm timings.Measurer) (ts []*state.TaskSet, err error) { 346 c.Assert(opts, NotNil) 347 c.Check(opts.Label, Equals, "20191127") 348 c.Check(opts.Mode, Equals, "install") 349 350 t := s.state.NewTask("test-task", "a random task") 351 ts = append(ts, state.NewTaskSet(t)) 352 353 n++ 354 return ts, nil 355 }) 356 defer restore() 357 358 // mock the modeenv file 359 m := boot.Modeenv{ 360 Mode: "install", 361 RecoverySystem: "20191127", 362 } 363 err := m.WriteTo("") 364 c.Assert(err, IsNil) 365 366 // re-create manager so that modeenv file is-read 367 s.mgr, err = devicestate.Manager(s.state, s.hookMgr, s.o.TaskRunner(), s.newStore) 368 c.Assert(err, IsNil) 369 370 err = devicestate.EnsureSeeded(s.mgr) 371 c.Assert(err, IsNil) 372 373 s.state.Lock() 374 defer s.state.Unlock() 375 376 c.Check(s.state.Changes(), HasLen, 1) 377 c.Check(n, Equals, 1) 378 } 379 380 func (s *deviceMgrBaseSuite) makeModelAssertionInState(c *C, brandID, model string, extras map[string]interface{}) *asserts.Model { 381 modelAs := s.brands.Model(brandID, model, extras) 382 383 s.setupBrands(c) 384 assertstatetest.AddMany(s.state, modelAs) 385 return modelAs 386 } 387 388 func (s *deviceMgrBaseSuite) setPCModelInState(c *C) { 389 s.state.Lock() 390 defer s.state.Unlock() 391 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 392 "architecture": "amd64", 393 "kernel": "pc-kernel", 394 "gadget": "pc", 395 }) 396 397 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 398 Brand: "canonical", 399 Model: "pc", 400 Serial: "serialserialserial", 401 }) 402 } 403 404 func (s *deviceMgrSuite) TestDeviceManagerEnsureBootOkBootloaderHappy(c *C) { 405 s.setPCModelInState(c) 406 407 s.bootloader.SetBootVars(map[string]string{ 408 "snap_mode": boot.TryingStatus, 409 "snap_try_core": "core_1.snap", 410 }) 411 412 s.state.Lock() 413 defer s.state.Unlock() 414 siCore1 := &snap.SideInfo{RealName: "core", Revision: snap.R(1)} 415 snapstate.Set(s.state, "core", &snapstate.SnapState{ 416 SnapType: "os", 417 Active: true, 418 Sequence: []*snap.SideInfo{siCore1}, 419 Current: siCore1.Revision, 420 }) 421 422 s.state.Unlock() 423 err := devicestate.EnsureBootOk(s.mgr) 424 s.state.Lock() 425 c.Assert(err, IsNil) 426 427 m, err := s.bootloader.GetBootVars("snap_mode") 428 c.Assert(err, IsNil) 429 c.Assert(m, DeepEquals, map[string]string{"snap_mode": ""}) 430 } 431 432 func (s *deviceMgrSuite) TestDeviceManagerEnsureBootOkUpdateBootRevisionsHappy(c *C) { 433 s.setPCModelInState(c) 434 435 // simulate that we have a new core_2, tried to boot it but that failed 436 s.bootloader.SetBootVars(map[string]string{ 437 "snap_mode": "", 438 "snap_kernel": "kernel_1.snap", 439 "snap_try_core": "core_2.snap", 440 "snap_core": "core_1.snap", 441 }) 442 443 s.state.Lock() 444 defer s.state.Unlock() 445 siKernel1 := &snap.SideInfo{RealName: "kernel", Revision: snap.R(1)} 446 snapstate.Set(s.state, "kernel", &snapstate.SnapState{ 447 SnapType: "kernel", 448 Active: true, 449 Sequence: []*snap.SideInfo{siKernel1}, 450 Current: siKernel1.Revision, 451 }) 452 453 siCore1 := &snap.SideInfo{RealName: "core", Revision: snap.R(1)} 454 siCore2 := &snap.SideInfo{RealName: "core", Revision: snap.R(2)} 455 snapstate.Set(s.state, "core", &snapstate.SnapState{ 456 SnapType: "os", 457 Active: true, 458 Sequence: []*snap.SideInfo{siCore1, siCore2}, 459 Current: siCore2.Revision, 460 }) 461 462 s.state.Unlock() 463 err := devicestate.EnsureBootOk(s.mgr) 464 s.state.Lock() 465 c.Assert(err, IsNil) 466 467 c.Check(s.state.Changes(), HasLen, 1) 468 c.Check(s.state.Changes()[0].Kind(), Equals, "update-revisions") 469 } 470 471 func (s *deviceMgrSuite) TestDeviceManagerEnsureBootOkNotRunAgain(c *C) { 472 s.setPCModelInState(c) 473 474 s.bootloader.SetBootVars(map[string]string{ 475 "snap_mode": boot.TryingStatus, 476 "snap_try_core": "core_1.snap", 477 }) 478 s.bootloader.SetErr = fmt.Errorf("ensure bootloader is not used") 479 480 devicestate.SetBootOkRan(s.mgr, true) 481 482 err := devicestate.EnsureBootOk(s.mgr) 483 c.Assert(err, IsNil) 484 } 485 486 func (s *deviceMgrSuite) TestDeviceManagerEnsureBootOkError(c *C) { 487 s.setPCModelInState(c) 488 489 s.state.Lock() 490 // seeded 491 s.state.Set("seeded", true) 492 // has serial 493 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 494 Brand: "canonical", 495 Model: "pc", 496 Serial: "8989", 497 }) 498 s.state.Unlock() 499 500 s.bootloader.GetErr = fmt.Errorf("bootloader err") 501 502 devicestate.SetBootOkRan(s.mgr, false) 503 504 err := s.mgr.Ensure() 505 c.Assert(err, ErrorMatches, "devicemgr: cannot mark boot successful: bootloader err") 506 } 507 508 func (s *deviceMgrBaseSuite) setupBrands(c *C) { 509 assertstatetest.AddMany(s.state, s.brands.AccountsAndKeys("my-brand")...) 510 otherAcct := assertstest.NewAccount(s.storeSigning, "other-brand", map[string]interface{}{ 511 "account-id": "other-brand", 512 }, "") 513 assertstatetest.AddMany(s.state, otherAcct) 514 } 515 516 func (s *deviceMgrSuite) setupSnapDecl(c *C, info *snap.Info, publisherID string) { 517 snapDecl, err := s.storeSigning.Sign(asserts.SnapDeclarationType, map[string]interface{}{ 518 "series": "16", 519 "snap-name": info.SnapName(), 520 "snap-id": info.SnapID, 521 "publisher-id": publisherID, 522 "timestamp": time.Now().UTC().Format(time.RFC3339), 523 }, nil, "") 524 c.Assert(err, IsNil) 525 assertstatetest.AddMany(s.state, snapDecl) 526 } 527 528 func fakeMyModel(extra map[string]interface{}) *asserts.Model { 529 model := map[string]interface{}{ 530 "type": "model", 531 "authority-id": "my-brand", 532 "series": "16", 533 "brand-id": "my-brand", 534 "model": "my-model", 535 } 536 return assertstest.FakeAssertion(model, extra).(*asserts.Model) 537 } 538 539 func (s *deviceMgrSuite) TestCheckGadget(c *C) { 540 s.state.Lock() 541 defer s.state.Unlock() 542 543 gadgetInfo := snaptest.MockInfo(c, "{type: gadget, name: other-gadget, version: 0}", nil) 544 545 s.setupBrands(c) 546 // model assertion in device context 547 model := fakeMyModel(map[string]interface{}{ 548 "architecture": "amd64", 549 "gadget": "gadget", 550 "kernel": "krnl", 551 }) 552 deviceCtx := &snapstatetest.TrivialDeviceContext{DeviceModel: model} 553 554 err := devicestate.CheckGadgetOrKernel(s.state, gadgetInfo, nil, nil, snapstate.Flags{}, deviceCtx) 555 c.Check(err, ErrorMatches, `cannot install gadget "other-gadget", model assertion requests "gadget"`) 556 557 // brand gadget 558 brandGadgetInfo := snaptest.MockInfo(c, "{type: gadget, name: gadget, version: 0}", nil) 559 brandGadgetInfo.SnapID = "brand-gadget-id" 560 s.setupSnapDecl(c, brandGadgetInfo, "my-brand") 561 562 // canonical gadget 563 canonicalGadgetInfo := snaptest.MockInfo(c, "{type: gadget, name: gadget, version: 0}", nil) 564 canonicalGadgetInfo.SnapID = "canonical-gadget-id" 565 s.setupSnapDecl(c, canonicalGadgetInfo, "canonical") 566 567 // other gadget 568 otherGadgetInfo := snaptest.MockInfo(c, "{type: gadget, name: gadget, version: 0}", nil) 569 otherGadgetInfo.SnapID = "other-gadget-id" 570 s.setupSnapDecl(c, otherGadgetInfo, "other-brand") 571 572 // install brand gadget ok 573 err = devicestate.CheckGadgetOrKernel(s.state, brandGadgetInfo, nil, nil, snapstate.Flags{}, deviceCtx) 574 c.Check(err, IsNil) 575 576 // install canonical gadget ok 577 err = devicestate.CheckGadgetOrKernel(s.state, canonicalGadgetInfo, nil, nil, snapstate.Flags{}, deviceCtx) 578 c.Check(err, IsNil) 579 580 // install other gadget fails 581 err = devicestate.CheckGadgetOrKernel(s.state, otherGadgetInfo, nil, nil, snapstate.Flags{}, deviceCtx) 582 c.Check(err, ErrorMatches, `cannot install gadget "gadget" published by "other-brand" for model by "my-brand"`) 583 584 // unasserted installation of other works 585 otherGadgetInfo.SnapID = "" 586 err = devicestate.CheckGadgetOrKernel(s.state, otherGadgetInfo, nil, nil, snapstate.Flags{}, deviceCtx) 587 c.Check(err, IsNil) 588 589 // parallel install fails 590 otherGadgetInfo.InstanceKey = "foo" 591 err = devicestate.CheckGadgetOrKernel(s.state, otherGadgetInfo, nil, nil, snapstate.Flags{}, deviceCtx) 592 c.Check(err, ErrorMatches, `cannot install "gadget_foo", parallel installation of kernel or gadget snaps is not supported`) 593 } 594 595 func (s *deviceMgrSuite) TestCheckGadgetOnClassic(c *C) { 596 release.OnClassic = true 597 598 s.state.Lock() 599 defer s.state.Unlock() 600 601 gadgetInfo := snaptest.MockInfo(c, "{type: gadget, name: other-gadget, version: 0}", nil) 602 603 s.setupBrands(c) 604 // model assertion in device context 605 model := fakeMyModel(map[string]interface{}{ 606 "classic": "true", 607 "gadget": "gadget", 608 }) 609 deviceCtx := &snapstatetest.TrivialDeviceContext{DeviceModel: model} 610 611 err := devicestate.CheckGadgetOrKernel(s.state, gadgetInfo, nil, nil, snapstate.Flags{}, deviceCtx) 612 c.Check(err, ErrorMatches, `cannot install gadget "other-gadget", model assertion requests "gadget"`) 613 614 // brand gadget 615 brandGadgetInfo := snaptest.MockInfo(c, "{type: gadget, name: gadget, version: 0}", nil) 616 brandGadgetInfo.SnapID = "brand-gadget-id" 617 s.setupSnapDecl(c, brandGadgetInfo, "my-brand") 618 619 // canonical gadget 620 canonicalGadgetInfo := snaptest.MockInfo(c, "{type: gadget, name: gadget, version: 0}", nil) 621 canonicalGadgetInfo.SnapID = "canonical-gadget-id" 622 s.setupSnapDecl(c, canonicalGadgetInfo, "canonical") 623 624 // other gadget 625 otherGadgetInfo := snaptest.MockInfo(c, "{type: gadget, name: gadget, version: 0}", nil) 626 otherGadgetInfo.SnapID = "other-gadget-id" 627 s.setupSnapDecl(c, otherGadgetInfo, "other-brand") 628 629 // install brand gadget ok 630 err = devicestate.CheckGadgetOrKernel(s.state, brandGadgetInfo, nil, nil, snapstate.Flags{}, deviceCtx) 631 c.Check(err, IsNil) 632 633 // install canonical gadget ok 634 err = devicestate.CheckGadgetOrKernel(s.state, canonicalGadgetInfo, nil, nil, snapstate.Flags{}, deviceCtx) 635 c.Check(err, IsNil) 636 637 // install other gadget fails 638 err = devicestate.CheckGadgetOrKernel(s.state, otherGadgetInfo, nil, nil, snapstate.Flags{}, deviceCtx) 639 c.Check(err, ErrorMatches, `cannot install gadget "gadget" published by "other-brand" for model by "my-brand"`) 640 641 // unasserted installation of other works 642 otherGadgetInfo.SnapID = "" 643 err = devicestate.CheckGadgetOrKernel(s.state, otherGadgetInfo, nil, nil, snapstate.Flags{}, deviceCtx) 644 c.Check(err, IsNil) 645 } 646 647 func (s *deviceMgrSuite) TestCheckGadgetOnClassicGadgetNotSpecified(c *C) { 648 release.OnClassic = true 649 650 s.state.Lock() 651 defer s.state.Unlock() 652 653 gadgetInfo := snaptest.MockInfo(c, "{type: gadget, name: gadget, version: 0}", nil) 654 655 s.setupBrands(c) 656 // model assertion in device context 657 model := fakeMyModel(map[string]interface{}{ 658 "classic": "true", 659 }) 660 deviceCtx := &snapstatetest.TrivialDeviceContext{DeviceModel: model} 661 662 err := devicestate.CheckGadgetOrKernel(s.state, gadgetInfo, nil, nil, snapstate.Flags{}, deviceCtx) 663 c.Check(err, ErrorMatches, `cannot install gadget snap on classic if not requested by the model`) 664 } 665 666 func (s *deviceMgrSuite) TestCheckGadgetValid(c *C) { 667 s.state.Lock() 668 defer s.state.Unlock() 669 670 // model assertion in device context 671 model := fakeMyModel(map[string]interface{}{ 672 "architecture": "amd64", 673 "gadget": "gadget", 674 "kernel": "krnl", 675 }) 676 deviceCtx := &snapstatetest.TrivialDeviceContext{DeviceModel: model} 677 678 gadgetInfo := snaptest.MockInfo(c, "{type: gadget, name: gadget, version: 0}", nil) 679 680 // valid gadget.yaml 681 cont := snaptest.MockContainer(c, [][]string{ 682 {"meta/gadget.yaml", gadgetYaml}, 683 }) 684 err := devicestate.CheckGadgetValid(s.state, gadgetInfo, nil, cont, snapstate.Flags{}, deviceCtx) 685 c.Check(err, IsNil) 686 687 // invalid gadget.yaml 688 cont = snaptest.MockContainer(c, [][]string{ 689 {"meta/gadget.yaml", `defaults:`}, 690 }) 691 err = devicestate.CheckGadgetValid(s.state, gadgetInfo, nil, cont, snapstate.Flags{}, deviceCtx) 692 c.Check(err, ErrorMatches, `bootloader not declared in any volume`) 693 694 } 695 696 func (s *deviceMgrSuite) TestCheckKernel(c *C) { 697 s.state.Lock() 698 defer s.state.Unlock() 699 kernelInfo := snaptest.MockInfo(c, "{type: kernel, name: lnrk, version: 0}", nil) 700 701 // not on classic 702 release.OnClassic = true 703 err := devicestate.CheckGadgetOrKernel(s.state, kernelInfo, nil, nil, snapstate.Flags{}, nil) 704 c.Check(err, ErrorMatches, `cannot install a kernel snap on classic`) 705 release.OnClassic = false 706 707 s.setupBrands(c) 708 // model assertion in device context 709 model := fakeMyModel(map[string]interface{}{ 710 "architecture": "amd64", 711 "gadget": "gadget", 712 "kernel": "krnl", 713 }) 714 deviceCtx := &snapstatetest.TrivialDeviceContext{DeviceModel: model} 715 716 err = devicestate.CheckGadgetOrKernel(s.state, kernelInfo, nil, nil, snapstate.Flags{}, deviceCtx) 717 c.Check(err, ErrorMatches, `cannot install kernel "lnrk", model assertion requests "krnl"`) 718 719 // brand kernel 720 brandKrnlInfo := snaptest.MockInfo(c, "{type: kernel, name: krnl, version: 0}", nil) 721 brandKrnlInfo.SnapID = "brand-krnl-id" 722 s.setupSnapDecl(c, brandKrnlInfo, "my-brand") 723 724 // canonical kernel 725 canonicalKrnlInfo := snaptest.MockInfo(c, "{type: kernel, name: krnl, version: 0}", nil) 726 canonicalKrnlInfo.SnapID = "canonical-krnl-id" 727 s.setupSnapDecl(c, canonicalKrnlInfo, "canonical") 728 729 // other kernel 730 otherKrnlInfo := snaptest.MockInfo(c, "{type: kernel, name: krnl, version: 0}", nil) 731 otherKrnlInfo.SnapID = "other-krnl-id" 732 s.setupSnapDecl(c, otherKrnlInfo, "other-brand") 733 734 // install brand kernel ok 735 err = devicestate.CheckGadgetOrKernel(s.state, brandKrnlInfo, nil, nil, snapstate.Flags{}, deviceCtx) 736 c.Check(err, IsNil) 737 738 // install canonical kernel ok 739 err = devicestate.CheckGadgetOrKernel(s.state, canonicalKrnlInfo, nil, nil, snapstate.Flags{}, deviceCtx) 740 c.Check(err, IsNil) 741 742 // install other kernel fails 743 err = devicestate.CheckGadgetOrKernel(s.state, otherKrnlInfo, nil, nil, snapstate.Flags{}, deviceCtx) 744 c.Check(err, ErrorMatches, `cannot install kernel "krnl" published by "other-brand" for model by "my-brand"`) 745 746 // unasserted installation of other works 747 otherKrnlInfo.SnapID = "" 748 err = devicestate.CheckGadgetOrKernel(s.state, otherKrnlInfo, nil, nil, snapstate.Flags{}, deviceCtx) 749 c.Check(err, IsNil) 750 751 // parallel install fails 752 otherKrnlInfo.InstanceKey = "foo" 753 err = devicestate.CheckGadgetOrKernel(s.state, otherKrnlInfo, nil, nil, snapstate.Flags{}, deviceCtx) 754 c.Check(err, ErrorMatches, `cannot install "krnl_foo", parallel installation of kernel or gadget snaps is not supported`) 755 } 756 757 func makeSerialAssertionInState(c *C, brands *assertstest.SigningAccounts, st *state.State, brandID, model, serialN string) *asserts.Serial { 758 encDevKey, err := asserts.EncodePublicKey(devKey.PublicKey()) 759 c.Assert(err, IsNil) 760 serial, err := brands.Signing(brandID).Sign(asserts.SerialType, map[string]interface{}{ 761 "brand-id": brandID, 762 "model": model, 763 "serial": serialN, 764 "device-key": string(encDevKey), 765 "device-key-sha3-384": devKey.PublicKey().ID(), 766 "timestamp": time.Now().Format(time.RFC3339), 767 }, nil, "") 768 c.Assert(err, IsNil) 769 err = assertstate.Add(st, serial) 770 c.Assert(err, IsNil) 771 return serial.(*asserts.Serial) 772 } 773 774 func (s *deviceMgrBaseSuite) makeSerialAssertionInState(c *C, brandID, model, serialN string) *asserts.Serial { 775 return makeSerialAssertionInState(c, s.brands, s.state, brandID, model, serialN) 776 } 777 778 func (s *deviceMgrSuite) TestCanAutoRefreshOnCore(c *C) { 779 s.state.Lock() 780 defer s.state.Unlock() 781 782 canAutoRefresh := func() bool { 783 ok, err := devicestate.CanAutoRefresh(s.state) 784 c.Assert(err, IsNil) 785 return ok 786 } 787 788 // not seeded, no model, no serial -> no auto-refresh 789 s.state.Set("seeded", false) 790 c.Check(canAutoRefresh(), Equals, false) 791 792 // seeded, model, no serial -> no auto-refresh 793 s.state.Set("seeded", true) 794 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 795 Brand: "canonical", 796 Model: "pc", 797 }) 798 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 799 "architecture": "amd64", 800 "kernel": "pc-kernel", 801 "gadget": "pc", 802 }) 803 c.Check(canAutoRefresh(), Equals, false) 804 805 // seeded, model, serial -> auto-refresh 806 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 807 Brand: "canonical", 808 Model: "pc", 809 Serial: "8989", 810 }) 811 s.makeSerialAssertionInState(c, "canonical", "pc", "8989") 812 c.Check(canAutoRefresh(), Equals, true) 813 814 // not seeded, model, serial -> no auto-refresh 815 s.state.Set("seeded", false) 816 c.Check(canAutoRefresh(), Equals, false) 817 } 818 819 func (s *deviceMgrSuite) TestCanAutoRefreshNoSerialFallback(c *C) { 820 s.state.Lock() 821 defer s.state.Unlock() 822 823 canAutoRefresh := func() bool { 824 ok, err := devicestate.CanAutoRefresh(s.state) 825 c.Assert(err, IsNil) 826 return ok 827 } 828 829 // seeded, model, no serial, two attempts at getting serial 830 // -> no auto-refresh 831 devicestate.IncEnsureOperationalAttempts(s.state) 832 devicestate.IncEnsureOperationalAttempts(s.state) 833 s.state.Set("seeded", true) 834 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 835 Brand: "canonical", 836 Model: "pc", 837 }) 838 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 839 "architecture": "amd64", 840 "kernel": "pc-kernel", 841 "gadget": "pc", 842 }) 843 c.Check(canAutoRefresh(), Equals, false) 844 845 // third attempt ongoing, or done 846 // fallback, try auto-refresh 847 devicestate.IncEnsureOperationalAttempts(s.state) 848 // sanity 849 c.Check(devicestate.EnsureOperationalAttempts(s.state), Equals, 3) 850 c.Check(canAutoRefresh(), Equals, true) 851 } 852 853 func (s *deviceMgrSuite) TestCanAutoRefreshOnClassic(c *C) { 854 release.OnClassic = true 855 856 s.state.Lock() 857 defer s.state.Unlock() 858 859 canAutoRefresh := func() bool { 860 ok, err := devicestate.CanAutoRefresh(s.state) 861 c.Assert(err, IsNil) 862 return ok 863 } 864 865 // not seeded, no model, no serial -> no auto-refresh 866 s.state.Set("seeded", false) 867 c.Check(canAutoRefresh(), Equals, false) 868 869 // seeded, no model -> auto-refresh 870 s.state.Set("seeded", true) 871 c.Check(canAutoRefresh(), Equals, false) 872 873 // seeded, model, no serial -> no auto-refresh 874 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 875 Brand: "canonical", 876 Model: "pc", 877 }) 878 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 879 "classic": "true", 880 }) 881 c.Check(canAutoRefresh(), Equals, false) 882 883 // seeded, model, serial -> auto-refresh 884 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 885 Brand: "canonical", 886 Model: "pc", 887 Serial: "8989", 888 }) 889 s.makeSerialAssertionInState(c, "canonical", "pc", "8989") 890 c.Check(canAutoRefresh(), Equals, true) 891 892 // not seeded, model, serial -> no auto-refresh 893 s.state.Set("seeded", false) 894 c.Check(canAutoRefresh(), Equals, false) 895 } 896 897 func makeInstalledMockCoreSnapWithSnapdControl(c *C, st *state.State) *snap.Info { 898 sideInfoCore11 := &snap.SideInfo{RealName: "core", Revision: snap.R(11), SnapID: "core-id"} 899 snapstate.Set(st, "core", &snapstate.SnapState{ 900 Active: true, 901 Sequence: []*snap.SideInfo{sideInfoCore11}, 902 Current: sideInfoCore11.Revision, 903 SnapType: "os", 904 }) 905 core11 := snaptest.MockSnap(c, ` 906 name: core 907 version: 1.0 908 slots: 909 snapd-control: 910 `, sideInfoCore11) 911 c.Assert(core11.Slots, HasLen, 1) 912 913 return core11 914 } 915 916 var snapWithSnapdControlRefreshScheduleManagedYAML = ` 917 name: snap-with-snapd-control 918 version: 1.0 919 plugs: 920 snapd-control: 921 refresh-schedule: managed 922 ` 923 924 var snapWithSnapdControlOnlyYAML = ` 925 name: snap-with-snapd-control 926 version: 1.0 927 plugs: 928 snapd-control: 929 ` 930 931 func makeInstalledMockSnap(c *C, st *state.State, yml string) *snap.Info { 932 sideInfo11 := &snap.SideInfo{RealName: "snap-with-snapd-control", Revision: snap.R(11), SnapID: "snap-with-snapd-control-id"} 933 snapstate.Set(st, "snap-with-snapd-control", &snapstate.SnapState{ 934 Active: true, 935 Sequence: []*snap.SideInfo{sideInfo11}, 936 Current: sideInfo11.Revision, 937 SnapType: "app", 938 }) 939 info11 := snaptest.MockSnap(c, yml, sideInfo11) 940 c.Assert(info11.Plugs, HasLen, 1) 941 942 return info11 943 } 944 945 func makeMockRepoWithConnectedSnaps(c *C, st *state.State, info11, core11 *snap.Info, ifname string) { 946 repo := interfaces.NewRepository() 947 for _, iface := range builtin.Interfaces() { 948 err := repo.AddInterface(iface) 949 c.Assert(err, IsNil) 950 } 951 err := repo.AddSnap(info11) 952 c.Assert(err, IsNil) 953 err = repo.AddSnap(core11) 954 c.Assert(err, IsNil) 955 _, err = repo.Connect(&interfaces.ConnRef{ 956 PlugRef: interfaces.PlugRef{Snap: info11.InstanceName(), Name: ifname}, 957 SlotRef: interfaces.SlotRef{Snap: core11.InstanceName(), Name: ifname}, 958 }, nil, nil, nil, nil, nil) 959 c.Assert(err, IsNil) 960 conns, err := repo.Connected("snap-with-snapd-control", "snapd-control") 961 c.Assert(err, IsNil) 962 c.Assert(conns, HasLen, 1) 963 ifacerepo.Replace(st, repo) 964 } 965 966 func (s *deviceMgrSuite) TestCanManageRefreshes(c *C) { 967 st := s.state 968 st.Lock() 969 defer st.Unlock() 970 971 // not possbile to manage by default 972 c.Check(devicestate.CanManageRefreshes(st), Equals, false) 973 974 // not possible with just a snap with "snapd-control" plug with the 975 // right attribute 976 info11 := makeInstalledMockSnap(c, st, snapWithSnapdControlRefreshScheduleManagedYAML) 977 c.Check(devicestate.CanManageRefreshes(st), Equals, false) 978 979 // not possible with a core snap with snapd control 980 core11 := makeInstalledMockCoreSnapWithSnapdControl(c, st) 981 c.Check(devicestate.CanManageRefreshes(st), Equals, false) 982 983 // not possible even with connected interfaces 984 makeMockRepoWithConnectedSnaps(c, st, info11, core11, "snapd-control") 985 c.Check(devicestate.CanManageRefreshes(st), Equals, false) 986 987 // if all of the above plus a snap declaration are in place we can 988 // manage schedules 989 s.setupSnapDecl(c, info11, "canonical") 990 c.Check(devicestate.CanManageRefreshes(st), Equals, true) 991 992 // works if the snap is not active as well (to fix race when a 993 // snap is refreshed) 994 var sideInfo11 snapstate.SnapState 995 err := snapstate.Get(st, "snap-with-snapd-control", &sideInfo11) 996 c.Assert(err, IsNil) 997 sideInfo11.Active = false 998 snapstate.Set(st, "snap-with-snapd-control", &sideInfo11) 999 c.Check(devicestate.CanManageRefreshes(st), Equals, true) 1000 } 1001 1002 func (s *deviceMgrSuite) TestCanManageRefreshesNoRefreshScheduleManaged(c *C) { 1003 st := s.state 1004 st.Lock() 1005 defer st.Unlock() 1006 1007 // just having a connected "snapd-control" interface is not enough 1008 // for setting refresh.schedule=managed 1009 info11 := makeInstalledMockSnap(c, st, snapWithSnapdControlOnlyYAML) 1010 core11 := makeInstalledMockCoreSnapWithSnapdControl(c, st) 1011 makeMockRepoWithConnectedSnaps(c, st, info11, core11, "snapd-control") 1012 s.setupSnapDecl(c, info11, "canonical") 1013 1014 c.Check(devicestate.CanManageRefreshes(st), Equals, false) 1015 } 1016 1017 func (s *deviceMgrSuite) TestReloadRegistered(c *C) { 1018 st := state.New(nil) 1019 1020 runner1 := state.NewTaskRunner(st) 1021 hookMgr1, err := hookstate.Manager(st, runner1) 1022 c.Assert(err, IsNil) 1023 mgr1, err := devicestate.Manager(st, hookMgr1, runner1, nil) 1024 c.Assert(err, IsNil) 1025 1026 ok := false 1027 select { 1028 case <-mgr1.Registered(): 1029 default: 1030 ok = true 1031 } 1032 c.Check(ok, Equals, true) 1033 1034 st.Lock() 1035 devicestatetest.SetDevice(st, &auth.DeviceState{ 1036 Brand: "canonical", 1037 Model: "pc", 1038 Serial: "serial", 1039 }) 1040 st.Unlock() 1041 1042 runner2 := state.NewTaskRunner(st) 1043 hookMgr2, err := hookstate.Manager(st, runner2) 1044 c.Assert(err, IsNil) 1045 mgr2, err := devicestate.Manager(st, hookMgr2, runner2, nil) 1046 c.Assert(err, IsNil) 1047 1048 ok = false 1049 select { 1050 case <-mgr2.Registered(): 1051 ok = true 1052 case <-time.After(5 * time.Second): 1053 c.Fatal("should have been marked registered") 1054 } 1055 c.Check(ok, Equals, true) 1056 } 1057 1058 func (s *deviceMgrSuite) TestMarkSeededInConfig(c *C) { 1059 st := s.state 1060 st.Lock() 1061 defer st.Unlock() 1062 1063 // avoid device registration 1064 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1065 Serial: "123", 1066 }) 1067 1068 // avoid full seeding 1069 s.seeding() 1070 1071 // not seeded -> no config is set 1072 s.state.Unlock() 1073 s.mgr.Ensure() 1074 s.state.Lock() 1075 1076 var seedLoaded bool 1077 tr := config.NewTransaction(st) 1078 tr.Get("core", "seed.loaded", &seedLoaded) 1079 c.Check(seedLoaded, Equals, false) 1080 1081 // pretend we are seeded now 1082 s.state.Set("seeded", true) 1083 1084 // seeded -> config got updated 1085 s.state.Unlock() 1086 s.mgr.Ensure() 1087 s.state.Lock() 1088 1089 tr = config.NewTransaction(st) 1090 tr.Get("core", "seed.loaded", &seedLoaded) 1091 c.Check(seedLoaded, Equals, true) 1092 1093 // only the fake seeding change is in the state, no further 1094 // changes 1095 c.Check(s.state.Changes(), HasLen, 1) 1096 } 1097 1098 func (s *deviceMgrSuite) TestDevicemgrCanStandby(c *C) { 1099 st := state.New(nil) 1100 1101 runner := state.NewTaskRunner(st) 1102 hookMgr, err := hookstate.Manager(st, runner) 1103 c.Assert(err, IsNil) 1104 mgr, err := devicestate.Manager(st, hookMgr, runner, nil) 1105 c.Assert(err, IsNil) 1106 1107 st.Lock() 1108 defer st.Unlock() 1109 c.Check(mgr.CanStandby(), Equals, false) 1110 1111 st.Set("seeded", true) 1112 c.Check(mgr.CanStandby(), Equals, true) 1113 } 1114 1115 func (s *deviceMgrSuite) TestDeviceManagerReadsModeenv(c *C) { 1116 modeEnv := &boot.Modeenv{Mode: "install"} 1117 err := modeEnv.WriteTo("") 1118 c.Assert(err, IsNil) 1119 1120 runner := s.o.TaskRunner() 1121 mgr, err := devicestate.Manager(s.state, s.hookMgr, runner, s.newStore) 1122 c.Assert(err, IsNil) 1123 c.Assert(mgr, NotNil) 1124 c.Assert(mgr.SystemMode(), Equals, "install") 1125 } 1126 1127 func (s *deviceMgrSuite) TestDeviceManagerEmptySystemModeRun(c *C) { 1128 // set empty system mode 1129 devicestate.SetSystemMode(s.mgr, "") 1130 1131 // empty is returned as "run" 1132 c.Check(s.mgr.SystemMode(), Equals, "run") 1133 } 1134 1135 type startOfOperationTimeSuite struct { 1136 state *state.State 1137 mgr *devicestate.DeviceManager 1138 runner *state.TaskRunner 1139 } 1140 1141 var _ = Suite(&startOfOperationTimeSuite{}) 1142 1143 func (s *startOfOperationTimeSuite) SetUpTest(c *C) { 1144 dirs.SetRootDir(c.MkDir()) 1145 os.MkdirAll(dirs.SnapRunDir, 0755) 1146 1147 s.state = state.New(nil) 1148 s.runner = state.NewTaskRunner(s.state) 1149 s.mgr = nil 1150 } 1151 1152 func (s *startOfOperationTimeSuite) TearDownTest(c *C) { 1153 dirs.SetRootDir("") 1154 } 1155 1156 func (s *startOfOperationTimeSuite) manager(c *C) *devicestate.DeviceManager { 1157 if s.mgr == nil { 1158 hookMgr, err := hookstate.Manager(s.state, s.runner) 1159 c.Assert(err, IsNil) 1160 mgr, err := devicestate.Manager(s.state, hookMgr, s.runner, nil) 1161 c.Assert(err, IsNil) 1162 s.mgr = mgr 1163 } 1164 return s.mgr 1165 } 1166 1167 func (s *startOfOperationTimeSuite) TestStartOfOperationTimeFromSeedTime(c *C) { 1168 mgr := s.manager(c) 1169 1170 st := s.state 1171 st.Lock() 1172 defer st.Unlock() 1173 1174 seedTime := time.Now().AddDate(0, -1, 0) 1175 st.Set("seed-time", seedTime) 1176 1177 operationTime, err := mgr.StartOfOperationTime() 1178 c.Assert(err, IsNil) 1179 c.Check(operationTime.Equal(seedTime), Equals, true) 1180 1181 var op time.Time 1182 st.Get("start-of-operation-time", &op) 1183 c.Check(op.Equal(operationTime), Equals, true) 1184 } 1185 1186 func (s *startOfOperationTimeSuite) TestStartOfOperationTimeAlreadySet(c *C) { 1187 mgr := s.manager(c) 1188 1189 st := s.state 1190 st.Lock() 1191 defer st.Unlock() 1192 1193 op := time.Now().AddDate(0, -1, 0) 1194 st.Set("start-of-operation-time", op) 1195 1196 operationTime, err := mgr.StartOfOperationTime() 1197 c.Assert(err, IsNil) 1198 c.Check(operationTime.Equal(op), Equals, true) 1199 } 1200 1201 func (s *startOfOperationTimeSuite) TestStartOfOperationTimeNoSeedTime(c *C) { 1202 mgr := s.manager(c) 1203 1204 st := s.state 1205 st.Lock() 1206 defer st.Unlock() 1207 1208 now := time.Now().Add(-1 * time.Second) 1209 devicestate.MockTimeNow(func() time.Time { 1210 return now 1211 }) 1212 1213 operationTime, err := mgr.StartOfOperationTime() 1214 c.Assert(err, IsNil) 1215 c.Check(operationTime.Equal(now), Equals, true) 1216 1217 // repeated call returns already set time 1218 prev := now 1219 now = time.Now().Add(-10 * time.Hour) 1220 operationTime, err = s.manager(c).StartOfOperationTime() 1221 c.Assert(err, IsNil) 1222 c.Check(operationTime.Equal(prev), Equals, true) 1223 } 1224 1225 func (s *startOfOperationTimeSuite) TestStartOfOperationErrorIfPreseed(c *C) { 1226 restore := snapdenv.MockPreseeding(true) 1227 defer restore() 1228 1229 mgr := s.manager(c) 1230 st := s.state 1231 1232 st.Lock() 1233 defer st.Unlock() 1234 _, err := mgr.StartOfOperationTime() 1235 c.Assert(err, ErrorMatches, `internal error: unexpected call to StartOfOperationTime in preseed mode`) 1236 }