blob: 42b32c2459eb6cda8bf979d7d37ff5980f7f41aa [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"
"fmt"
"io/ioutil"
"log"
"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(dir string) (*Repository, string, error) {
ctx := context.Background()
// Initialize a repo.
fmt.Printf("Creating repo at %s.\n", dir)
pmRepo, err := repo.New(dir)
if err != nil {
return nil, "", fmt.Errorf("failed to create repo. %w", err)
}
if err = pmRepo.Init(); err != nil {
return nil, "", fmt.Errorf("failed to init repo. %w", err)
}
// Create a config.
config := build.TestConfig()
log.Printf("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)
var packageManifest build.PackageManifest
if err := json.Unmarshal(manifest, &packageManifest); err != nil {
return nil, "", fmt.Errorf("could not decode package_manifest.json. %w", err)
}
metaMerkle := ""
for _, blob := range packageManifest.Blobs {
if blob.Path == "meta/" {
metaMerkle = blob.Merkle.String()
}
}
if metaMerkle == "" {
return nil, "", fmt.Errorf("did not find meta.far in manifest")
}
// Publish the config to the repo.
_, err = pmRepo.PublishManifest(manifestDir)
if err != nil {
return nil, "", fmt.Errorf("failed to publish manifest. %w", err)
}
if err = pmRepo.CommitUpdates(true); err != nil {
return nil, "", fmt.Errorf("failed to commit updates to repo. %w", err)
}
pkgRepo, err := NewRepository(ctx, dir)
if err != nil {
return nil, "", fmt.Errorf("failed to read repo. %w", err)
}
return pkgRepo, metaMerkle, nil
}
// expandPackage expands the given merkle from the given repository into the given directory.
func expandPackage(pkgRepo *Repository, merkle string, dir string) error {
// Parse the package we want.
pkg, err := newPackage(pkgRepo, merkle)
if err != nil {
return fmt.Errorf("failed to read package. %w", err)
}
// Expand to the given directory.
if err = pkg.Expand(dir); err != nil {
return fmt.Errorf("failed to expand to dir. %w", err)
}
return nil
}
// createAndExpandPackage creates temporary directories and expands a test package, returning the expand directory.
func createAndExpandPackage(parentDir string) (*Repository, string, error) {
dir, err := ioutil.TempDir(parentDir, "package")
if err != nil {
return nil, "", fmt.Errorf("Failed to create directory %s. %w", dir, err)
}
pkgRepo, metaMerkle, err := createTestPackage(dir)
if err != nil {
return nil, "", fmt.Errorf("Failed to create test package. %w", err)
}
dir, err = ioutil.TempDir(parentDir, "expand")
if err != nil {
return nil, "", fmt.Errorf("Failed to create directory %s. %w", dir, err)
}
err = expandPackage(pkgRepo, metaMerkle, dir)
if err != nil {
return nil, "", fmt.Errorf("Failed to expand package to directory %s. %w", dir, err)
}
return pkgRepo, dir, nil
}
func TestAddResource(t *testing.T) {
parentDir := filepath.Join("", "omaha-pkg-test-add-resource")
if err := os.MkdirAll(parentDir, 0755); err != nil {
t.Fatalf("Failed to create directory %s, %s", parentDir, err)
}
defer os.RemoveAll(parentDir)
_, expandDir, err := createAndExpandPackage(parentDir)
if err != nil {
t.Fatalf("Failed to create and expand package. %s", err)
}
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.Fatalf("File %s is not expected.", key)
}
}
if len(expectedFiles) != len(pkgBuilder.Contents) {
t.Fatalf("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 := filepath.Join("", "omaha-pkg-test-publish")
if err := os.MkdirAll(parentDir, 0755); err != nil {
t.Fatalf("Failed to create directory %s, %s", parentDir, err)
}
defer os.RemoveAll(parentDir)
pkgRepo, expandDir, err := createAndExpandPackage(parentDir)
if err != nil {
t.Fatalf("Failed to create and expand package. %s", err)
}
pkgBuilder, err := NewPackageBuilderFromDir(expandDir, "testpackage", "0")
if err != nil {
t.Fatalf("Failed to parse package from %s. %s", expandDir, err)
}
defer pkgBuilder.Close()
fullPkgName := fmt.Sprintf("%s/%s", pkgBuilder.Name, pkgBuilder.Version)
newResource := "blah/z"
// Confirm package in repo is as expected.
pkg, err := pkgRepo.OpenPackage(fullPkgName)
if err != nil {
t.Fatalf("Repo does not contain '%s'. %s", fullPkgName, err)
}
if _, err := pkg.ReadFile(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))
// Confirm that the package is published and updated.
pkg, err = pkgRepo.OpenPackage(fullPkgName)
if err != nil {
t.Fatalf("Repo does not contain '%s'. %s", fullPkgName, err)
}
if data, err := pkg.ReadFile(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)
}
}
}