github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/environs/simplestreams/simplestreams_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package simplestreams_test
     5  
     6  import (
     7  	"bytes"
     8  	"strings"
     9  	"testing"
    10  
    11  	jc "github.com/juju/testing/checkers"
    12  	"github.com/juju/utils"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/environs/simplestreams"
    16  	sstesting "github.com/juju/juju/environs/simplestreams/testing"
    17  )
    18  
    19  func Test(t *testing.T) {
    20  	registerSimpleStreamsTests()
    21  	gc.Suite(&signingSuite{})
    22  	gc.Suite(&jsonSuite{})
    23  	gc.TestingT(t)
    24  }
    25  
    26  func registerSimpleStreamsTests() {
    27  	gc.Suite(&simplestreamsSuite{
    28  		LocalLiveSimplestreamsSuite: sstesting.LocalLiveSimplestreamsSuite{
    29  			Source:         simplestreams.NewURLDataSource("test", "test:", utils.VerifySSLHostnames),
    30  			RequireSigned:  false,
    31  			DataType:       "image-ids",
    32  			StreamsVersion: "v1",
    33  			ValidConstraint: sstesting.NewTestConstraint(simplestreams.LookupParams{
    34  				CloudSpec: simplestreams.CloudSpec{
    35  					Region:   "us-east-1",
    36  					Endpoint: "https://ec2.us-east-1.amazonaws.com",
    37  				},
    38  				Series: []string{"precise"},
    39  				Arches: []string{"amd64", "arm"},
    40  			}),
    41  		},
    42  	})
    43  }
    44  
    45  type simplestreamsSuite struct {
    46  	sstesting.TestDataSuite
    47  	sstesting.LocalLiveSimplestreamsSuite
    48  }
    49  
    50  func (s *simplestreamsSuite) SetUpSuite(c *gc.C) {
    51  	s.LocalLiveSimplestreamsSuite.SetUpSuite(c)
    52  	s.TestDataSuite.SetUpSuite(c)
    53  }
    54  
    55  func (s *simplestreamsSuite) TearDownSuite(c *gc.C) {
    56  	s.TestDataSuite.TearDownSuite(c)
    57  	s.LocalLiveSimplestreamsSuite.TearDownSuite(c)
    58  }
    59  
    60  func (s *simplestreamsSuite) TestGetProductsPath(c *gc.C) {
    61  	indexRef, err := s.GetIndexRef(sstesting.Index_v1)
    62  	c.Assert(err, jc.ErrorIsNil)
    63  	path, err := indexRef.GetProductsPath(s.ValidConstraint)
    64  	c.Assert(err, jc.ErrorIsNil)
    65  	c.Assert(path, gc.Equals, "streams/v1/image_metadata.json")
    66  }
    67  
    68  func (*simplestreamsSuite) TestExtractCatalogsForProductsAcceptsNil(c *gc.C) {
    69  	empty := simplestreams.CloudMetadata{}
    70  	c.Check(simplestreams.ExtractCatalogsForProducts(empty, nil), gc.HasLen, 0)
    71  }
    72  
    73  func (*simplestreamsSuite) TestExtractCatalogsForProductsReturnsMatch(c *gc.C) {
    74  	metadata := simplestreams.CloudMetadata{
    75  		Products: map[string]simplestreams.MetadataCatalog{
    76  			"foo": {},
    77  		},
    78  	}
    79  	c.Check(
    80  		simplestreams.ExtractCatalogsForProducts(metadata, []string{"foo"}),
    81  		gc.DeepEquals,
    82  		[]simplestreams.MetadataCatalog{metadata.Products["foo"]})
    83  }
    84  
    85  func (*simplestreamsSuite) TestExtractCatalogsForProductsIgnoresNonMatches(c *gc.C) {
    86  	metadata := simplestreams.CloudMetadata{
    87  		Products: map[string]simplestreams.MetadataCatalog{
    88  			"one-product": {},
    89  		},
    90  	}
    91  	absentProducts := []string{"another-product"}
    92  	c.Check(simplestreams.ExtractCatalogsForProducts(metadata, absentProducts), gc.HasLen, 0)
    93  }
    94  
    95  func (*simplestreamsSuite) TestExtractCatalogsForProductsPreservesOrder(c *gc.C) {
    96  	products := map[string]simplestreams.MetadataCatalog{
    97  		"1": {},
    98  		"2": {},
    99  		"3": {},
   100  		"4": {},
   101  	}
   102  
   103  	metadata := simplestreams.CloudMetadata{Products: products}
   104  
   105  	c.Check(
   106  		simplestreams.ExtractCatalogsForProducts(metadata, []string{"1", "3", "4", "2"}),
   107  		gc.DeepEquals,
   108  		[]simplestreams.MetadataCatalog{
   109  			products["1"],
   110  			products["3"],
   111  			products["4"],
   112  			products["2"],
   113  		})
   114  }
   115  
   116  func (*simplestreamsSuite) TestExtractIndexesAcceptsEmpty(c *gc.C) {
   117  	ind := simplestreams.Indices{}
   118  	c.Check(simplestreams.ExtractIndexes(ind, nil), gc.HasLen, 0)
   119  }
   120  
   121  func (*simplestreamsSuite) TestExtractIndexesReturnsIndex(c *gc.C) {
   122  	metadata := simplestreams.IndexMetadata{}
   123  	ind := simplestreams.Indices{Indexes: map[string]*simplestreams.IndexMetadata{"foo": &metadata}}
   124  	c.Check(simplestreams.ExtractIndexes(ind, nil), gc.DeepEquals, simplestreams.IndexMetadataSlice{&metadata})
   125  }
   126  
   127  func (*simplestreamsSuite) TestExtractIndexesReturnsAllIndexes(c *gc.C) {
   128  	ind := simplestreams.Indices{
   129  		Indexes: map[string]*simplestreams.IndexMetadata{
   130  			"foo": {},
   131  			"bar": {},
   132  		},
   133  	}
   134  
   135  	array := simplestreams.ExtractIndexes(ind, nil)
   136  
   137  	c.Assert(array, gc.HasLen, len(ind.Indexes))
   138  	c.Check(array[0], gc.NotNil)
   139  	c.Check(array[1], gc.NotNil)
   140  	c.Check(array[0], gc.Not(gc.Equals), array[1])
   141  	c.Check(
   142  		(array[0] == ind.Indexes["foo"]),
   143  		gc.Not(gc.Equals),
   144  		(array[1] == ind.Indexes["foo"]))
   145  	c.Check(
   146  		(array[0] == ind.Indexes["bar"]),
   147  		gc.Not(gc.Equals),
   148  		(array[1] == ind.Indexes["bar"]))
   149  }
   150  
   151  func (*simplestreamsSuite) TestExtractIndexesReturnsSpecifiedIndexes(c *gc.C) {
   152  	ind := simplestreams.Indices{
   153  		Indexes: map[string]*simplestreams.IndexMetadata{
   154  			"foo":    {},
   155  			"bar":    {},
   156  			"foobar": {},
   157  		},
   158  	}
   159  
   160  	array := simplestreams.ExtractIndexes(ind, []string{"foobar"})
   161  	c.Assert(array, gc.HasLen, 1)
   162  	c.Assert(array[0], gc.Equals, ind.Indexes["foobar"])
   163  }
   164  
   165  func (*simplestreamsSuite) TestHasCloudAcceptsNil(c *gc.C) {
   166  	metadata := simplestreams.IndexMetadata{Clouds: nil}
   167  	c.Check(simplestreams.HasCloud(metadata, simplestreams.CloudSpec{}), jc.IsTrue)
   168  }
   169  
   170  func (*simplestreamsSuite) TestHasCloudFindsMatch(c *gc.C) {
   171  	metadata := simplestreams.IndexMetadata{
   172  		Clouds: []simplestreams.CloudSpec{
   173  			{Region: "r1", Endpoint: "http://e1"},
   174  			{Region: "r2", Endpoint: "http://e2"},
   175  		},
   176  	}
   177  	c.Check(simplestreams.HasCloud(metadata, metadata.Clouds[1]), jc.IsTrue)
   178  }
   179  
   180  func (*simplestreamsSuite) TestHasCloudFindsMatchWithTrailingSlash(c *gc.C) {
   181  	metadata := simplestreams.IndexMetadata{
   182  		Clouds: []simplestreams.CloudSpec{
   183  			{Region: "r1", Endpoint: "http://e1/"},
   184  			{Region: "r2", Endpoint: "http://e2"},
   185  		},
   186  	}
   187  	spec := simplestreams.CloudSpec{Region: "r1", Endpoint: "http://e1"}
   188  	c.Check(simplestreams.HasCloud(metadata, spec), jc.IsTrue)
   189  	spec = simplestreams.CloudSpec{Region: "r1", Endpoint: "http://e1/"}
   190  	c.Check(simplestreams.HasCloud(metadata, spec), jc.IsTrue)
   191  	spec = simplestreams.CloudSpec{Region: "r2", Endpoint: "http://e2/"}
   192  	c.Check(simplestreams.HasCloud(metadata, spec), jc.IsTrue)
   193  }
   194  
   195  func (*simplestreamsSuite) TestHasCloudReturnsFalseIfCloudsDoNotMatch(c *gc.C) {
   196  	metadata := simplestreams.IndexMetadata{
   197  		Clouds: []simplestreams.CloudSpec{
   198  			{Region: "r1", Endpoint: "http://e1"},
   199  			{Region: "r2", Endpoint: "http://e2"},
   200  		},
   201  	}
   202  	otherCloud := simplestreams.CloudSpec{Region: "r9", Endpoint: "http://e9"}
   203  	c.Check(simplestreams.HasCloud(metadata, otherCloud), jc.IsFalse)
   204  }
   205  
   206  func (*simplestreamsSuite) TestHasCloudRequiresIdenticalRegion(c *gc.C) {
   207  	metadata := simplestreams.IndexMetadata{
   208  		Clouds: []simplestreams.CloudSpec{
   209  			{Region: "around", Endpoint: "http://nearby"},
   210  		},
   211  	}
   212  	similarCloud := metadata.Clouds[0]
   213  	similarCloud.Region = "elsewhere"
   214  	c.Assert(similarCloud, gc.Not(gc.Equals), metadata.Clouds[0])
   215  
   216  	c.Check(simplestreams.HasCloud(metadata, similarCloud), jc.IsFalse)
   217  }
   218  
   219  func (*simplestreamsSuite) TestHasCloudRequiresIdenticalEndpoint(c *gc.C) {
   220  	metadata := simplestreams.IndexMetadata{
   221  		Clouds: []simplestreams.CloudSpec{
   222  			{Region: "around", Endpoint: "http://nearby"},
   223  		},
   224  	}
   225  	similarCloud := metadata.Clouds[0]
   226  	similarCloud.Endpoint = "http://far"
   227  	c.Assert(similarCloud, gc.Not(gc.Equals), metadata.Clouds[0])
   228  
   229  	c.Check(simplestreams.HasCloud(metadata, similarCloud), jc.IsFalse)
   230  }
   231  
   232  func (*simplestreamsSuite) TestHasProductAcceptsNils(c *gc.C) {
   233  	metadata := simplestreams.IndexMetadata{}
   234  	c.Check(simplestreams.HasProduct(metadata, nil), jc.IsFalse)
   235  }
   236  
   237  func (*simplestreamsSuite) TestHasProductFindsMatchingProduct(c *gc.C) {
   238  	metadata := simplestreams.IndexMetadata{ProductIds: []string{"x", "y", "z"}}
   239  	c.Check(
   240  		simplestreams.HasProduct(metadata, []string{"a", "b", metadata.ProductIds[1]}),
   241  		gc.Equals,
   242  		true)
   243  }
   244  
   245  func (*simplestreamsSuite) TestHasProductReturnsFalseIfProductsDoNotMatch(c *gc.C) {
   246  	metadata := simplestreams.IndexMetadata{ProductIds: []string{"x", "y", "z"}}
   247  	c.Check(simplestreams.HasProduct(metadata, []string{"a", "b", "c"}), jc.IsFalse)
   248  }
   249  
   250  func (*simplestreamsSuite) TestFilterReturnsNothingForEmptyArray(c *gc.C) {
   251  	empty := simplestreams.IndexMetadataSlice{}
   252  	c.Check(
   253  		simplestreams.Filter(empty, func(*simplestreams.IndexMetadata) bool { return true }),
   254  		gc.HasLen,
   255  		0)
   256  }
   257  
   258  func (*simplestreamsSuite) TestFilterRemovesNonMatches(c *gc.C) {
   259  	array := simplestreams.IndexMetadataSlice{&simplestreams.IndexMetadata{}}
   260  	c.Check(
   261  		simplestreams.Filter(array, func(*simplestreams.IndexMetadata) bool { return false }),
   262  		gc.HasLen,
   263  		0)
   264  }
   265  
   266  func (*simplestreamsSuite) TestFilterIncludesMatches(c *gc.C) {
   267  	metadata := simplestreams.IndexMetadata{}
   268  	array := simplestreams.IndexMetadataSlice{&metadata}
   269  	c.Check(
   270  		simplestreams.Filter(array, func(*simplestreams.IndexMetadata) bool { return true }),
   271  		gc.DeepEquals,
   272  		simplestreams.IndexMetadataSlice{&metadata})
   273  }
   274  
   275  func (*simplestreamsSuite) TestFilterLeavesOriginalUnchanged(c *gc.C) {
   276  	item1 := simplestreams.IndexMetadata{CloudName: "aws"}
   277  	item2 := simplestreams.IndexMetadata{CloudName: "openstack"}
   278  	array := simplestreams.IndexMetadataSlice{&item1, &item2}
   279  
   280  	result := simplestreams.Filter(array, func(metadata *simplestreams.IndexMetadata) bool {
   281  		return metadata.CloudName == "aws"
   282  	})
   283  	// This exercises both the "leave out" and the "include" code paths.
   284  	c.Assert(result, gc.HasLen, 1)
   285  
   286  	// The original, however, has not changed.
   287  	c.Assert(array, gc.HasLen, 2)
   288  	c.Check(array, gc.DeepEquals, simplestreams.IndexMetadataSlice{&item1, &item2})
   289  }
   290  
   291  func (*simplestreamsSuite) TestFilterPreservesOrder(c *gc.C) {
   292  	array := simplestreams.IndexMetadataSlice{
   293  		&simplestreams.IndexMetadata{CloudName: "aws"},
   294  		&simplestreams.IndexMetadata{CloudName: "maas"},
   295  		&simplestreams.IndexMetadata{CloudName: "openstack"},
   296  	}
   297  
   298  	c.Check(
   299  		simplestreams.Filter(array, func(metadata *simplestreams.IndexMetadata) bool { return true }),
   300  		gc.DeepEquals,
   301  		array)
   302  }
   303  
   304  func (*simplestreamsSuite) TestFilterCombinesMatchesAndNonMatches(c *gc.C) {
   305  	array := simplestreams.IndexMetadataSlice{
   306  		&simplestreams.IndexMetadata{Format: "1.0"},
   307  		&simplestreams.IndexMetadata{Format: "1.1"},
   308  		&simplestreams.IndexMetadata{Format: "2.0"},
   309  		&simplestreams.IndexMetadata{Format: "2.1"},
   310  	}
   311  
   312  	dotOFormats := simplestreams.Filter(array, func(metadata *simplestreams.IndexMetadata) bool {
   313  		return strings.HasSuffix(metadata.Format, ".0")
   314  	})
   315  
   316  	c.Check(dotOFormats, gc.DeepEquals, simplestreams.IndexMetadataSlice{array[0], array[2]})
   317  }
   318  
   319  // countingSource is used to check that a DataSource has been queried.
   320  type countingSource struct {
   321  	simplestreams.DataSource
   322  	count int
   323  }
   324  
   325  func (s *countingSource) URL(path string) (string, error) {
   326  	s.count++
   327  	return s.DataSource.URL(path)
   328  }
   329  
   330  func (s *simplestreamsSuite) TestGetMetadataNoMatching(c *gc.C) {
   331  	source := &countingSource{
   332  		DataSource: simplestreams.NewURLDataSource(
   333  			"test", "test:/daily", utils.VerifySSLHostnames,
   334  		),
   335  	}
   336  	sources := []simplestreams.DataSource{source, source, source}
   337  	constraint := sstesting.NewTestConstraint(simplestreams.LookupParams{
   338  		CloudSpec: simplestreams.CloudSpec{
   339  			Region:   "us-east-1",
   340  			Endpoint: "https://ec2.us-east-1.amazonaws.com",
   341  		},
   342  		Series: []string{"precise"},
   343  		Arches: []string{"not-a-real-arch"}, // never matches
   344  	})
   345  	params := simplestreams.GetMetadataParams{
   346  		StreamsVersion:   s.StreamsVersion,
   347  		LookupConstraint: constraint,
   348  		ValueParams:      simplestreams.ValueParams{DataType: "image-ids"},
   349  	}
   350  
   351  	items, resolveInfo, err := simplestreams.GetMetadata(sources, params)
   352  	c.Assert(err, jc.ErrorIsNil)
   353  	c.Assert(items, gc.HasLen, 0)
   354  	c.Assert(resolveInfo, gc.DeepEquals, &simplestreams.ResolveInfo{
   355  		Source:    "test",
   356  		Signed:    false,
   357  		IndexURL:  "test:/daily/streams/v1/index.json",
   358  		MirrorURL: "",
   359  	})
   360  
   361  	// There should be 4 calls to each data-source:
   362  	// one for .sjson, one for .json, repeated for legacy vs new index files.
   363  	c.Assert(source.count, gc.Equals, 4*len(sources))
   364  }
   365  
   366  func (s *simplestreamsSuite) TestMetadataCatalog(c *gc.C) {
   367  	metadata := s.AssertGetMetadata(c)
   368  	c.Check(len(metadata.Products), gc.Equals, 3)
   369  	c.Check(len(metadata.Aliases), gc.Equals, 1)
   370  	metadataCatalog := metadata.Products["com.ubuntu.cloud:server:12.04:amd64"]
   371  	c.Check(len(metadataCatalog.Items), gc.Equals, 2)
   372  	c.Check(metadataCatalog.Series, gc.Equals, "precise")
   373  	c.Check(metadataCatalog.Version, gc.Equals, "12.04")
   374  	c.Check(metadataCatalog.Arch, gc.Equals, "amd64")
   375  	c.Check(metadataCatalog.RegionName, gc.Equals, "au-east-1")
   376  	c.Check(metadataCatalog.Endpoint, gc.Equals, "https://somewhere")
   377  }
   378  
   379  func (s *simplestreamsSuite) TestItemCollection(c *gc.C) {
   380  	ic := s.AssertGetItemCollections(c, "20121218")
   381  	c.Check(ic.RegionName, gc.Equals, "au-east-2")
   382  	c.Check(ic.Endpoint, gc.Equals, "https://somewhere-else")
   383  	c.Assert(len(ic.Items) > 0, jc.IsTrue)
   384  	ti := ic.Items["usww2he"].(*sstesting.TestItem)
   385  	c.Check(ti.Id, gc.Equals, "ami-442ea674")
   386  	c.Check(ti.Storage, gc.Equals, "ebs")
   387  	c.Check(ti.VirtType, gc.Equals, "hvm")
   388  	c.Check(ti.RegionName, gc.Equals, "us-east-1")
   389  	c.Check(ti.Endpoint, gc.Equals, "https://ec2.us-east-1.amazonaws.com")
   390  }
   391  
   392  func (s *simplestreamsSuite) TestDenormalisationFromCollection(c *gc.C) {
   393  	ic := s.AssertGetItemCollections(c, "20121218")
   394  	ti := ic.Items["usww1pe"].(*sstesting.TestItem)
   395  	c.Check(ti.RegionName, gc.Equals, ic.RegionName)
   396  	c.Check(ti.Endpoint, gc.Equals, ic.Endpoint)
   397  }
   398  
   399  func (s *simplestreamsSuite) TestDenormalisationFromCatalog(c *gc.C) {
   400  	metadata := s.AssertGetMetadata(c)
   401  	metadataCatalog := metadata.Products["com.ubuntu.cloud:server:12.04:amd64"]
   402  	ic := metadataCatalog.Items["20111111"]
   403  	ti := ic.Items["usww3pe"].(*sstesting.TestItem)
   404  	c.Check(ti.RegionName, gc.Equals, metadataCatalog.RegionName)
   405  	c.Check(ti.Endpoint, gc.Equals, metadataCatalog.Endpoint)
   406  }
   407  
   408  func (s *simplestreamsSuite) TestDenormalisationFromTopLevel(c *gc.C) {
   409  	metadata := s.AssertGetMetadata(c)
   410  	metadataCatalog := metadata.Products["com.ubuntu.cloud:server:14.04:amd64"]
   411  	ic := metadataCatalog.Items["20140118"]
   412  	ti := ic.Items["nzww1pe"].(*sstesting.TestItem)
   413  	c.Check(ti.RegionName, gc.Equals, metadata.RegionName)
   414  	c.Check(ti.Endpoint, gc.Equals, metadata.Endpoint)
   415  }
   416  
   417  func (s *simplestreamsSuite) TestDealiasing(c *gc.C) {
   418  	metadata := s.AssertGetMetadata(c)
   419  	metadataCatalog := metadata.Products["com.ubuntu.cloud:server:12.04:amd64"]
   420  	ic := metadataCatalog.Items["20121218"]
   421  	ti := ic.Items["usww3he"].(*sstesting.TestItem)
   422  	c.Check(ti.RegionName, gc.Equals, "us-west-3")
   423  	c.Check(ti.Endpoint, gc.Equals, "https://ec2.us-west-3.amazonaws.com")
   424  }
   425  
   426  var getMirrorTests = []struct {
   427  	region    string
   428  	endpoint  string
   429  	err       string
   430  	mirrorURL string
   431  	path      string
   432  }{{
   433  	// defaults
   434  	mirrorURL: "http://some-mirror/",
   435  	path:      "com.ubuntu.juju:download.json",
   436  }, {
   437  	// default mirror index entry
   438  	region:    "some-region",
   439  	endpoint:  "https://some-endpoint.com",
   440  	mirrorURL: "http://big-mirror/",
   441  	path:      "big:download.json",
   442  }, {
   443  	// endpoint with trailing "/"
   444  	region:    "some-region",
   445  	endpoint:  "https://some-endpoint.com/",
   446  	mirrorURL: "http://big-mirror/",
   447  	path:      "big:download.json",
   448  }}
   449  
   450  func (s *simplestreamsSuite) TestGetMirrorMetadata(c *gc.C) {
   451  	for i, t := range getMirrorTests {
   452  		c.Logf("test %d", i)
   453  		if t.region == "" {
   454  			t.region = "us-east-2"
   455  		}
   456  		if t.endpoint == "" {
   457  			t.endpoint = "https://ec2.us-east-2.amazonaws.com"
   458  		}
   459  		cloud := simplestreams.CloudSpec{t.region, t.endpoint}
   460  		params := simplestreams.ValueParams{
   461  			DataType:        "content-download",
   462  			MirrorContentId: "com.ubuntu.juju:released:tools",
   463  		}
   464  		indexRef, err := simplestreams.GetIndexWithFormat(
   465  			s.Source, s.IndexPath(), sstesting.Index_v1,
   466  			simplestreams.MirrorsPath("v1"), s.RequireSigned, cloud, params)
   467  		if !c.Check(err, jc.ErrorIsNil) {
   468  			continue
   469  		}
   470  		if t.err != "" {
   471  			c.Check(err, gc.ErrorMatches, t.err)
   472  			continue
   473  		}
   474  		if !c.Check(err, jc.ErrorIsNil) {
   475  			continue
   476  		}
   477  		mirrorURL, err := indexRef.Source.URL("")
   478  		if !c.Check(err, jc.ErrorIsNil) {
   479  			continue
   480  		}
   481  		c.Check(mirrorURL, gc.Equals, t.mirrorURL)
   482  		c.Check(indexRef.MirroredProductsPath, gc.Equals, t.path)
   483  	}
   484  }
   485  
   486  var testSigningKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
   487  Version: GnuPG v1.4.10 (GNU/Linux)
   488  
   489  lQHYBE2rFNoBBADFwqWQIW/DSqcB4yCQqnAFTJ27qS5AnB46ccAdw3u4Greeu3Bp
   490  idpoHdjULy7zSKlwR1EA873dO/k/e11Ml3dlAFUinWeejWaK2ugFP6JjiieSsrKn
   491  vWNicdCS4HTWn0X4sjl0ZiAygw6GNhqEQ3cpLeL0g8E9hnYzJKQ0LWJa0QARAQAB
   492  AAP/TB81EIo2VYNmTq0pK1ZXwUpxCrvAAIG3hwKjEzHcbQznsjNvPUihZ+NZQ6+X
   493  0HCfPAdPkGDCLCb6NavcSW+iNnLTrdDnSI6+3BbIONqWWdRDYJhqZCkqmG6zqSfL
   494  IdkJgCw94taUg5BWP/AAeQrhzjChvpMQTVKQL5mnuZbUCeMCAN5qrYMP2S9iKdnk
   495  VANIFj7656ARKt/nf4CBzxcpHTyB8+d2CtPDKCmlJP6vL8t58Jmih+kHJMvC0dzn
   496  gr5f5+sCAOOe5gt9e0am7AvQWhdbHVfJU0TQJx+m2OiCJAqGTB1nvtBLHdJnfdC9
   497  TnXXQ6ZXibqLyBies/xeY2sCKL5qtTMCAKnX9+9d/5yQxRyrQUHt1NYhaXZnJbHx
   498  q4ytu0eWz+5i68IYUSK69jJ1NWPM0T6SkqpB3KCAIv68VFm9PxqG1KmhSrQIVGVz
   499  dCBLZXmIuAQTAQIAIgUCTasU2gIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
   500  CgkQO9o98PRieSoLhgQAkLEZex02Qt7vGhZzMwuN0R22w3VwyYyjBx+fM3JFETy1
   501  ut4xcLJoJfIaF5ZS38UplgakHG0FQ+b49i8dMij0aZmDqGxrew1m4kBfjXw9B/v+
   502  eIqpODryb6cOSwyQFH0lQkXC040pjq9YqDsO5w0WYNXYKDnzRV0p4H1pweo2VDid
   503  AdgETasU2gEEAN46UPeWRqKHvA99arOxee38fBt2CI08iiWyI8T3J6ivtFGixSqV
   504  bRcPxYO/qLpVe5l84Nb3X71GfVXlc9hyv7CD6tcowL59hg1E/DC5ydI8K8iEpUmK
   505  /UnHdIY5h8/kqgGxkY/T/hgp5fRQgW1ZoZxLajVlMRZ8W4tFtT0DeA+JABEBAAEA
   506  A/0bE1jaaZKj6ndqcw86jd+QtD1SF+Cf21CWRNeLKnUds4FRRvclzTyUMuWPkUeX
   507  TaNNsUOFqBsf6QQ2oHUBBK4VCHffHCW4ZEX2cd6umz7mpHW6XzN4DECEzOVksXtc
   508  lUC1j4UB91DC/RNQqwX1IV2QLSwssVotPMPqhOi0ZLNY7wIA3n7DWKInxYZZ4K+6
   509  rQ+POsz6brEoRHwr8x6XlHenq1Oki855pSa1yXIARoTrSJkBtn5oI+f8AzrnN0BN
   510  oyeQAwIA/7E++3HDi5aweWrViiul9cd3rcsS0dEnksPhvS0ozCJiHsq/6GFmy7J8
   511  QSHZPteedBnZyNp5jR+H7cIfVN3KgwH/Skq4PsuPhDq5TKK6i8Pc1WW8MA6DXTdU
   512  nLkX7RGmMwjC0DBf7KWAlPjFaONAX3a8ndnz//fy1q7u2l9AZwrj1qa1iJ8EGAEC
   513  AAkFAk2rFNoCGwwACgkQO9o98PRieSo2/QP/WTzr4ioINVsvN1akKuekmEMI3LAp
   514  BfHwatufxxP1U+3Si/6YIk7kuPB9Hs+pRqCXzbvPRrI8NHZBmc8qIGthishdCYad
   515  AHcVnXjtxrULkQFGbGvhKURLvS9WnzD/m1K2zzwxzkPTzT9/Yf06O6Mal5AdugPL
   516  VrM0m72/jnpKo04=
   517  =zNCn
   518  -----END PGP PRIVATE KEY BLOCK-----
   519  `
   520  
   521  var validClearsignInput = `
   522  -----BEGIN PGP SIGNED MESSAGE-----
   523  Hash: SHA1
   524  
   525  Hello world
   526  line 2
   527  `
   528  
   529  var invalidClearsignInput = `
   530  -----BEGIN PGP SIGNED MESSAGE-----
   531  Hash: SHA1
   532  
   533  Invalid
   534  `
   535  
   536  var testSig = `-----BEGIN PGP SIGNATURE-----
   537  Version: GnuPG v1.4.10 (GNU/Linux)
   538  
   539  iJwEAQECAAYFAk8kMuEACgkQO9o98PRieSpMsAQAhmY/vwmNpflrPgmfWsYhk5O8
   540  pjnBUzZwqTDoDeINjZEoPDSpQAHGhjFjgaDx/Gj4fAl0dM4D0wuUEBb6QOrwflog
   541  2A2k9kfSOMOtk0IH/H5VuFN1Mie9L/erYXjTQIptv9t9J7NoRBMU0QOOaFU0JaO9
   542  MyTpno24AjIAGb+mH1U=
   543  =hIJ6
   544  -----END PGP SIGNATURE-----
   545  `
   546  
   547  type signingSuite struct{}
   548  
   549  func (s *signingSuite) TestDecodeCheckValidSignature(c *gc.C) {
   550  	r := bytes.NewReader([]byte(validClearsignInput + testSig))
   551  	txt, err := simplestreams.DecodeCheckSignature(r, testSigningKey)
   552  	c.Assert(err, jc.ErrorIsNil)
   553  	c.Assert(txt, gc.DeepEquals, []byte("Hello world\nline 2\n"))
   554  }
   555  
   556  func (s *signingSuite) TestDecodeCheckInvalidSignature(c *gc.C) {
   557  	r := bytes.NewReader([]byte(invalidClearsignInput + testSig))
   558  	_, err := simplestreams.DecodeCheckSignature(r, testSigningKey)
   559  	c.Assert(err, gc.Not(gc.IsNil))
   560  	_, ok := err.(*simplestreams.NotPGPSignedError)
   561  	c.Assert(ok, jc.IsFalse)
   562  }
   563  
   564  func (s *signingSuite) TestDecodeCheckMissingSignature(c *gc.C) {
   565  	r := bytes.NewReader([]byte("foo"))
   566  	_, err := simplestreams.DecodeCheckSignature(r, testSigningKey)
   567  	_, ok := err.(*simplestreams.NotPGPSignedError)
   568  	c.Assert(ok, jc.IsTrue)
   569  }