http_test.go

  1package plugin
  2
  3import (
  4	"io"
  5	"net/http"
  6	"net/http/httptest"
  7	"strings"
  8	"testing"
  9
 10	lua "github.com/yuin/gopher-lua"
 11)
 12
 13// newTestManager creates a Manager with a fresh Lua VM for testing.
 14func newTestManager() *Manager {
 15	return NewManager()
 16}
 17
 18func TestHTTPGet(t *testing.T) {
 19	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 20		if r.Method != "GET" {
 21			t.Errorf("expected GET, got %s", r.Method)
 22		}
 23		w.Header().Set("X-Test", "hello")
 24		w.WriteHeader(200)
 25		w.Write([]byte("ok"))
 26	}))
 27	defer srv.Close()
 28
 29	m := newTestManager()
 30	defer m.Close()
 31
 32	err := m.state.DoString(`
 33		local matcha = require("matcha")
 34		res, err = matcha.http({ url = "` + srv.URL + `" })
 35	`)
 36	if err != nil {
 37		t.Fatal(err)
 38	}
 39
 40	errVal := m.state.GetGlobal("err")
 41	if errVal != lua.LNil {
 42		t.Fatalf("expected nil error, got %v", errVal)
 43	}
 44
 45	res := m.state.GetGlobal("res")
 46	tbl, ok := res.(*lua.LTable)
 47	if !ok {
 48		t.Fatalf("expected table, got %T", res)
 49	}
 50
 51	if status := tbl.RawGetString("status"); status.(lua.LNumber) != 200 {
 52		t.Errorf("expected status 200, got %v", status)
 53	}
 54	if body := tbl.RawGetString("body"); body.String() != "ok" {
 55		t.Errorf("expected body 'ok', got %q", body.String())
 56	}
 57
 58	headers := tbl.RawGetString("headers").(*lua.LTable)
 59	if v := headers.RawGetString("x-test"); v.String() != "hello" {
 60		t.Errorf("expected header x-test='hello', got %q", v.String())
 61	}
 62}
 63
 64func TestHTTPPostWithBodyAndHeaders(t *testing.T) {
 65	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 66		if r.Method != "POST" {
 67			t.Errorf("expected POST, got %s", r.Method)
 68		}
 69		if ct := r.Header.Get("Content-Type"); ct != "application/json" {
 70			t.Errorf("expected Content-Type application/json, got %q", ct)
 71		}
 72		body, _ := io.ReadAll(r.Body)
 73		w.Write(body)
 74	}))
 75	defer srv.Close()
 76
 77	m := newTestManager()
 78	defer m.Close()
 79
 80	err := m.state.DoString(`
 81		local matcha = require("matcha")
 82		res, err = matcha.http({
 83			url = "` + srv.URL + `",
 84			method = "post",
 85			headers = { ["Content-Type"] = "application/json" },
 86			body = '{"key":"value"}',
 87		})
 88	`)
 89	if err != nil {
 90		t.Fatal(err)
 91	}
 92
 93	errVal := m.state.GetGlobal("err")
 94	if errVal != lua.LNil {
 95		t.Fatalf("expected nil error, got %v", errVal)
 96	}
 97
 98	res := m.state.GetGlobal("res")
 99	tbl := res.(*lua.LTable)
100	if body := tbl.RawGetString("body"); body.String() != `{"key":"value"}` {
101		t.Errorf("expected echoed body, got %q", body.String())
102	}
103}
104
105func TestHTTPMissingURL(t *testing.T) {
106	m := newTestManager()
107	defer m.Close()
108
109	err := m.state.DoString(`
110		local matcha = require("matcha")
111		res, err = matcha.http({})
112	`)
113	if err != nil {
114		t.Fatal(err)
115	}
116
117	resVal := m.state.GetGlobal("res")
118	if resVal != lua.LNil {
119		t.Errorf("expected nil result, got %v", resVal)
120	}
121
122	errVal := m.state.GetGlobal("err")
123	if errVal == lua.LNil {
124		t.Fatal("expected error, got nil")
125	}
126	if !strings.Contains(errVal.String(), "url") {
127		t.Errorf("expected error about url, got %q", errVal.String())
128	}
129}
130
131func TestHTTPInvalidScheme(t *testing.T) {
132	m := newTestManager()
133	defer m.Close()
134
135	err := m.state.DoString(`
136		local matcha = require("matcha")
137		res, err = matcha.http({ url = "file:///etc/passwd" })
138	`)
139	if err != nil {
140		t.Fatal(err)
141	}
142
143	resVal := m.state.GetGlobal("res")
144	if resVal != lua.LNil {
145		t.Errorf("expected nil result, got %v", resVal)
146	}
147
148	errVal := m.state.GetGlobal("err")
149	if errVal == lua.LNil {
150		t.Fatal("expected error, got nil")
151	}
152	if !strings.Contains(errVal.String(), "scheme") {
153		t.Errorf("expected error about scheme, got %q", errVal.String())
154	}
155}
156
157func TestHTTPBodyTruncation(t *testing.T) {
158	// Server returns more than 1 MB.
159	bigBody := strings.Repeat("x", httpMaxBodySize+1024)
160	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
161		w.Write([]byte(bigBody))
162	}))
163	defer srv.Close()
164
165	m := newTestManager()
166	defer m.Close()
167
168	err := m.state.DoString(`
169		local matcha = require("matcha")
170		res, err = matcha.http({ url = "` + srv.URL + `" })
171		body_len = #res.body
172	`)
173	if err != nil {
174		t.Fatal(err)
175	}
176
177	bodyLen := m.state.GetGlobal("body_len")
178	n, ok := bodyLen.(lua.LNumber)
179	if !ok {
180		t.Fatalf("expected number, got %T", bodyLen)
181	}
182	if int(n) > httpMaxBodySize {
183		t.Errorf("expected body to be capped at %d, got %d", httpMaxBodySize, int(n))
184	}
185}