blob: 82320426dc12a6665ef746e4fc48cad02b243ef4 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package packages
import (
"bytes"
"context"
"encoding/json"
"io/ioutil"
"os"
"path"
"path/filepath"
"testing"
"go.fuchsia.dev/fuchsia/src/sys/pkg/bin/pm/build"
"go.fuchsia.dev/fuchsia/src/sys/pkg/bin/pm/repo"
)
// createTestPackage fills the given directory with a new repository.
func createTestPackage(t *testing.T, dir string) (*Repository, string) {
ctx := context.Background()
// Initialize a repo.
t.Logf("Creating repo at %s", dir)
blobsDir := filepath.Join(dir, "blobs")
pmRepo, err := repo.New(dir, blobsDir)
if err != nil {
t.Fatal(err)
}
if err = pmRepo.Init(); err != nil {
t.Fatal(err)
}
// Create a config.
config := build.TestConfig()
t.Logf("Creating meta.far in %s", config.OutputDir)
build.BuildTestPackage(config)
defer os.RemoveAll(filepath.Dir(config.OutputDir))
// Grab the merkle of the config's package manifest.
manifestDir := filepath.Join(config.OutputDir, "package_manifest.json")
manifest, err := ioutil.ReadFile(manifestDir)
if err != nil {
t.Fatal(err)
}
var packageManifest build.PackageManifest
if err := json.Unmarshal(manifest, &packageManifest); err != nil {
t.Fatal(err)
}
metaMerkle := ""
for _, blob := range packageManifest.Blobs {
if blob.Path == "meta/" {
metaMerkle = blob.Merkle.String()
}
}
if metaMerkle == "" {
t.Fatal("did not find meta.far in manifest")
}
// Publish the config to the repo.
if _, err = pmRepo.PublishManifest(manifestDir); err != nil {
t.Fatalf("failed to publish manifest: %s", err)
}
if err = pmRepo.CommitUpdates(true); err != nil {
t.Fatalf("failed to commit updates to repo: %s", err)
}
pkgRepo, err := NewRepository(ctx, dir, NewDirBlobStore(blobsDir))
if err != nil {
t.Fatalf("failed to read repo: %s", err)
}
return pkgRepo, metaMerkle
}
// expandPackage expands the given merkle from the given repository into the given directory.
func expandPackage(t *testing.T, pkgRepo *Repository, merkle string, dir string) {
ctx := context.Background()
// Parse the package we want.
pkg, err := newPackage(ctx, pkgRepo, merkle)
if err != nil {
t.Fatalf("failed to read package: %s", err)
}
// Expand to the given directory.
if err = pkg.Expand(ctx, dir); err != nil {
t.Fatalf("failed to expand to dir: %s", err)
}
}
// createAndExpandPackage creates temporary directories and expands a test package, returning the expand directory.
func createAndExpandPackage(t *testing.T, parentDir string) (*Repository, string) {
dir := filepath.Join(parentDir, "package")
if err := os.Mkdir(dir, 0o700); err != nil {
t.Fatal(err)
}
pkgRepo, metaMerkle := createTestPackage(t, dir)
expand := filepath.Join(parentDir, "expand")
if err := os.Mkdir(expand, 0o700); err != nil {
t.Fatal(err)
}
expandPackage(t, pkgRepo, metaMerkle, expand)
return pkgRepo, expand
}
func TestAddResource(t *testing.T) {
parentDir := t.TempDir()
_, expandDir := createAndExpandPackage(t, parentDir)
pkgBuilder, err := NewPackageBuilderFromDir(expandDir, "testpackage", "0")
if err != nil {
t.Fatalf("Failed to parse package from %s. %s", expandDir, err)
}
defer pkgBuilder.Close()
newResource := "blah/z"
// Confirm the new resource doesn't exist yet.
if _, ok := pkgBuilder.Contents[newResource]; ok {
t.Fatalf("Test resource %s should not exist yet in the package.", newResource)
}
pkgBuilder.AddResource(newResource, bytes.NewReader([]byte(newResource)))
// Confirm the file and contents were added.
path, ok := pkgBuilder.Contents[newResource]
if !ok {
t.Fatalf("Test resource %s failed to be added.", newResource)
}
newData, err := ioutil.ReadFile(path)
if err != nil {
t.Fatalf("Failed to read contents of %s. %s", newResource, err)
}
if string(newData) != newResource {
t.Fatalf("%s expects to have %s, but has %s", newResource, newResource, string(newData))
}
expectedFiles := map[string]struct{}{
"meta/contents": {},
"meta/foo/one": {},
"meta/package": {},
"blah/z": {},
}
for _, item := range build.TestFiles {
expectedFiles[item] = struct{}{}
}
for key := range pkgBuilder.Contents {
if _, ok := expectedFiles[key]; !ok {
t.Errorf("File %s is not expected", key)
}
}
if len(expectedFiles) != len(pkgBuilder.Contents) {
t.Errorf("Package contents has %d files, should have %d", len(pkgBuilder.Contents), len(expectedFiles))
}
if err := pkgBuilder.AddResource(newResource, bytes.NewReader([]byte(newResource))); err == nil {
t.Fatalf("Resource %s should have failed to be added twice.", newResource)
}
}
func TestPublish(t *testing.T) {
ctx := context.Background()
parentDir := t.TempDir()
pkgRepo, expandDir := createAndExpandPackage(t, parentDir)
pkgBuilder, err := NewPackageBuilderFromDir(expandDir, "testpackage", "0")
if err != nil {
t.Fatalf("Failed to parse package from %s. %s", expandDir, err)
}
defer pkgBuilder.Close()
fullPkgName := pkgBuilder.Name + "/" + pkgBuilder.Version
newResource := "blah/z"
// Confirm package in repo is as expected.
pkg, err := pkgRepo.OpenPackage(ctx, fullPkgName)
if err != nil {
t.Fatalf("Repo does not contain '%s'. %s", fullPkgName, err)
}
if _, err := pkg.ReadFile(ctx, newResource); err == nil {
t.Fatalf("%s should not be found in package", newResource)
}
// Add resource to package.
pkgBuilder.AddResource(newResource, bytes.NewReader([]byte(newResource)))
// Update repo with updated package. We don't check the merkle since the package includes randomly generated files.
actualPkgName, _, err := pkgBuilder.Publish(ctx, pkgRepo)
if err != nil {
t.Fatalf("Publishing package failed. %s", err)
}
if actualPkgName != fullPkgName {
t.Fatalf("package path should be %q, not %q", fullPkgName, actualPkgName)
}
pkgRepo, err = NewRepository(ctx, path.Dir(pkgRepo.Dir), pkgRepo.BlobStore)
// Confirm that the package is published and updated.
pkg, err = pkgRepo.OpenPackage(ctx, fullPkgName)
if err != nil {
t.Fatalf("Repo does not contain '%s'. %s", fullPkgName, err)
}
if data, err := pkg.ReadFile(ctx, newResource); err != nil {
t.Fatalf("%s should be in package.", newResource)
} else {
if string(data) != newResource {
t.Fatalf("%s should have value %s but is %s", newResource, newResource, data)
}
}
}