blob: f46a6b457f49766a2f7f441e08b6cf311e8ee02b [file] [log] [blame]
// Copyright 2017 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 daemon
import (
"crypto/rand"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"fidl/fuchsia/amber"
"fuchsia.googlesource.com/merkle"
"fuchsia.googlesource.com/pm/repo"
)
func TestSources(t *testing.T) {
store, err := ioutil.TempDir("", "amber-test")
if err != nil {
panic(err)
}
defer os.RemoveAll(store)
d, err := NewDaemon(store, "", "", "", nil)
if err != nil {
panic(err)
}
t.Run("Add", func(t *testing.T) {
if err := d.AddSource(&amber.SourceConfig{
Id: "addtest",
RepoUrl: "http://localhost/addtest",
RootKeys: []amber.KeyConfig{
{
Type: "ed25519",
Value: "be0b983f7396da675c40c6b93e47fced7c1e9ea8a32a1fe952ba8f519760b307",
},
},
StatusConfig: &amber.StatusConfig{Enabled: true},
}); err != nil {
t.Fatal(err)
}
if d.GetSources()["addtest"] == nil {
t.Errorf("source missing after add, got %#v", d.GetSources())
}
})
t.Run("Remove", func(t *testing.T) {
if err := d.AddSource(&amber.SourceConfig{
Id: "removetest",
RepoUrl: "http://localhost/removetest",
RootKeys: []amber.KeyConfig{
{
Type: "ed25519",
Value: "be0b983f7396da675c40c6b93e47fced7c1e9ea8a32a1fe952ba8f519760b307",
},
},
StatusConfig: &amber.StatusConfig{Enabled: true},
}); err != nil {
t.Fatal(err)
}
if _, err := d.RemoveSource("removetest"); err != nil {
t.Fatal(err)
}
if s := d.GetSources()["removetest"]; s != nil {
t.Errorf("expected source to be removed, got %#v", s)
}
})
t.Run("Disable", func(t *testing.T) {
if err := d.AddSource(&amber.SourceConfig{
Id: "disabletest",
RepoUrl: "http://localhost/disabletest",
RootKeys: []amber.KeyConfig{
{
Type: "ed25519",
Value: "be0b983f7396da675c40c6b93e47fced7c1e9ea8a32a1fe952ba8f519760b307",
},
},
StatusConfig: &amber.StatusConfig{Enabled: true},
}); err != nil {
t.Fatal(err)
}
if d.GetActiveSources()["disabletest"] == nil {
t.Fatal("expected source to be enabled initially")
}
d.DisableSource("disabletest")
if d.GetActiveSources()["disabletest"] != nil {
t.Fatal("expected source to be disabled")
}
})
t.Run("Enable", func(t *testing.T) {
if err := d.AddSource(&amber.SourceConfig{
Id: "enabletest",
RepoUrl: "http://localhost/enabletest",
RootKeys: []amber.KeyConfig{
{
Type: "ed25519",
Value: "be0b983f7396da675c40c6b93e47fced7c1e9ea8a32a1fe952ba8f519760b307",
},
},
StatusConfig: &amber.StatusConfig{Enabled: true},
}); err != nil {
t.Fatal(err)
}
d.DisableSource("enabletest")
if d.GetActiveSources()["enabletest"] != nil {
t.Fatal("expected source to be disabled")
}
d.EnableSource("enabletest")
if d.GetActiveSources()["enabletest"] == nil {
t.Fatal("expected source to be enabled")
}
})
t.Run("Login", func(t *testing.T) {
t.Skip("TODO: add coverage for oauth2")
})
}
func panicerr(err error) {
if err != nil {
panic(err)
}
}
func makeBlob(dir, content string) (string, error) {
var t merkle.Tree
if _, err := t.ReadFrom(strings.NewReader(content)); err != nil {
return "", err
}
merkleroot := fmt.Sprintf("%x", t.Root())
path := filepath.Join(dir, merkleroot)
return merkleroot, ioutil.WriteFile(path, []byte(content), 0644)
}
func TestDaemon(t *testing.T) {
store, err := ioutil.TempDir("", "amber-test-store")
panicerr(err)
defer os.RemoveAll(store)
// TODO(raggi): make this a real package instead, but that's a lot more setup
pkgContent := "very fake package"
pkgBlobLength := int64(len(pkgContent))
pkgBlob, err := makeBlob(store, pkgContent)
panicerr(err)
root1, err := makeBlob(store, "first blob")
panicerr(err)
repoDir, err := ioutil.TempDir("", "amber-test-repo")
panicerr(err)
defer os.RemoveAll(repoDir)
// initialize the repo, adding the staged target
repo, err := repo.New(repoDir)
panicerr(err)
panicerr(repo.Init())
panicerr(repo.GenKeys())
mf, err := os.Open(store + "/" + pkgBlob)
panicerr(err)
defer mf.Close()
panicerr(repo.AddPackage("foo/0", mf))
for _, blob := range []string{pkgBlob, root1} {
b, err := os.Open(store + "/" + blob)
panicerr(err)
_, _, err = repo.AddBlob(blob, b)
b.Close()
panicerr(err)
}
panicerr(repo.CommitUpdates(false))
keys, err := repo.RootKeys()
panicerr(err)
rootKey := keys[0]
server := httptest.NewServer(http.FileServer(http.Dir(repoDir + "/repository")))
// XXX(raggi): cleanup disabled because networking bug!
// defer server.Close()
// // so that the httptest server can close:
// defer http.DefaultTransport.(*http.Transport).CloseIdleConnections()
store, err = ioutil.TempDir("", "amber-test")
panicerr(err)
defer os.RemoveAll(store)
pkgsDir, err := ioutil.TempDir("", "amber-test-pkgs")
panicerr(err)
defer os.RemoveAll(pkgsDir)
blobsDir, err := ioutil.TempDir("", "amber-test-blobs")
panicerr(err)
defer os.RemoveAll(blobsDir)
pkgNeedsDir, err := ioutil.TempDir("", "amber-test-pkgneeds")
panicerr(err)
defer os.RemoveAll(pkgNeedsDir)
d, err := NewDaemon(store, pkgsDir, blobsDir, pkgNeedsDir, nil)
panicerr(err)
err = d.AddSource(&amber.SourceConfig{
Id: "testing",
RepoUrl: server.URL,
BlobRepoUrl: server.URL + "/blobs",
// TODO(raggi): fix keyconfig
RootKeys: []amber.KeyConfig{
{
Type: rootKey.Type,
Value: rootKey.Value.Public.String(),
},
},
StatusConfig: &amber.StatusConfig{Enabled: true},
})
panicerr(err)
// TODO(raggi): add test for the update semantics
d.Update()
merkle, length, err := d.MerkleFor("foo", "0", "")
if err != nil {
t.Fatal(err)
}
if merkle != pkgBlob {
t.Errorf("merkleFor: got %q, want %q", merkle, pkgBlob)
}
if length != int64(pkgBlobLength) {
t.Errorf("merkleFor length: got %d, want %d", length, pkgBlobLength)
}
os.MkdirAll(filepath.Join(pkgNeedsDir, pkgBlob), 0755)
panicerr(ioutil.WriteFile(filepath.Join(pkgNeedsDir, pkgBlob, root1), []byte{}, 0644))
panicerr(d.GetPkg(pkgBlob, pkgBlobLength))
c, err := ioutil.ReadFile(pkgsDir + "/" + pkgBlob)
panicerr(err)
if got := string(c); got != pkgContent {
t.Errorf("getpkg: got %q, want %q", got, pkgContent)
}
c, err = ioutil.ReadFile(blobsDir + "/" + root1)
panicerr(err)
if got, want := string(c), "first blob"; got != want {
t.Errorf("getblob: got %q, want %q", got, want)
}
}
func TestDaemonWithEncryption(t *testing.T) {
store, err := ioutil.TempDir("", "amber-test-store")
panicerr(err)
defer os.RemoveAll(store)
// TODO(raggi): make this a real package instead, but that's a lot more setup
pkgContent := "very fake package"
pkgBlobLength := int64(len(pkgContent))
pkgBlob, err := makeBlob(store, pkgContent)
panicerr(err)
root1, err := makeBlob(store, "first blob")
panicerr(err)
repoDir, err := ioutil.TempDir("", "amber-test-repo")
panicerr(err)
defer os.RemoveAll(repoDir)
// initialize the repo, adding the staged target
repo, err := repo.New(repoDir)
panicerr(err)
panicerr(repo.Init())
panicerr(repo.GenKeys())
// Create a blob encryption key
var key [32]byte
_, err = io.ReadFull(rand.Reader, key[:])
panicerr(err)
keyPath := store + "/crypt.key"
err = ioutil.WriteFile(keyPath, key[:], 0600)
panicerr(err)
panicerr(repo.EncryptWith(keyPath))
mf, err := os.Open(store + "/" + pkgBlob)
panicerr(err)
defer mf.Close()
panicerr(repo.AddPackage("foo/0", mf))
for _, blob := range []string{pkgBlob, root1} {
b, err := os.Open(store + "/" + blob)
panicerr(err)
_, _, err = repo.AddBlob(blob, b)
b.Close()
panicerr(err)
}
panicerr(repo.CommitUpdates(false))
keys, err := repo.RootKeys()
panicerr(err)
rootKey := keys[0]
server := httptest.NewServer(http.FileServer(http.Dir(repoDir + "/repository")))
// XXX(raggi): cleanup disabled because networking bug!
// defer server.Close()
// // so that the httptest server can close:
// defer http.DefaultTransport.(*http.Transport).CloseIdleConnections()
store, err = ioutil.TempDir("", "amber-test")
panicerr(err)
defer os.RemoveAll(store)
pkgsDir, err := ioutil.TempDir("", "amber-test-pkgs")
panicerr(err)
defer os.RemoveAll(pkgsDir)
blobsDir, err := ioutil.TempDir("", "amber-test-blobs")
panicerr(err)
defer os.RemoveAll(blobsDir)
pkgNeedsDir, err := ioutil.TempDir("", "amber-test-pkgneeds")
panicerr(err)
defer os.RemoveAll(pkgNeedsDir)
d, err := NewDaemon(store, pkgsDir, blobsDir, pkgNeedsDir, nil)
panicerr(err)
err = d.AddSource(&amber.SourceConfig{
Id: "testing",
RepoUrl: server.URL,
BlobRepoUrl: server.URL + "/blobs",
// TODO(raggi): fix keyconfig
RootKeys: []amber.KeyConfig{
{
Type: rootKey.Type,
Value: rootKey.Value.Public.String(),
},
},
BlobKey: &amber.BlobEncryptionKey{
Data: key,
},
StatusConfig: &amber.StatusConfig{Enabled: true},
})
panicerr(err)
// TODO(raggi): add test for the update semantics
d.Update()
merkle, length, err := d.MerkleFor("foo", "0", "")
if err != nil {
t.Fatal(err)
}
if merkle != pkgBlob {
t.Errorf("merkleFor: got %q, want %q", merkle, pkgBlob)
}
if length != int64(pkgBlobLength) {
t.Errorf("merkleFor length: got %d, want %d", length, pkgBlobLength)
}
os.MkdirAll(filepath.Join(pkgNeedsDir, pkgBlob), 0755)
panicerr(ioutil.WriteFile(filepath.Join(pkgNeedsDir, pkgBlob, root1), []byte{}, 0644))
panicerr(d.GetPkg(pkgBlob, pkgBlobLength))
c, err := ioutil.ReadFile(pkgsDir + "/" + pkgBlob)
panicerr(err)
if got := string(c); got != pkgContent {
t.Errorf("getpkg: got %q, want %q", got, pkgContent)
}
c, err = ioutil.ReadFile(blobsDir + "/" + root1)
panicerr(err)
if got, want := string(c), "first blob"; got != want {
t.Errorf("getblob: got %q, want %q", got, want)
}
}