package fjord import "core:fmt" import "core:log" import "core:net" import "core:os/os2" import "core:strings" import "core:thread" import "core:time" import "core:testing" import http "http" Error :: enum { TestError, } first_handler :: proc(request: ^http.Request) -> (http.Response, Error) { entity := request.path_variables["entity"] body := strings.concatenate( {"
Hello first", entity, "
"}, context.temp_allocator, ) response := http.make_response( .Ok, transmute([]byte)body, .Html, context.temp_allocator, ) return response, nil } second_handler :: proc(request: ^http.Request) -> (http.Response, Error) { entity := request.path_variables["entity"] body := strings.concatenate( {"
Hello second", entity, "
"}, context.temp_allocator, ) response := http.make_response( .Ok, transmute([]byte)body, .Html, context.temp_allocator, ) return response, nil } third_handler :: proc(request: ^http.Request) -> (http.Response, Error) { entity := request.path_variables["entity"] other_entity := request.path_variables["other_entity"] body := strings.concatenate( {"
Hello third", entity, "and", other_entity, "
"}, context.temp_allocator, ) response := http.make_response( .Ok, transmute([]byte)body, .Html, context.temp_allocator, ) return response, nil } @(test) test_router_ok :: proc(t: ^testing.T) { context.logger = log.create_console_logger(.Info) defer log.destroy_console_logger(context.logger) endpoint := net.Endpoint { address = net.IP4_Address{127, 0, 0, 1}, port = 8080, } server: Server(Error) server_init(&server, endpoint, context.allocator) defer server_destroy(&server) server_add_route(&server, .GET, {"hello", ":entity"}, first_handler) server_add_route( &server, .GET, {"hello", ":entity", "only"}, second_handler, ) server_add_route( &server, .GET, {"hello", ":entity", "and", ":other_entity"}, third_handler, ) handler, path_vars, ok := router_lookup( &server.router, .GET, {"hello", "world"}, context.temp_allocator, ); assert(ok) assert(handler == first_handler) assert(path_vars["entity"] == "world") handler, path_vars, ok = router_lookup( &server.router, .GET, {"hello", "lonely world", "only"}, context.temp_allocator, ); assert(ok) assert(handler == second_handler) assert(path_vars["entity"] == "lonely world") handler, path_vars, ok = router_lookup( &server.router, .GET, {"hello", "world", "and", "worlds friend"}, context.temp_allocator, ); assert(ok) assert(handler == third_handler) assert(path_vars["entity"] == "world") assert(path_vars["other_entity"] == "worlds friend") ok = server_remove_route(&server, .GET, {"hello", ":entity"}); assert(ok) ok = server_remove_route(&server, .GET, {"hello", ":entity"}); assert(!ok) free_all(context.temp_allocator) } start_concurrent_server :: proc( server: ^Server($Error_Type), ) -> ^thread.Thread { ServerThreadData :: struct { server: ^Server(Error_Type), thread: ^thread.Thread, } server_thread_proc :: proc(t: ^thread.Thread) { d := (^ServerThreadData)(t.data) listen_and_serve(d.server) } d := new(ServerThreadData, context.temp_allocator) d.server = server if d.thread = thread.create(server_thread_proc); d.thread != nil { d.thread.init_context = context d.thread.data = rawptr(d) thread.start(d.thread) } // Give server some time to start time.sleep(100 * time.Millisecond) return d.thread } shutdown_concurrent_server :: proc( server: ^Server($Error_Type), t: ^thread.Thread, ) { server_shutdown(server) // Send a dummy request to unblock accept_tcp, todo: fix this immidiate server shutdown _, _, _, err := os2.process_exec( {command = []string{"curl", "-s", "http://127.0.0.1:8080/dummy"}}, context.temp_allocator, ) assert(err == nil) thread.join(t) thread.destroy(t) } assert_endpoint_response :: proc(url: string, expected_response: string) { state, stdout, stderr, err := os2.process_exec( {command = []string{"curl", "-s", url}}, context.temp_allocator, ) if err != nil { log.errorf("Failed to execute curl: %v", err) assert(false, "curl execution failed") return } if state.exit_code != 0 { log.errorf("curl failed with exit code: %d", state.exit_code) assert(false, "curl returned non-zero exit code") return } response := string(stdout) log.assertf( response == expected_response, "Expected: %s, but got: %s", response, expected_response, ) } @(test) test_server_general_ok :: proc(t: ^testing.T) { context.logger = log.create_console_logger(.Info) defer log.destroy_console_logger(context.logger) endpoint := net.Endpoint { address = net.IP4_Address{127, 0, 0, 1}, port = 8080, } server: Server(Error) server_init(&server, endpoint, context.allocator) defer server_destroy(&server) server_add_route(&server, .GET, {"hello", ":entity"}, first_handler) server_add_route( &server, .GET, {"hello", ":entity", "only"}, second_handler, ) server_add_route( &server, .GET, {"hello", ":entity", "and", ":other_entity"}, third_handler, ) t := start_concurrent_server(&server) assert_endpoint_response( "http://127.0.0.1:8080/hello/world", "
Hello firstworld
", ) assert_endpoint_response( "http://127.0.0.1:8080/hello/lonely%20world/only", "
Hello secondlonely%20world
", ) assert_endpoint_response( "http://127.0.0.1:8080/hello/world/and/worlds%20friend", "
Hello thirdworldandworlds%20friend
", ) shutdown_concurrent_server(&server, t) free_all(context.temp_allocator) }