diff --git a/internal/app/action/action.go b/internal/app/action/action.go index c3e97ae..edb738f 100644 --- a/internal/app/action/action.go +++ b/internal/app/action/action.go @@ -345,6 +345,9 @@ func (a *Action) renderResultsText(w http.ResponseWriter, valuesStr []string) er } func (a *Action) renderResultsTable(w http.ResponseWriter, valuesMap []map[string]any) error { + if len(valuesMap) == 0 { + return nil + } firstRow := valuesMap[0] keys := make([]string, 0, len(firstRow)) for k := range firstRow { diff --git a/internal/app/tests/appaction_test.go b/internal/app/tests/appaction_test.go index bac6d6f..423bb6e 100644 --- a/internal/app/tests/appaction_test.go +++ b/internal/app/tests/appaction_test.go @@ -2,7 +2,9 @@ package app_test import ( "net/http/httptest" + "net/url" "path" + "strings" "testing" "github.com/claceio/clace/internal/app" @@ -95,7 +97,7 @@ func TestParamErrors(t *testing.T) { def handler(dry_run, args): return ace.result(status="done", values=["a", "b"], param_errors={"param1": "param1error", "param3": "param3error"}) -app = ace.app("testApp", +app = ace.app("testApp", actions=[ace.action("testAction", "/", handler)]) `, @@ -365,3 +367,237 @@ app = ace.app("testApp", `, response.Body.String()) } + +func TestParamPost(t *testing.T) { + logger := testutil.TestLogger() + fileData := map[string]string{ + "app.star": ` +def handler(dry_run, args): + return ace.result(status="done", values=[{"c1": args.param1, "c2": args.param2, "c3": args.param3}]) + +app = ace.app("testApp", + actions=[ace.action("testAction", "/", handler, report=ace.TABLE)]) + + `, + "params.star": `param("param1", description="param1 description", type=STRING, default="myvalue") +param("param2", description="param2 description", type=BOOLEAN, default=False) +param("param3", description="param3 description", type=INT, default=10)`, + } + a, _, err := CreateTestApp(logger, fileData) + if err != nil { + t.Fatalf("Error %s", err) + } + + request := httptest.NewRequest("GET", "/test/", nil) + response := httptest.NewRecorder() + a.ServeHTTP(response, request) + + testutil.AssertEqualsInt(t, "code", 200, response.Code) + testutil.AssertStringContains(t, response.Body.String(), "testAction") + testutil.AssertStringContains(t, response.Body.String(), `id="param_param1"`) + + values := url.Values{ + "param1": {"abc"}, + "param2": {"true"}, + "param3": {"20"}, + } + + request = httptest.NewRequest("POST", "/test", strings.NewReader(values.Encode())) + request.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + response = httptest.NewRecorder() + a.ServeHTTP(response, request) + testutil.AssertEqualsInt(t, "code", 200, response.Code) + testutil.AssertStringMatch(t, "match response", ` +
+ done +
+ +
+
Report
+ + + + + + + + + + + + + + + + +
c1c2c3
abctrue20
+
`, response.Body.String()) +} + +func TestCustomReport(t *testing.T) { + logger := testutil.TestLogger() + fileData := map[string]string{ + "app.star": ` +def handler(dry_run, args): + return ace.result(status="done", values=[{"a": 1, "b": "abc"}]) + +app = ace.app("testApp", + actions=[ace.action("testAction", "/", handler, report="custom")]) + + `, + "params.star": `param("param1", description="param1 description", type=STRING, default="myvalue")`, + "myfile.go.html": `{{block "custom" .}} customdata {{end}}`, + } + a, _, err := CreateTestApp(logger, fileData) + if err != nil { + t.Fatalf("Error %s", err) + } + + request := httptest.NewRequest("GET", "/test/", nil) + response := httptest.NewRecorder() + a.ServeHTTP(response, request) + + testutil.AssertEqualsInt(t, "code", 200, response.Code) + testutil.AssertStringContains(t, response.Body.String(), "testAction") + testutil.AssertStringContains(t, response.Body.String(), `id="param_param1"`) + + request = httptest.NewRequest("POST", "/test", nil) + response = httptest.NewRecorder() + a.ServeHTTP(response, request) + testutil.AssertEqualsInt(t, "code", 200, response.Code) + testutil.AssertStringMatch(t, "match response", `
+ done +
+
customdata
`, response.Body.String()) + + // Unset the template + fileData["myfile.go.html"] = `` + a, _, err = CreateTestApp(logger, fileData) + if err != nil { + t.Fatalf("Error %s", err) + } + request = httptest.NewRequest("GET", "/test/", nil) + response = httptest.NewRecorder() + a.ServeHTTP(response, request) + + testutil.AssertEqualsInt(t, "code", 200, response.Code) + testutil.AssertStringContains(t, response.Body.String(), "testAction") + testutil.AssertStringContains(t, response.Body.String(), `id="param_param1"`) + + request = httptest.NewRequest("POST", "/test", nil) + response = httptest.NewRecorder() + a.ServeHTTP(response, request) + testutil.AssertEqualsInt(t, "code", 200, response.Code) + testutil.AssertStringMatch(t, "match response", `
done
+
html/template: "custom" is undefined`, response.Body.String()) +} + +func TestActionError(t *testing.T) { + logger := testutil.TestLogger() + fileData := map[string]string{ + "app.star": ` +def handler(dry_run, args): + if args.param1 == "error": + return "errormessage" + 10/args.param3 + return ace.result(status="done", values=[{"c1": args.param1, "c2": args.param2, "c3": args.param3}]) + +app = ace.app("testApp", + actions=[ace.action("testAction", "/", handler, report=ace.TABLE)]) + + `, + "params.star": `param("param1", description="param1 description", type=STRING, default="myvalue") +param("param2", description="param2 description", type=BOOLEAN, default=False) +param("param3", description="param3 description", type=INT, default=10)`, + } + a, _, err := CreateTestApp(logger, fileData) + if err != nil { + t.Fatalf("Error %s", err) + } + + request := httptest.NewRequest("GET", "/test/", nil) + response := httptest.NewRecorder() + a.ServeHTTP(response, request) + + testutil.AssertEqualsInt(t, "code", 200, response.Code) + testutil.AssertStringContains(t, response.Body.String(), "testAction") + testutil.AssertStringContains(t, response.Body.String(), `id="param_param1"`) + + values := url.Values{ + "param1": {"error"}, + "param2": {"true"}, + "param3": {"20"}, + } + + request = httptest.NewRequest("POST", "/test", strings.NewReader(values.Encode())) + request.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + response = httptest.NewRecorder() + a.ServeHTTP(response, request) + testutil.AssertEqualsInt(t, "code", 200, response.Code) + testutil.AssertStringMatch(t, "match response", `
+ "errormessage" +
`, response.Body.String()) + + values = url.Values{ + "param1": {"p1val"}, + "param2": {"true"}, + "param3": {"0"}, + } + + request = httptest.NewRequest("POST", "/test", strings.NewReader(values.Encode())) + request.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + response = httptest.NewRecorder() + a.ServeHTTP(response, request) + testutil.AssertEqualsInt(t, "code", 500, response.Code) + testutil.AssertStringMatch(t, "response", `floating-point division by zero`, response.Body.String()) + + values = url.Values{ + "param1": {"p1val"}, + "param2": {"true"}, + "param3": {"50"}, + } + + request = httptest.NewRequest("POST", "/test", strings.NewReader(values.Encode())) + request.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + response = httptest.NewRecorder() + a.ServeHTTP(response, request) + testutil.AssertEqualsInt(t, "code", 200, response.Code) + testutil.AssertStringMatch(t, "response", `
+ done +
+ +
+
Report
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
c1c2c3
p1valtrue50
+
`, response.Body.String()) +}