-- furt-lua/tests/test_http.lua -- Basic HTTP tests for Furt Lua HTTP-Server local socket = require("socket") local cjson = require("cjson") -- Test configuration local TEST_HOST = "127.0.0.1" local TEST_PORT = 8080 local TEST_TIMEOUT = 5 -- Test results local tests_run = 0 local tests_passed = 0 local tests_failed = 0 -- ANSI colors local GREEN = "\27[32m" local RED = "\27[31m" local YELLOW = "\27[33m" local RESET = "\27[0m" -- Test helper functions local function log(level, message) local prefix = { INFO = YELLOW .. "[INFO]" .. RESET, PASS = GREEN .. "[PASS]" .. RESET, FAIL = RED .. "[FAIL]" .. RESET } print(prefix[level] .. " " .. message) end local function http_request(method, path, body, headers) local client = socket.connect(TEST_HOST, TEST_PORT) if not client then return nil, "Connection failed" end client:settimeout(TEST_TIMEOUT) -- Build request headers = headers or {} local request_lines = {method .. " " .. path .. " HTTP/1.1"} -- Add headers table.insert(request_lines, "Host: " .. TEST_HOST .. ":" .. TEST_PORT) if body then table.insert(request_lines, "Content-Length: " .. #body) table.insert(request_lines, "Content-Type: application/json") end for key, value in pairs(headers) do table.insert(request_lines, key .. ": " .. value) end table.insert(request_lines, "") -- Empty line local request = table.concat(request_lines, "\r\n") if body then request = request .. body end -- Send request local success, err = client:send(request) if not success then client:close() return nil, "Send failed: " .. (err or "unknown") end -- Read response local response_line = client:receive() if not response_line then client:close() return nil, "No response received" end -- Parse status local status = response_line:match("HTTP/1%.1 (%d+)") status = tonumber(status) -- Read headers local response_headers = {} local content_length = 0 while true do local line = client:receive() if not line or line == "" then break end local key, value = line:match("([^:]+): (.+)") if key and value then response_headers[key:lower()] = value if key:lower() == "content-length" then content_length = tonumber(value) or 0 end end end -- Read body local response_body = "" if content_length > 0 then response_body = client:receive(content_length) or "" end client:close() return { status = status, headers = response_headers, body = response_body } end local function assert_equal(actual, expected, message) tests_run = tests_run + 1 if actual == expected then tests_passed = tests_passed + 1 log("PASS", message) return true else tests_failed = tests_failed + 1 log("FAIL", message .. " (expected: " .. tostring(expected) .. ", got: " .. tostring(actual) .. ")") return false end end local function assert_status(response, expected_status, test_name) return assert_equal(response and response.status, expected_status, test_name .. " - Status Code") end -- Test functions local function test_health_check() log("INFO", "Testing health check endpoint...") local response = http_request("GET", "/health") if not response then log("FAIL", "Health check - No response") tests_run = tests_run + 1 tests_failed = tests_failed + 1 return end assert_status(response, 200, "Health check") if response.body then local success, data = pcall(cjson.decode, response.body) if success then assert_equal(data.status, "healthy", "Health check - Status field") assert_equal(data.service, "furt-lua", "Health check - Service field") else log("FAIL", "Health check - Invalid JSON response") tests_run = tests_run + 1 tests_failed = tests_failed + 1 end end end local function test_basic_post() log("INFO", "Testing basic POST endpoint...") local test_data = {test = "data", number = 42} local response = http_request("POST", "/test", cjson.encode(test_data)) if not response then log("FAIL", "Basic POST - No response") tests_run = tests_run + 1 tests_failed = tests_failed + 1 return end assert_status(response, 200, "Basic POST") if response.body then local success, data = pcall(cjson.decode, response.body) if success then assert_equal(data.message, "Test endpoint working", "Basic POST - Message field") else log("FAIL", "Basic POST - Invalid JSON response") tests_run = tests_run + 1 tests_failed = tests_failed + 1 end end end local function test_mail_endpoint() log("INFO", "Testing mail endpoint...") -- Test with valid data local mail_data = { name = "Test User", email = "test@example.com", message = "This is a test message" } local response = http_request("POST", "/v1/mail/send", cjson.encode(mail_data)) if not response then log("FAIL", "Mail endpoint - No response") tests_run = tests_run + 1 tests_failed = tests_failed + 1 return end assert_status(response, 200, "Mail endpoint - Valid data") -- Test with invalid data (missing fields) local invalid_data = {name = "Test"} local response2 = http_request("POST", "/v1/mail/send", cjson.encode(invalid_data)) assert_status(response2, 400, "Mail endpoint - Invalid data") -- Test with no body local response3 = http_request("POST", "/v1/mail/send") assert_status(response3, 400, "Mail endpoint - No body") end local function test_404_handling() log("INFO", "Testing 404 handling...") local response = http_request("GET", "/nonexistent") assert_status(response, 404, "404 handling") end -- Main test runner local function run_tests() log("INFO", "Starting Furt HTTP-Server tests...") log("INFO", "Target: http://" .. TEST_HOST .. ":" .. TEST_PORT) print("") -- Check if server is running local test_response = http_request("GET", "/health") if not test_response then log("FAIL", "Server is not running on " .. TEST_HOST .. ":" .. TEST_PORT) log("INFO", "Start server with: ./scripts/start.sh") return false end -- Run tests test_health_check() test_basic_post() test_mail_endpoint() test_404_handling() -- Print results print("") log("INFO", "Test Results:") log("INFO", "Tests run: " .. tests_run) log("INFO", "Passed: " .. tests_passed) log("INFO", "Failed: " .. tests_failed) if tests_failed == 0 then log("PASS", "All tests passed! 🎉") return true else log("FAIL", tests_failed .. " test(s) failed") return false end end -- Run tests if executed directly if arg and arg[0] and arg[0]:match("test_http%.lua$") then local success = run_tests() os.exit(success and 0 or 1) end -- Export for use as module return { run_tests = run_tests, http_request = http_request }