package main import ( "bytes" "encoding/json" "fmt" "net/http" "os" "os/exec" "testing" "time" ) const ( testPort = "9999" baseURL = "http://localhost:" + testPort ) func TestToolboxE2E(t *testing.T) { // 1. Build the binary fmt.Println("--- Step 1: Building binary... ---") _ = os.MkdirAll("build", 0755) buildPath := "build/toolbox_test_bin" buildCmd := exec.Command("go", "build", "-o", buildPath, "main.go") if err := buildCmd.Run(); err != nil { t.Fatalf("Failed to build binary: %v", err) } defer func() { _ = os.Remove(buildPath) }() // 2. Start the server fmt.Println("--- Step 2: Starting server... ---") serverCmd := exec.Command("./"+buildPath, "-port", testPort) if err := serverCmd.Start(); err != nil { t.Fatalf("Failed to start server: %v", err) } defer func() { if serverCmd.Process != nil { _ = serverCmd.Process.Kill() } }() // 3. Wait for server to be ready fmt.Println("--- Step 3: Waiting for server readiness... ---") ready := false for i := 0; i < 10; i++ { resp, err := http.Get(baseURL + "/api/tools") if err == nil && resp.StatusCode == http.StatusOK { ready = true _ = resp.Body.Close() break } time.Sleep(500 * time.Millisecond) } if !ready { t.Fatal("Server failed to become ready in time") } // 4. Test endpoints fmt.Println("--- Step 4: Testing tool endpoints... ---") testOutputDir, err := os.MkdirTemp("", "toolbox_test_output_*") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } fmt.Printf("--- Test Artifacts will be saved to: %s ---\n", testOutputDir) tests := []struct { name string path string method string fileName string body interface{} }{ { name: "Zitie Teaching", path: "/api/zitie/teaching", method: "POST", fileName: "zitie_teaching.pdf", body: map[string]string{"chars": "永和九年", "paper_size": "A4"}, }, { name: "Zitie Step", path: "/api/zitie/step", method: "POST", fileName: "zitie_step.pdf", body: map[string]string{"chars": "永", "paper_size": "A4"}, }, { name: "Zitie Manuscript", path: "/api/zitie/manuscript", method: "POST", fileName: "zitie_manuscript.pdf", body: map[string]string{"chars": "天道酬勤", "paper_size": "A4", "font_type": "kaiti"}, }, { name: "Learn Number Counting", path: "/api/learn-number/counting", method: "POST", fileName: "counting.pdf", body: map[string]interface{}{"page_count": 1, "paper_size": "A4"}, }, { name: "Learn Number Writing", path: "/api/learn-number/writing", method: "POST", fileName: "writing.pdf", body: map[string]interface{}{"start_num": 1, "end_num": 5, "paper_size": "A4"}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var resp *http.Response var err error if tt.method == "POST" { b, _ := json.Marshal(tt.body) resp, err = http.Post(baseURL+tt.path, "application/json", bytes.NewBuffer(b)) } else { resp, err = http.Get(baseURL + tt.path) } if err != nil { t.Errorf("%s failed: %v", tt.name, err) return } defer func() { _ = resp.Body.Close() }() if resp.StatusCode != http.StatusOK { t.Errorf("%s returned status %d", tt.name, resp.StatusCode) return } contentType := resp.Header.Get("Content-Type") if contentType != "application/pdf" { t.Errorf("%s expected application/pdf, got %s", tt.name, contentType) } else { // Save PDF to temp directory for human review outPath := testOutputDir + "/" + tt.fileName f, err := os.Create(outPath) if err != nil { t.Errorf("Failed to create output file: %v", err) return } defer func() { _ = f.Close() }() _, err = f.ReadFrom(resp.Body) if err != nil { t.Errorf("Failed to save PDF: %v", err) return } fmt.Printf("[PASS] %s: Saved to %s\n", tt.name, outPath) } }) } fmt.Printf("\n--- ALL TESTS DONE. PLEASE REVIEW PDFS IN: %s ---\n", testOutputDir) }