-
Notifications
You must be signed in to change notification settings - Fork 88
/
Copy pathtest_tp_isotp_compliance.c
331 lines (282 loc) · 13.6 KB
/
test_tp_isotp_compliance.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
#include "test/env.h"
#include <unistd.h>
int SetupMockTpPair(void **state) {
Env_t *env = malloc(sizeof(Env_t));
memset(env, 0, sizeof(Env_t));
env->server_tp = ISOTPMockNew("server", &(ISOTPMockArgs_t){.sa_phys = 0x7E0,
.ta_phys = 0x7E8,
.sa_func = 0x7DF,
.ta_func = UDS_TP_NOOP_ADDR});
env->client_tp = ISOTPMockNew("client", &(ISOTPMockArgs_t){.sa_phys = 0x7E8,
.ta_phys = 0x7E0,
.sa_func = UDS_TP_NOOP_ADDR,
.ta_func = 0x7DF});
*state = env;
return 0;
}
int TeardownMockTpPair(void **state) {
Env_t *env = *state;
ISOTPMockFree(env->server_tp);
ISOTPMockFree(env->client_tp);
ISOTPMockReset();
free(env);
return 0;
}
int SetupMockTpPairExtendedID(void **state) {
Env_t *env = malloc(sizeof(Env_t));
memset(env, 0, sizeof(Env_t));
env->server_tp = ISOTPMockNew("server", &(ISOTPMockArgs_t){.sa_phys = 0x1ffffff0,
.ta_phys = 0x1ffffff8,
.sa_func = 0x1fffffff,
.ta_func = UDS_TP_NOOP_ADDR});
env->client_tp = ISOTPMockNew("client", &(ISOTPMockArgs_t){.sa_phys = 0x1ffffff8,
.ta_phys = 0x1ffffff0,
.sa_func = UDS_TP_NOOP_ADDR,
.ta_func = 0x1fffffff});
*state = env;
return 0;
}
int SetupMockTpClientOnly(void **state) {
Env_t *env = malloc(sizeof(Env_t));
memset(env, 0, sizeof(Env_t));
env->client_tp = ISOTPMockNew("client", &(ISOTPMockArgs_t){.sa_phys = 0x7E8,
.ta_phys = 0x7E0,
.sa_func = UDS_TP_NOOP_ADDR,
.ta_func = 0x7DF});
*state = env;
return 0;
}
int TeardownMockTpClientOnly(void **state) {
Env_t *env = *state;
ISOTPMockFree(env->client_tp);
ISOTPMockReset();
free(env);
return 0;
}
int SetupIsoTpCPair(void **state) {
Env_t *env = malloc(sizeof(Env_t));
memset(env, 0, sizeof(Env_t));
UDSTpISOTpC_t *server_isotp = malloc(sizeof(UDSTpISOTpC_t));
strcpy(server_isotp->tag, "server");
assert(UDS_OK == UDSTpISOTpCInit(server_isotp, "vcan0", 0x7e8, 0x7e0, 0x7df, 0));
env->server_tp = (UDSTp_t *)server_isotp;
UDSTpISOTpC_t *client_isotp = malloc(sizeof(UDSTpISOTpC_t));
strcpy(client_isotp->tag, "client");
assert(UDS_OK == UDSTpISOTpCInit(client_isotp, "vcan0", 0x7e0, 0x7e8, 0, 0x7df));
env->client_tp = (UDSTp_t *)client_isotp;
env->is_real_time = true;
*state = env;
return 0;
}
int TeardownIsoTpCPair(void **state) {
Env_t *env = *state;
UDSTpISOTpCDeinit((UDSTpISOTpC_t *)env->server_tp);
UDSTpISOTpCDeinit((UDSTpISOTpC_t *)env->client_tp);
free(env->server_tp);
free(env->client_tp);
free(env);
return 0;
}
int SetupIsoTpCClientOnly(void **state) {
Env_t *env = malloc(sizeof(Env_t));
memset(env, 0, sizeof(Env_t));
UDSTpISOTpC_t *client_isotp = malloc(sizeof(UDSTpISOTpC_t));
strcpy(client_isotp->tag, "client");
assert(UDS_OK == UDSTpISOTpCInit(client_isotp, "vcan0", 0x7e0, 0x7e8, 0, 0x7df));
env->client_tp = (UDSTp_t *)client_isotp;
env->is_real_time = true;
*state = env;
return 0;
}
int TeardownIsoTpCClientOnly(void **state) {
Env_t *env = *state;
UDSTpISOTpCDeinit((UDSTpISOTpC_t *)env->client_tp);
free(env->client_tp);
free(env);
return 0;
}
int SetupIsoTpSockPair(void **state) {
Env_t *env = malloc(sizeof(Env_t));
memset(env, 0, sizeof(Env_t));
UDSTpIsoTpSock_t *server_isotp = malloc(sizeof(UDSTpIsoTpSock_t));
strcpy(server_isotp->tag, "server");
assert(UDS_OK == UDSTpIsoTpSockInitServer(server_isotp, "vcan0", 0x7e8, 0x7e0, 0x7df));
env->server_tp = (UDSTp_t *)server_isotp;
UDSTpIsoTpSock_t *client_isotp = malloc(sizeof(UDSTpIsoTpSock_t));
strcpy(client_isotp->tag, "client");
assert(UDS_OK == UDSTpIsoTpSockInitClient(client_isotp, "vcan0", 0x7e0, 0x7e8, 0x7df));
env->client_tp = (UDSTp_t *)client_isotp;
env->is_real_time = true;
*state = env;
return 0;
}
int TeardownIsoTpSockPair(void **state) {
Env_t *env = *state;
UDSTpIsoTpSockDeinit((UDSTpIsoTpSock_t *)env->server_tp);
UDSTpIsoTpSockDeinit((UDSTpIsoTpSock_t *)env->client_tp);
free(env->server_tp);
free(env->client_tp);
free(env);
return 0;
}
int SetupIsoTpSockClientOnly(void **state) {
Env_t *env = malloc(sizeof(Env_t));
memset(env, 0, sizeof(Env_t));
UDSTpIsoTpSock_t *client_isotp = malloc(sizeof(UDSTpIsoTpSock_t));
strcpy(client_isotp->tag, "client");
assert(UDS_OK == UDSTpIsoTpSockInitClient(client_isotp, "vcan0", 0x7e0, 0x7e8, 0x7df));
env->client_tp = (UDSTp_t *)client_isotp;
env->is_real_time = true;
*state = env;
return 0;
}
int TeardownIsoTpSockClientOnly(void **state) {
Env_t *env = *state;
UDSTpIsoTpSockDeinit((UDSTpIsoTpSock_t *)env->client_tp);
free(env->client_tp);
free(env);
return 0;
}
void test_send_recv(void **state) {
Env_t *e = *state;
// When some data is sent by one transport
const uint8_t MSG[] = {0x10, 0x02};
UDSTpSend(e->client_tp, MSG, sizeof(MSG), NULL);
// it should be received soon by the other transport.
EXPECT_WITHIN_MS(e, UDSTpGetRecvLen(e->server_tp) > 0, 10);
TEST_MEMORY_EQUAL(UDSTpGetRecvBuf(e->server_tp, NULL), MSG, sizeof(MSG));
}
void test_send_recv_functional(void **state) {
Env_t *e = *state;
// When a functional request is sent
const uint8_t MSG[] = {0x10, 0x02};
UDSSDU_t info = {0};
UDSTpSend(e->client_tp, MSG, sizeof(MSG), &(UDSSDU_t){.A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL});
// the server should receive it quickly
EXPECT_WITHIN_MS(e, UDSTpGetRecvLen(e->server_tp) > 0, 10);
// it should be the same message
uint8_t *buf = NULL;
UDSSDU_t info2 = {0};
UDSTpPeek(e->server_tp, &buf, &info2);
TEST_MEMORY_EQUAL(buf, MSG, sizeof(MSG));
// and the server should know it's a functional request
assert_int_equal(info2.A_TA_Type, UDS_A_TA_TYPE_FUNCTIONAL);
}
void test_send_recv_largest_single_frame(void **state) {
Env_t *e = *state;
// When a functional request is sent
const uint8_t MSG[] = {1, 2, 3, 4, 5, 6, 7};
UDSSDU_t info = {0};
UDSTpSend(e->client_tp, MSG, sizeof(MSG), &(UDSSDU_t){.A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL});
// the server should receive it quickly
EXPECT_WITHIN_MS(e, UDSTpGetRecvLen(e->server_tp) > 0, 10);
// it should be the same message
uint8_t *buf = NULL;
UDSSDU_t info2 = {0};
UDSTpPeek(e->server_tp, &buf, &info2);
TEST_MEMORY_EQUAL(buf, MSG, sizeof(MSG));
// and the server should know it's a functional request
assert_int_equal(info2.A_TA_Type, UDS_A_TA_TYPE_FUNCTIONAL);
}
// ISO 15765-2 2016 Table 4 note b. Functional addressing shall only be supported for SingleFrame communication.
void test_send_functional_larger_than_single_frame_fails(void **state){
Env_t *e = *state;
// When a functional request is sent with more than 7 bytes
const uint8_t MSG[] = {1, 2, 3, 4, 5, 6, 7, 8};
ssize_t ret = UDSTpSend(e->client_tp, MSG, sizeof(MSG), &(UDSSDU_t){.A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL});
// it should fail
assert_true(ret < 0);
}
void test_send_recv_max_len(void **state) {
Env_t *e = *state;
// When a request is sent with the maximum length
uint8_t MSG[4095] = {0};
MSG[0] = 0x10;
MSG[4094] = 0x02;
UDSTpSend(e->client_tp, MSG, sizeof(MSG), NULL);
// the server should receive it quickly, albeit perhaps with a slight delay on vcan
EXPECT_WITHIN_MS(e, UDSTpGetRecvLen(e->server_tp) > 0, 1000);
// it should be the same message
uint8_t *buf = NULL;
UDSSDU_t info = {0};
UDSTpPeek(e->server_tp, &buf, &info);
TEST_MEMORY_EQUAL(buf, MSG, sizeof(MSG));
}
void test_flow_control_frame_timeout(void **state) {
Env_t *e = *state;
e->do_not_poll = true;
// sending multiframe to wait for Flow Control frame
// which will not arrive since no server is running
const uint8_t MSG[] = {1, 2, 3, 4, 5, 6, 7, 8};
ssize_t ret = UDSTpSend(e->client_tp, MSG, sizeof(MSG), NULL);
TEST_INT_EQUAL(ret, 8);
UDSTpStatus_t status = 0;
for (int i = 0; i < 2000; i++) {
status = UDSTpPoll(e->client_tp);
if (status & UDS_TP_ERR) {
// success
return;
}
EnvRunMillis(e, 1);
}
fail();
}
// clang-format off
const struct CMUnitTest tests_tp_mock[] = {
cmocka_unit_test_setup_teardown(test_send_recv, SetupMockTpPair, TeardownMockTpPair),
cmocka_unit_test_setup_teardown(test_send_recv_functional, SetupMockTpPair, TeardownMockTpPair),
cmocka_unit_test_setup_teardown(test_send_recv_largest_single_frame, SetupMockTpPair, TeardownMockTpPair),
cmocka_unit_test_setup_teardown(test_send_functional_larger_than_single_frame_fails, SetupMockTpPair, TeardownMockTpPair),
cmocka_unit_test_setup_teardown(test_send_recv_max_len, SetupMockTpPair, TeardownMockTpPair),
// The mock server doesn't implement fc timeouts
// cmocka_unit_test_setup_teardown(test_flow_control_frame_timeout, SetupMockTpClientOnly, TeardownMockTpClientOnly),
// Extended ID tests
cmocka_unit_test_setup_teardown(test_send_recv, SetupMockTpPairExtendedID, TeardownMockTpPair),
cmocka_unit_test_setup_teardown(test_send_recv_functional, SetupMockTpPairExtendedID, TeardownMockTpPair),
cmocka_unit_test_setup_teardown(test_send_recv_largest_single_frame, SetupMockTpPairExtendedID, TeardownMockTpPair),
cmocka_unit_test_setup_teardown(test_send_functional_larger_than_single_frame_fails, SetupMockTpPairExtendedID, TeardownMockTpPair),
cmocka_unit_test_setup_teardown(test_send_recv_max_len, SetupMockTpPairExtendedID, TeardownMockTpPair),
};
const struct CMUnitTest tests_tp_isotp_c[] = {
cmocka_unit_test_setup_teardown(test_send_recv, SetupIsoTpCPair, TeardownIsoTpCPair),
cmocka_unit_test_setup_teardown(test_send_recv_functional, SetupIsoTpCPair, TeardownIsoTpCPair),
cmocka_unit_test_setup_teardown(test_send_recv_largest_single_frame, SetupIsoTpCPair, TeardownIsoTpCPair),
cmocka_unit_test_setup_teardown(test_send_functional_larger_than_single_frame_fails, SetupIsoTpCPair, TeardownIsoTpCPair),
cmocka_unit_test_setup_teardown(test_send_recv_max_len, SetupIsoTpCPair, TeardownIsoTpCPair),
cmocka_unit_test_setup_teardown(test_flow_control_frame_timeout, SetupIsoTpCClientOnly, TeardownIsoTpCClientOnly),
};
const struct CMUnitTest tests_tp_isotp_sock[] = {
cmocka_unit_test_setup_teardown(test_send_recv, SetupIsoTpSockPair, TeardownIsoTpSockPair),
cmocka_unit_test_setup_teardown(test_send_recv_functional, SetupIsoTpSockPair, TeardownIsoTpSockPair),
cmocka_unit_test_setup_teardown(test_send_recv_largest_single_frame, SetupIsoTpSockPair, TeardownIsoTpSockPair),
cmocka_unit_test_setup_teardown(test_send_functional_larger_than_single_frame_fails, SetupIsoTpSockPair, TeardownIsoTpSockPair),
cmocka_unit_test_setup_teardown(test_send_recv_max_len, SetupIsoTpSockPair, TeardownIsoTpSockPair),
cmocka_unit_test_setup_teardown(test_flow_control_frame_timeout, SetupIsoTpSockClientOnly, TeardownIsoTpSockClientOnly),
};
// clang-format on
int main(int ac, char **av) {
if (ac > 1) {
if (ac > 2) {
cmocka_set_test_filter(av[2]);
}
// because these are compliance tests and we explicitly want to run the same test functions
// against different types of transport, filtering by the test name with
// cmocka_set_test_filter won't work.
if (0 == strcmp(av[1], "mock")) {
UDS_LOGI(__FILE__, "running mock tests. av[1]=%s", av[1]);
return cmocka_run_group_tests(tests_tp_mock, NULL, NULL);
} else if (0 == strcmp(av[1], "c")) {
UDS_LOGI(__FILE__, "running isotp_c tests. av[1]=%s", av[1]);
return cmocka_run_group_tests(tests_tp_isotp_c, NULL, NULL);
} else if (0 == strcmp(av[1], "sock")) {
UDS_LOGI(__FILE__, "running isotp_sock tests. av[1]=%s", av[1]);
return cmocka_run_group_tests(tests_tp_isotp_sock, NULL, NULL);
} else {
UDS_LOGE(__FILE__, "unknown test type: %s", av[1]);
}
}
UDS_LOGI(__FILE__, "running all tests");
return cmocka_run_group_tests(tests_tp_mock, NULL, NULL) +
cmocka_run_group_tests(tests_tp_isotp_c, NULL, NULL) +
cmocka_run_group_tests(tests_tp_isotp_sock, NULL, NULL);
}