Files

97 lines
2.7 KiB
Go

package e2e
import (
"context"
"net"
"strconv"
"testing"
"time"
"git.veillax.com/Veillax/bamboo"
"git.veillax.com/Veillax/blacktip"
)
type exposed struct {
ID, Host, Hostname, URL, SiteToken string
Port int
}
// createExpose retries until an edge is online and the call succeeds.
func (w *world) createExpose(c *client, in map[string]any) exposed {
w.t.Helper()
var out exposed
for i := 0; i < 40; i++ {
if code, _ := c.do("POST", "/api/orgs/-/expose", in, &out); code == 200 {
return out
}
time.Sleep(150 * time.Millisecond)
}
c.must("POST", "/api/orgs/-/expose", in, &out)
return out
}
func (w *world) agentFor(e exposed) context.CancelFunc {
ctx, cancel := context.WithCancel(context.Background())
w.t.Cleanup(cancel)
b, err := bamboo.New(bamboo.Config{Hammerhead: w.ts.URL, Token: e.SiteToken, DataDir: w.t.TempDir()})
if err != nil {
w.t.Fatal(err)
}
go b.Run(ctx)
return cancel
}
// An ephemeral exposure carries traffic through the tunnel, and is gone after DELETE.
func TestEphemeralExpose(t *testing.T) {
w := setup(t, blacktip.TraefikConfig{})
var key struct{ Key string }
w.admin.must("POST", "/api/orgs/"+w.org+"/apikeys", map[string]string{"name": "shark"}, &key)
kc := newClient(t, w.ts.URL)
kc.key = key.Key
w.admin.must("POST", "/api/orgs/"+w.org+"/domains", map[string]any{"name": "example.test", "edgeId": w.edge}, nil)
// ----- tcp -----
svc := tcpBackend(t, "SVC")
e := w.createExpose(kc, map[string]any{"proto": "tcp", "targetPort": svc, "ttlSeconds": 60})
stop := w.agentFor(e)
addr := net.JoinHostPort("127.0.0.1", strconv.Itoa(e.Port))
if got := tcpAsk(t, addr, "hi"); got != "SVC:hi" {
t.Fatalf("through the tunnel: %q", got)
}
kc.must("POST", "/api/orgs/-/expose/"+e.ID+"/renew", nil, nil)
kc.must("DELETE", "/api/orgs/-/expose/"+e.ID, nil, nil)
stop()
closed := false
for i := 0; i < 40 && !closed; i++ {
c, err := net.DialTimeout("tcp", addr, 300*time.Millisecond)
if err != nil {
closed = true
break
}
c.Close()
time.Sleep(150 * time.Millisecond)
}
if !closed {
t.Error("the port is still open after DELETE")
}
kc.expect(404, "GET", "/api/orgs/-/expose/"+e.ID, nil)
// ----- http, with a password -----
web := webBackend(t, "app", 200)
port := freePort(t)
h := w.createExpose(kc, map[string]any{"proto": "http", "name": "demo", "port": port, "targetPort": web,
"auth": map[string]any{"password": "hunter22"}})
w.agentFor(h)
_, get := edgeClient("http", port)
var r webResp
for i := 0; i < 60; i++ {
if r = get("GET", h.Hostname, "/x"); r.status == 302 {
break
}
time.Sleep(150 * time.Millisecond)
}
if r.status != 302 {
t.Fatalf("protected exposure should send visitors to the login, got %+v", r)
}
}