package control import ( "io" "log" "net/http" "net/url" "os" "path/filepath" "strings" "testing" "git.t5de.dev/t5de/t5de-proxy/internal/hub" "git.t5de.dev/t5de/t5de-proxy/internal/proxy" ) func TestServer(t *testing.T) { choice := filepath.Join(t.TempDir(), "server.json") for channel, want := range map[string]string{"release": Production, "": Production, "nightly": Staging, "dev": Staging} { if got := Server(choice, channel, ""); got != want { t.Errorf("channel %q: %s", channel, got) } } if err := SaveChoice(choice, "https://hub.example.org"); err != nil { t.Fatal(err) } if got := Server(choice, "nightly", ""); got != "https://hub.example.org" { t.Errorf("chosen: %s", got) } if got := Server(choice, "nightly", "http://localhost:4101/"); got != "http://localhost:4101" { t.Errorf("$T5DE_HUB: %s", got) } if err := SaveChoice(choice, ""); err != nil { t.Fatal(err) } if got := Server(choice, "release", ""); got != Production { t.Errorf("default again: %s", got) } // A choice that isn't a hub address is ignored. os.WriteFile(choice, []byte(`{"hub": "http://evil.test"}`), 0o600) if got := Server(choice, "release", ""); got != Production { t.Errorf("bad choice: %s", got) } data := `C:\data` if got := StateDir(data, Production); got != data { t.Errorf("production state %s", got) } if got := StateDir(data, Staging); got != filepath.Join(data, "hubs", "hub.staging.t5de.dev") { t.Errorf("staging state %s", got) } if got := StateDir(data, "http://LocalHost:4101/x"); got != filepath.Join(data, "hubs", "localhost_4101_x") { t.Errorf("local state %s", got) } for _, bad := range []string{"http://evil.test", "ftp://x", "hub.t5de.dev", "https://", "https://x/?a=1"} { if _, err := CheckHub(bad); err == nil { t.Errorf("accepted %q", bad) } } } func TestChoosingServer(t *testing.T) { dir := t.TempDir() m := &Manager{Path: filepath.Join(dir, "hub.json"), Hub: Staging, Default: Staging, ChoicePath: filepath.Join(dir, "server.json"), Log: log.New(io.Discard, "", 0)} if s := ask(t, m, "GET", "/hub", ""); s.Hub != Staging || s.Default != Staging || s.Choice != "" || s.Restart { t.Fatalf("status %+v", s) } if s := ask(t, m, "POST", "/hub/server", "hub="+url.QueryEscape(Production+"/")); s.Choice != Production || !s.Restart || s.Hub != Staging { t.Fatalf("chose production: %+v", s) } // Choosing the default again forgets the choice. if s := ask(t, m, "POST", "/hub/server", "hub="+url.QueryEscape(Staging)); s.Choice != "" || s.Restart { t.Fatalf("back to the default: %+v", s) } if _, err := os.Stat(m.ChoicePath); !os.IsNotExist(err) { t.Fatalf("server.json kept: %v", err) } u, _ := url.Parse("http://" + Host + "/hub/server") body := "hub=http://evil.test" req, _ := http.NewRequest("POST", u.String(), strings.NewReader(body)) x := &proxy.Exchange{URL: u, Request: req, Body: []byte(body)} m.Intercept(x) if x.Response.StatusCode != 400 { t.Fatalf("plain http hub: %d", x.Response.StatusCode) } // Set by $T5DE_HUB: never a restart to suggest. m.Fixed = true ask(t, m, "POST", "/hub/server", "hub="+url.QueryEscape(Production)) if s := ask(t, m, "GET", "/hub", ""); s.Restart || !s.Fixed { t.Fatalf("fixed: %+v", s) } } func TestSignInForAnotherHub(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "hub.json") if err := (&hub.Saved{URL: "http://localhost:4101", Token: "old"}).Save(path); err != nil { t.Fatal(err) } attached := 0 m := &Manager{Path: path, Hub: Production, Log: log.New(io.Discard, "", 0), Attach: func(*hub.Client) { attached++ }} m.Start() if s := ask(t, m, "GET", "/hub", ""); s.SignedIn || attached != 0 { t.Fatalf("used another hub's sign-in: %+v", s) } }