dehub/repo_test.go
mediocregopher cf05b3a072 Refactor commit type and logic to account for future commit types
---
type: change
message: |-
  Refactor commit type and logic to account for future commit types

  This commit introduces a CommitInterface which CommitChange (previously
  ChangeCommit) now implements. Additionally, now all commit messages will include
  a type field and a "---" separator. The code is written to still accept all the
  old commit messages used in this repo. Other than those changes, most of this is
  just rearranging existing code.
change_hash: AHjWAUxCjXgOL0Sb+oQZc6TmuVgVHJn08zpGreYyChwx
credentials:
- type: pgp_signature
  pub_key_id: 95C46FA6A41148AC
  body: iQIzBAABAgAdFiEEJ6tQKp6olvZKJ0lwlcRvpqQRSKwFAl5gOuoACgkQlcRvpqQRSKxapA//bODd2IwX2D7nFBkEEd00ol1l4vaw7pgwCjqyQtyskeCZ5IH6H6PkYOSmU9DIBde+cGo35Oi5ynChmfnSatvUZ1dLRJqm8FfOGDw/IsccyYDd1iptj16Ckr6Bsht1XgFJNN10hufuAg77fRIwbGi003WCQdnrJZ1Xbtgex6a4rUqVFW+sjXAB1msmo5B5nabfm/ta0epptxhlINIY2qP5Vb+ftdb2lRUNQwkIEr5GErfAgN3sxYEfqQvLzr/007tEeVznyhdgww47awWsBaTEd6njycbWpphnNA8PbcgUGKDYsj3qLz/bCR1VQOdWgod8PLEru2O+uC2+72ssfT9NDn8HB/WrBKG4W4oykJIhXJ5um18/B9ZSxPMlTQv2Yr4nF7w+Sx3UynEdUTducbIOUq2K+JnI+Ln3gHe0yRw5UEfrzymR4f2Nfe1I13rJk2W7SVRDmOYidr0MwBlLs8tmnJFMWmWZtd1hpPOpyOyUF1jKgvMuR9ferb5niuc3Lk4trqDiaF+tjy/NmAv/7c+qiVmKKpVJVVqvT60TqBR9DTHjRGktcPFD50sc811Th+Xd9RdhzpIYM+0DT790FTf8E0hY6wm/NKTGplfqwBSNZk87SeIiFTu7sZWVpAaPz1vTmVGduC1oj3/Zlv6TzNrUAp3VwBepROBhZlHCHUr9tKg=
  account: mediocregopher
2020-03-04 16:34:02 -07:00

225 lines
5.5 KiB
Go

