github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/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  	ok, err := pool.Add(s.rev1_1111, asserts.MakePoolGrouping(0))
   216  	c.Assert(err, IsNil)
   217  	c.Assert(ok, Equals, true)
   218  
   219  	toResolve, err = pool.ToResolve()
   220  	c.Assert(err, IsNil)
   221  	sortToResolve(toResolve)
   222  	dev1AcctAt := s.dev1Acct.At()
   223  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   224  	decl1At := s.decl1.At()
   225  	decl1At.Revision = asserts.RevisionNotKnown
   226  	storeKeyAt := s.hub.StoreAccountKey("").At()
   227  	storeKeyAt.Revision = asserts.RevisionNotKnown
   228  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   229  		asserts.MakePoolGrouping(0): {storeKeyAt, dev1AcctAt, decl1At},
   230  	})
   231  
   232  	c.Check(pool.Err("for_one"), IsNil)
   233  }
   234  
   235  func (s *poolSuite) TestCompleteFetch(c *C) {
   236  	pool := asserts.NewPool(s.db, 64)
   237  
   238  	at1111 := &asserts.AtRevision{
   239  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   240  		Revision: asserts.RevisionNotKnown,
   241  	}
   242  	err := pool.AddUnresolved(at1111, "for_one")
   243  	c.Assert(err, IsNil)
   244  
   245  	toResolve, err := pool.ToResolve()
   246  	c.Assert(err, IsNil)
   247  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   248  		asserts.MakePoolGrouping(0): {at1111},
   249  	})
   250  
   251  	ok, err := pool.Add(s.rev1_1111, asserts.MakePoolGrouping(0))
   252  	c.Assert(err, IsNil)
   253  	c.Assert(ok, Equals, true)
   254  
   255  	toResolve, err = pool.ToResolve()
   256  	c.Assert(err, IsNil)
   257  	sortToResolve(toResolve)
   258  	dev1AcctAt := s.dev1Acct.At()
   259  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   260  	decl1At := s.decl1.At()
   261  	decl1At.Revision = asserts.RevisionNotKnown
   262  	storeKey := s.hub.StoreAccountKey("")
   263  	storeKeyAt := storeKey.At()
   264  	storeKeyAt.Revision = asserts.RevisionNotKnown
   265  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   266  		asserts.MakePoolGrouping(0): {storeKeyAt, dev1AcctAt, decl1At},
   267  	})
   268  
   269  	b := asserts.NewBatch(nil)
   270  	err = b.Add(s.decl1)
   271  	c.Assert(err, IsNil)
   272  	err = b.Add(storeKey)
   273  	c.Assert(err, IsNil)
   274  	err = b.Add(s.dev1Acct)
   275  	c.Assert(err, IsNil)
   276  
   277  	ok, err = pool.AddBatch(b, asserts.MakePoolGrouping(0))
   278  	c.Assert(err, IsNil)
   279  	c.Assert(ok, Equals, true)
   280  
   281  	toResolve, err = pool.ToResolve()
   282  	c.Assert(err, IsNil)
   283  	c.Check(toResolve, HasLen, 0)
   284  
   285  	c.Check(pool.Err("for_one"), IsNil)
   286  
   287  	err = pool.CommitTo(s.db)
   288  	c.Check(err, IsNil)
   289  	c.Assert(pool.Err("for_one"), IsNil)
   290  
   291  	a, err := at1111.Ref.Resolve(s.db.Find)
   292  	c.Assert(err, IsNil)
   293  	c.Check(a.(*asserts.TestOnlyRev).H(), Equals, "1111")
   294  }
   295  
   296  func (s *poolSuite) TestPushSuggestionForPrerequisite(c *C) {
   297  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   298  
   299  	pool := asserts.NewPool(s.db, 64)
   300  
   301  	at1111 := &asserts.AtRevision{
   302  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   303  		Revision: asserts.RevisionNotKnown,
   304  	}
   305  	err := pool.AddUnresolved(at1111, "for_one")
   306  	c.Assert(err, IsNil)
   307  
   308  	toResolve, err := pool.ToResolve()
   309  	c.Assert(err, IsNil)
   310  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   311  		asserts.MakePoolGrouping(0): {at1111},
   312  	})
   313  
   314  	ok, err := pool.Add(s.rev1_1111, asserts.MakePoolGrouping(0))
   315  	c.Assert(err, IsNil)
   316  	c.Assert(ok, Equals, true)
   317  
   318  	// push prerequisite suggestion
   319  	ok, err = pool.Add(s.decl1, asserts.MakePoolGrouping(0))
   320  	c.Assert(err, IsNil)
   321  	c.Assert(ok, Equals, true)
   322  
   323  	toResolve, err = pool.ToResolve()
   324  	c.Assert(err, IsNil)
   325  	sortToResolve(toResolve)
   326  	dev1AcctAt := s.dev1Acct.At()
   327  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   328  	storeKey := s.hub.StoreAccountKey("")
   329  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   330  		asserts.MakePoolGrouping(0): {storeKey.At(), dev1AcctAt},
   331  	})
   332  
   333  	c.Check(pool.Err("for_one"), IsNil)
   334  
   335  	ok, err = pool.Add(s.dev1Acct, asserts.MakePoolGrouping(0))
   336  	c.Assert(err, IsNil)
   337  	c.Assert(ok, Equals, true)
   338  
   339  	toResolve, err = pool.ToResolve()
   340  	c.Assert(err, IsNil)
   341  	c.Check(toResolve, HasLen, 0)
   342  
   343  	c.Check(pool.Err("for_one"), IsNil)
   344  
   345  	err = pool.CommitTo(s.db)
   346  	c.Check(err, IsNil)
   347  	c.Assert(pool.Err("for_one"), IsNil)
   348  
   349  	a, err := at1111.Ref.Resolve(s.db.Find)
   350  	c.Assert(err, IsNil)
   351  	c.Check(a.(*asserts.TestOnlyRev).H(), Equals, "1111")
   352  }
   353  
   354  func (s *poolSuite) TestPushSuggestionForNew(c *C) {
   355  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   356  
   357  	pool := asserts.NewPool(s.db, 64)
   358  
   359  	atOne := &asserts.AtRevision{
   360  		Ref:      asserts.Ref{Type: asserts.TestOnlyDeclType, PrimaryKey: []string{"one"}},
   361  		Revision: asserts.RevisionNotKnown,
   362  	}
   363  	err := pool.AddUnresolved(atOne, "for_one")
   364  	c.Assert(err, IsNil)
   365  
   366  	toResolve, err := pool.ToResolve()
   367  	c.Assert(err, IsNil)
   368  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   369  		asserts.MakePoolGrouping(0): {atOne},
   370  	})
   371  
   372  	ok, err := pool.Add(s.decl1, asserts.MakePoolGrouping(0))
   373  	c.Assert(err, IsNil)
   374  	c.Assert(ok, Equals, true)
   375  
   376  	// new push suggestion
   377  	ok, err = pool.Add(s.rev1_1111, asserts.MakePoolGrouping(0))
   378  	c.Assert(err, IsNil)
   379  	c.Assert(ok, Equals, true)
   380  
   381  	toResolve, err = pool.ToResolve()
   382  	c.Assert(err, IsNil)
   383  	sortToResolve(toResolve)
   384  	dev1AcctAt := s.dev1Acct.At()
   385  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   386  	storeKeyAt := s.hub.StoreAccountKey("").At()
   387  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   388  		asserts.MakePoolGrouping(0): {storeKeyAt, dev1AcctAt},
   389  	})
   390  
   391  	c.Check(pool.Err("for_one"), IsNil)
   392  
   393  	ok, err = pool.Add(s.dev1Acct, asserts.MakePoolGrouping(0))
   394  	c.Assert(err, IsNil)
   395  	c.Assert(ok, Equals, true)
   396  
   397  	toResolve, err = pool.ToResolve()
   398  	c.Assert(err, IsNil)
   399  	c.Check(toResolve, HasLen, 0)
   400  
   401  	c.Check(pool.Err("for_one"), IsNil)
   402  
   403  	err = pool.CommitTo(s.db)
   404  	c.Check(err, IsNil)
   405  	c.Assert(pool.Err("for_one"), IsNil)
   406  
   407  	a, err := s.rev1_1111.Ref().Resolve(s.db.Find)
   408  	c.Assert(err, IsNil)
   409  	c.Check(a.(*asserts.TestOnlyRev).H(), Equals, "1111")
   410  }
   411  
   412  func (s *poolSuite) TestPushSuggestionForNewViaBatch(c *C) {
   413  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   414  
   415  	pool := asserts.NewPool(s.db, 64)
   416  
   417  	atOne := &asserts.AtRevision{
   418  		Ref:      asserts.Ref{Type: asserts.TestOnlyDeclType, PrimaryKey: []string{"one"}},
   419  		Revision: asserts.RevisionNotKnown,
   420  	}
   421  	err := pool.AddUnresolved(atOne, "for_one")
   422  	c.Assert(err, IsNil)
   423  
   424  	toResolve, err := pool.ToResolve()
   425  	c.Assert(err, IsNil)
   426  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   427  		asserts.MakePoolGrouping(0): {atOne},
   428  	})
   429  
   430  	b := asserts.NewBatch(nil)
   431  	err = b.Add(s.decl1)
   432  	c.Assert(err, IsNil)
   433  
   434  	// new push suggestions
   435  	err = b.Add(s.rev1_1111)
   436  	c.Assert(err, IsNil)
   437  	err = b.Add(s.rev1_3333)
   438  	c.Assert(err, IsNil)
   439  
   440  	ok, err := pool.AddBatch(b, asserts.MakePoolGrouping(0))
   441  	c.Assert(err, IsNil)
   442  	c.Assert(ok, Equals, true)
   443  
   444  	toResolve, err = pool.ToResolve()
   445  	c.Assert(err, IsNil)
   446  	sortToResolve(toResolve)
   447  	dev1AcctAt := s.dev1Acct.At()
   448  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   449  	storeKeyAt := s.hub.StoreAccountKey("").At()
   450  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   451  		asserts.MakePoolGrouping(0): {storeKeyAt, dev1AcctAt},
   452  	})
   453  
   454  	c.Check(pool.Err("for_one"), IsNil)
   455  
   456  	ok, err = pool.Add(s.dev1Acct, asserts.MakePoolGrouping(0))
   457  	c.Assert(err, IsNil)
   458  	c.Assert(ok, Equals, true)
   459  
   460  	toResolve, err = pool.ToResolve()
   461  	c.Assert(err, IsNil)
   462  	c.Check(toResolve, HasLen, 0)
   463  
   464  	c.Check(pool.Err("for_one"), IsNil)
   465  
   466  	err = pool.CommitTo(s.db)
   467  	c.Check(err, IsNil)
   468  	c.Assert(pool.Err("for_one"), IsNil)
   469  
   470  	a, err := s.rev1_1111.Ref().Resolve(s.db.Find)
   471  	c.Assert(err, IsNil)
   472  	c.Check(a.(*asserts.TestOnlyRev).H(), Equals, "1111")
   473  
   474  	a, err = s.rev1_3333.Ref().Resolve(s.db.Find)
   475  	c.Assert(err, IsNil)
   476  	c.Check(a.(*asserts.TestOnlyRev).H(), Equals, "3333")
   477  }
   478  
   479  func (s *poolSuite) TestAddUnresolvedUnresolved(c *C) {
   480  	pool := asserts.NewPool(s.db, 64)
   481  
   482  	at1 := &asserts.AtRevision{
   483  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   484  		Revision: asserts.RevisionNotKnown,
   485  	}
   486  	err := pool.AddUnresolved(at1, "for_one")
   487  	c.Assert(err, IsNil)
   488  
   489  	toResolve, err := pool.ToResolve()
   490  	c.Assert(err, IsNil)
   491  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   492  		asserts.MakePoolGrouping(0): {at1},
   493  	})
   494  
   495  	toResolve, err = pool.ToResolve()
   496  	c.Assert(err, IsNil)
   497  	c.Check(toResolve, HasLen, 0)
   498  
   499  	c.Check(pool.Err("for_one"), Equals, asserts.ErrUnresolved)
   500  }
   501  
   502  func (s *poolSuite) TestAddFormatTooNew(c *C) {
   503  	pool := asserts.NewPool(s.db, 64)
   504  
   505  	_, err := pool.ToResolve()
   506  	c.Assert(err, IsNil)
   507  
   508  	var a asserts.Assertion
   509  	(func() {
   510  		restore := asserts.MockMaxSupportedFormat(asserts.TestOnlyDeclType, 2)
   511  		defer restore()
   512  
   513  		a, err = s.hub.Sign(asserts.TestOnlyDeclType, map[string]interface{}{
   514  			"id":     "three",
   515  			"dev-id": "developer1",
   516  			"format": "2",
   517  		}, nil, "")
   518  		c.Assert(err, IsNil)
   519  	})()
   520  
   521  	gSuggestion, err := pool.Singleton("suggestion")
   522  	c.Assert(err, IsNil)
   523  
   524  	ok, err := pool.Add(a, gSuggestion)
   525  	c.Check(err, IsNil)
   526  	c.Check(ok, Equals, false)
   527  	c.Assert(pool.Err("suggestion"), ErrorMatches, `proposed "test-only-decl" assertion has format 2 but 0 is latest supported`)
   528  }
   529  
   530  func (s *poolSuite) TestAddOlderIgnored(c *C) {
   531  	pool := asserts.NewPool(s.db, 64)
   532  
   533  	_, err := pool.ToResolve()
   534  	c.Assert(err, IsNil)
   535  
   536  	gSuggestion, err := pool.Singleton("suggestion")
   537  	c.Assert(err, IsNil)
   538  
   539  	ok, err := pool.Add(s.decl1_1, gSuggestion)
   540  	c.Assert(err, IsNil)
   541  	c.Assert(ok, Equals, true)
   542  
   543  	ok, err = pool.Add(s.decl1, gSuggestion)
   544  	c.Assert(err, IsNil)
   545  	c.Assert(ok, Equals, true)
   546  
   547  	toResolve, err := pool.ToResolve()
   548  	c.Assert(err, IsNil)
   549  	sortToResolve(toResolve)
   550  	dev1AcctAt := s.dev1Acct.At()
   551  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   552  	storeKeyAt := s.hub.StoreAccountKey("").At()
   553  	storeKeyAt.Revision = asserts.RevisionNotKnown
   554  
   555  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   556  		gSuggestion: {storeKeyAt, dev1AcctAt},
   557  	})
   558  }
   559  
   560  func (s *poolSuite) TestUnknownGroup(c *C) {
   561  	pool := asserts.NewPool(s.db, 64)
   562  
   563  	_, err := pool.Singleton("suggestion")
   564  	c.Assert(err, IsNil)
   565  	// sanity
   566  	c.Check(pool.Err("suggestion"), IsNil)
   567  
   568  	c.Check(pool.Err("foo"), Equals, asserts.ErrUnknownPoolGroup)
   569  }
   570  
   571  func (s *poolSuite) TestAddCurrentRevision(c *C) {
   572  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""), s.dev1Acct, s.decl1)
   573  
   574  	pool := asserts.NewPool(s.db, 64)
   575  
   576  	atDev1Acct := s.dev1Acct.At()
   577  	atDev1Acct.Revision = asserts.RevisionNotKnown
   578  	err := pool.AddUnresolved(atDev1Acct, "one")
   579  	c.Assert(err, IsNil)
   580  
   581  	atDecl1 := s.decl1.At()
   582  	atDecl1.Revision = asserts.RevisionNotKnown
   583  	err = pool.AddUnresolved(atDecl1, "one")
   584  	c.Assert(err, IsNil)
   585  
   586  	toResolve, err := pool.ToResolve()
   587  	c.Assert(err, IsNil)
   588  	sortToResolve(toResolve)
   589  
   590  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   591  		asserts.MakePoolGrouping(0): {s.dev1Acct.At(), s.decl1.At()},
   592  	})
   593  
   594  	// re-adding of current revisions, is not what we expect
   595  	// but needs not to produce unneeded roundtrips
   596  
   597  	ok, err := pool.Add(s.hub.StoreAccountKey(""), asserts.MakePoolGrouping(0))
   598  	c.Assert(err, IsNil)
   599  	c.Assert(ok, Equals, true)
   600  
   601  	// this will be kept marked as unresolved until the ToResolve
   602  	ok, err = pool.Add(s.dev1Acct, asserts.MakePoolGrouping(0))
   603  	c.Assert(err, IsNil)
   604  	c.Assert(ok, Equals, true)
   605  
   606  	ok, err = pool.Add(s.decl1_1, asserts.MakePoolGrouping(0))
   607  	c.Assert(err, IsNil)
   608  	c.Assert(ok, Equals, true)
   609  
   610  	toResolve, err = pool.ToResolve()
   611  	c.Assert(err, IsNil)
   612  	c.Assert(toResolve, HasLen, 0)
   613  
   614  	c.Check(pool.Err("one"), IsNil)
   615  }
   616  
   617  func (s *poolSuite) TestUpdate(c *C) {
   618  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   619  	assertstest.AddMany(s.db, s.dev1Acct, s.decl1, s.rev1_1111)
   620  	assertstest.AddMany(s.db, s.dev2Acct, s.decl2, s.rev2_2222)
   621  
   622  	pool := asserts.NewPool(s.db, 64)
   623  
   624  	err := pool.AddToUpdate(s.decl1.Ref(), "for_one") // group num: 0
   625  	c.Assert(err, IsNil)
   626  	err = pool.AddToUpdate(s.decl2.Ref(), "for_two") // group num: 1
   627  	c.Assert(err, IsNil)
   628  
   629  	storeKeyAt := s.hub.StoreAccountKey("").At()
   630  
   631  	toResolve, err := pool.ToResolve()
   632  	c.Assert(err, IsNil)
   633  	sortToResolve(toResolve)
   634  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   635  		asserts.MakePoolGrouping(0, 1): {storeKeyAt},
   636  		asserts.MakePoolGrouping(0):    {s.dev1Acct.At(), s.decl1.At()},
   637  		asserts.MakePoolGrouping(1):    {s.dev2Acct.At(), s.decl2.At()},
   638  	})
   639  
   640  	ok, err := pool.Add(s.decl1_1, asserts.MakePoolGrouping(0))
   641  	c.Assert(err, IsNil)
   642  	c.Assert(ok, Equals, true)
   643  
   644  	toResolve, err = pool.ToResolve()
   645  	c.Assert(err, IsNil)
   646  	c.Check(toResolve, HasLen, 0)
   647  
   648  	at2222 := &asserts.AtRevision{
   649  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"2222"}},
   650  		Revision: asserts.RevisionNotKnown,
   651  	}
   652  	err = pool.AddUnresolved(at2222, "for_two")
   653  	c.Assert(err, IsNil)
   654  
   655  	toResolve, err = pool.ToResolve()
   656  	c.Assert(err, IsNil)
   657  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   658  		asserts.MakePoolGrouping(1): {&asserts.AtRevision{
   659  			Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"2222"}},
   660  			Revision: 0,
   661  		}},
   662  	})
   663  
   664  	c.Check(pool.Err("for_one"), IsNil)
   665  	c.Check(pool.Err("for_two"), IsNil)
   666  }
   667  
   668  var errBoom = errors.New("boom")
   669  
   670  func (s *poolSuite) TestAddErrorEarly(c *C) {
   671  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   672  
   673  	pool := asserts.NewPool(s.db, 64)
   674  
   675  	storeKey := s.hub.StoreAccountKey("")
   676  	err := pool.AddToUpdate(storeKey.Ref(), "store_key")
   677  	c.Assert(err, IsNil)
   678  
   679  	at1111 := &asserts.AtRevision{
   680  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   681  		Revision: asserts.RevisionNotKnown,
   682  	}
   683  	err = pool.AddUnresolved(at1111, "for_one")
   684  	c.Assert(err, IsNil)
   685  
   686  	toResolve, err := pool.ToResolve()
   687  	c.Assert(err, IsNil)
   688  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   689  		asserts.MakePoolGrouping(0): {storeKey.At()},
   690  		asserts.MakePoolGrouping(1): {at1111},
   691  	})
   692  
   693  	err = pool.AddError(errBoom, storeKey.Ref())
   694  	c.Assert(err, IsNil)
   695  
   696  	ok, err := pool.Add(s.rev1_1111, asserts.MakePoolGrouping(1))
   697  	c.Assert(err, IsNil)
   698  	c.Assert(ok, Equals, true)
   699  
   700  	toResolve, err = pool.ToResolve()
   701  	c.Assert(err, IsNil)
   702  	c.Check(toResolve, HasLen, 0)
   703  
   704  	c.Check(pool.Err("store_key"), Equals, errBoom)
   705  	c.Check(pool.Err("for_one"), Equals, errBoom)
   706  }
   707  
   708  func (s *poolSuite) TestAddErrorLater(c *C) {
   709  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   710  
   711  	pool := asserts.NewPool(s.db, 64)
   712  
   713  	storeKey := s.hub.StoreAccountKey("")
   714  	err := pool.AddToUpdate(storeKey.Ref(), "store_key")
   715  	c.Assert(err, IsNil)
   716  
   717  	at1111 := &asserts.AtRevision{
   718  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   719  		Revision: asserts.RevisionNotKnown,
   720  	}
   721  	err = pool.AddUnresolved(at1111, "for_one")
   722  	c.Assert(err, IsNil)
   723  
   724  	toResolve, err := pool.ToResolve()
   725  	c.Assert(err, IsNil)
   726  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   727  		asserts.MakePoolGrouping(0): {storeKey.At()},
   728  		asserts.MakePoolGrouping(1): {at1111},
   729  	})
   730  
   731  	ok, err := pool.Add(s.rev1_1111, asserts.MakePoolGrouping(1))
   732  	c.Assert(err, IsNil)
   733  	c.Assert(ok, Equals, true)
   734  
   735  	err = pool.AddError(errBoom, storeKey.Ref())
   736  	c.Assert(err, IsNil)
   737  
   738  	toResolve, err = pool.ToResolve()
   739  	c.Assert(err, IsNil)
   740  	c.Check(toResolve, HasLen, 0)
   741  
   742  	c.Check(pool.Err("store_key"), Equals, errBoom)
   743  	c.Check(pool.Err("for_one"), Equals, errBoom)
   744  }
   745  
   746  func (s *poolSuite) TestNopUpdatePlusFetchOfPushed(c *C) {
   747  	storeKey := s.hub.StoreAccountKey("")
   748  	assertstest.AddMany(s.db, storeKey)
   749  	assertstest.AddMany(s.db, s.dev1Acct)
   750  	assertstest.AddMany(s.db, s.decl1)
   751  	assertstest.AddMany(s.db, s.rev1_1111)
   752  
   753  	pool := asserts.NewPool(s.db, 64)
   754  
   755  	atOne := s.decl1.At()
   756  	err := pool.AddToUpdate(&atOne.Ref, "for_one")
   757  	c.Assert(err, IsNil)
   758  
   759  	toResolve, err := pool.ToResolve()
   760  	c.Assert(err, IsNil)
   761  	sortToResolve(toResolve)
   762  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   763  		asserts.MakePoolGrouping(0): {storeKey.At(), s.dev1Acct.At(), atOne},
   764  	})
   765  
   766  	// no updates but
   767  	// new push suggestion
   768  
   769  	gSuggestion, err := pool.Singleton("suggestion")
   770  	c.Assert(err, IsNil)
   771  
   772  	ok, err := pool.Add(s.rev1_3333, gSuggestion)
   773  	c.Assert(err, IsNil)
   774  	c.Assert(ok, Equals, true)
   775  
   776  	toResolve, err = pool.ToResolve()
   777  	c.Assert(err, IsNil)
   778  	c.Assert(toResolve, HasLen, 0)
   779  
   780  	c.Check(pool.Err("for_one"), IsNil)
   781  
   782  	pool.AddGroupingError(errBoom, gSuggestion)
   783  
   784  	c.Assert(pool.Err("for_one"), IsNil)
   785  	c.Assert(pool.Err("suggestion"), Equals, errBoom)
   786  
   787  	at3333 := s.rev1_3333.At()
   788  	at3333.Revision = asserts.RevisionNotKnown
   789  	err = pool.AddUnresolved(at3333, at3333.Unique())
   790  	c.Assert(err, IsNil)
   791  
   792  	toResolve, err = pool.ToResolve()
   793  	c.Assert(err, IsNil)
   794  	c.Assert(toResolve, HasLen, 0)
   795  
   796  	err = pool.CommitTo(s.db)
   797  	c.Check(err, IsNil)
   798  
   799  	c.Assert(pool.Err(at3333.Unique()), IsNil)
   800  
   801  	a, err := s.rev1_3333.Ref().Resolve(s.db.Find)
   802  	c.Assert(err, IsNil)
   803  	c.Check(a.(*asserts.TestOnlyRev).H(), Equals, "3333")
   804  }
   805  
   806  func (s *poolSuite) TestAddToUpdateThenUnresolved(c *C) {
   807  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   808  
   809  	pool := asserts.NewPool(s.db, 64)
   810  
   811  	storeKey := s.hub.StoreAccountKey("")
   812  	storeKeyAt := storeKey.At()
   813  	storeKeyAt.Revision = asserts.RevisionNotKnown
   814  
   815  	err := pool.AddToUpdate(storeKey.Ref(), "for_one")
   816  	c.Assert(err, IsNil)
   817  	err = pool.AddUnresolved(storeKeyAt, "for_one")
   818  	c.Assert(err, IsNil)
   819  
   820  	toResolve, err := pool.ToResolve()
   821  	c.Assert(err, IsNil)
   822  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   823  		asserts.MakePoolGrouping(0): {storeKey.At()},
   824  	})
   825  }
   826  
   827  func (s *poolSuite) TestAddUnresolvedThenToUpdate(c *C) {
   828  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   829  
   830  	pool := asserts.NewPool(s.db, 64)
   831  
   832  	storeKey := s.hub.StoreAccountKey("")
   833  	storeKeyAt := storeKey.At()
   834  	storeKeyAt.Revision = asserts.RevisionNotKnown
   835  
   836  	err := pool.AddUnresolved(storeKeyAt, "for_one")
   837  	c.Assert(err, IsNil)
   838  	err = pool.AddToUpdate(storeKey.Ref(), "for_one")
   839  	c.Assert(err, IsNil)
   840  
   841  	toResolve, err := pool.ToResolve()
   842  	c.Assert(err, IsNil)
   843  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   844  		asserts.MakePoolGrouping(0): {storeKey.At()},
   845  	})
   846  }
   847  
   848  func (s *poolSuite) TestNopUpdatePlusFetch(c *C) {
   849  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   850  
   851  	pool := asserts.NewPool(s.db, 64)
   852  
   853  	storeKey := s.hub.StoreAccountKey("")
   854  	err := pool.AddToUpdate(storeKey.Ref(), "store_key")
   855  	c.Assert(err, IsNil)
   856  
   857  	at1111 := &asserts.AtRevision{
   858  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   859  		Revision: asserts.RevisionNotKnown,
   860  	}
   861  	err = pool.AddUnresolved(at1111, "for_one")
   862  	c.Assert(err, IsNil)
   863  
   864  	toResolve, err := pool.ToResolve()
   865  	c.Assert(err, IsNil)
   866  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   867  		asserts.MakePoolGrouping(0): {storeKey.At()},
   868  		asserts.MakePoolGrouping(1): {at1111},
   869  	})
   870  
   871  	ok, err := pool.Add(s.rev1_1111, asserts.MakePoolGrouping(1))
   872  	c.Assert(err, IsNil)
   873  	c.Assert(ok, Equals, true)
   874  
   875  	toResolve, err = pool.ToResolve()
   876  	c.Assert(err, IsNil)
   877  	sortToResolve(toResolve)
   878  	dev1AcctAt := s.dev1Acct.At()
   879  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   880  	decl1At := s.decl1.At()
   881  	decl1At.Revision = asserts.RevisionNotKnown
   882  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   883  		asserts.MakePoolGrouping(1): {dev1AcctAt, decl1At},
   884  	})
   885  
   886  	c.Check(pool.Err("store_key"), IsNil)
   887  	c.Check(pool.Err("for_one"), IsNil)
   888  }
   889  
   890  func (s *poolSuite) TestParallelPartialResolutionFailure(c *C) {
   891  	pool := asserts.NewPool(s.db, 64)
   892  
   893  	atOne := &asserts.AtRevision{
   894  		Ref:      asserts.Ref{Type: asserts.TestOnlyDeclType, PrimaryKey: []string{"one"}},
   895  		Revision: asserts.RevisionNotKnown,
   896  	}
   897  	err := pool.AddUnresolved(atOne, "one")
   898  	c.Assert(err, IsNil)
   899  
   900  	toResolve, err := pool.ToResolve()
   901  	c.Assert(err, IsNil)
   902  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   903  		asserts.MakePoolGrouping(0): {atOne},
   904  	})
   905  
   906  	ok, err := pool.Add(s.decl1, asserts.MakePoolGrouping(0))
   907  	c.Assert(err, IsNil)
   908  	c.Assert(ok, Equals, true)
   909  
   910  	toResolve, err = pool.ToResolve()
   911  	c.Assert(err, IsNil)
   912  	sortToResolve(toResolve)
   913  	dev1AcctAt := s.dev1Acct.At()
   914  	dev1AcctAt.Revision = asserts.RevisionNotKnown
   915  	decl1At := s.decl1.At()
   916  	decl1At.Revision = asserts.RevisionNotKnown
   917  	storeKeyAt := s.hub.StoreAccountKey("").At()
   918  	storeKeyAt.Revision = asserts.RevisionNotKnown
   919  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   920  		asserts.MakePoolGrouping(0): {storeKeyAt, dev1AcctAt},
   921  	})
   922  
   923  	// failed to get prereqs
   924  	c.Check(pool.AddGroupingError(errBoom, asserts.MakePoolGrouping(0)), IsNil)
   925  
   926  	err = pool.AddUnresolved(atOne, "other")
   927  	c.Assert(err, IsNil)
   928  
   929  	toResolve, err = pool.ToResolve()
   930  	c.Assert(err, IsNil)
   931  	c.Check(toResolve, HasLen, 0)
   932  
   933  	c.Check(pool.Err("one"), Equals, errBoom)
   934  	c.Check(pool.Err("other"), IsNil)
   935  
   936  	// we fail at commit though
   937  	err = pool.CommitTo(s.db)
   938  	c.Check(err, IsNil)
   939  	c.Check(pool.Err("one"), Equals, errBoom)
   940  	c.Check(pool.Err("other"), ErrorMatches, "cannot resolve prerequisite assertion.*")
   941  }
   942  
   943  func (s *poolSuite) TestAddErrors(c *C) {
   944  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   945  
   946  	pool := asserts.NewPool(s.db, 64)
   947  
   948  	storeKey := s.hub.StoreAccountKey("")
   949  	err := pool.AddToUpdate(storeKey.Ref(), "store_key")
   950  	c.Assert(err, IsNil)
   951  
   952  	at1111 := &asserts.AtRevision{
   953  		Ref:      asserts.Ref{Type: asserts.TestOnlyRevType, PrimaryKey: []string{"1111"}},
   954  		Revision: asserts.RevisionNotKnown,
   955  	}
   956  	err = pool.AddUnresolved(at1111, "for_one")
   957  	c.Assert(err, IsNil)
   958  
   959  	toResolve, err := pool.ToResolve()
   960  	c.Assert(err, IsNil)
   961  	c.Check(toResolve, HasLen, 2)
   962  
   963  	err = pool.AddError(errBoom, storeKey.Ref())
   964  	c.Assert(err, IsNil)
   965  
   966  	toResolve, err = pool.ToResolve()
   967  	c.Assert(err, IsNil)
   968  	c.Check(toResolve, HasLen, 0)
   969  
   970  	c.Check(pool.Errors(), DeepEquals, map[string]error{
   971  		"store_key": errBoom,
   972  		"for_one":   asserts.ErrUnresolved,
   973  	})
   974  }
   975  
   976  func (s *poolSuite) TestPoolReuseWithClearGroupsAndUnchanged(c *C) {
   977  	assertstest.AddMany(s.db, s.hub.StoreAccountKey(""))
   978  	assertstest.AddMany(s.db, s.dev1Acct, s.decl1)
   979  	assertstest.AddMany(s.db, s.dev2Acct, s.decl2)
   980  
   981  	pool := asserts.NewPool(s.db, 64)
   982  
   983  	err := pool.AddToUpdate(s.decl1.Ref(), "for_one") // group num: 0
   984  	c.Assert(err, IsNil)
   985  
   986  	storeKeyAt := s.hub.StoreAccountKey("").At()
   987  
   988  	toResolve, err := pool.ToResolve()
   989  	c.Assert(err, IsNil)
   990  	sortToResolve(toResolve)
   991  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
   992  		asserts.MakePoolGrouping(0): {storeKeyAt, s.dev1Acct.At(), s.decl1.At()},
   993  	})
   994  
   995  	ok, err := pool.Add(s.decl1_1, asserts.MakePoolGrouping(0))
   996  	c.Assert(err, IsNil)
   997  	c.Assert(ok, Equals, true)
   998  
   999  	toResolve, err = pool.ToResolve()
  1000  	c.Assert(err, IsNil)
  1001  	c.Check(toResolve, HasLen, 0)
  1002  
  1003  	// clear the groups as we would do for real reuse when we have
  1004  	// exhausted allowed groups
  1005  	err = pool.ClearGroups()
  1006  	c.Assert(err, IsNil)
  1007  
  1008  	err = pool.AddToUpdate(s.decl2.Ref(), "for_two") // group num: 0 again
  1009  	c.Assert(err, IsNil)
  1010  
  1011  	// no reference to store key because it is remebered as unchanged
  1012  	// across the clearing
  1013  	toResolve, err = pool.ToResolve()
  1014  	c.Assert(err, IsNil)
  1015  	sortToResolve(toResolve)
  1016  	c.Check(toResolve, DeepEquals, map[asserts.Grouping][]*asserts.AtRevision{
  1017  		asserts.MakePoolGrouping(0): {s.dev2Acct.At(), s.decl2.At()},
  1018  	})
  1019  }