Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_network_mock.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
28#include "nilorea/n_str.h"
29#include "nilorea/n_log.h"
30#include "nilorea/n_network.h"
31#include "nilorea/n_common.h"
32
33#include <getopt.h>
34#include <string.h>
35#include <pthread.h>
36#include <unistd.h>
37
39#define MOCK_PORT 19090
40
42static N_MOCK_SERVER* g_server = NULL;
43
50static void on_request(N_HTTP_REQUEST* req, N_HTTP_RESPONSE* resp, void* user_data) {
51 (void)user_data;
52 n_log(LOG_INFO, "mock: %s %s", req->method, req->path);
53
54 if (strcmp(req->method, "GET") == 0 &&
55 strcmp(req->path, "/api/test") == 0) {
56 resp->status_code = 200;
57 strncpy(resp->content_type, "application/json",
58 sizeof(resp->content_type) - 1);
59 resp->body = char_to_nstr("{\"status\":\"ok\"}");
60 } else {
61 resp->status_code = 404;
62 strncpy(resp->content_type, "text/plain",
63 sizeof(resp->content_type) - 1);
64 resp->body = char_to_nstr("Not Found");
65 }
66}
67
73static void* server_thread(void* arg) {
74 (void)arg;
76 return NULL;
77}
78
79int main(int argc, char* argv[]) {
80 int log_level = LOG_ERR;
81 int getoptret = 0;
82
83 while ((getoptret = getopt(argc, argv, "V:h")) != -1) {
84 switch (getoptret) {
85 case 'V':
86 if (strcmp(optarg, "LOG_DEBUG") == 0)
88 else if (strcmp(optarg, "LOG_INFO") == 0)
90 else if (strcmp(optarg, "LOG_NOTICE") == 0)
92 else if (strcmp(optarg, "LOG_ERR") == 0)
94 break;
95 case 'h':
96 default:
97 fprintf(stderr, "Usage: %s [-V LOG_LEVEL]\n", argv[0]);
98 return 1;
99 }
100 }
102
103 /* Start mock server */
105 if (!g_server) {
106 fprintf(stderr, "FAIL: could not start mock server\n");
107 return 1;
108 }
109 printf("CHECK start server ... PASS\n");
110
111 /* Run server in a thread */
112 pthread_t thr;
113 if (pthread_create(&thr, NULL, server_thread, NULL) != 0) {
114 fprintf(stderr, "FAIL: could not create server thread\n");
116 return 1;
117 }
118
119 /* Give the server thread time to start accepting */
120 usleep(100000); /* 100ms */
121
122 /* Connect and send a GET /api/test request */
123 SOCKET sock_fd = INVALID_SOCKET;
124 {
125 struct addrinfo hints;
126 struct addrinfo* res = NULL;
127 memset(&hints, 0, sizeof(hints));
128 hints.ai_family = AF_INET;
129 hints.ai_socktype = SOCK_STREAM;
130 char port_str[16];
131 snprintf(port_str, sizeof(port_str), "%d", MOCK_PORT);
132 if (getaddrinfo("127.0.0.1", port_str, &hints, &res) != 0 || !res) {
133 fprintf(stderr, "FAIL: getaddrinfo\n");
135 pthread_join(thr, NULL);
137 return 1;
138 }
139 sock_fd = socket(res->ai_family, res->ai_socktype,
140 res->ai_protocol);
141 if (sock_fd == INVALID_SOCKET ||
142 connect(sock_fd, res->ai_addr, (socklen_t)res->ai_addrlen) != 0) {
143 fprintf(stderr, "FAIL: connect\n");
144 freeaddrinfo(res);
146 pthread_join(thr, NULL);
148 return 1;
149 }
150 freeaddrinfo(res);
151 }
152
153 /* Send HTTP request */
154 const char* http_req =
155 "GET /api/test HTTP/1.1\r\n"
156 "Host: localhost\r\n"
157 "Connection: close\r\n"
158 "\r\n";
159 ssize_t sent = send(sock_fd, http_req, NETW_BUFLEN_CAST(strlen(http_req)), 0);
160 if (sent <= 0) {
161 fprintf(stderr, "FAIL: send\n");
162 closesocket(sock_fd);
164 pthread_join(thr, NULL);
166 return 1;
167 }
168
169 /* Read response */
170 char resp_buf[4096];
171 memset(resp_buf, 0, sizeof(resp_buf));
172 ssize_t total = 0;
173 ssize_t nr = 0;
174 while ((nr = recv(sock_fd, resp_buf + total,
175 NETW_BUFLEN_CAST(sizeof(resp_buf) - 1 - (size_t)total), 0)) > 0) {
176 total += nr;
177 }
178 closesocket(sock_fd);
179
180 printf("Response:\n%s\n", resp_buf);
181
182 /* Verify response contains expected data */
183 int pass = 1;
184 if (strstr(resp_buf, "200") == NULL) {
185 fprintf(stderr, "FAIL: expected 200 in response\n");
186 pass = 0;
187 }
188 if (strstr(resp_buf, "{\"status\":\"ok\"}") == NULL) {
189 fprintf(stderr, "FAIL: expected JSON body in response\n");
190 pass = 0;
191 }
192 printf("CHECK GET /api/test ... %s\n", pass ? "PASS" : "FAIL");
193
194 /* Stop server and clean up */
196 pthread_join(thr, NULL);
198
199 printf("CHECK cleanup ... PASS\n");
200 return pass ? 0 : 1;
201}
int main(void)
int getoptret
Definition ex_fluid.c:59
int log_level
Definition ex_fluid.c:60
static char * port_str
static void * server_thread(void *arg)
Thread function that runs the server accept loop.
#define MOCK_PORT
mock server port
static void on_request(N_HTTP_REQUEST *req, N_HTTP_RESPONSE *resp, void *user_data)
Request handler: returns JSON for GET /api/test, 404 otherwise.
static N_MOCK_SERVER * g_server
global server pointer for thread
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:89
#define LOG_DEBUG
debug-level messages
Definition n_log.h:84
#define LOG_ERR
error conditions
Definition n_log.h:76
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:121
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:80
#define LOG_INFO
informational
Definition n_log.h:82
N_STR * char_to_nstr(const char *src)
Convert a char into a N_STR, short version.
Definition n_str.c:255
N_STR * body
response body
Definition n_network.h:1049
char path[2048]
request path
Definition n_network.h:1039
char method[16]
HTTP method.
Definition n_network.h:1038
int status_code
HTTP status code.
Definition n_network.h:1047
char content_type[128]
Content-Type header value.
Definition n_network.h:1048
void n_mock_server_free(N_MOCK_SERVER **server)
Free a mock server and close the listening socket.
Definition n_network.c:7224
void n_mock_server_stop(N_MOCK_SERVER *server)
Signal the mock server to stop accepting connections.
Definition n_network.c:7215
int SOCKET
default socket declaration
Definition n_network.h:102
void n_mock_server_run(N_MOCK_SERVER *server)
Run the mock server accept loop.
Definition n_network.c:7130
N_MOCK_SERVER * n_mock_server_start(int port, void(*on_request)(N_HTTP_REQUEST *, N_HTTP_RESPONSE *, void *), void *user_data)
Start a mock HTTP server: set up listener and return immediately.
Definition n_network.c:7096
parsed HTTP request for mock server callback
Definition n_network.h:1037
HTTP response to send from mock server callback.
Definition n_network.h:1046
mock HTTP server handle
Definition n_network.h:1053
Common headers and low-level functions & define.
Generic log system.
Network Engine.
N_STR and string function declaration.