71e42811fb
- add agent.ParseDurationFlag: bare integer means seconds, duration strings still parse - take --interval as a string and parse it in the command - reject unparseable and non-positive values with an error naming the flag
108 lines
3.4 KiB
Go
108 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// A bad PR reference must fail the command (so main exits non-zero) rather than
|
|
// return nil. Parsing rejects the ref before any Vault/Gitea call, so this stays
|
|
// hermetic.
|
|
func TestExecuteBadRefErrors(t *testing.T) {
|
|
cmd := newRootCmd()
|
|
cmd.SetArgs([]string{"--once", "not-a-ref"})
|
|
cmd.SetOut(io.Discard)
|
|
cmd.SetErr(io.Discard)
|
|
if err := cmd.Execute(); err == nil {
|
|
t.Fatal("Execute() = nil, want error for a bad PR reference")
|
|
}
|
|
}
|
|
|
|
// No arguments is also an error (nothing to watch).
|
|
func TestExecuteNoArgsErrors(t *testing.T) {
|
|
cmd := newRootCmd()
|
|
cmd.SetArgs(nil)
|
|
cmd.SetOut(io.Discard)
|
|
cmd.SetErr(io.Discard)
|
|
if err := cmd.Execute(); err == nil {
|
|
t.Fatal("Execute() = nil, want error when no PR references are given")
|
|
}
|
|
}
|
|
|
|
// Watching a public repo with no credentials available must work: the failed
|
|
// mint is a warning, the poll goes out unauthenticated, and the command exits 0.
|
|
func TestOnceRunsAnonymouslyWhenNoTokenIsAvailable(t *testing.T) {
|
|
vault := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusForbidden)
|
|
}))
|
|
defer vault.Close()
|
|
|
|
authHeaders := 0
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/api/v1/repos/unkin/repo/pulls/7", func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Header.Get("Authorization") != "" {
|
|
authHeaders++
|
|
}
|
|
_, _ = io.WriteString(w, `{"number":7,"state":"open","mergeable":true,"head":{"sha":"cafebabe"}}`)
|
|
})
|
|
mux.HandleFunc("/api/v1/repos/unkin/repo/commits/cafebabe/status", func(w http.ResponseWriter, r *http.Request) {
|
|
_, _ = io.WriteString(w, `{"state":"success"}`)
|
|
})
|
|
mux.HandleFunc("/api/v1/repos/unkin/repo/issues/7/comments", func(w http.ResponseWriter, r *http.Request) {
|
|
_, _ = io.WriteString(w, `[]`)
|
|
})
|
|
gitea := httptest.NewServer(mux)
|
|
defer gitea.Close()
|
|
|
|
t.Setenv("VAULT_ADDR", vault.URL)
|
|
t.Setenv("GITEA_URL", gitea.URL)
|
|
|
|
cmd := newRootCmd()
|
|
cmd.SetArgs([]string{"--once", "unkin/repo#7"})
|
|
cmd.SetOut(io.Discard)
|
|
cmd.SetErr(io.Discard)
|
|
if err := cmd.Execute(); err != nil {
|
|
t.Fatalf("anonymous --once should succeed without a token: %v", err)
|
|
}
|
|
if authHeaders != 0 {
|
|
t.Errorf("sent %d Authorization headers, want none", authHeaders)
|
|
}
|
|
}
|
|
|
|
// A bare integer interval means seconds and must survive flag parsing: the
|
|
// command should fail on the missing PR reference, not on the flag value.
|
|
func TestExecuteBareIntervalIsSeconds(t *testing.T) {
|
|
cmd := newRootCmd()
|
|
cmd.SetArgs([]string{"--interval", "15"})
|
|
cmd.SetOut(io.Discard)
|
|
cmd.SetErr(io.Discard)
|
|
err := cmd.Execute()
|
|
if err == nil {
|
|
t.Fatal("Execute() = nil, want the no-references error")
|
|
}
|
|
if !strings.Contains(err.Error(), "no PR references given") {
|
|
t.Fatalf("Execute() error = %v, want the no-references error", err)
|
|
}
|
|
}
|
|
|
|
// An unparseable interval is rejected before any Vault/Gitea call, with an
|
|
// error naming the flag and showing valid forms.
|
|
func TestExecuteBadIntervalErrors(t *testing.T) {
|
|
cmd := newRootCmd()
|
|
cmd.SetArgs([]string{"--interval", "soon", "unkin/repo#1"})
|
|
cmd.SetOut(io.Discard)
|
|
cmd.SetErr(io.Discard)
|
|
err := cmd.Execute()
|
|
if err == nil {
|
|
t.Fatal("Execute() = nil, want error for an unparseable --interval")
|
|
}
|
|
for _, want := range []string{"--interval", "30s"} {
|
|
if !strings.Contains(err.Error(), want) {
|
|
t.Errorf("Execute() error %q does not mention %q", err, want)
|
|
}
|
|
}
|
|
}
|