Skip to content

Commit

Permalink
feat: control app name through bootstrap server
Browse files Browse the repository at this point in the history
We only allow the echo app to start, but eventually there will be other
kinds of apps.
  • Loading branch information
mark-rushakoff committed May 16, 2024
1 parent 063ac2c commit e60d121
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 0 deletions.
26 changes: 26 additions & 0 deletions cmd/gordian-stress/internal/gstress/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,32 @@ func TestBootstrap_chainID(t *testing.T) {
require.Equal(t, "foo", chainID)
}

func TestBootstrap_app(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

bfx := newFixture(ctx, t, fixtureConfig{SeedAddrs: []string{"a"}})

c := bfx.NewClient()

// The default app is echo.
app, err := c.App()
require.NoError(t, err)
require.Equal(t, "echo", app)

// Setting the app to anything else currently fails,
// because we don't yet support any other built-in app.
// Change the chain ID.
require.Error(t, c.SetApp("foo"))

// Confirm it didn't change.
app, err = c.App()
require.NoError(t, err)
require.Equal(t, "echo", app)
}

type fixture struct {
Log *slog.Logger

Expand Down
40 changes: 40 additions & 0 deletions cmd/gordian-stress/internal/gstress/bootstrapclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,43 @@ func (c *BootstrapClient) SetChainID(newID string) error {

return nil
}

func (c *BootstrapClient) App() (string, error) {
resp, err := c.client.Get(bootstrapURL + "/app")
if err != nil {
return "", fmt.Errorf("failed to get app: %w", err)
}

defer resp.Body.Close()

b, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("failed to read app response: %w", err)
}

app, ok := strings.CutSuffix(string(b), "\n")
if !ok {
return "", fmt.Errorf("got malformatted app: %q", b)
}

return app, nil
}

func (c *BootstrapClient) SetApp(a string) error {
resp, err := c.client.Post(
bootstrapURL+"/app",
"text/plain",
strings.NewReader(a+"\n"),
)
if err != nil {
return fmt.Errorf("failed to get app: %w", err)
}

resp.Body.Close()

if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("got unexpected response status: %d", resp.StatusCode)
}

return nil
}
46 changes: 46 additions & 0 deletions cmd/gordian-stress/internal/gstress/bootstraphost.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func NewBootstrapHost(
log: log,

s: bState{
app: "echo",
chainID: fmt.Sprintf("gstress%d", time.Now().Unix()),
},

Expand Down Expand Up @@ -140,6 +141,7 @@ func (h *BootstrapHost) newMux() *http.ServeMux {
newID, ok := strings.CutSuffix(string(b), "\n")
if !ok {
w.WriteHeader(http.StatusBadRequest)
_, _ = fmt.Fprintf(w, "new chain ID %q missing required trailing newline", newID)
return
}

Expand All @@ -152,5 +154,49 @@ func (h *BootstrapHost) newMux() *http.ServeMux {
w.WriteHeader(http.StatusMethodNotAllowed)
})

m.HandleFunc("/app", func(w http.ResponseWriter, req *http.Request) {
if req.Method == http.MethodGet {
// GET: report the current app.
if _, err := io.WriteString(w, h.s.App()+"\n"); err != nil {
h.log.Info("Failed to write app", "err", err)
}
return
}

if req.Method == http.MethodPost {
// POST: replace the chain ID with what the client supplied.
b, err := io.ReadAll(req.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
h.log.Info("Failed to read new app from client", "err", err)
return
}

a, ok := strings.CutSuffix(string(b), "\n")
if !ok {
w.WriteHeader(http.StatusBadRequest)
_, _ = fmt.Fprintf(w, "new app %q missing required trailing newline", a)
return
}

switch a {
// There are only a small set of valid apps.
case "echo":
// Okay.
default:
w.WriteHeader(http.StatusBadRequest)
_, _ = fmt.Fprintf(w, "invalid app name %q", a)
return
}

w.WriteHeader(http.StatusNoContent)
h.s.SetApp(strings.TrimSpace(string(a)))
return
}

// Didn't return earlier, so this was a bad method.
w.WriteHeader(http.StatusMethodNotAllowed)
})

return m
}
15 changes: 15 additions & 0 deletions cmd/gordian-stress/internal/gstress/bstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "sync"
type bState struct {
mu sync.Mutex

app string
chainID string
}

Expand All @@ -21,3 +22,17 @@ func (s *bState) SetChainID(newID string) {

s.chainID = newID
}

func (s *bState) App() string {
s.mu.Lock()
defer s.mu.Unlock()

return s.app
}

func (s *bState) SetApp(a string) {
s.mu.Lock()
defer s.mu.Unlock()

s.app = a
}

0 comments on commit e60d121

Please sign in to comment.