1 /*
2  * Copyright (c) 2023 Basalte bv
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <string.h>
8 
9 #include <zephyr/ztest.h>
10 #include <zephyr/net/coap_service.h>
11 
coap_method1(struct coap_resource * resource,struct coap_packet * request,struct sockaddr * addr,socklen_t addr_len)12 static int coap_method1(struct coap_resource *resource, struct coap_packet *request,
13 			struct sockaddr *addr, socklen_t addr_len)
14 {
15 	ARG_UNUSED(resource);
16 	ARG_UNUSED(request);
17 	ARG_UNUSED(addr);
18 	ARG_UNUSED(addr_len);
19 
20 	return -ENOSYS;
21 }
22 
coap_method2(struct coap_resource * resource,struct coap_packet * request,struct sockaddr * addr,socklen_t addr_len)23 static int coap_method2(struct coap_resource *resource, struct coap_packet *request,
24 			struct sockaddr *addr, socklen_t addr_len)
25 {
26 	ARG_UNUSED(resource);
27 	ARG_UNUSED(request);
28 	ARG_UNUSED(addr);
29 	ARG_UNUSED(addr_len);
30 
31 	return -ENOSYS;
32 }
33 
34 static const uint16_t service_A_port = 4242;
35 COAP_SERVICE_DEFINE(service_A, "a.service.com", &service_A_port, COAP_SERVICE_AUTOSTART);
36 
37 static const char * const resource_0_path[] = { "res0", NULL };
38 COAP_RESOURCE_DEFINE(resource_0, service_A, {
39 	.path = resource_0_path,
40 	.get = coap_method1,
41 	.put = coap_method2,
42 });
43 
44 static const char * const resource_1_path[] = { "res1", NULL };
45 COAP_RESOURCE_DEFINE(resource_1, service_A, {
46 	.path = resource_1_path,
47 	.post = coap_method1,
48 });
49 
50 static uint16_t service_B_port;
51 COAP_SERVICE_DEFINE(service_B, "b.service.com", &service_B_port, 0);
52 
53 static const char * const resource_2_path[] = { "res2", "sub", NULL };
54 COAP_RESOURCE_DEFINE(resource_2, service_B, {
55 	.path = resource_2_path,
56 	.get = coap_method2,
57 	.put = coap_method1,
58 });
59 
60 static const char * const resource_3_path[] = { "res3", "+", NULL };
61 COAP_RESOURCE_DEFINE(resource_3, service_B, {
62 	.path = resource_3_path,
63 	.post = coap_method2,
64 });
65 
66 static const uint16_t service_C_port = 5959;
67 #ifdef CONFIG_NET_SOCKETS_ENABLE_DTLS
68 static const sec_tag_t sec_tag_list[] = { 1 };
69 
70 COAPS_SERVICE_DEFINE(service_C, "192.168.1.1", &service_C_port, 0, sec_tag_list,
71 		     sizeof(sec_tag_list));
72 
73 #else
74 
75 COAP_SERVICE_DEFINE(service_C, "192.168.1.1", &service_C_port, 0);
76 #endif /* CONFIG_NET_SOCKETS_ENABLE_DTLS */
77 
78 static const char * const resource_4_path[] = { "res4", "*", NULL };
79 COAP_RESOURCE_DEFINE(resource_4, service_C, {
80 	.path = resource_4_path,
81 	.get = coap_method1,
82 });
83 
ZTEST(coap_service,test_COAP_SERVICE_DEFINE)84 ZTEST(coap_service, test_COAP_SERVICE_DEFINE)
85 {
86 	zassert_ok(strcmp(service_A.host, "a.service.com"));
87 	zassert_equal(service_A.port, &service_A_port);
88 	zassert_equal(*service_A.port, 4242);
89 	zassert_equal(service_A.sec_tag_list, NULL);
90 	zassert_equal(service_A.sec_tag_list_size, 0);
91 
92 	zassert_ok(strcmp(service_B.host, "b.service.com"));
93 	zassert_equal(service_B.port, &service_B_port);
94 	zassert_equal(*service_B.port, 0);
95 	zassert_equal(service_B.sec_tag_list, NULL);
96 	zassert_equal(service_B.sec_tag_list_size, 0);
97 
98 	zassert_ok(strcmp(service_C.host, "192.168.1.1"));
99 	zassert_equal(service_C.port, &service_C_port);
100 	zassert_equal(*service_C.port, 5959);
101 
102 #ifdef CONFIG_NET_SOCKETS_ENABLE_DTLS
103 	zassert_equal(service_C.sec_tag_list, sec_tag_list);
104 	zassert_equal(service_C.sec_tag_list_size, sizeof(sec_tag_list));
105 #else
106 	zassert_equal(service_C.sec_tag_list, NULL);
107 	zassert_equal(service_C.sec_tag_list_size, 0);
108 #endif
109 }
110 
ZTEST(coap_service,test_COAP_SERVICE_COUNT)111 ZTEST(coap_service, test_COAP_SERVICE_COUNT)
112 {
113 	size_t n_svc;
114 
115 	n_svc = 4273;
116 	COAP_SERVICE_COUNT(&n_svc);
117 	zassert_equal(n_svc, 3);
118 }
119 
ZTEST(coap_service,test_COAP_SERVICE_RESOURCE_COUNT)120 ZTEST(coap_service, test_COAP_SERVICE_RESOURCE_COUNT)
121 {
122 	zassert_equal(COAP_SERVICE_RESOURCE_COUNT(&service_A), 2);
123 	zassert_equal(COAP_SERVICE_RESOURCE_COUNT(&service_B), 2);
124 	zassert_equal(COAP_SERVICE_RESOURCE_COUNT(&service_C), 1);
125 }
126 
ZTEST(coap_service,test_COAP_SERVICE_HAS_RESOURCE)127 ZTEST(coap_service, test_COAP_SERVICE_HAS_RESOURCE)
128 {
129 	zassert_true(COAP_SERVICE_HAS_RESOURCE(&service_A, &resource_0));
130 	zassert_true(COAP_SERVICE_HAS_RESOURCE(&service_A, &resource_1));
131 	zassert_false(COAP_SERVICE_HAS_RESOURCE(&service_A, &resource_2));
132 	zassert_false(COAP_SERVICE_HAS_RESOURCE(&service_A, &resource_3));
133 
134 	zassert_false(COAP_SERVICE_HAS_RESOURCE(&service_B, &resource_0));
135 	zassert_false(COAP_SERVICE_HAS_RESOURCE(&service_B, &resource_1));
136 	zassert_true(COAP_SERVICE_HAS_RESOURCE(&service_B, &resource_2));
137 	zassert_true(COAP_SERVICE_HAS_RESOURCE(&service_B, &resource_3));
138 
139 	zassert_false(COAP_SERVICE_HAS_RESOURCE(&service_C, &resource_0));
140 	zassert_true(COAP_SERVICE_HAS_RESOURCE(&service_C, &resource_4));
141 }
142 
ZTEST(coap_service,test_COAP_SERVICE_FOREACH)143 ZTEST(coap_service, test_COAP_SERVICE_FOREACH)
144 {
145 	size_t n_svc = 0;
146 	size_t have_service_A = 0;
147 	size_t have_service_B = 0;
148 	size_t have_service_C = 0;
149 
150 	COAP_SERVICE_FOREACH(svc) {
151 		if (svc == &service_A) {
152 			have_service_A = 1;
153 			zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, COAP_SERVICE_AUTOSTART);
154 		} else if (svc == &service_B) {
155 			have_service_B = 1;
156 			zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, 0);
157 		} else if (svc == &service_C) {
158 			have_service_C = 1;
159 			zassert_equal(svc->flags & COAP_SERVICE_AUTOSTART, 0);
160 		} else {
161 			zassert_unreachable("svc (%p) not equal to &service_A (%p), &service_B "
162 					    "(%p), or &service_C (%p)",
163 					    svc, &service_A, &service_B, &service_C);
164 		}
165 
166 		n_svc++;
167 	}
168 
169 	zassert_equal(n_svc, 3);
170 	zassert_equal(have_service_A + have_service_B + have_service_C, n_svc);
171 }
172 
ZTEST(coap_service,test_COAP_RESOURCE_FOREACH)173 ZTEST(coap_service, test_COAP_RESOURCE_FOREACH)
174 {
175 	size_t first_res, second_res, n_res;
176 
177 	n_res = 0;
178 	first_res = 0;
179 	second_res = 0;
180 	COAP_RESOURCE_FOREACH(service_A, res) {
181 		if (res == &resource_0) {
182 			first_res = 1;
183 		} else if (res == &resource_1) {
184 			second_res = 1;
185 		} else {
186 			zassert_unreachable(
187 				"res (%p) not equal to &resource_0 (%p) or &resource_1 (%p)", res,
188 				&resource_0, &resource_1);
189 		}
190 
191 		n_res++;
192 	}
193 
194 	zassert_equal(n_res, 2);
195 	zassert_equal(first_res + second_res, n_res);
196 
197 	n_res = 0;
198 	first_res = 0;
199 	second_res = 0;
200 	COAP_RESOURCE_FOREACH(service_B, res) {
201 		if (res == &resource_2) {
202 			first_res = 1;
203 		} else if (res == &resource_3) {
204 			second_res = 1;
205 		} else {
206 			zassert_unreachable(
207 				"res (%p) not equal to &resource_2 (%p) or &resource_3 (%p)", res,
208 				&resource_2, &resource_3);
209 		}
210 
211 		n_res++;
212 	}
213 
214 	zassert_equal(n_res, 2);
215 	zassert_equal(first_res + second_res, n_res);
216 
217 	n_res = 0;
218 	first_res = 0;
219 	second_res = 0;
220 	COAP_RESOURCE_FOREACH(service_C, res) {
221 		if (res == &resource_4) {
222 			first_res = 1;
223 		} else {
224 			zassert_unreachable(
225 				"res (%p) not equal to &resource_4 (%p)", res, &resource_4);
226 		}
227 		n_res++;
228 	}
229 
230 	zassert_equal(n_res, 1);
231 	zassert_equal(first_res + second_res, n_res);
232 }
233 
ZTEST(coap_service,test_COAP_SERVICE_FOREACH_RESOURCE)234 ZTEST(coap_service, test_COAP_SERVICE_FOREACH_RESOURCE)
235 {
236 	size_t first_res, second_res, n_res;
237 
238 	n_res = 0;
239 	first_res = 0;
240 	second_res = 0;
241 	COAP_SERVICE_FOREACH_RESOURCE(&service_A, res) {
242 		if (res == &resource_0) {
243 			first_res = 1;
244 		} else if (res == &resource_1) {
245 			second_res = 1;
246 		} else {
247 			zassert_unreachable(
248 				"res (%p) not equal to &resource_0 (%p) or &resource_1 (%p)", res,
249 				&resource_0, &resource_1);
250 		}
251 
252 		n_res++;
253 	}
254 
255 	zassert_equal(n_res, 2);
256 	zassert_equal(first_res + second_res, n_res);
257 
258 	n_res = 0;
259 	first_res = 0;
260 	second_res = 0;
261 	COAP_SERVICE_FOREACH_RESOURCE(&service_B, res) {
262 		if (res == &resource_2) {
263 			first_res = 1;
264 		} else if (res == &resource_3) {
265 			second_res = 1;
266 		} else {
267 			zassert_unreachable(
268 				"res (%p) not equal to &resource_2 (%p) or &resource_3 (%p)", res,
269 				&resource_2, &resource_3);
270 		}
271 
272 		n_res++;
273 	}
274 
275 	zassert_equal(n_res, 2);
276 	zassert_equal(first_res + second_res, n_res);
277 
278 	n_res = 0;
279 	first_res = 0;
280 	second_res = 0;
281 	COAP_SERVICE_FOREACH_RESOURCE(&service_C, res) {
282 		if (res == &resource_4) {
283 			first_res = 1;
284 		} else {
285 			zassert_unreachable(
286 				"res (%p) not equal to &resource_4 (%p)", res, &resource_4);
287 		}
288 		n_res++;
289 	}
290 
291 	zassert_equal(n_res, 1);
292 	zassert_equal(first_res + second_res, n_res);
293 }
294 
ZTEST(coap_service,test_COAP_RESOURCE_DEFINE)295 ZTEST(coap_service, test_COAP_RESOURCE_DEFINE)
296 {
297 	COAP_SERVICE_FOREACH_RESOURCE(&service_A, res) {
298 		if (res == &resource_0) {
299 			zassert_ok(strcmp(res->path[0], "res0"));
300 			zassert_equal(res->get, coap_method1);
301 			zassert_equal(res->put, coap_method2);
302 		} else if (res == &resource_1) {
303 			zassert_ok(strcmp(res->path[0], "res1"));
304 			zassert_equal(res->post, coap_method1);
305 		} else {
306 			zassert_unreachable(
307 				"res (%p) not equal to &resource_0 (%p) or &resource_1 (%p)", res,
308 				&resource_0, &resource_1);
309 		}
310 	}
311 
312 	COAP_SERVICE_FOREACH_RESOURCE(&service_B, res) {
313 		if (res == &resource_2) {
314 			zassert_ok(strcmp(res->path[0], "res2"));
315 			zassert_ok(strcmp(res->path[1], "sub"));
316 			zassert_equal(res->get, coap_method2);
317 			zassert_equal(res->put, coap_method1);
318 		} else if (res == &resource_3) {
319 			zassert_ok(strcmp(res->path[0], "res3"));
320 			zassert_ok(strcmp(res->path[1], "+"));
321 			zassert_equal(res->post, coap_method2);
322 		} else {
323 			zassert_unreachable(
324 				"res (%p) not equal to &resource_2 (%p) or &resource_3 (%p)", res,
325 				&resource_2, &resource_3);
326 		}
327 	}
328 
329 	COAP_SERVICE_FOREACH_RESOURCE(&service_C, res) {
330 		if (res == &resource_4) {
331 			zassert_ok(strcmp(res->path[0], "res4"));
332 			zassert_ok(strcmp(res->path[1], "*"));
333 			zassert_equal(res->get, coap_method1);
334 			zassert_equal(res->put, NULL);
335 		} else {
336 			zassert_unreachable(
337 				"res (%p) not equal to &resource_4 (%p)", res, &resource_4);
338 		}
339 	}
340 }
341 
342 ZTEST_SUITE(coap_service, NULL, NULL, NULL, NULL, NULL);
343