refactor: clean repository structure for v0.1.0 open source release
- Remove Go artifacts (cmd/, internal/, pkg/, go.mod) - Move furt-lua/* content to repository root - Restructure as clean src/, config/, scripts/, tests/ layout - Rewrite README.md as practical tool documentation - Remove timeline references and marketing language - Clean .gitignore from Go-era artifacts - Update config/server.lua with example.org defaults - Add .env.production to .gitignore for security Repository now ready for open source distribution with minimal, focused structure and generic configuration templates. close issue DAW/furt#86
This commit is contained in:
parent
87c935379b
commit
be3b9614d0
38 changed files with 280 additions and 5892 deletions
273
tests/test_http.lua
Normal file
273
tests/test_http.lua
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
-- 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
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue