vcs as string, not int.
No longer do we keep track of const iota style. Just encode the behavior in the server for defaults, add a validation function, call it a day. Change-Id: I603e9dd287a57084c78c543f1ce83b0acf47a765
This commit is contained in:
parent
a1f6e15f28
commit
ce00d933aa
66
api_test.go
66
api_test.go
@ -2,21 +2,21 @@ package vain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
ms := NewSimpleStore("")
|
||||
s := &Server{
|
||||
storage: ms,
|
||||
}
|
||||
ts := httptest.NewServer(s)
|
||||
s.hostname = ts.URL
|
||||
sm := http.NewServeMux()
|
||||
_ = NewServer(sm, ms)
|
||||
ts := httptest.NewServer(sm)
|
||||
resp, err := http.Get(ts.URL)
|
||||
if err != nil {
|
||||
t.Errorf("couldn't GET: %v", err)
|
||||
@ -36,8 +36,25 @@ func TestAdd(t *testing.T) {
|
||||
t.Errorf("started with something in it; got %d, want %d", len(ms.p), 0)
|
||||
}
|
||||
|
||||
good := fmt.Sprintf("%s/foo", ts.URL)
|
||||
resp, err = http.Post(good, "application/json", strings.NewReader(`{"repo": "https://s.mcquay.me/sm/vain"}`))
|
||||
{
|
||||
u := fmt.Sprintf("%s/db/", ts.URL)
|
||||
resp, err := http.Get(u)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
io.Copy(buf, resp.Body)
|
||||
pkgs := []Package{}
|
||||
if err := json.NewDecoder(buf).Decode(&pkgs); err != nil {
|
||||
t.Errorf("problem parsing json: %v, \n%q", err, buf)
|
||||
}
|
||||
if got, want := len(pkgs), 0; got != want {
|
||||
t.Errorf("should have empty pkg list; got %d, want %d", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
u := fmt.Sprintf("%s/foo", ts.URL)
|
||||
resp, err = http.Post(u, "application/json", strings.NewReader(`{"repo": "https://s.mcquay.me/sm/vain"}`))
|
||||
if err != nil {
|
||||
t.Errorf("couldn't POST: %v", err)
|
||||
}
|
||||
@ -46,6 +63,11 @@ func TestAdd(t *testing.T) {
|
||||
t.Errorf("storage should have something in it; got %d, want %d", len(ms.p), 1)
|
||||
}
|
||||
|
||||
ur, err := url.Parse(ts.URL)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
good := fmt.Sprintf("%s/foo", ur.Host)
|
||||
p, ok := ms.p[good]
|
||||
if !ok {
|
||||
t.Fatalf("did not find package for %s; should have posted a valid package", good)
|
||||
@ -56,8 +78,8 @@ func TestAdd(t *testing.T) {
|
||||
if want := "https://s.mcquay.me/sm/vain"; p.Repo != want {
|
||||
t.Errorf("repo did not go through as expected; got %q, want %q", p.Repo, want)
|
||||
}
|
||||
if want := Git; p.Vcs != want {
|
||||
t.Errorf("Vcs did not go through as expected; got %q, want %q", p.Vcs, want)
|
||||
if got, want := p.Vcs, "git"; got != want {
|
||||
t.Errorf("Vcs did not go through as expected; got %q, want %q", got, want)
|
||||
}
|
||||
|
||||
resp, err = http.Get(ts.URL)
|
||||
@ -75,6 +97,23 @@ func TestAdd(t *testing.T) {
|
||||
if got, want := strings.Count(buf.String(), "meta"), 1; got != want {
|
||||
t.Errorf("did not find all the tags I need; got %d, want %d", got, want)
|
||||
}
|
||||
|
||||
{
|
||||
u := fmt.Sprintf("%s/db/", ts.URL)
|
||||
resp, err := http.Get(u)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
io.Copy(buf, resp.Body)
|
||||
pkgs := []Package{}
|
||||
if err := json.NewDecoder(buf).Decode(&pkgs); err != nil {
|
||||
t.Errorf("problem parsing json: %v, \n%q", err, buf)
|
||||
}
|
||||
if got, want := len(pkgs), 1; got != want {
|
||||
t.Errorf("should (mildly) populated pkg list; got %d, want %d", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidPath(t *testing.T) {
|
||||
@ -83,7 +122,6 @@ func TestInvalidPath(t *testing.T) {
|
||||
storage: ms,
|
||||
}
|
||||
ts := httptest.NewServer(s)
|
||||
s.hostname = ts.URL
|
||||
|
||||
resp, err := http.Post(ts.URL, "application/json", strings.NewReader(`{"repo": "https://s.mcquay.me/sm/vain"}`))
|
||||
if err != nil {
|
||||
@ -103,7 +141,6 @@ func TestCannotDuplicateExistingPath(t *testing.T) {
|
||||
storage: ms,
|
||||
}
|
||||
ts := httptest.NewServer(s)
|
||||
s.hostname = ts.URL
|
||||
|
||||
url := fmt.Sprintf("%s/foo", ts.URL)
|
||||
resp, err := http.Post(url, "application/json", strings.NewReader(`{"repo": "https://s.mcquay.me/sm/vain"}`))
|
||||
@ -128,7 +165,6 @@ func TestCannotAddExistingSubPath(t *testing.T) {
|
||||
storage: ms,
|
||||
}
|
||||
ts := httptest.NewServer(s)
|
||||
s.hostname = ts.URL
|
||||
|
||||
url := fmt.Sprintf("%s/foo/bar", ts.URL)
|
||||
resp, err := http.Post(url, "application/json", strings.NewReader(`{"repo": "https://s.mcquay.me/sm/vain"}`))
|
||||
@ -156,7 +192,6 @@ func TestMissingRepo(t *testing.T) {
|
||||
storage: ms,
|
||||
}
|
||||
ts := httptest.NewServer(s)
|
||||
s.hostname = ts.URL
|
||||
url := fmt.Sprintf("%s/foo", ts.URL)
|
||||
resp, err := http.Post(url, "application/json", strings.NewReader(`{}`))
|
||||
if err != nil {
|
||||
@ -176,7 +211,6 @@ func TestBadJson(t *testing.T) {
|
||||
storage: ms,
|
||||
}
|
||||
ts := httptest.NewServer(s)
|
||||
s.hostname = ts.URL
|
||||
url := fmt.Sprintf("%s/foo", ts.URL)
|
||||
resp, err := http.Post(url, "application/json", strings.NewReader(`{`))
|
||||
if err != nil {
|
||||
@ -196,7 +230,6 @@ func TestUnsupportedMethod(t *testing.T) {
|
||||
storage: ms,
|
||||
}
|
||||
ts := httptest.NewServer(s)
|
||||
s.hostname = ts.URL
|
||||
url := fmt.Sprintf("%s/foo", ts.URL)
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("PUT", url, nil)
|
||||
@ -215,9 +248,8 @@ func TestUnsupportedMethod(t *testing.T) {
|
||||
func TestNewServer(t *testing.T) {
|
||||
ms := NewSimpleStore("")
|
||||
sm := http.NewServeMux()
|
||||
s := NewServer(sm, ms, "foo")
|
||||
s := NewServer(sm, ms)
|
||||
ts := httptest.NewServer(s)
|
||||
s.hostname = ts.URL
|
||||
url := fmt.Sprintf("%s/foo", ts.URL)
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("PUT", url, nil)
|
||||
|
@ -65,7 +65,7 @@ func main() {
|
||||
c := &config{
|
||||
Port: 4040,
|
||||
}
|
||||
if err := envconfig.Process("ysv", c); err != nil {
|
||||
if err := envconfig.Process("vain", c); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "problem processing environment: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
@ -77,7 +77,7 @@ func main() {
|
||||
}
|
||||
}
|
||||
if c.DB == "" {
|
||||
log.Printf("warning: in-memory db mode; if you do not want this set YSV_DB")
|
||||
log.Printf("warning: in-memory db mode; if you do not want this set VAIN_DB")
|
||||
}
|
||||
hostname := "localhost"
|
||||
if hn, err := os.Hostname(); err != nil {
|
||||
|
20
server.go
20
server.go
@ -12,7 +12,7 @@ func NewServer(sm *http.ServeMux, store Storage) *Server {
|
||||
s := &Server{
|
||||
storage: store,
|
||||
}
|
||||
sm.Handle("/", s)
|
||||
addRoutes(sm, s)
|
||||
return s
|
||||
}
|
||||
|
||||
@ -43,6 +43,13 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
http.Error(w, fmt.Sprintf("invalid repository %q", req.URL.Path), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if p.Vcs == "" {
|
||||
p.Vcs = "git"
|
||||
}
|
||||
if !valid(p.Vcs) {
|
||||
http.Error(w, fmt.Sprintf("invalid vcs %q", p.Vcs), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
p.path = fmt.Sprintf("%s/%s", req.Host, strings.Trim(req.URL.Path, "/"))
|
||||
if !Valid(p.path, s.storage.All()) {
|
||||
http.Error(w, fmt.Sprintf("invalid path; prefix already taken %q", req.URL.Path), http.StatusConflict)
|
||||
@ -56,3 +63,14 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
http.Error(w, fmt.Sprintf("unsupported method %q; accepted: POST, GET", req.Method), http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) db(w http.ResponseWriter, req *http.Request) {
|
||||
all := s.storage.All()
|
||||
w.Header().Set("Content-type", "application/json")
|
||||
json.NewEncoder(w).Encode(&all)
|
||||
}
|
||||
|
||||
func addRoutes(sm *http.ServeMux, s *Server) {
|
||||
sm.Handle("/", s)
|
||||
sm.HandleFunc("/db/", s.db)
|
||||
}
|
||||
|
11
storage.go
11
storage.go
@ -107,5 +107,14 @@ func (ms *SimpleStore) Load() error {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
return json.NewDecoder(f).Decode(&ms.p)
|
||||
|
||||
in := map[string]Package{}
|
||||
if err := json.NewDecoder(f).Decode(&in); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range in {
|
||||
v.path = k
|
||||
ms.p[k] = v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
package vain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -13,7 +16,7 @@ func equiv(a, b map[string]Package) (bool, []error) {
|
||||
errs := []error{}
|
||||
if got, want := len(a), len(b); got != want {
|
||||
equiv = false
|
||||
errs = append(errs, fmt.Errorf("uncorrect number of elements: got %d, want %d", got, want))
|
||||
errs = append(errs, fmt.Errorf("incorrect number of elements: got %d, want %d", got, want))
|
||||
return false, errs
|
||||
}
|
||||
|
||||
@ -37,10 +40,14 @@ func TestSimpleStorage(t *testing.T) {
|
||||
db := filepath.Join(root, "vain.json")
|
||||
ms := NewSimpleStore(db)
|
||||
orig := map[string]Package{
|
||||
"foo": {},
|
||||
"bar": {},
|
||||
"foo": {Vcs: "mercurial"},
|
||||
"bar": {Vcs: "bzr"},
|
||||
"baz": {},
|
||||
}
|
||||
for k, v := range orig {
|
||||
v.path = k
|
||||
orig[k] = v
|
||||
}
|
||||
ms.p = orig
|
||||
if err := ms.Save(); err != nil {
|
||||
t.Errorf("should have been able to Save: %v", err)
|
||||
@ -49,7 +56,7 @@ func TestSimpleStorage(t *testing.T) {
|
||||
if err := ms.Load(); err != nil {
|
||||
t.Errorf("should have been able to Load: %v", err)
|
||||
}
|
||||
if ok, errs := equiv(orig, ms.p); !ok {
|
||||
if ok, errs := equiv(ms.p, orig); !ok {
|
||||
for _, err := range errs {
|
||||
t.Error(err)
|
||||
}
|
||||
@ -82,3 +89,39 @@ func TestRemove(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackageJsonParsing(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
output string
|
||||
parsed Package
|
||||
}{
|
||||
{
|
||||
input: `{"vcs":"git","repo":"https://s.mcquay.me/sm/ud/"}`,
|
||||
output: `{"vcs":"git","repo":"https://s.mcquay.me/sm/ud/"}`,
|
||||
parsed: Package{Vcs: "git", Repo: "https://s.mcquay.me/sm/ud/"},
|
||||
},
|
||||
{
|
||||
input: `{"vcs":"hg","repo":"https://s.mcquay.me/sm/ud/"}`,
|
||||
output: `{"vcs":"hg","repo":"https://s.mcquay.me/sm/ud/"}`,
|
||||
parsed: Package{Vcs: "hg", Repo: "https://s.mcquay.me/sm/ud/"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
p := Package{}
|
||||
if err := json.NewDecoder(strings.NewReader(test.input)).Decode(&p); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if p != test.parsed {
|
||||
t.Errorf("got:\n\t%v, want\n\t%v", p, test.parsed)
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
if err := json.NewEncoder(buf).Encode(&p); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if got, want := strings.TrimSpace(buf.String()), test.output; got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
60
vain.go
60
vain.go
@ -3,45 +3,20 @@
|
||||
// The executable, cmd/vaind, is located in the respective subdirectory.
|
||||
package vain
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
import "fmt"
|
||||
|
||||
type vcs int
|
||||
|
||||
const (
|
||||
// Git is the default Vcs.
|
||||
Git vcs = iota
|
||||
|
||||
// Hg is mercurial
|
||||
Hg
|
||||
|
||||
// Svn
|
||||
Svn
|
||||
|
||||
// Bazaar
|
||||
Bzr
|
||||
)
|
||||
|
||||
var vcss = [...]string{
|
||||
"git",
|
||||
"mercurial",
|
||||
"svn",
|
||||
"bazaar",
|
||||
var vcss = map[string]bool{
|
||||
"hg": true,
|
||||
"git": true,
|
||||
"bzr": true,
|
||||
"svn": true,
|
||||
}
|
||||
|
||||
var labelToVcs = map[string]vcs{
|
||||
"git": Git,
|
||||
"mercurial": Hg,
|
||||
"hg": Hg,
|
||||
"svn": Svn,
|
||||
"bazaar": Bzr,
|
||||
func valid(vcs string) bool {
|
||||
_, ok := vcss[vcs]
|
||||
return ok
|
||||
}
|
||||
|
||||
// String returns the name of the vcs ("git", "mercurial", ...).
|
||||
func (v vcs) String() string { return vcss[v] }
|
||||
|
||||
// Package stores the three pieces of information needed to create the meta
|
||||
// tag. Two of these (Vcs and Repo) are stored explicitly, and the third is
|
||||
// determined implicitly by the path POSTed to. For more information refer to
|
||||
@ -49,8 +24,8 @@ func (v vcs) String() string { return vcss[v] }
|
||||
//
|
||||
// https://golang.org/cmd/go/#hdr-Remote_import_paths
|
||||
type Package struct {
|
||||
//Vcs (version control system) supported: "git", "mercurial"
|
||||
Vcs vcs `json:"vcs"`
|
||||
//Vcs (version control system) supported: "hg", "git", "bzr", "svn"
|
||||
Vcs string `json:"vcs"`
|
||||
// Repo: the remote repository url
|
||||
Repo string `json:"repo"`
|
||||
|
||||
@ -65,16 +40,3 @@ func (p Package) String() string {
|
||||
p.Repo,
|
||||
)
|
||||
}
|
||||
|
||||
func (p *Package) UnmarshalJSON(b []byte) (err error) {
|
||||
pkg := struct {
|
||||
Vcs string
|
||||
Repo string
|
||||
}{}
|
||||
err = json.Unmarshal(b, &pkg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.Vcs, p.Repo = labelToVcs[pkg.Vcs], pkg.Repo
|
||||
return nil
|
||||
}
|
||||
|
22
vain_test.go
22
vain_test.go
@ -7,6 +7,7 @@ import (
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
p := Package{
|
||||
Vcs: "git",
|
||||
path: "mcquay.me/bps",
|
||||
Repo: "https://s.mcquay.me/sm/bps",
|
||||
}
|
||||
@ -21,19 +22,22 @@ func TestString(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestVcsStrings(t *testing.T) {
|
||||
func TestSupportedVcsStrings(t *testing.T) {
|
||||
tests := []struct {
|
||||
got string
|
||||
want string
|
||||
in string
|
||||
want bool
|
||||
}{
|
||||
{fmt.Sprintf("%+v", Git), "git"},
|
||||
{fmt.Sprintf("%+v", Hg), "mercurial"},
|
||||
{fmt.Sprintf("%+v", Svn), "svn"},
|
||||
{fmt.Sprintf("%+v", Bzr), "bazaar"},
|
||||
{"hg", true},
|
||||
{"git", true},
|
||||
{"bzr", true},
|
||||
|
||||
{"", false},
|
||||
{"bazar", false},
|
||||
{"mercurial", false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if test.got != test.want {
|
||||
t.Errorf("incorrect conversion of vain.Vcs -> string; got %q, want %q", test.got, test.want)
|
||||
if got, want := valid(test.in), test.want; got != want {
|
||||
t.Errorf("%s: %t is incorrect validity", test.in, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user