github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/asserts/pool_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2020 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 asserts_test
    21  
    22  import (
    23  	"errors"
    24  	"sort"
    25  
    26  	. "gopkg.in/check.v1"
    27  
    28  	"github.com/snapcore/snapd/asserts"
    29  	"github.com/snapcore/snapd/asserts/assertstest"
    30  	"github.com/snapcore/snapd/testutil"
    31  )
    32  
    33  type poolSuite struct {
    34  	testutil.BaseTest
    35  
    36  	hub      *assertstest.StoreStack
    37  	dev1Acct *asserts.Account
    38  	dev2Acct *asserts.Account
    39  
    40  	decl1     *asserts.TestOnlyDecl
    41  	decl1_1   *asserts.TestOnlyDecl
    42  	rev1_1111 *asserts.TestOnlyRev
    43  	rev1_3333 *asserts.TestOnlyRev
    44  
    45  	decl2     *asserts.TestOnlyDecl
    46  	rev2_2222 *asserts.TestOnlyRev
    47  
    48  	db *asserts.Database
    49  }
    50  
    51  var _ = Suite(&poolSuite{})
    52  
    53  func (s *poolSuite) SetUpTest(c *C) {
    54  	s.BaseTest.SetUpTest(c)
    55  
    56  	s.hub = assertstest.NewStoreStack("hub", nil)
    57  	s.dev1Acct = assertstest.NewAccount(s.hub, "developer1", map[string]interface{}{
    58  		"account-id": "developer1",
    59  	}, "")
    60  	s.dev2Acct = assertstest.NewAccount(s.hub, "developer2", map[string]interface{}{
    61  		"account-id": "developer2",
    62  	}, "")
    63  
    64  	a, err := s.hub.Sign(asserts.TestOnlyDeclType, map[string]interface{}{
    65  		"id":     "one",
    66  		"dev-id": "developer1",
    67  	}, nil, "")
    68  	c.Assert(err, IsNil)
    69  	s.decl1 = a.(*asserts.TestOnlyDecl)
    70  
    71  	a, err = s.hub.Sign(asserts.TestOnlyDeclType, map[string]interface{}{
    72  		"id":       "one",
    73  		"dev-id":   "developer1",
    74  		"revision": "1",
    75  	}, nil, "")
    76  	c.Assert(err, IsNil)
    77  	s.decl1_1 = a.(*asserts.TestOnlyDecl)
    78  
    79  	a, err = s.hub.Sign(asserts.TestOnlyDeclType, map[string]interface{}{
    80  		"id":     "two",
    81  		"dev-id": "developer2",
    82  	}, nil, "")
    83  	c.Assert(err, IsNil)
    84  	s.decl2 = a.(*asserts.TestOnlyDecl)
    85  
    86  	a, err = s.hub.Sign(asserts.TestOnlyRevType, map[string]interface{}{
    87  		"h":      "1111",
    88  		"id":     "one",
    89  		"dev-id": "developer1",
    90  	}, nil, "")
    91  	c.Assert(err, IsNil)
    92  	s.rev1_1111 = a.(*asserts.TestOnlyRev)
    93  
    94  	a, err = s.hub.Sign(asserts.TestOnlyRevType, map[string]interface{}{
    95  		"h":      "3333",
    96  		"id":     "one",
    97  		"dev-id": "developer1",
    98  	}, nil, "")
    99  	c.Assert(err, IsNil)
   100  	s.rev1_3333 = a.(*asserts.TestOnlyRev)
   101  
   102  	a, err = s.hub.Sign(asserts.TestOnlyRevType, map[string]interface{}{
   103  		"h":      "2222",
   104  		"id":     "two",
   105  		"dev-id": "developer2",
   106  	}, nil, "")
   107  	c.Assert(err, IsNil)
   108  	s.rev2_2222 = a.(*asserts.TestOnlyRev)
   109  
   110  	db, err := asserts.OpenDatabase(&asserts.DatabaseConfig{
   111  		Backstore: asserts.NewMemoryBackstore(),
   112  		Trusted:   s.hub.Trusted,
   113  	})
   114  	c.Assert(err, IsNil)
   115  	s.db = db
   116  }
   117  
   118  func (s *poolSuite) TestAddUnresolved(c *C) {
   119  	pool := asserts.NewPool(s.db, 64)
   120  
   121  	at1 := &asserts.AtRevision{
   122  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   123  		Revision: asserts.RevisionNotKnown,
   124  	}
   125  	err := pool.AddUnresolved(at1, "for_one") // group num: 0
   126  	c.Assert(err, IsNil)
   127  
   128  	toResolve, err := pool.ToResolve()
   129  	c.Assert(err, IsNil)
   130  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   131  		asserts.MakePoolGrouping(0): {at1},
   132  	})
   133  }
   134  
   135  func (s *poolSuite) TestAddUnresolvedPredefined(c *C) {
   136  	pool := asserts.NewPool(s.db, 64)
   137  
   138  	at := s.hub.TrustedAccount.At()
   139  	at.Revision = asserts.RevisionNotKnown
   140  	err := pool.AddUnresolved(at, "for_one")
   141  	c.Assert(err, IsNil)
   142  
   143  	// nothing to resolve
   144  	toResolve, err := pool.ToResolve()
   145  	c.Assert(err, IsNil)
   146  	c.Check(toResolve, HasLen, 0)
   147  }
   148  
   149  func (s *poolSuite) TestAddUnresolvedGrouping(c *C) {
   150  	pool := asserts.NewPool(s.db, 64)
   151  
   152  	storeKeyAt := s.hub.StoreAccountKey("").At()
   153  
   154  	pool.AddUnresolved(storeKeyAt, "for_two") // group num: 0
   155  	pool.AddUnresolved(storeKeyAt, "for_one") // group num: 1
   156  
   157  	toResolve, err := pool.ToResolve()
   158  	c.Assert(err, IsNil)
   159  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   160  		asserts.MakePoolGrouping(0, 1): {storeKeyAt},
   161  	})
   162  }
   163  
   164  func (s *poolSuite) TestAddUnresolvedDup(c *C) {
   165  	pool := asserts.NewPool(s.db, 64)
   166  
   167  	storeKeyAt := s.hub.StoreAccountKey("").At()
   168  
   169  	pool.AddUnresolved(storeKeyAt, "for_one") // group num: 0
   170  	pool.AddUnresolved(storeKeyAt, "for_one") // group num: 0
   171  
   172  	toResolve, err := pool.ToResolve()
   173  	c.Assert(err, IsNil)
   174  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   175  		asserts.MakePoolGrouping(0): {storeKeyAt},
   176  	})
   177  }
   178  
   179  type byAtRevision []*asserts.AtRevision
   180  
   181  func (ats byAtRevision) Len() int {
   182  	return len(ats)
   183  }
   184  
   185  func (ats byAtRevision) Less(i, j int) bool {
   186  	return ats[i].Ref.Unique() < ats[j].Ref.Unique()
   187  }
   188  
   189  func (ats byAtRevision) Swap(i, j int) {
   190  	ats[i], ats[j] = ats[j], ats[i]
   191  }
   192  
   193  func sortToResolve(toResolve map[asserts.Grouping][]*asserts.AtRevision) {
   194  	for _, ats := range toResolve {
   195  		sort.Sort(byAtRevision(ats))
   196  	}
   197  }
   198  
   199  func (s *poolSuite) TestFetch(c *C) {
   200  	pool := asserts.NewPool(s.db, 64)
   201  
   202  	at1111 := &asserts.AtRevision{
   203  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   204  		Revision: asserts.RevisionNotKnown,
   205  	}
   206  	err := pool.AddUnresolved(at1111, "for_one")
   207  	c.Assert(err, IsNil)
   208  
   209  	toResolve, err := pool.ToResolve()
   210  	c.Assert(err, IsNil)
   211  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   212  		asserts.MakePoolGrouping(0): {at1111},
   213  	})
   214  
   215  	err = pool.Add(s.rev1_1111, asserts.MakePoolGrouping(0))
   216  	c.Assert(err, IsNil)
   217  
   218  	toResolve, err = pool.ToResolve()
   219  	c.Assert(err, IsNil)
   220  	sortToResolve(toResolve)
   221  	dev1AcctAt := s.dev1Acct.At()
   222  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   223  	decl1At := s.decl1.At()
   224  	decl1At.Revision = asserts.RevisionNotKnown
   225  	storeKeyAt := s.hub.StoreAccountKey("").At()
   226  	storeKeyAt.Revision = asserts.RevisionNotKnown
   227  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   228  		asserts.MakePoolGrouping(0): {storeKeyAt, dev1AcctAt, decl1At},
   229  	})
   230  
   231  	c.Check(pool.Err("for_one"), IsNil)
   232  }
   233  
   234  func (s *poolSuite) TestCompleteFetch(c *C) {
   235  	pool := asserts.NewPool(s.db, 64)
   236  
   237  	at1111 := &asserts.AtRevision{
   238  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   239  		Revision: asserts.RevisionNotKnown,
   240  	}
   241  	err := pool.AddUnresolved(at1111, "for_one")
   242  	c.Assert(err, IsNil)
   243  
   244  	toResolve, err := pool.ToResolve()
   245  	c.Assert(err, IsNil)
   246  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   247  		asserts.MakePoolGrouping(0): {at1111},
   248  	})
   249  
   250  	err = pool.Add(s.rev1_1111, asserts.MakePoolGrouping(0))
   251  	c.Assert(err, IsNil)
   252  
   253  	toResolve, err = pool.ToResolve()
   254  	c.Assert(err, IsNil)
   255  	sortToResolve(toResolve)
   256  	dev1AcctAt := s.dev1Acct.At()
   257  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   258  	decl1At := s.decl1.At()
   259  	decl1At.Revision = asserts.RevisionNotKnown
   260  	storeKey := s.hub.StoreAccountKey("")
   261  	storeKeyAt := storeKey.At()
   262  	storeKeyAt.Revision = asserts.RevisionNotKnown
   263  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   264  		asserts.MakePoolGrouping(0): {storeKeyAt, dev1AcctAt, decl1At},
   265  	})
   266  
   267  	err = pool.Add(s.decl1, asserts.MakePoolGrouping(0))
   268  	c.Assert(err, IsNil)
   269  
   270  	err = pool.Add(storeKey, asserts.MakePoolGrouping(0))
   271  	c.Assert(err, IsNil)
   272  
   273  	err = pool.Add(s.dev1Acct, asserts.MakePoolGrouping(0))
   274  	c.Assert(err, IsNil)
   275  
   276  	toResolve, err = pool.ToResolve()
   277  	c.Assert(err, IsNil)
   278  	c.Check(toResolve, HasLen, 0)
   279  
   280  	c.Check(pool.Err("for_one"), IsNil)
   281  
   282  	err = pool.CommitTo(s.db)
   283  	c.Check(err, IsNil)
   284  	c.Assert(pool.Err("for_one"), IsNil)
   285  
   286  	a, err := at1111.Ref.Resolve(s.db.Find)
   287  	c.Assert(err, IsNil)
   288  	c.Check(a.(*asserts.TestOnlyRev).H(), Equals, "1111")
   289  }
   290  
   291  func (s *poolSuite) TestPushSuggestionForPrerequisite(c *C) {
   292  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   293  
   294  	pool := asserts.NewPool(s.db, 64)
   295  
   296  	at1111 := &asserts.AtRevision{
   297  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   298  		Revision: asserts.RevisionNotKnown,
   299  	}
   300  	err := pool.AddUnresolved(at1111, "for_one")
   301  	c.Assert(err, IsNil)
   302  
   303  	toResolve, err := pool.ToResolve()
   304  	c.Assert(err, IsNil)
   305  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   306  		asserts.MakePoolGrouping(0): {at1111},
   307  	})
   308  
   309  	err = pool.Add(s.rev1_1111, asserts.MakePoolGrouping(0))
   310  	c.Assert(err, IsNil)
   311  
   312  	// push prerequisite suggestion
   313  	err = pool.Add(s.decl1, asserts.MakePoolGrouping(0))
   314  	c.Assert(err, IsNil)
   315  
   316  	toResolve, err = pool.ToResolve()
   317  	c.Assert(err, IsNil)
   318  	sortToResolve(toResolve)
   319  	dev1AcctAt := s.dev1Acct.At()
   320  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   321  	storeKey := s.hub.StoreAccountKey("")
   322  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   323  		asserts.MakePoolGrouping(0): {storeKey.At(), dev1AcctAt},
   324  	})
   325  
   326  	c.Check(pool.Err("for_one"), IsNil)
   327  
   328  	err = pool.Add(s.dev1Acct, asserts.MakePoolGrouping(0))
   329  	c.Assert(err, IsNil)
   330  
   331  	toResolve, err = pool.ToResolve()
   332  	c.Assert(err, IsNil)
   333  	c.Check(toResolve, HasLen, 0)
   334  
   335  	c.Check(pool.Err("for_one"), IsNil)
   336  
   337  	err = pool.CommitTo(s.db)
   338  	c.Check(err, IsNil)
   339  	c.Assert(pool.Err("for_one"), IsNil)
   340  
   341  	a, err := at1111.Ref.Resolve(s.db.Find)
   342  	c.Assert(err, IsNil)
   343  	c.Check(a.(*asserts.TestOnlyRev).H(), Equals, "1111")
   344  }
   345  
   346  func (s *poolSuite) TestPushSuggestionForNew(c *C) {
   347  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   348  
   349  	pool := asserts.NewPool(s.db, 64)
   350  
   351  	atOne := &asserts.AtRevision{
   352  		Ref:      asserts.Ref{Type: asserts.TestOnlyDeclType, PrimaryKey: []string{"one"}},
   353  		Revision: asserts.RevisionNotKnown,
   354  	}
   355  	err := pool.AddUnresolved(atOne, "for_one")
   356  	c.Assert(err, IsNil)
   357  
   358  	toResolve, err := pool.ToResolve()
   359  	c.Assert(err, IsNil)
   360  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   361  		asserts.MakePoolGrouping(0): {atOne},
   362  	})
   363  
   364  	err = pool.Add(s.decl1, asserts.MakePoolGrouping(0))
   365  	c.Assert(err, IsNil)
   366  
   367  	// new push suggestion
   368  	err = pool.Add(s.rev1_1111, asserts.MakePoolGrouping(0))
   369  	c.Assert(err, IsNil)
   370  
   371  	toResolve, err = pool.ToResolve()
   372  	c.Assert(err, IsNil)
   373  	sortToResolve(toResolve)
   374  	dev1AcctAt := s.dev1Acct.At()
   375  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   376  	storeKeyAt := s.hub.StoreAccountKey("").At()
   377  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   378  		asserts.MakePoolGrouping(0): {storeKeyAt, dev1AcctAt},
   379  	})
   380  
   381  	c.Check(pool.Err("for_one"), IsNil)
   382  
   383  	err = pool.Add(s.dev1Acct, asserts.MakePoolGrouping(0))
   384  	c.Assert(err, IsNil)
   385  
   386  	toResolve, err = pool.ToResolve()
   387  	c.Assert(err, IsNil)
   388  	c.Check(toResolve, HasLen, 0)
   389  
   390  	c.Check(pool.Err("for_one"), IsNil)
   391  
   392  	err = pool.CommitTo(s.db)
   393  	c.Check(err, IsNil)
   394  	c.Assert(pool.Err("for_one"), IsNil)
   395  
   396  	a, err := s.rev1_1111.Ref().Resolve(s.db.Find)
   397  	c.Assert(err, IsNil)
   398  	c.Check(a.(*asserts.TestOnlyRev).H(), Equals, "1111")
   399  }
   400  
   401  func (s *poolSuite) TestAddUnresolvedUnresolved(c *C) {
   402  	pool := asserts.NewPool(s.db, 64)
   403  
   404  	at1 := &asserts.AtRevision{
   405  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   406  		Revision: asserts.RevisionNotKnown,
   407  	}
   408  	err := pool.AddUnresolved(at1, "for_one")
   409  	c.Assert(err, IsNil)
   410  
   411  	toResolve, err := pool.ToResolve()
   412  	c.Assert(err, IsNil)
   413  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   414  		asserts.MakePoolGrouping(0): {at1},
   415  	})
   416  
   417  	toResolve, err = pool.ToResolve()
   418  	c.Assert(err, IsNil)
   419  	c.Check(toResolve, HasLen, 0)
   420  
   421  	c.Check(pool.Err("for_one"), Equals, asserts.ErrUnresolved)
   422  }
   423  
   424  func (s *poolSuite) TestAddFormatTooNew(c *C) {
   425  	pool := asserts.NewPool(s.db, 64)
   426  
   427  	_, err := pool.ToResolve()
   428  	c.Assert(err, IsNil)
   429  
   430  	var a asserts.Assertion
   431  	(func() {
   432  		restore := asserts.MockMaxSupportedFormat(asserts.TestOnlyDeclType, 2)
   433  		defer restore()
   434  
   435  		a, err = s.hub.Sign(asserts.TestOnlyDeclType, map[string]interface{}{
   436  			"id":     "three",
   437  			"dev-id": "developer1",
   438  			"format": "2",
   439  		}, nil, "")
   440  		c.Assert(err, IsNil)
   441  	})()
   442  
   443  	gSuggestion, err := pool.Singleton("suggestion")
   444  	c.Assert(err, IsNil)
   445  
   446  	err = pool.Add(a, gSuggestion)
   447  	c.Assert(err, ErrorMatches, `proposed "test-only-decl" assertion has format 2 but 0 is latest supported`)
   448  }
   449  
   450  func (s *poolSuite) TestAddOlderIgnored(c *C) {
   451  	pool := asserts.NewPool(s.db, 64)
   452  
   453  	_, err := pool.ToResolve()
   454  	c.Assert(err, IsNil)
   455  
   456  	gSuggestion, err := pool.Singleton("suggestion")
   457  	c.Assert(err, IsNil)
   458  
   459  	err = pool.Add(s.decl1_1, gSuggestion)
   460  	c.Assert(err, IsNil)
   461  
   462  	err = pool.Add(s.decl1, gSuggestion)
   463  	c.Assert(err, IsNil)
   464  
   465  	toResolve, err := pool.ToResolve()
   466  	c.Assert(err, IsNil)
   467  	sortToResolve(toResolve)
   468  	dev1AcctAt := s.dev1Acct.At()
   469  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   470  	storeKeyAt := s.hub.StoreAccountKey("").At()
   471  	storeKeyAt.Revision = asserts.RevisionNotKnown
   472  
   473  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   474  		gSuggestion: {storeKeyAt, dev1AcctAt},
   475  	})
   476  }
   477  
   478  func (s *poolSuite) TestUnknownGroup(c *C) {
   479  	pool := asserts.NewPool(s.db, 64)
   480  
   481  	_, err := pool.Singleton("suggestion")
   482  	c.Assert(err, IsNil)
   483  	// sanity
   484  	c.Check(pool.Err("suggestion"), IsNil)
   485  
   486  	c.Check(pool.Err("foo"), Equals, asserts.ErrUnknownPoolGroup)
   487  }
   488  
   489  func (s *poolSuite) TestAddCurrentRevision(c *C) {
   490  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""), s.dev1Acct, s.decl1)
   491  
   492  	pool := asserts.NewPool(s.db, 64)
   493  
   494  	atDev1Acct := s.dev1Acct.At()
   495  	atDev1Acct.Revision = asserts.RevisionNotKnown
   496  	err := pool.AddUnresolved(atDev1Acct, "one")
   497  	c.Assert(err, IsNil)
   498  
   499  	atDecl1 := s.decl1.At()
   500  	atDecl1.Revision = asserts.RevisionNotKnown
   501  	err = pool.AddUnresolved(atDecl1, "one")
   502  	c.Assert(err, IsNil)
   503  
   504  	toResolve, err := pool.ToResolve()
   505  	c.Assert(err, IsNil)
   506  	sortToResolve(toResolve)
   507  
   508  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   509  		asserts.MakePoolGrouping(0): {s.dev1Acct.At(), s.decl1.At()},
   510  	})
   511  
   512  	// re-adding of current revisions, is not what we expect
   513  	// but needs not to produce unneeded roundtrips
   514  
   515  	err = pool.Add(s.hub.StoreAccountKey(""), asserts.MakePoolGrouping(0))
   516  	c.Assert(err, IsNil)
   517  
   518  	// this will be kept marked as unresolved until the ToResolve
   519  	err = pool.Add(s.dev1Acct, asserts.MakePoolGrouping(0))
   520  	c.Assert(err, IsNil)
   521  
   522  	err = pool.Add(s.decl1_1, asserts.MakePoolGrouping(0))
   523  	c.Assert(err, IsNil)
   524  
   525  	toResolve, err = pool.ToResolve()
   526  	c.Assert(err, IsNil)
   527  	c.Assert(toResolve, HasLen, 0)
   528  
   529  	c.Check(pool.Err("one"), IsNil)
   530  }
   531  
   532  func (s *poolSuite) TestUpdate(c *C) {
   533  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   534  	assertstest.AddMany(s.db, s.dev1Acct, s.decl1, s.rev1_1111)
   535  	assertstest.AddMany(s.db, s.dev2Acct, s.decl2, s.rev2_2222)
   536  
   537  	pool := asserts.NewPool(s.db, 64)
   538  
   539  	err := pool.AddToUpdate(s.decl1.Ref(), "for_one") // group num: 0
   540  	c.Assert(err, IsNil)
   541  	err = pool.AddToUpdate(s.decl2.Ref(), "for_two") // group num: 1
   542  	c.Assert(err, IsNil)
   543  
   544  	storeKeyAt := s.hub.StoreAccountKey("").At()
   545  
   546  	toResolve, err := pool.ToResolve()
   547  	c.Assert(err, IsNil)
   548  	sortToResolve(toResolve)
   549  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   550  		asserts.MakePoolGrouping(0, 1): {storeKeyAt},
   551  		asserts.MakePoolGrouping(0):    {s.dev1Acct.At(), s.decl1.At()},
   552  		asserts.MakePoolGrouping(1):    {s.dev2Acct.At(), s.decl2.At()},
   553  	})
   554  
   555  	err = pool.Add(s.decl1_1, asserts.MakePoolGrouping(0))
   556  	c.Assert(err, IsNil)
   557  
   558  	toResolve, err = pool.ToResolve()
   559  	c.Assert(err, IsNil)
   560  	c.Check(toResolve, HasLen, 0)
   561  
   562  	at2222 := &asserts.AtRevision{
   563  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"2222"}},
   564  		Revision: asserts.RevisionNotKnown,
   565  	}
   566  	err = pool.AddUnresolved(at2222, "for_two")
   567  	c.Assert(err, IsNil)
   568  
   569  	toResolve, err = pool.ToResolve()
   570  	c.Assert(err, IsNil)
   571  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   572  		asserts.MakePoolGrouping(1): {&asserts.AtRevision{
   573  			Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"2222"}},
   574  			Revision: 0,
   575  		}},
   576  	})
   577  
   578  	c.Check(pool.Err("for_one"), IsNil)
   579  	c.Check(pool.Err("for_two"), IsNil)
   580  }
   581  
   582  var errBoom = errors.New("boom")
   583  
   584  func (s *poolSuite) TestAddErrorEarly(c *C) {
   585  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   586  
   587  	pool := asserts.NewPool(s.db, 64)
   588  
   589  	storeKey := s.hub.StoreAccountKey("")
   590  	err := pool.AddToUpdate(storeKey.Ref(), "store_key")
   591  	c.Assert(err, IsNil)
   592  
   593  	at1111 := &asserts.AtRevision{
   594  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   595  		Revision: asserts.RevisionNotKnown,
   596  	}
   597  	err = pool.AddUnresolved(at1111, "for_one")
   598  	c.Assert(err, IsNil)
   599  
   600  	toResolve, err := pool.ToResolve()
   601  	c.Assert(err, IsNil)
   602  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   603  		asserts.MakePoolGrouping(0): {storeKey.At()},
   604  		asserts.MakePoolGrouping(1): {at1111},
   605  	})
   606  
   607  	err = pool.AddError(errBoom, storeKey.Ref())
   608  	c.Assert(err, IsNil)
   609  
   610  	err = pool.Add(s.rev1_1111, asserts.MakePoolGrouping(1))
   611  	c.Assert(err, IsNil)
   612  
   613  	toResolve, err = pool.ToResolve()
   614  	c.Assert(err, IsNil)
   615  	c.Check(toResolve, HasLen, 0)
   616  
   617  	c.Check(pool.Err("store_key"), Equals, errBoom)
   618  	c.Check(pool.Err("for_one"), Equals, errBoom)
   619  }
   620  
   621  func (s *poolSuite) TestAddErrorLater(c *C) {
   622  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   623  
   624  	pool := asserts.NewPool(s.db, 64)
   625  
   626  	storeKey := s.hub.StoreAccountKey("")
   627  	err := pool.AddToUpdate(storeKey.Ref(), "store_key")
   628  	c.Assert(err, IsNil)
   629  
   630  	at1111 := &asserts.AtRevision{
   631  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   632  		Revision: asserts.RevisionNotKnown,
   633  	}
   634  	err = pool.AddUnresolved(at1111, "for_one")
   635  	c.Assert(err, IsNil)
   636  
   637  	toResolve, err := pool.ToResolve()
   638  	c.Assert(err, IsNil)
   639  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   640  		asserts.MakePoolGrouping(0): {storeKey.At()},
   641  		asserts.MakePoolGrouping(1): {at1111},
   642  	})
   643  
   644  	err = pool.Add(s.rev1_1111, asserts.MakePoolGrouping(1))
   645  	c.Assert(err, IsNil)
   646  
   647  	err = pool.AddError(errBoom, storeKey.Ref())
   648  	c.Assert(err, IsNil)
   649  
   650  	toResolve, err = pool.ToResolve()
   651  	c.Assert(err, IsNil)
   652  	c.Check(toResolve, HasLen, 0)
   653  
   654  	c.Check(pool.Err("store_key"), Equals, errBoom)
   655  	c.Check(pool.Err("for_one"), Equals, errBoom)
   656  }
   657  
   658  func (s *poolSuite) TestNopUpdatePlusFetchOfPushed(c *C) {
   659  	storeKey := s.hub.StoreAccountKey("")
   660  	assertstest.AddMany(s.db, storeKey)
   661  	assertstest.AddMany(s.db, s.dev1Acct)
   662  	assertstest.AddMany(s.db, s.decl1)
   663  	assertstest.AddMany(s.db, s.rev1_1111)
   664  
   665  	pool := asserts.NewPool(s.db, 64)
   666  
   667  	atOne := s.decl1.At()
   668  	err := pool.AddToUpdate(&atOne.Ref, "for_one")
   669  	c.Assert(err, IsNil)
   670  
   671  	toResolve, err := pool.ToResolve()
   672  	c.Assert(err, IsNil)
   673  	sortToResolve(toResolve)
   674  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   675  		asserts.MakePoolGrouping(0): {storeKey.At(), s.dev1Acct.At(), atOne},
   676  	})
   677  
   678  	// no updates but
   679  	// new push suggestion
   680  
   681  	gSuggestion, err := pool.Singleton("suggestion")
   682  	c.Assert(err, IsNil)
   683  
   684  	err = pool.Add(s.rev1_3333, gSuggestion)
   685  	c.Assert(err, IsNil)
   686  
   687  	toResolve, err = pool.ToResolve()
   688  	c.Assert(err, IsNil)
   689  	c.Assert(toResolve, HasLen, 0)
   690  
   691  	c.Check(pool.Err("for_one"), IsNil)
   692  
   693  	pool.AddGroupingError(errBoom, gSuggestion)
   694  
   695  	c.Assert(pool.Err("for_one"), IsNil)
   696  	c.Assert(pool.Err("suggestion"), Equals, errBoom)
   697  
   698  	at3333 := s.rev1_3333.At()
   699  	at3333.Revision = asserts.RevisionNotKnown
   700  	err = pool.AddUnresolved(at3333, at3333.Unique())
   701  	c.Assert(err, IsNil)
   702  
   703  	toResolve, err = pool.ToResolve()
   704  	c.Assert(err, IsNil)
   705  	c.Assert(toResolve, HasLen, 0)
   706  
   707  	err = pool.CommitTo(s.db)
   708  	c.Check(err, IsNil)
   709  
   710  	c.Assert(pool.Err(at3333.Unique()), IsNil)
   711  
   712  	a, err := s.rev1_3333.Ref().Resolve(s.db.Find)
   713  	c.Assert(err, IsNil)
   714  	c.Check(a.(*asserts.TestOnlyRev).H(), Equals, "3333")
   715  }
   716  
   717  func (s *poolSuite) TestAddToUpdateThenUnresolved(c *C) {
   718  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   719  
   720  	pool := asserts.NewPool(s.db, 64)
   721  
   722  	storeKey := s.hub.StoreAccountKey("")
   723  	storeKeyAt := storeKey.At()
   724  	storeKeyAt.Revision = asserts.RevisionNotKnown
   725  
   726  	err := pool.AddToUpdate(storeKey.Ref(), "for_one")
   727  	c.Assert(err, IsNil)
   728  	err = pool.AddUnresolved(storeKeyAt, "for_one")
   729  	c.Assert(err, IsNil)
   730  
   731  	toResolve, err := pool.ToResolve()
   732  	c.Assert(err, IsNil)
   733  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   734  		asserts.MakePoolGrouping(0): {storeKey.At()},
   735  	})
   736  }
   737  
   738  func (s *poolSuite) TestAddUnresolvedThenToUpdate(c *C) {
   739  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   740  
   741  	pool := asserts.NewPool(s.db, 64)
   742  
   743  	storeKey := s.hub.StoreAccountKey("")
   744  	storeKeyAt := storeKey.At()
   745  	storeKeyAt.Revision = asserts.RevisionNotKnown
   746  
   747  	err := pool.AddUnresolved(storeKeyAt, "for_one")
   748  	c.Assert(err, IsNil)
   749  	err = pool.AddToUpdate(storeKey.Ref(), "for_one")
   750  	c.Assert(err, IsNil)
   751  
   752  	toResolve, err := pool.ToResolve()
   753  	c.Assert(err, IsNil)
   754  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   755  		asserts.MakePoolGrouping(0): {storeKey.At()},
   756  	})
   757  }
   758  
   759  func (s *poolSuite) TestNopUpdatePlusFetch(c *C) {
   760  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   761  
   762  	pool := asserts.NewPool(s.db, 64)
   763  
   764  	storeKey := s.hub.StoreAccountKey("")
   765  	err := pool.AddToUpdate(storeKey.Ref(), "store_key")
   766  	c.Assert(err, IsNil)
   767  
   768  	at1111 := &asserts.AtRevision{
   769  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   770  		Revision: asserts.RevisionNotKnown,
   771  	}
   772  	err = pool.AddUnresolved(at1111, "for_one")
   773  	c.Assert(err, IsNil)
   774  
   775  	toResolve, err := pool.ToResolve()
   776  	c.Assert(err, IsNil)
   777  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   778  		asserts.MakePoolGrouping(0): {storeKey.At()},
   779  		asserts.MakePoolGrouping(1): {at1111},
   780  	})
   781  
   782  	err = pool.Add(s.rev1_1111, asserts.MakePoolGrouping(1))
   783  	c.Assert(err, IsNil)
   784  
   785  	toResolve, err = pool.ToResolve()
   786  	c.Assert(err, IsNil)
   787  	sortToResolve(toResolve)
   788  	dev1AcctAt := s.dev1Acct.At()
   789  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   790  	decl1At := s.decl1.At()
   791  	decl1At.Revision = asserts.RevisionNotKnown
   792  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   793  		asserts.MakePoolGrouping(1): {dev1AcctAt, decl1At},
   794  	})
   795  
   796  	c.Check(pool.Err("store_key"), IsNil)
   797  	c.Check(pool.Err("for_one"), IsNil)
   798  }
   799  
   800  func (s *poolSuite) TestParallelPartialResolutionFailure(c *C) {
   801  	pool := asserts.NewPool(s.db, 64)
   802  
   803  	atOne := &asserts.AtRevision{
   804  		Ref:      asserts.Ref{Type: asserts.TestOnlyDeclType, PrimaryKey: []string{"one"}},
   805  		Revision: asserts.RevisionNotKnown,
   806  	}
   807  	err := pool.AddUnresolved(atOne, "one")
   808  	c.Assert(err, IsNil)
   809  
   810  	toResolve, err := pool.ToResolve()
   811  	c.Assert(err, IsNil)
   812  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   813  		asserts.MakePoolGrouping(0): {atOne},
   814  	})
   815  
   816  	err = pool.Add(s.decl1, asserts.MakePoolGrouping(0))
   817  	c.Assert(err, IsNil)
   818  
   819  	toResolve, err = pool.ToResolve()
   820  	c.Assert(err, IsNil)
   821  	sortToResolve(toResolve)
   822  	dev1AcctAt := s.dev1Acct.At()
   823  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   824  	decl1At := s.decl1.At()
   825  	decl1At.Revision = asserts.RevisionNotKnown
   826  	storeKeyAt := s.hub.StoreAccountKey("").At()
   827  	storeKeyAt.Revision = asserts.RevisionNotKnown
   828  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   829  		asserts.MakePoolGrouping(0): {storeKeyAt, dev1AcctAt},
   830  	})
   831  
   832  	// failed to get prereqs
   833  	c.Check(pool.AddGroupingError(errBoom, asserts.MakePoolGrouping(0)), IsNil)
   834  
   835  	err = pool.AddUnresolved(atOne, "other")
   836  	c.Assert(err, IsNil)
   837  
   838  	toResolve, err = pool.ToResolve()
   839  	c.Assert(err, IsNil)
   840  	c.Check(toResolve, HasLen, 0)
   841  
   842  	c.Check(pool.Err("one"), Equals, errBoom)
   843  	c.Check(pool.Err("other"), IsNil)
   844  
   845  	// we fail at commit though
   846  	err = pool.CommitTo(s.db)
   847  	c.Check(err, IsNil)
   848  	c.Check(pool.Err("one"), Equals, errBoom)
   849  	c.Check(pool.Err("other"), ErrorMatches, "cannot resolve prerequisite assertion.*")
   850  }