package dehub
import (
"bytes"
"dehub/accessctl"
"dehub/sigcred"
"io"
"math/rand"
"path/filepath"
"runtime/debug"
"testing"
"gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/plumbing"
yaml "gopkg.in/yaml.v2"
)
type harness struct {
t *testing.T
rand *rand.Rand
repo *Repo
cfg *Config
sig sigcred.SignifierInterface
}
func newHarness(t *testing.T) *harness {
rand := rand.New(rand.NewSource(0xb4eadb01))
sig, pubKeyBody := sigcred.SignifierPGPTmp(rand)
pubKeyPath := filepath.Join(DehubDir, "root.asc")
cfg := &Config{
Accounts: []Account{{
ID: "root",
Signifiers: []sigcred.Signifier{{PGPPublicKeyFile: &sigcred.SignifierPGPFile{
Path: pubKeyPath,
}}},
}},
AccessControls: []accessctl.BranchAccessControl{
{
BranchPattern: "**",
ChangeAccessControls: []accessctl.ChangeAccessControl{
{
FilePathPattern: "**",
Condition: accessctl.Condition{
Signature: &accessctl.ConditionSignature{
AccountIDs: []string{"root"},
Count: "100%",
},
},
},
},
},
},
}
cfgBody, err := yaml.Marshal(cfg)
if err != nil {
t.Fatal(err)
}
h := &harness{
t: t,
rand: rand,
repo: InitMemRepo(),
cfg: cfg,
sig: sig,
}
h.stage(map[string]string{
ConfigPath: string(cfgBody),
pubKeyPath: string(pubKeyBody),
})
return h
}
func (h *harness) stage(tree map[string]string) {
w, err := h.repo.GitRepo.Worktree()
if err != nil {
h.t.Fatal(err)
}
fs := w.Filesystem
for path, content := range tree {
if content == "" {
if _, err := w.Remove(path); err != nil {
h.t.Fatalf("error removing %q: %v", path, err)
}
continue
}
dir := filepath.Dir(path)
if err := fs.MkdirAll(dir, 0666); err != nil {
h.t.Fatalf("error making directory %q: %v", dir, err)
}
f, err := fs.Create(path)
if err != nil {
h.t.Fatalf("error creating file %q: %v", path, err)
} else if _, err := io.Copy(f, bytes.NewBufferString(content)); err != nil {
h.t.Fatalf("error writing to file %q: %v", path, err)
} else if err := f.Close(); err != nil {
h.t.Fatalf("error closing file %q: %v", path, err)
} else if _, err := w.Add(path); err != nil {
h.t.Fatalf("error adding file %q to index: %v", path, err)
}
}
}
func (h *harness) changeCommit(msg, accountID string, sig sigcred.SignifierInterface) (Commit, plumbing.Hash) {
commit, err := h.repo.NewCommitChange(msg)
if err != nil {
h.t.Fatalf("failed to create CommitChange: %v", err)
}
if sig != nil {
if commit, err = h.repo.AccreditCommit(commit, accountID, sig); err != nil {
h.t.Fatalf("failed to accredit commit: %v", err)
}
}
hash, err := h.repo.Commit(commit, accountID)
if err != nil {
h.t.Fatalf("failed to commit ChangeCommit: %v", err)
}
return commit, hash
}
func (h *harness) reset(to plumbing.Hash, mode git.ResetMode) {
w, err := h.repo.GitRepo.Worktree()
if err != nil {
h.t.Fatal(err)
}
err = w.Reset(&git.ResetOptions{
Commit: to,
Mode: mode,
})
if err != nil {
h.t.Fatal(err)
}
}
func TestHasStagedChanges(t *testing.T) {
harness := newHarness(t)
assertHasStaged := func(expHasStaged bool) {
hasStaged, err := harness.repo.HasStagedChanges()
if err != nil {
debug.PrintStack()
t.Fatalf("error calling HasStagedChanges: %v", err)
} else if hasStaged != expHasStaged {
debug.PrintStack()
t.Fatalf("expected HasStagedChanges to return %v", expHasStaged)
}
}
// the harness starts with some staged changes
assertHasStaged(true)
harness.stage(map[string]string{"foo": "bar"})
assertHasStaged(true)
harness.changeCommit("first commit", "root", harness.sig)
assertHasStaged(false)
harness.stage(map[string]string{"foo": ""}) // delete foo
assertHasStaged(true)
harness.changeCommit("second commit", "root", harness.sig)
assertHasStaged(false)
}
// TestOldConfig tests that having an older, now malformed, Config doesn't mess
// with the current parsing, as long as the default access controls still work.
func TestOldConfig(t *testing.T) {
harness := newHarness(t)
// overwrite the currently staged config file with an older form
harness.stage(map[string]string{ConfigPath: `
---
accounts:
- id: root
signifiers:
- type: pgp_public_key_file
path: ".dehub/root.asc"
access_controls:
- pattern: "**"
condition:
type: signature
account_ids:
- root
count: 0
`})
_, hash0 := harness.changeCommit("first commit, this is going great", "root", harness.sig)
// even though that access_controls doesn't actually require any signatures,
// it should be used because it's not well formed.
harness.stage(map[string]string{"foo": "no rules!"})
_, hash1 := harness.changeCommit("ain't no laws", "toot", nil)
// verifying the first should work, but not the second.
if err := harness.repo.VerifyCommit(MainRefName, hash0); err != nil {
t.Fatalf("first commit %q should be verifiable, but got: %v", hash0, err)
} else if err := harness.repo.VerifyCommit(MainRefName, hash1); err == nil {
t.Fatalf("second commit %q should not have been verified", hash1)
}
// reset back to hash0
harness.reset(hash0, git.HardReset)
// make a commit fixing the config. everything should still be fine.
harness.stage(map[string]string{ConfigPath: `
---
accounts:
- id: root
signifiers:
- type: pgp_public_key_file
path: ".dehub/root.asc"
`})
_, hash2 := harness.changeCommit("Fix the config!", "root", harness.sig)
if err := harness.repo.VerifyCommit(MainRefName, hash2); err != nil {
t.Fatalf("config fix commit %q should be verifiable, but got: %v", hash2, err)
}
}