11package org .tinystruct .system ;
22
3- import org .junit .jupiter .api .BeforeEach ;
4- import org .junit .jupiter .api .Test ;
3+ import org .junit .jupiter .api .*;
54import org .tinystruct .AbstractApplication ;
65import org .tinystruct .ApplicationContext ;
7- import org .tinystruct .ApplicationException ;
86import org .tinystruct .application .Action ;
9- import org .tinystruct .application .ActionRegistry ;
107import org .tinystruct .http .Method ;
8+ import org .tinystruct .http .Response ;
9+ import org .tinystruct .net .URLRequest ;
10+ import org .tinystruct .net .URLResponse ;
11+ import org .tinystruct .net .handlers .HTTPHandler ;
12+ import org .tinystruct .system .Dispatcher ;
13+
14+ import java .io .BufferedReader ;
15+ import java .io .InputStreamReader ;
16+ import java .io .OutputStream ;
17+ import java .net .HttpURLConnection ;
18+ import java .net .Socket ;
19+ import java .net .URI ;
20+ import java .net .URL ;
21+ import java .nio .charset .StandardCharsets ;
1122
1223import static org .junit .jupiter .api .Assertions .*;
1324
25+ @ TestInstance (TestInstance .Lifecycle .PER_CLASS )
1426public class HttpServerHttpModeTest {
1527
28+ private static final int TEST_PORT = 18080 ;
29+ private static final String BASE_URL = "http://localhost:" + TEST_PORT ;
30+ private HttpServer httpServer ;
31+ private Thread serverThread ;
1632 private TestWebApp app ;
17- private ActionRegistry registry ;
1833
19- @ BeforeEach
20- public void setup () throws ApplicationException {
34+ @ BeforeAll
35+ public void setUp () throws Exception {
36+ // Initialize settings
37+ Settings settings = new Settings ();
38+ settings .set ("default.base_url" , "/?q=" );
39+ settings .set ("default.language" , "en_US" );
40+ settings .set ("charset" , "utf-8" );
41+
42+ // Create and install test app
2143 this .app = new TestWebApp ();
44+ ApplicationManager .install (this .app , settings );
45+
46+ // Install required applications
47+ ApplicationManager .install (new Dispatcher ());
48+ this .httpServer = new HttpServer ();
49+ ApplicationManager .install (this .httpServer , settings );
50+
51+ // Start server in a separate thread
52+ serverThread = new Thread (() -> {
53+ try {
54+ ApplicationContext context = new ApplicationContext ();
55+ context .setAttribute ("--server-port" , String .valueOf (TEST_PORT ));
56+ ApplicationManager .call ("start" , context , Action .Mode .CLI );
57+ } catch (Exception e ) {
58+ e .printStackTrace ();
59+ }
60+ });
61+ serverThread .setDaemon (true );
62+ serverThread .start ();
63+
64+ // Wait for server to be ready
65+ boolean started = false ;
66+ for (int i = 0 ; i < 30 ; i ++) {
67+ try (Socket socket = new Socket ("localhost" , TEST_PORT )) {
68+ started = true ;
69+ break ;
70+ } catch (Exception e ) {
71+ Thread .sleep (1000 );
72+ }
73+ }
74+ if (!started ) {
75+ throw new RuntimeException ("Server failed to start within 30 seconds" );
76+ }
77+
78+ // Give server a moment to fully initialize
79+ Thread .sleep (500 );
80+ }
2281
23- this .registry = ActionRegistry .getInstance ();
24- // Initialize configuration to trigger annotation processing
25- this .app .setConfiguration (new Settings ());
26- // Ensure annotations are processed
27- new AnnotationProcessor (this .app ).processActionAnnotations ();
82+ @ AfterAll
83+ public void tearDown () {
84+ if (httpServer != null ) {
85+ httpServer .stop ();
86+ }
87+ if (serverThread != null && serverThread .isAlive ()) {
88+ serverThread .interrupt ();
89+ }
2890 }
2991
3092 @ Test
@@ -48,109 +110,91 @@ public void testActionModeFromName() {
48110 }
49111
50112 @ Test
51- public void testHttpGetRouting () throws ApplicationException {
52- // Test that GET requests match HTTP_GET mode actions
53- Action action = registry .getAction ("api/users" , Action .Mode .HTTP_GET );
54- assertNotNull (action , "GET action should be found" );
55- assertEquals (Action .Mode .HTTP_GET , action .getMode ());
56-
57- Object result = action .execute ();
58- assertEquals ("GET users" , String .valueOf (result ));
113+ public void testHttpGetRequest () throws Exception {
114+ // Make actual HTTP GET request
115+ String response = sendHttpRequest ("GET" , BASE_URL + "/?q=api/users" , null );
116+ assertTrue (response .contains ("GET users" ), "GET request should return 'GET users'" );
59117 }
60118
61119 @ Test
62- public void testHttpPostRouting () throws ApplicationException {
63- // Test that POST requests match HTTP_POST mode actions
64- Action action = registry .getAction ("api/users" , Action .Mode .HTTP_POST );
65- assertNotNull (action , "POST action should be found" );
66- assertEquals (Action .Mode .HTTP_POST , action .getMode ());
67-
68- Object result = action .execute ();
69- assertEquals ("POST users" , String .valueOf (result ));
120+ public void testHttpPostRequest () throws Exception {
121+ // Make actual HTTP POST request
122+ String response = sendHttpRequest ("POST" , BASE_URL + "/?q=api/users" , null );
123+ assertTrue (response .contains ("POST users" ), "POST request should return 'POST users'" );
70124 }
71125
72126 @ Test
73- public void testHttpPutRouting () throws ApplicationException {
74- // Test that PUT requests match HTTP_PUT mode actions
75- // Note: The path pattern "api/users" with a String parameter will match "api/users/123"
76- Action action = registry .getAction ("api/users/123" , Action .Mode .HTTP_PUT );
77- assertNotNull (action , "PUT action should be found" );
78- assertEquals (Action .Mode .HTTP_PUT , action .getMode ());
79-
80- // The action will extract "123" from the path
81- Object result = action .execute ();
82- assertEquals ("PUT user 123" , String .valueOf (result ));
127+ public void testHttpPutRequest () throws Exception {
128+ // Make actual HTTP PUT request
129+ String response = sendHttpRequest ("PUT" , BASE_URL + "/?q=api/users/123" , null );
130+ assertTrue (response .contains ("PUT user" ), "PUT request should return 'PUT user'" );
131+ assertTrue (response .contains ("123" ), "PUT request should include the ID parameter" );
83132 }
84133
85134 @ Test
86- public void testHttpDeleteRouting () throws ApplicationException {
87- // Test that DELETE requests match HTTP_DELETE mode actions
88- // Note: The path pattern "api/users" with a String parameter will match "api/users/123"
89- Action action = registry .getAction ("api/users/123" , Action .Mode .HTTP_DELETE );
90- assertNotNull (action , "DELETE action should be found" );
91- assertEquals (Action .Mode .HTTP_DELETE , action .getMode ());
92-
93- // The action will extract "123" from the path
94- Object result = action .execute ();
95- assertEquals ("DELETE user 123" , String .valueOf (result ));
135+ public void testHttpDeleteRequest () throws Exception {
136+ // Make actual HTTP DELETE request
137+ String response = sendHttpRequest ("DELETE" , BASE_URL + "/?q=api/users/456" , null );
138+ assertTrue (response .contains ("DELETE user" ), "DELETE request should return 'DELETE user'" );
139+ assertTrue (response .contains ("456" ), "DELETE request should include the ID parameter" );
96140 }
97141
98142 @ Test
99- public void testHttpMethodMismatch () {
100- // Test that wrong HTTP method doesn't match
101- Action getAction = registry .getAction ("api/users" , Action .Mode .HTTP_GET );
102- assertNotNull (getAction , "GET action should exist" );
103-
104- // POST mode should not match GET action
105- Action postAction = registry .getAction ("api/users" , Action .Mode .HTTP_POST );
106- assertNotNull (postAction , "POST action should exist" );
107- assertNotEquals (getAction .getMode (), postAction .getMode ());
143+ public void testDefaultModeAcceptsAllMethods () throws Exception {
144+ // Test that DEFAULT mode actions accept any HTTP method
145+ String getResponse = sendHttpRequest ("GET" , BASE_URL + "/?q=api/ping" , null );
146+ assertTrue (getResponse .contains ("pong" ), "GET request to ping should return 'pong'" );
147+
148+ String postResponse = sendHttpRequest ("POST" , BASE_URL + "/?q=api/ping" , null );
149+ assertTrue (postResponse .contains ("pong" ), "POST request to ping should return 'pong'" );
150+
151+ String putResponse = sendHttpRequest ("PUT" , BASE_URL + "/?q=api/ping" , null );
152+ assertTrue (putResponse .contains ("pong" ), "PUT request to ping should return 'pong'" );
108153 }
109154
110155 @ Test
111- public void testDefaultModeAcceptsAllMethods () throws ApplicationException {
112- // Test that DEFAULT mode actions accept any HTTP method
113- Action getAction = registry .getAction ("api/ping" , Action .Mode .HTTP_GET );
114- Action postAction = registry .getAction ("api/ping" , Action .Mode .HTTP_POST );
115- Action putAction = registry .getAction ("api/ping" , Action .Mode .HTTP_PUT );
116-
117- // All should match the same DEFAULT mode action
118- assertNotNull (getAction );
119- assertNotNull (postAction );
120- assertNotNull (putAction );
121-
122- // They should all return the same result
123- assertEquals ("pong" , String .valueOf (getAction .execute ()));
124- assertEquals ("pong" , String .valueOf (postAction .execute ()));
125- assertEquals ("pong" , String .valueOf (putAction .execute ()));
156+ public void testHttpMethodMismatch () throws Exception {
157+ // Try to access GET endpoint with POST method - should fail or return error
158+ // Note: This depends on how the server handles method mismatches
159+ String response = sendHttpRequest ("POST" , BASE_URL + "/?q=api/users" , null );
160+ // POST to api/users should work (there's a POST handler), but let's verify it's not the GET handler
161+ assertTrue (response .contains ("POST users" ), "POST request should match POST handler, not GET" );
126162 }
127163
128- @ Test
129- public void testApplicationManagerCallWithMode () throws ApplicationException {
130- // Test that ApplicationManager.call correctly uses mode
131- ApplicationContext context = new ApplicationContext ();
132-
133- // GET request
134- Object getResult = ApplicationManager .call ("api/users" , context , Action .Mode .HTTP_GET );
135- assertEquals ("GET users" , String .valueOf (getResult ));
136-
137- // POST request
138- Object postResult = ApplicationManager .call ("api/users" , context , Action .Mode .HTTP_POST );
139- assertEquals ("POST users" , String .valueOf (postResult ));
140-
141- // PUT request with parameter (path includes the ID)
142- Object putResult = ApplicationManager .call ("api/users/456" , context , Action .Mode .HTTP_PUT );
143- assertTrue (String .valueOf (putResult ).contains ("PUT user" ));
164+ /**
165+ * Helper method to send HTTP requests
166+ */
167+ private String sendHttpRequest (String method , String urlString , String body ) throws Exception {
168+ URLRequest request = new URLRequest (URI .create (urlString ).toURL ());
169+ request .setMethod (method .toUpperCase ());
170+
171+ if (body != null && (method .equalsIgnoreCase ("POST" ) || method .equalsIgnoreCase ("PUT" ))) {
172+ request .setHeader ("Content-Type" , "application/x-www-form-urlencoded" );
173+ request .setBody (body );
174+ }
175+
176+ HTTPHandler handler = new HTTPHandler ();
177+ URLResponse response = handler .handleRequest (request );
178+
179+ int statusCode = response .getStatusCode ();
180+ String responseText = response .getBody ();
181+
182+ if (statusCode >= 200 && statusCode < 300 ) {
183+ return responseText ;
184+ } else {
185+ // return error response text for non-2xx responses
186+ return responseText ;
187+ }
144188 }
145189
146190 @ Test
147191 public void testHttpMethodExtractionFromRequest () {
148192 // Test that HTTP method can be extracted from Method enum
149- Method getMethod = Method .GET ;
193+ org . tinystruct . http . Method getMethod = org . tinystruct . http . Method .GET ;
150194 Action .Mode mode = Action .Mode .fromName (getMethod .name ());
151195 assertEquals (Action .Mode .HTTP_GET , mode );
152196
153- Method postMethod = Method .POST ;
197+ org . tinystruct . http . Method postMethod = org . tinystruct . http . Method .POST ;
154198 mode = Action .Mode .fromName (postMethod .name ());
155199 assertEquals (Action .Mode .HTTP_POST , mode );
156200 }
0 commit comments