1 /*
2  * Copyright (c) 2021 Nordic Semiconductor
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Test log list
10  *
11  */
12 
13 #include <../subsys/logging/log_cache.h>
14 
15 #include <zephyr/tc_util.h>
16 #include <zephyr/kernel.h>
17 #include <zephyr/ztest.h>
18 #include <stdbool.h>
19 
20 
21 #define ENTRY_SIZE(data_len) \
22 	ROUND_UP(sizeof(struct log_cache_entry) + data_len, sizeof(uintptr_t))
23 #define TEST_ENTRY_LEN 8
24 
25 struct test_id {
26 	uint8_t x;
27 	uint16_t y;
28 };
29 
30 union test_ids {
31 	struct test_id id;
32 	uintptr_t raw;
33 };
34 
cmp(uintptr_t id0,uintptr_t id1)35 static bool cmp(uintptr_t id0, uintptr_t id1)
36 {
37 	union test_ids t0 = { .raw = id0 };
38 	union test_ids t1 = { .raw = id1 };
39 
40 	return (t0.id.x == t1.id.x) && (t0.id.y == t1.id.y);
41 }
42 
buf_fill(uint8_t * data,uint8_t x)43 static void buf_fill(uint8_t *data, uint8_t x)
44 {
45 	for (int i = 0; i < TEST_ENTRY_LEN; i++) {
46 		data[i] = x;
47 	}
48 }
49 
buf_check(uint8_t * data,uint8_t x)50 static bool buf_check(uint8_t *data, uint8_t x)
51 {
52 	for (int i = 0; i < TEST_ENTRY_LEN; i++) {
53 		if (data[i] !=  x) {
54 			return false;
55 		}
56 	}
57 
58 	return true;
59 }
60 
cache_get(struct log_cache * cache,uintptr_t id,uint8_t ** buf,bool exp_hit,uint32_t line)61 static void cache_get(struct log_cache *cache, uintptr_t id,
62 		      uint8_t **buf, bool exp_hit, uint32_t line)
63 {
64 	uint32_t hit = log_cache_get_hit(cache);
65 	uint32_t miss = log_cache_get_miss(cache);
66 	bool res;
67 
68 	res = log_cache_get(cache, id, buf);
69 	zassert_equal(res, exp_hit, "line %u\n", line);
70 	if (exp_hit) {
71 		zassert_equal(hit + 1, log_cache_get_hit(cache), "line %u\n", line);
72 		zassert_equal(miss, log_cache_get_miss(cache), "line %u\n", line);
73 	} else {
74 		zassert_equal(hit, log_cache_get_hit(cache), "line %u\n", line);
75 		zassert_equal(miss + 1, log_cache_get_miss(cache), "line %u\n", line);
76 	}
77 }
78 
ZTEST(test_log_cache,test_log_cache_basic)79 ZTEST(test_log_cache, test_log_cache_basic)
80 {
81 	/* Space for 3 entries */
82 	static uint8_t data[3 * ENTRY_SIZE(TEST_ENTRY_LEN)];
83 	static const struct log_cache_config config = {
84 		.buf = data,
85 		.buf_len = sizeof(data),
86 		.item_size = TEST_ENTRY_LEN,
87 		.cmp = cmp
88 	};
89 	int err;
90 	uint8_t *buf;
91 	struct log_cache cache;
92 	union test_ids id0 = {
93 		.id = { .x = 100, .y = 1245 }
94 	};
95 	union test_ids id1 = {
96 		.id = { .x = 101, .y = 1245 }
97 	};
98 	union test_ids id2 = {
99 		.id = { .x = 102, .y = 1245 }
100 	};
101 	union test_ids id3 = {
102 		.id = { .x = 103, .y = 1245 }
103 	};
104 
105 	err = log_cache_init(&cache, &config);
106 	zassert_equal(err, 0, NULL);
107 
108 	/* Try to find id0, cache is empty */
109 	cache_get(&cache, id0.raw, &buf, false, __LINE__);
110 
111 	buf_fill(buf, 1);
112 	/* Put id0 entry */
113 	log_cache_put(&cache, buf);
114 
115 	/* Try to find id0 with success. */
116 	cache_get(&cache, id0.raw, &buf, true, __LINE__);
117 	zassert_true(buf_check(buf, 1), "Buffer check failed");
118 
119 	/* Miss id1 in cache then put it */
120 	cache_get(&cache, id1.raw, &buf, false, __LINE__);
121 	buf_fill(buf, 2);
122 	log_cache_put(&cache, buf);
123 
124 	/* Miss id2 in cache then put it */
125 	cache_get(&cache, id2.raw, &buf, false, __LINE__);
126 	buf_fill(buf, 3);
127 	log_cache_put(&cache, buf);
128 
129 	/* Miss id3 in cache then put it. At that point id0 should still be in
130 	 * the cache but we now filled whole cache and oldest entry will be
131 	 * evicted.
132 	 */
133 	cache_get(&cache, id0.raw, &buf, true, __LINE__);
134 	cache_get(&cache, id1.raw, &buf, true, __LINE__);
135 	cache_get(&cache, id2.raw, &buf, true, __LINE__);
136 	cache_get(&cache, id3.raw, &buf, false, __LINE__);
137 	buf_fill(buf, 4);
138 	log_cache_put(&cache, buf);
139 
140 	/* id0 is evicted since it is the oldest one. */
141 	cache_get(&cache, id0.raw, &buf, false, __LINE__);
142 	zassert_true(buf_check(buf, 2), "Buffer check failed");
143 	log_cache_put(&cache, buf);
144 
145 	/* And id0 is now in cache */
146 	cache_get(&cache, id0.raw, &buf, true, __LINE__);
147 
148 	/* buf id1 got evicted */
149 	cache_get(&cache, id1.raw, &buf, false, __LINE__);
150 	zassert_true(buf_check(buf, 3), "Buffer check failed");
151 	log_cache_put(&cache, buf);
152 }
153 
154 ZTEST_SUITE(test_log_cache, NULL, NULL, NULL, NULL, NULL);
155