Add admin dashboard at / with bearer-token overview API
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestAdminOverview(t *testing.T) {
|
||||
store, err := OpenStore("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
api := &API{
|
||||
Store: store, Hub: NewHub(store), Domain: "opentunnel.test",
|
||||
AdminToken: "admin-secret", StartedAt: time.Now().Add(-90 * time.Second), Version: "test",
|
||||
}
|
||||
srv := httptest.NewServer(api)
|
||||
defer srv.Close()
|
||||
|
||||
if _, _, err := store.createTunnel("opentunnel.test"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// no token configured → 503
|
||||
noToken := &API{Store: store, Hub: NewHub(store), Domain: "opentunnel.test", StartedAt: time.Now()}
|
||||
noTokenSrv := httptest.NewServer(noToken)
|
||||
defer noTokenSrv.Close()
|
||||
resp, err := http.Get(noTokenSrv.URL + "/api/admin/overview")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.StatusCode != 503 {
|
||||
t.Errorf("unconfigured admin token: got %d, want 503", resp.StatusCode)
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
// missing and wrong token → 401
|
||||
for _, header := range []string{"", "Bearer nope"} {
|
||||
req, _ := http.NewRequest("GET", srv.URL+"/api/admin/overview", nil)
|
||||
if header != "" {
|
||||
req.Header.Set("Authorization", header)
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.StatusCode != 401 {
|
||||
t.Errorf("auth %q: got %d, want 401", header, resp.StatusCode)
|
||||
}
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
// correct token → 200 with the tunnel and server info
|
||||
req, _ := http.NewRequest("GET", srv.URL+"/api/admin/overview", nil)
|
||||
req.Header.Set("Authorization", "Bearer admin-secret")
|
||||
resp, err = http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("admin overview: got %d, want 200", resp.StatusCode)
|
||||
}
|
||||
var overview adminOverview
|
||||
if err := json.NewDecoder(resp.Body).Decode(&overview); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if overview.Server.Domain != "opentunnel.test" || overview.Server.Version != "test" {
|
||||
t.Errorf("server info: %+v", overview.Server)
|
||||
}
|
||||
if overview.Server.UptimeSeconds < 60 {
|
||||
t.Errorf("uptime: %d", overview.Server.UptimeSeconds)
|
||||
}
|
||||
if overview.Totals.Tunnels != 1 || overview.Totals.Online != 0 {
|
||||
t.Errorf("totals: %+v", overview.Totals)
|
||||
}
|
||||
if len(overview.Tunnels) != 1 || !strings.HasSuffix(overview.Tunnels[0].Hostname, ".opentunnel.test") {
|
||||
t.Errorf("tunnels: %+v", overview.Tunnels)
|
||||
}
|
||||
if overview.Tunnels[0].State != "offline" {
|
||||
t.Errorf("tunnel state: %q", overview.Tunnels[0].State)
|
||||
}
|
||||
if overview.CA.Expires == "" {
|
||||
t.Error("CA expiry missing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDashboardPage(t *testing.T) {
|
||||
store, err := OpenStore("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
api := &API{Store: store, Hub: NewHub(store), Domain: "opentunnel.test", StartedAt: time.Now()}
|
||||
srv := httptest.NewServer(api)
|
||||
defer srv.Close()
|
||||
|
||||
for _, path := range []string{"/", "/admin"} {
|
||||
resp, err := http.Get(srv.URL + path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
body := make([]byte, 512)
|
||||
n, _ := resp.Body.Read(body)
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != 200 || !strings.Contains(resp.Header.Get("Content-Type"), "text/html") {
|
||||
t.Errorf("%s: got %d %q", path, resp.StatusCode, resp.Header.Get("Content-Type"))
|
||||
}
|
||||
if !strings.Contains(string(body[:n]), "tunneld admin") {
|
||||
t.Errorf("%s: unexpected body", path)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user