package middleware import ( "net/http/httptest" "strings" "testing" "github.com/gofiber/fiber/v2" ) // The outlet a request names has to be found wherever the route happens to put // it. These cover the extraction alone — it is the part that decides whether // the authorisation check runs at all, and a miss here reads exactly like a // pass. func locationFor(t *testing.T, method, target, body string) int { t.Helper() app := fiber.New() found := -1 app.All("/probe", func(c *fiber.Ctx) error { found = requestedLocation(c) return c.SendStatus(fiber.StatusOK) }) var reader *strings.Reader if body == "" { reader = strings.NewReader("") } else { reader = strings.NewReader(body) } req := httptest.NewRequest(method, target, reader) if body != "" { req.Header.Set("Content-Type", "application/json") } if _, err := app.Test(req); err != nil { t.Fatalf("probing: %v", err) } return found } func TestTheOutletIsFoundUnderEveryNameTheRoutesUse(t *testing.T) { // Three spellings for one thing across the POS routes. Missing any of them // leaves that route unguarded. cases := []struct { name string target string }{ {"catalogue says store_id", "/probe?store_id=1135"}, {"sales say locationid", "/probe?locationid=1135"}, {"health says location_id", "/probe?location_id=1135"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { if got := locationFor(t, "GET", tc.target, ""); got != 1135 { t.Fatalf("wanted outlet 1135, got %d", got) } }) } } // The two routes that *write* carry the outlet in a JSON batch and never in the // URL. Checking only the query string would leave the exact call that posts // bills into another tenant's books unguarded. func TestTheOutletIsFoundInAnIngestBody(t *testing.T) { body := `{"batch_id":"b1","terminal_id":"T5EDD","store_id":"1135","orders":[]}` if got := locationFor(t, "POST", "/probe", body); got != 1135 { t.Fatalf("wanted outlet 1135 from the batch body, got %d", got) } } // The till quotes its ids; other callers send them bare. Accepting only one // shape silently skips the check for the other. func TestAnOutletIsReadWhetherQuotedOrNot(t *testing.T) { quoted := `{"store_id":"1135"}` bare := `{"store_id":1135}` if got := locationFor(t, "POST", "/probe", quoted); got != 1135 { t.Fatalf("quoted store_id: wanted 1135, got %d", got) } if got := locationFor(t, "POST", "/probe", bare); got != 1135 { t.Fatalf("bare store_id: wanted 1135, got %d", got) } } func TestAHealthBodyNamesItsOutlet(t *testing.T) { body := `{"terminal_id":"T5EDD","location_id":"1135","status":"online"}` if got := locationFor(t, "POST", "/probe", body); got != 1135 { t.Fatalf("wanted outlet 1135 from the health body, got %d", got) } } // A request naming no outlet is not an error — /session names none — so it must // come back as "nothing to check" rather than as outlet zero. func TestARequestNamingNoOutletReportsNone(t *testing.T) { if got := locationFor(t, "GET", "/probe", ""); got != 0 { t.Fatalf("wanted 0 for a request naming no outlet, got %d", got) } if got := locationFor(t, "POST", "/probe", `{"batch_id":"b1"}`); got != 0 { t.Fatalf("wanted 0 for a body naming no outlet, got %d", got) } } // A body this middleware cannot parse must not be treated as naming an outlet. // The handler will refuse it on its own terms; guessing here would either // reject a good request or wave a bad one through. func TestAnUnparseableBodyNamesNoOutlet(t *testing.T) { if got := locationFor(t, "POST", "/probe", `{not json at all`); got != 0 { t.Fatalf("wanted 0 for an unparseable body, got %d", got) } } func TestABearerTokenIsReadInEveryFormTheFieldSends(t *testing.T) { app := fiber.New() var got string app.Get("/probe", func(c *fiber.Ctx) error { got = bearerToken(c) return c.SendStatus(fiber.StatusOK) }) cases := []struct { name string header string value string want string }{ {"the standard form", "Authorization", "Bearer abc.def", "abc.def"}, {"a bare token, which terminals send", "Authorization", "abc.def", "abc.def"}, {"the fallback header", "X-Pos-Token", "abc.def", "abc.def"}, {"a scheme we do not issue", "Authorization", "Basic dXNlcjpwdw==", ""}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got = "" req := httptest.NewRequest("GET", "/probe", nil) req.Header.Set(tc.header, tc.value) if _, err := app.Test(req); err != nil { t.Fatalf("probing: %v", err) } if got != tc.want { t.Fatalf("wanted %q, got %q", tc.want, got) } }) } }