github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/environs/simplestreams/testing/testing.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package testing
     5  
     6  // Provides a TestDataSuite which creates and provides http access to sample simplestreams metadata.
     7  
     8  import (
     9  	"fmt"
    10  	"io"
    11  	"net/http"
    12  	"strings"
    13  
    14  	jujuhttp "github.com/juju/http/v2"
    15  	jc "github.com/juju/testing/checkers"
    16  	gc "gopkg.in/check.v1"
    17  
    18  	"github.com/juju/juju/environs/simplestreams"
    19  	"github.com/juju/juju/testing"
    20  )
    21  
    22  var PrivateKeyPassphrase = "12345"
    23  
    24  var SignedMetadataPrivateKey = `
    25  -----BEGIN PGP PRIVATE KEY BLOCK-----
    26  Version: GnuPG v1.4.12 (GNU/Linux)
    27  
    28  lQH+BFJCk2EBBAC4wo3+aJ0PSeE54sv+GYNYckqysjazcZfJSdPK1GCN+Teat7ey
    29  9dwlLhUIS34H29V+0/RcXmmRV+dObSkXzCx5ltKPSnuDsxvqiDEP0CgWdyFxhDf0
    30  TbQuKK5OXcZ9rOTSFmnMxGaAzaV7T1IyuqA9HqntTIfC2tL4Y+QN41gS+QARAQAB
    31  /gMDAjYGIOoxe8CYYGwpat1V7NGuphvvZRpqeP0RrJ6h4vHV3hXu5NK3tn6LZF0n
    32  Qp31LfTH4BHF091UTiebexuuF1/ixLVihtv45mEVejFG1U3G298+WkWUP6AYA/5c
    33  QRzXGiuTXlsBUuFVTGn1mvxRmG3yVoLkDj0l5rN9Tq3Ir4BACIWyxjBv1n8fqw+x
    34  ti4b7YoE35FpIXQqLOdfdcKTOqUJt+5c+bed4Yx82BsLiY2/huqG2dLnbwln80Dz
    35  iYudtG8xLJ1AeHBBFB0nVdyO+mPzXgLNEbP3zle2W+rUfz+s6te7y+rlV0gad2VG
    36  tBAvUy08T9rDk0DNQl7jMq/3cGfDI1Zi/nzf2BuuBu2ddgIRmsXgKYly+Fq6eIpa
    37  nM+P1hd1Fa3rQwUSJc/zrl48tukf8sdPLDk/+nMhLHy86jp+NeXyXPLvsMAlF5kR
    38  eFjxEjHOnJlo4uIUxvlUuePyEOEl0XkQfZs+VWAPo+l2tB5UZXN0IFVzZXIgPHRl
    39  c3RAc29tZXdoZXJlLmNvbT6IuAQTAQIAIgUCUkKTYQIbAwYLCQgHAwIGFQgCCQoL
    40  BBYCAwECHgECF4AACgkQuK3uqWB66vCVugP/eJFir6Qdcvl+y9/HuP4q2iECi8ny
    41  z9tC3YC9DcJePyoBnt1LJO3HvaquZh1AIr6hgMFaujjx6cCb7YEgE0pJ4m74dvtS
    42  Y03MUPQ+Ok4cYV66zaDZLk6zpYJXZhxP7ZhlBvwQRES/rudBEQMfBcU9PrduFU39
    43  iI+2ojHI4lsnMQE=
    44  =UUIf
    45  -----END PGP PRIVATE KEY BLOCK-----
    46  `
    47  
    48  var SignedMetadataPublicKey = `
    49  -----BEGIN PGP PUBLIC KEY BLOCK-----
    50  Version: GnuPG v1.4.12 (GNU/Linux)
    51  
    52  mI0EUkKTYQEEALjCjf5onQ9J4Tniy/4Zg1hySrKyNrNxl8lJ08rUYI35N5q3t7L1
    53  3CUuFQhLfgfb1X7T9FxeaZFX505tKRfMLHmW0o9Ke4OzG+qIMQ/QKBZ3IXGEN/RN
    54  tC4ork5dxn2s5NIWaczEZoDNpXtPUjK6oD0eqe1Mh8La0vhj5A3jWBL5ABEBAAG0
    55  HlRlc3QgVXNlciA8dGVzdEBzb21ld2hlcmUuY29tPoi4BBMBAgAiBQJSQpNhAhsD
    56  BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRC4re6pYHrq8JW6A/94kWKvpB1y
    57  +X7L38e4/iraIQKLyfLP20LdgL0Nwl4/KgGe3Usk7ce9qq5mHUAivqGAwVq6OPHp
    58  wJvtgSATSknibvh2+1JjTcxQ9D46ThxhXrrNoNkuTrOlgldmHE/tmGUG/BBERL+u
    59  50ERAx8FxT0+t24VTf2Ij7aiMcjiWycxAQ==
    60  =zBYH
    61  -----END PGP PUBLIC KEY BLOCK-----`
    62  
    63  var imageData = map[string]string{
    64  	"/daily/streams/v1/index.json": `
    65          {
    66           "index": {
    67            "com.ubuntu.cloud:released:raring": {
    68             "updated": "Wed, 01 May 2013 13:31:26 +0000",
    69             "clouds": [
    70              {
    71               "region": "us-east-1",
    72               "endpoint": "https://ec2.us-east-1.amazonaws.com"
    73              }
    74             ],
    75             "cloudname": "aws",
    76             "datatype": "image-ids",
    77             "format": "products:1.0",
    78             "products": [
    79              "com.ubuntu.cloud:server:13.04:amd64"
    80             ],
    81             "path": "streams/v1/raring_metadata.json"
    82            }
    83           },
    84           "updated": "Wed, 01 May 2013 13:31:26 +0000",
    85           "format": "index:1.0"
    86          }
    87      `,
    88  	"/streams/v1/index.json": `
    89  		{
    90  		 "index": {
    91  		  "com.ubuntu.cloud:released:precise": {
    92  		   "updated": "Wed, 01 May 2013 13:31:26 +0000",
    93  		   "clouds": [
    94  		    {
    95  		     "region": "us-east-1",
    96  		     "endpoint": "https://ec2.us-east-1.amazonaws.com"
    97  		    }
    98  		   ],
    99  		   "cloudname": "aws",
   100  		   "datatype": "image-ids",
   101  		   "format": "products:1.0",
   102  		   "products": [
   103  		    "com.ubuntu.cloud:server:12.04:amd64",
   104   		    "com.ubuntu.cloud:server:12.10:amd64",
   105   		    "com.ubuntu.cloud:server:13.04:amd64",
   106   		    "com.ubuntu.cloud:server:14.04:amd64",
   107   		    "com.ubuntu.cloud:server:14.10:amd64",
   108   		    "com.ubuntu.cloud:server:12.04:arm"
   109  		   ],
   110  		   "path": "streams/v1/image_metadata.json"
   111  		  },
   112  		  "com.ubuntu.cloud:released:raring": {
   113  		   "updated": "Wed, 01 May 2013 13:31:26 +0000",
   114  		   "clouds": [
   115  		    {
   116  		     "region": "us-east-1",
   117  		     "endpoint": "https://ec2.us-east-1.amazonaws.com"
   118  		    }
   119  		   ],
   120  		   "cloudname": "aws",
   121  		   "datatype": "image-ids",
   122  		   "format": "products:1.0",
   123  		   "products": [
   124  		    "com.ubuntu.cloud:server:13.04:amd64"
   125  		   ],
   126  		   "path": "streams/v1/raring_metadata.json"
   127  		  },
   128  		  "com.ubuntu.cloud:released:download": {
   129  		   "datatype": "content-download",
   130  		   "path": "streams/v1/com.ubuntu.cloud:released:download.json",
   131  		   "updated": "Wed, 01 May 2013 13:30:37 +0000",
   132  		   "products": [
   133  		    "com.ubuntu.cloud:server:12.10:amd64",
   134  		    "com.ubuntu.cloud:server:13.04:amd64"
   135  		   ],
   136  		   "format": "products:1.0"
   137  		  },
   138  		  "com.ubuntu.juju:released:agents": {
   139  		   "updated": "Mon, 05 Aug 2013 11:07:04 +0000",
   140  		   "datatype": "content-download",
   141  		   "format": "products:1.0",
   142  		   "products": [
   143  		     "com.ubuntu.juju:ubuntu:amd64",
   144  		     "com.ubuntu.juju:ubuntu:arm"
   145  		   ],
   146  		   "path": "streams/v1/tools_metadata.json"
   147  		  },
   148  		  "com.ubuntu.juju:testing:agents": {
   149  		   "updated": "Mon, 05 Aug 2013 11:07:04 +0000",
   150  		   "datatype": "content-download",
   151  		   "format": "products:1.0",
   152  		   "products": [
   153  		     "com.ubuntu.juju:ubuntu:amd64"
   154  		   ],
   155  		   "path": "streams/v1/testing_tools_metadata.json"
   156  		  }
   157  		 },
   158  		 "updated": "Wed, 01 May 2013 13:31:26 +0000",
   159  		 "format": "index:1.0"
   160  		}
   161  `,
   162  	"/streams/v1/mirrors.json": `
   163          {
   164           "mirrors": {
   165            "com.ubuntu.juju:released:agents": [
   166               {
   167                "datatype": "content-download",
   168                "path": "streams/v1/tools_metadata:public-mirrors.json",
   169                "clouds": [
   170                 {
   171                  "region": "us-east-2",
   172                  "endpoint": "https://ec2.us-east-2.amazonaws.com"
   173                 },
   174                 {
   175                  "region": "us-west-2",
   176                  "endpoint": "https://ec2.us-west-2.amazonaws.com"
   177                 }
   178                ],
   179                "updated": "Wed, 14 Aug 2013 13:46:17 +0000",
   180                "format": "mirrors:1.0"
   181               },
   182               {
   183                "datatype": "content-download",
   184                "path": "streams/v1/tools_metadata:more-mirrors.json",
   185                "updated": "Wed, 14 Aug 2013 13:46:17 +0000",
   186                "format": "mirrors:1.0"
   187               }
   188            ]
   189           },
   190           "updated": "Wed, 01 May 2013 13:31:26 +0000",
   191           "format": "index:1.0"
   192          }
   193  `,
   194  	"/streams/v1/tools_metadata.json": `
   195  {
   196   "content_id": "com.ubuntu.juju:agents",
   197   "datatype": "content-download",
   198   "updated": "Tue, 04 Jun 2013 13:50:31 +0000",
   199   "format": "products:1.0",
   200   "products": {
   201    "com.ubuntu.juju:ubuntu:amd64": {
   202     "arch": "amd64",
   203     "release": "ubuntu",
   204     "versions": {
   205      "20130806": {
   206       "items": {
   207        "1130ubuntuamd64": {
   208         "version": "1.13.0",
   209         "size": 2973595,
   210         "path": "tools/released/20130806/juju-1.13.0-ubuntu-amd64.tgz",
   211         "ftype": "tar.gz",
   212         "sha256": "447aeb6a934a5eaec4f703eda4ef2dde"
   213        }
   214       }
   215      }
   216     }
   217    },
   218    "com.ubuntu.juju:ubuntu:arm": {
   219     "arch": "arm",
   220     "release": "ubuntu",
   221     "versions": {
   222      "20130806": {
   223       "items": {
   224        "201ubuntuarm": {
   225         "version": "2.0.1",
   226         "size": 1951096,
   227         "path": "tools/released/20130806/juju-2.0.1-ubuntu-arm.tgz",
   228         "ftype": "tar.gz",
   229         "sha256": "f65a92b3b41311bdf398663ee1c5cd0c"
   230        },
   231        "1114ubuntuarm": {
   232         "version": "1.11.4",
   233         "size": 1951096,
   234         "path": "tools/released/20130806/juju-1.11.4-ubuntu-arm.tgz",
   235         "ftype": "tar.gz",
   236         "sha256": "f65a92b3b41311bdf398663ee1c5cd0c"
   237        }
   238       }
   239      },
   240      "20130803": {
   241       "items": {
   242        "1114ubuntuarm": {
   243         "version": "1.11.4",
   244         "size": 2851541,
   245         "path": "tools/released/20130803/juju-1.11.4-ubuntu-arm.tgz",
   246         "ftype": "tar.gz",
   247         "sha256": "df07ac5e1fb4232d4e9aa2effa57918a"
   248        },
   249        "1115ubuntuarm": {
   250         "version": "1.11.5",
   251         "size": 2031281,
   252         "path": "tools/released/20130803/juju-1.11.5-ubuntu-arm.tgz",
   253         "ftype": "tar.gz",
   254         "sha256": "df07ac5e1fb4232d4e9aa2effa57918a"
   255        }
   256       }
   257      }
   258     }
   259    }
   260   }
   261  }
   262  `,
   263  	"/streams/v1/testing_tools_metadata.json": `
   264  {
   265   "content_id": "com.ubuntu.juju:agents",
   266   "datatype": "content-download",
   267   "updated": "Tue, 04 Jun 2013 13:50:31 +0000",
   268   "format": "products:1.0",
   269   "products": {
   270    "com.ubuntu.juju:ubuntu:amd64": {
   271     "arch": "amd64",
   272     "release": "ubuntu",
   273     "versions": {
   274      "20130806": {
   275       "items": {
   276        "1130ubuntuamd64": {
   277         "version": "1.16.0",
   278         "size": 2973512,
   279         "path": "tools/testing/20130806/juju-1.16.0-ubuntu-amd64.tgz",
   280         "ftype": "tar.gz",
   281         "sha256": "447aeb6a934a5eaec4f703eda4ef2dac"
   282        }
   283       }
   284      }
   285     }
   286    }
   287   }
   288  }
   289  `,
   290  	"/streams/v1/mirrored-tools-metadata.json": `
   291  {
   292   "content_id": "com.ubuntu.juju:agents",
   293   "datatype": "content-download",
   294   "updated": "Tue, 04 Jun 2013 13:50:31 +0000",
   295   "format": "products:1.0",
   296   "products": {
   297    "com.ubuntu.juju:ubuntu:amd64": {
   298     "arch": "amd64",
   299     "release": "ubuntu",
   300     "versions": {
   301      "20130806": {
   302       "items": {
   303        "1130ubuntuamd64": {
   304         "version": "1.13.0",
   305         "size": 2973595,
   306         "path": "mirrored-path/juju-1.13.0-ubuntu-amd64.tgz",
   307         "ftype": "tar.gz",
   308         "sha256": "447aeb6a934a5eaec4f703eda4ef2dde"
   309        }
   310       }
   311      }
   312     }
   313    }
   314   }
   315  }
   316  `,
   317  	"/streams/v1/tools_metadata:public-mirrors.json": `
   318  {
   319    "mirrors": {
   320      "com.ubuntu.juju:released:agents": [
   321        {
   322          "mirror": "http://some-mirror/",
   323          "path": "com.ubuntu.juju:download.json",
   324          "format": "products:1.0",
   325          "clouds": [
   326            {
   327              "endpoint": "https://ec2.us-east-2.amazonaws.com",
   328              "region": "us-east-2"
   329            }
   330          ]
   331        },
   332        {
   333          "mirror": "test:/",
   334          "path": "streams/v1/mirrored-tools-metadata.json",
   335          "format": "products:1.0",
   336          "clouds": [
   337            {
   338              "endpoint": "https://ec2.us-west-2.amazonaws.com",
   339              "region": "us-west-2"
   340            }
   341          ]
   342        },
   343        {
   344          "mirror": "http://another-mirror/",
   345          "path": "com.ubuntu.juju:download.json",
   346          "format": "products:1.0",
   347          "clouds": [
   348            {
   349              "endpoint": "https://ec2.us-west-1.amazonaws.com",
   350              "region": "us-west-1"
   351            }
   352          ]
   353        }
   354      ]
   355    },
   356    "format": "mirrors:1.0",
   357    "updated": "Mon, 05 Aug 2013 11:07:04 +0000"
   358  }
   359  `,
   360  	"/streams/v1/tools_metadata:more-mirrors.json": `
   361  {
   362    "mirrors": {
   363      "com.ubuntu.juju:released:agents": [
   364        {
   365          "mirror": "http://big-mirror/",
   366          "path": "big:download.json",
   367          "clouds": [
   368            {
   369              "endpoint": "https://some-endpoint.com",
   370              "region": "some-region"
   371            }
   372          ]
   373        }
   374      ]
   375    },
   376    "format": "mirrors:1.0",
   377    "updated": "Mon, 05 Aug 2013 11:07:04 +0000"
   378  }
   379  `,
   380  	"/streams/v1/image_metadata.json": `
   381  {
   382   "updated": "Wed, 01 May 2013 13:31:26 +0000",
   383   "content_id": "com.ubuntu.cloud:released:aws",
   384   "region": "nz-east-1",
   385   "endpoint": "https://anywhere",
   386   "root_store": "ebs",
   387   "virt": "pv", 
   388   "products": {
   389    "com.ubuntu.cloud:server:14.04:amd64": {
   390     "release": "trusty",
   391     "version": "14.04",
   392     "arch": "amd64",
   393     "versions": {
   394      "20140118": {
   395       "items": {
   396        "nzww1pe": {
   397         "root_store": "ssd",
   398         "virt": "hvm",
   399         "id": "ami-36745463"
   400        }
   401       },
   402       "pubname": "ubuntu-trusty-14.04-amd64-server-20140118",
   403       "label": "release"
   404      }
   405     }
   406    },
   407    "com.ubuntu.cloud:server:13.04:amd64": {
   408     "release": "raring",
   409     "version": "13.04",
   410     "arch": "amd64",
   411     "versions": {
   412      "20160318": {
   413       "items": {
   414        "nzww1pe": {
   415         "id": "ami-36745463"
   416        }
   417       },
   418       "pubname": "ubuntu-utopic-13.04-amd64-server-20160318",
   419       "label": "release"
   420      }
   421     }
   422    },
   423    "com.ubuntu.cloud:server:14.10:amd64": {
   424     "release": "utopic",
   425     "version": "14.10",
   426     "arch": "amd64",
   427     "root_store": "ebs",
   428     "virt": "pv",
   429     "versions": {
   430      "20160218": {
   431       "items": {
   432        "nzww1pe": {
   433         "id": "ami-36745463"
   434        }
   435       },
   436       "pubname": "ubuntu-utopic-14.10-amd64-server-20160218",
   437       "label": "release"
   438      }
   439     }
   440    },
   441    "com.ubuntu.cloud:server:12.10:amd64": {
   442     "release": "quantal",
   443     "version": "12.10",
   444     "arch": "amd64",
   445     "versions": {
   446      "20160118": {
   447       "items": {
   448        "nzww1pe": {
   449         "id": "ami-36745463"
   450        }
   451       },
   452       "root_store": "ebs",
   453       "virt": "pv",
   454       "pubname": "ubuntu-quantal-12.10-amd64-server-20160118",
   455       "label": "release"
   456      }
   457     }
   458    },
   459    "com.ubuntu.cloud:server:12.04:amd64": {
   460     "release": "precise",
   461     "version": "12.04",
   462     "arch": "amd64",
   463     "region": "au-east-1",
   464     "endpoint": "https://somewhere",
   465     "versions": {
   466      "20121218": {
   467       "region": "au-east-2",
   468       "endpoint": "https://somewhere-else",
   469       "items": {
   470        "usww1pe": {
   471         "root_store": "ebs",
   472         "virt": "pv",
   473         "id": "ami-26745463"
   474        },
   475        "usww2he": {
   476         "root_store": "ebs",
   477         "virt": "hvm",
   478         "id": "ami-442ea674",
   479         "region": "us-east-1",
   480         "endpoint": "https://ec2.us-east-1.amazonaws.com"
   481        },
   482        "usww3he": {
   483         "root_store": "ebs",
   484         "virt": "hvm",
   485         "crsn": "uswest3",
   486         "id": "ami-442ea675"
   487        }
   488       },
   489       "pubname": "ubuntu-precise-12.04-amd64-server-20121218",
   490       "label": "release"
   491      },
   492      "20111111": {
   493       "items": {
   494        "usww3pe": {
   495         "root_store": "ebs",
   496         "virt": "pv",
   497         "id": "ami-26745464"
   498        },
   499        "usww2pe": {
   500         "root_store": "instance",
   501         "virt": "pv",
   502         "id": "ami-442ea684",
   503         "region": "us-east-1",
   504         "endpoint": "https://ec2.us-east-1.amazonaws.com"
   505        }
   506       },
   507       "pubname": "ubuntu-precise-12.04-amd64-server-20111111",
   508       "label": "release"
   509      }
   510     }
   511    },
   512    "com.ubuntu.cloud:server:12.04:arm": {
   513     "release": "precise",
   514     "version": "12.04",
   515     "arch": "arm",
   516     "region": "us-east-1",
   517     "endpoint": "https://ec2.us-east-1.amazonaws.com",
   518     "versions": {
   519      "20121219": {
   520       "items": {
   521        "usww2he": {
   522         "root_store": "ebs",
   523         "virt": "pv",
   524         "id": "ami-442ea699"
   525        }
   526       },
   527       "pubname": "ubuntu-precise-12.04-arm-server-20121219",
   528       "label": "release"
   529      }
   530     }
   531    }
   532   },
   533   "_aliases": {
   534    "crsn": {
   535     "uswest3": {
   536      "region": "us-west-3",
   537      "endpoint": "https://ec2.us-west-3.amazonaws.com"
   538     }
   539    }
   540   },
   541   "format": "products:1.0"
   542  }
   543  `,
   544  }
   545  
   546  var TestRoundTripper = &testing.ProxyRoundTripper{}
   547  
   548  type TestDataSuite struct{}
   549  
   550  func (s *TestDataSuite) SetUpSuite(c *gc.C) {
   551  	TestRoundTripper.Sub = testing.NewCannedRoundTripper(imageData, map[string]int{"test://unauth": http.StatusUnauthorized})
   552  }
   553  
   554  func (s *TestDataSuite) TearDownSuite(c *gc.C) {
   555  	TestRoundTripper.Sub = nil
   556  }
   557  
   558  const (
   559  	UnsignedJsonSuffix = ".json"
   560  	SignedJsonSuffix   = ".sjson"
   561  )
   562  
   563  func SetRoundTripperFiles(files map[string]string, errorFiles map[string]int) {
   564  	TestRoundTripper.Sub = testing.NewCannedRoundTripper(files, errorFiles)
   565  }
   566  
   567  func AddSignedFiles(c *gc.C, files map[string]string) map[string]string {
   568  	all := make(map[string]string)
   569  	for name, content := range files {
   570  		all[name] = content
   571  		// Sign file content
   572  		r := strings.NewReader(content)
   573  		bytes, err := io.ReadAll(r)
   574  		c.Assert(err, jc.ErrorIsNil)
   575  		signedName, signedContent, err := SignMetadata(name, bytes)
   576  		c.Assert(err, jc.ErrorIsNil)
   577  		all[signedName] = string(signedContent)
   578  	}
   579  	return all
   580  }
   581  
   582  func SignMetadata(fileName string, fileData []byte) (string, []byte, error) {
   583  	signString := func(unsigned string) string {
   584  		return strings.Replace(unsigned, UnsignedJsonSuffix, SignedJsonSuffix, -1)
   585  	}
   586  
   587  	// Make sure that contents point to signed files too.
   588  	signedFileData := signString(string(fileData))
   589  	signedBytes, err := simplestreams.Encode(strings.NewReader(signedFileData), SignedMetadataPrivateKey, PrivateKeyPassphrase)
   590  	if err != nil {
   591  		return "", nil, err
   592  	}
   593  
   594  	return signString(fileName), signedBytes, nil
   595  }
   596  
   597  // SourceDetails stored some details that need to be checked about data source.
   598  type SourceDetails struct {
   599  	URL           string
   600  	Key           string
   601  	RequireSigned bool
   602  }
   603  
   604  func AssertExpectedSources(c *gc.C, obtained []simplestreams.DataSource, dsDetails []SourceDetails) {
   605  	// Some data sources do not require to contain signed data.
   606  	// However, they may still contain it.
   607  	// Since we will always try to read signed data first,
   608  	// we want to be able to try to read this signed data
   609  	// with a public key. Check keys are provided where needed.
   610  	// Bugs #1542127, #1542131
   611  	for i, source := range obtained {
   612  		url, err := source.URL("")
   613  		c.Assert(err, jc.ErrorIsNil)
   614  		expected := dsDetails[i]
   615  		c.Assert(url, gc.DeepEquals, expected.URL)
   616  		c.Assert(source.PublicSigningKey(), gc.DeepEquals, expected.Key)
   617  		c.Assert(source.RequireSigned(), gc.Equals, expected.RequireSigned)
   618  	}
   619  	c.Assert(obtained, gc.HasLen, len(dsDetails))
   620  }
   621  
   622  type LocalLiveSimplestreamsSuite struct {
   623  	testing.BaseSuite
   624  	Source          simplestreams.DataSource
   625  	RequireSigned   bool
   626  	StreamsVersion  string
   627  	DataType        string
   628  	ValidConstraint simplestreams.LookupConstraint
   629  }
   630  
   631  const (
   632  	Index_v1   = "index:1.0"
   633  	Product_v1 = "products:1.0"
   634  )
   635  
   636  type testConstraint struct {
   637  	simplestreams.LookupParams
   638  }
   639  
   640  func NewTestConstraint(params simplestreams.LookupParams) *testConstraint {
   641  	return &testConstraint{LookupParams: params}
   642  }
   643  
   644  func (tc *testConstraint) IndexIds() []string {
   645  	return nil
   646  }
   647  
   648  func (tc *testConstraint) ProductIds() ([]string, error) {
   649  	ids := make([]string, len(tc.Arches))
   650  	for i, arch := range tc.Arches {
   651  		ids[i] = fmt.Sprintf("com.ubuntu.cloud:server:%s:%s", tc.Releases[0], arch)
   652  	}
   653  	return ids, nil
   654  }
   655  
   656  type testDataSourceFactory struct{}
   657  
   658  func TestDataSourceFactory() simplestreams.DataSourceFactory {
   659  	return testDataSourceFactory{}
   660  }
   661  
   662  func (testDataSourceFactory) NewDataSource(cfg simplestreams.Config) simplestreams.DataSource {
   663  	return simplestreams.NewDataSourceWithClient(cfg, jujuhttp.NewClient(
   664  		jujuhttp.WithTransportMiddlewares(
   665  			jujuhttp.DialContextMiddleware(jujuhttp.NewLocalDialBreaker(false)),
   666  			jujuhttp.FileProtocolMiddleware,
   667  			FileProtocolMiddleware,
   668  		),
   669  	))
   670  }
   671  
   672  type testSkipVerifyDataSourceFactory struct{}
   673  
   674  func TestSkipVerifyDataSourceFactory() simplestreams.DataSourceFactory {
   675  	return testSkipVerifyDataSourceFactory{}
   676  }
   677  
   678  func (testSkipVerifyDataSourceFactory) NewDataSource(cfg simplestreams.Config) simplestreams.DataSource {
   679  	return simplestreams.NewDataSourceWithClient(cfg, jujuhttp.NewClient(
   680  		jujuhttp.WithSkipHostnameVerification(true),
   681  		jujuhttp.WithTransportMiddlewares(
   682  			jujuhttp.DialContextMiddleware(jujuhttp.NewLocalDialBreaker(false)),
   683  			jujuhttp.FileProtocolMiddleware,
   684  			FileProtocolMiddleware,
   685  		),
   686  	))
   687  }
   688  
   689  // FileProtocolMiddleware registers support for file:// URLs on the given
   690  // transport.
   691  func FileProtocolMiddleware(transport *http.Transport) *http.Transport {
   692  	TestRoundTripper.RegisterForTransportScheme(transport, "test")
   693  	TestRoundTripper.RegisterForTransportScheme(transport, "signedtest")
   694  	return transport
   695  }
   696  
   697  func init() {
   698  	// Ensure out test struct can have its tags extracted.
   699  	simplestreams.RegisterStructTags(TestItem{})
   700  }
   701  
   702  type TestItem struct {
   703  	Id          string `json:"id"`
   704  	Version     string `json:"version"`
   705  	Storage     string `json:"root_store"`
   706  	VirtType    string `json:"virt"`
   707  	Arch        string `json:"arch"`
   708  	RegionAlias string `json:"crsn"`
   709  	RegionName  string `json:"region"`
   710  	Endpoint    string `json:"endpoint"`
   711  }
   712  
   713  func (s *LocalLiveSimplestreamsSuite) IndexPath() string {
   714  	if s.RequireSigned {
   715  		return fmt.Sprintf("streams/%s/index.sjson", s.StreamsVersion)
   716  	}
   717  	return fmt.Sprintf("streams/%s/index.json", s.StreamsVersion)
   718  }
   719  
   720  func (s *LocalLiveSimplestreamsSuite) TestGetIndex(c *gc.C) {
   721  	indexRef, err := s.GetIndexRef(Index_v1)
   722  	c.Assert(err, jc.ErrorIsNil)
   723  	c.Assert(indexRef.Format, gc.Equals, Index_v1)
   724  	c.Assert(indexRef.Source, gc.Equals, s.Source)
   725  	c.Assert(len(indexRef.Indexes) > 0, jc.IsTrue)
   726  }
   727  
   728  func (s *LocalLiveSimplestreamsSuite) GetIndexRef(format string) (*simplestreams.IndexReference, error) {
   729  	params := simplestreams.ValueParams{
   730  		DataType:      s.DataType,
   731  		ValueTemplate: TestItem{},
   732  	}
   733  	ss := simplestreams.NewSimpleStreams(TestDataSourceFactory())
   734  	return ss.GetIndexWithFormat(
   735  		s.Source, s.IndexPath(),
   736  		format,
   737  		simplestreams.MirrorsPath(s.StreamsVersion),
   738  		s.RequireSigned,
   739  		s.ValidConstraint.Params().CloudSpec,
   740  		params,
   741  	)
   742  }
   743  
   744  func (s *LocalLiveSimplestreamsSuite) TestGetIndexWrongFormat(c *gc.C) {
   745  	_, err := s.GetIndexRef("bad")
   746  	c.Assert(err, gc.NotNil)
   747  }
   748  
   749  func (s *LocalLiveSimplestreamsSuite) TestGetProductsPathExists(c *gc.C) {
   750  	indexRef, err := s.GetIndexRef(Index_v1)
   751  	c.Assert(err, jc.ErrorIsNil)
   752  	path, err := indexRef.GetProductsPath(s.ValidConstraint)
   753  	c.Assert(err, jc.ErrorIsNil)
   754  	c.Assert(path, gc.Not(gc.Equals), "")
   755  }
   756  
   757  func (s *LocalLiveSimplestreamsSuite) TestGetProductsPathInvalidCloudSpec(c *gc.C) {
   758  	indexRef, err := s.GetIndexRef(Index_v1)
   759  	c.Assert(err, jc.ErrorIsNil)
   760  	ic := NewTestConstraint(simplestreams.LookupParams{
   761  		CloudSpec: simplestreams.CloudSpec{Region: "bad", Endpoint: "spec"},
   762  		Releases:  []string{"12.04"},
   763  	})
   764  	_, err = indexRef.GetProductsPath(ic)
   765  	c.Assert(err, gc.NotNil)
   766  }
   767  
   768  func (s *LocalLiveSimplestreamsSuite) TestGetProductsPathInvalidProductSpec(c *gc.C) {
   769  	indexRef, err := s.GetIndexRef(Index_v1)
   770  	c.Assert(err, jc.ErrorIsNil)
   771  	ic := NewTestConstraint(simplestreams.LookupParams{
   772  		CloudSpec: s.ValidConstraint.Params().CloudSpec,
   773  		Releases:  []string{"12.04"},
   774  		Arches:    []string{"bad"},
   775  		Stream:    "spec",
   776  	})
   777  	_, err = indexRef.GetProductsPath(ic)
   778  	c.Assert(err, gc.NotNil)
   779  }
   780  
   781  func (s *LocalLiveSimplestreamsSuite) AssertGetMetadata(c *gc.C) *simplestreams.CloudMetadata {
   782  	indexRef, err := s.GetIndexRef(Index_v1)
   783  	c.Assert(err, jc.ErrorIsNil)
   784  	metadata, err := indexRef.GetCloudMetadataWithFormat(s.ValidConstraint, Product_v1, s.RequireSigned)
   785  	c.Assert(err, jc.ErrorIsNil)
   786  	c.Assert(metadata.Format, gc.Equals, Product_v1)
   787  	c.Assert(len(metadata.Products) > 0, jc.IsTrue)
   788  	return metadata
   789  }
   790  
   791  func (s *LocalLiveSimplestreamsSuite) TestGetCloudMetadataWithFormat(c *gc.C) {
   792  	s.AssertGetMetadata(c)
   793  }
   794  
   795  func (s *LocalLiveSimplestreamsSuite) AssertGetItemCollections(c *gc.C, version string) *simplestreams.ItemCollection {
   796  	metadata := s.AssertGetMetadata(c)
   797  	metadataCatalog := metadata.Products["com.ubuntu.cloud:server:12.04:amd64"]
   798  	ic := metadataCatalog.Items[version]
   799  	return ic
   800  }
   801  
   802  func InvalidDataSource(requireSigned bool) simplestreams.DataSource {
   803  	factory := TestDataSourceFactory()
   804  	return factory.NewDataSource(simplestreams.Config{
   805  		Description:          "invalid",
   806  		BaseURL:              "file://invalid",
   807  		HostnameVerification: true,
   808  		Priority:             simplestreams.DEFAULT_CLOUD_DATA,
   809  		RequireSigned:        requireSigned})
   810  }
   811  
   812  func VerifyDefaultCloudDataSource(description, baseURL string) simplestreams.DataSource {
   813  	factory := TestDataSourceFactory()
   814  	return factory.NewDataSource(simplestreams.Config{
   815  		Description:          description,
   816  		BaseURL:              baseURL,
   817  		HostnameVerification: true,
   818  		Priority:             simplestreams.DEFAULT_CLOUD_DATA})
   819  }