1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <unittest/unittest.h> 6#include <kvstore/kvstore.h> 7#include <pretty/hexdump.h> 8#include <lib/cksum.h> 9 10static bool kvs_bad_args(void) { 11 BEGIN_TEST; 12 13 kvstore_t kvs; 14 uint8_t buffer[1024]; 15 16 char str[300]; 17 memset(str, 'a', 299); 18 str[299] = 0; 19 20 // kvstore too small for even the header 21 kvs_init(&kvs, buffer, 3); 22 ASSERT_EQ(kvs_save(&kvs), KVS_ERR_OUT_OF_SPACE, ""); 23 24 ASSERT_EQ(kvs_add(&kvs, "key", "value"), KVS_ERR_OUT_OF_SPACE, ""); 25 26 // too-large keys or values 27 ASSERT_EQ(kvs_add(&kvs, str, "value"), KVS_ERR_BAD_PARAM, ""); 28 ASSERT_EQ(kvs_add(&kvs, "key", str), KVS_ERR_BAD_PARAM, ""); 29 30 str[256] = 0; 31 // just one byte too large 32 ASSERT_EQ(kvs_add(&kvs, str, "value"), KVS_ERR_BAD_PARAM, ""); 33 ASSERT_EQ(kvs_add(&kvs, "key", str), KVS_ERR_BAD_PARAM, ""); 34 35 // empty keys are invalid 36 ASSERT_EQ(kvs_add(&kvs, "", "value"), KVS_ERR_BAD_PARAM, ""); 37 38 END_TEST; 39} 40 41static int kvs_check(kvstore_t* kvs, const char* key, const char* val) { 42 const char* out = kvs_get(kvs, key, NULL); 43 if (out == NULL) { 44 return KVS_ERR_NOT_FOUND; 45 } 46 if (strcmp(val, out)) { 47 return KVS_ERR_INTERNAL; 48 } 49 return KVS_OK; 50} 51 52static int kvs_verify(kvstore_t* kvs, const void* data, size_t dlen, size_t count) { 53 if (memcmp(kvs->data + sizeof(kvshdr_t), data, dlen)) { 54 printf("\ndata mismatch between kvs (first) and expected (second):\n"); 55 hexdump8(kvs->data + sizeof(kvshdr_t), dlen); 56 hexdump8(data, dlen); 57 return KVS_ERR_INTERNAL; 58 } 59 if ((kvs->datalen - sizeof(kvshdr_t)) != dlen) { 60 return KVS_ERR_BAD_PARAM; 61 } 62 if (kvs->kvcount != count) { 63 return KVS_ERR_BAD_PARAM; 64 } 65 return KVS_OK; 66} 67 68static bool kvs_get_put(void) { 69 BEGIN_TEST; 70 71 kvstore_t kvs; 72 uint8_t buffer[2048]; 73 memset(buffer, '@', sizeof(buffer)); 74 75 char str[256]; 76 memset(str, 'a', 255); 77 str[255] = 0; 78 79 kvs_init(&kvs, buffer, sizeof(buffer)); 80 81 // simple 82 ASSERT_EQ(kvs_add(&kvs, "key1", "val1"), KVS_OK, ""); 83 ASSERT_EQ(kvs_verify(&kvs, "\x04\x04key1\0val1\0", 12, 1), KVS_OK, ""); 84 ASSERT_EQ(kvs_check(&kvs, "key1", "val1"), KVS_OK, ""); 85 ASSERT_EQ(kvs_add(&kvs, "key2", "val2"), KVS_OK, ""); 86 ASSERT_EQ(kvs_verify(&kvs, "\x04\x04key1\0val1\0\x04\x04key2\0val2\0", 24, 2), KVS_OK, ""); 87 ASSERT_EQ(kvs_check(&kvs, "key1", "val1"), KVS_OK, ""); 88 ASSERT_EQ(kvs_check(&kvs, "key2", "val2"), KVS_OK, ""); 89 90 // max allowable key/value 91 ASSERT_EQ(kvs_add(&kvs, str, "value"), KVS_OK, ""); 92 ASSERT_EQ(kvs_check(&kvs, str, "value"), KVS_OK, ""); 93 ASSERT_EQ(kvs_add(&kvs, "key", str), KVS_OK, ""); 94 ASSERT_EQ(kvs_check(&kvs, "key", str), KVS_OK, ""); 95 ASSERT_EQ(kvs_add(&kvs, str, str), KVS_OK, ""); 96 97 END_TEST; 98} 99 100static bool kvs_wire_format(void) { 101 BEGIN_TEST; 102 103 const uint8_t content[] = 104 "\x04\x04key1\0aaaa\0\x04\x08key2\0abcdefgh\0\x06\x00keykey\0\0\x04\x04key4\0bbbb"; 105 kvshdr_t hdr = { 106 .version = KVSTORE_VERSION, 107 .flags = 0, 108 .length = sizeof(kvshdr_t) + sizeof(content), 109 .crc = 0, 110 .reserved = 0, 111 }; 112 113 kvstore_t kvs; 114 uint8_t buffer[1024]; 115 116 hdr.crc = crc32(0, (const void*) &hdr, sizeof(hdr) - sizeof(uint32_t)); 117 hdr.crc = crc32(hdr.crc, content, sizeof(content)); 118 memcpy(buffer, &hdr, sizeof(hdr)); 119 memcpy(buffer + sizeof(hdr), content, sizeof(content)); 120 121 // Create a new kvs with the same content, save it, compare raw data 122 uint8_t buffer2[1024]; 123 kvs_init(&kvs, buffer2, sizeof(buffer2)); 124 ASSERT_EQ(kvs_add(&kvs, "key1", "aaaa"), KVS_OK, ""); 125 ASSERT_EQ(kvs_add(&kvs, "key2", "abcdefgh"), KVS_OK, ""); 126 ASSERT_EQ(kvs_add(&kvs, "keykey", ""), KVS_OK, ""); 127 ASSERT_EQ(kvs_add(&kvs, "key4", "bbbb"), KVS_OK, ""); 128 ASSERT_EQ(kvs_save(&kvs), KVS_OK, ""); 129 ASSERT_EQ(kvs.datalen, sizeof(hdr) + sizeof(content), ""); 130 ASSERT_EQ(memcmp(buffer, buffer2, kvs.datalen), 0, ""); 131 132 // mutated data should fail due to crc check 133 buffer[sizeof(hdr) + 8] = 0x42; 134 ASSERT_EQ(kvs_load(&kvs, buffer, sizeof(hdr) + sizeof(content)), KVS_ERR_PARSE_CRC, ""); 135 136 // exactly sized should parse 137 memcpy(buffer, &hdr, sizeof(hdr)); 138 memcpy(buffer + sizeof(hdr), content, sizeof(content)); 139 ASSERT_EQ(kvs_load(&kvs, buffer, sizeof(hdr) + sizeof(content)), KVS_OK, ""); 140 141 // verify we can find all the keys 142 ASSERT_EQ(kvs_check(&kvs, "key1", "aaaa"), KVS_OK, ""); 143 ASSERT_EQ(kvs_check(&kvs, "key2", "abcdefgh"), KVS_OK, ""); 144 ASSERT_EQ(kvs_check(&kvs, "keykey", ""), KVS_OK, ""); 145 ASSERT_EQ(kvs_check(&kvs, "key4", "bbbb"), KVS_OK, ""); 146 147 // but there's no space left 148 ASSERT_EQ(kvs_add(&kvs, "newkey", "newval"), KVS_ERR_OUT_OF_SPACE, ""); 149 150 // larger buffer should allow keys to be added 151 memcpy(buffer, &hdr, sizeof(hdr)); 152 memcpy(buffer + sizeof(hdr), content, sizeof(content)); 153 ASSERT_EQ(kvs_load(&kvs, buffer, sizeof(buffer)), KVS_OK, ""); 154 155 // add additional keys 156 ASSERT_EQ(kvs_add(&kvs, "key000000", "val000000"), KVS_OK, ""); 157 ASSERT_EQ(kvs_add(&kvs, "key000001", "val000001"), KVS_OK, ""); 158 159 const uint8_t newcontent[] = 160 "\x09\x09key000000\0val000000\0\x09\x09key000001\0val000001"; 161 hdr.crc = crc32(0, (const void*) &hdr, sizeof(hdr) - sizeof(uint32_t)); 162 hdr.crc = crc32(hdr.crc, content, sizeof(content)); 163 164 uint8_t checkbuf[sizeof(content) + sizeof(newcontent)]; 165 memcpy(checkbuf, content, sizeof(content)); 166 memcpy(checkbuf + sizeof(content), newcontent, sizeof(newcontent)); 167 ASSERT_EQ(kvs_verify(&kvs, checkbuf, sizeof(checkbuf), 6), KVS_OK, ""); 168 ASSERT_EQ(kvs_check(&kvs, "key000000", "val000000"), KVS_OK, ""); 169 ASSERT_EQ(kvs_check(&kvs, "key000001", "val000001"), KVS_OK, ""); 170 171 // truncated buffer should fail 172 memcpy(buffer, &hdr, sizeof(hdr)); 173 memcpy(buffer + sizeof(hdr), content, sizeof(content)); 174 ASSERT_EQ(kvs_load(&kvs, buffer, sizeof(hdr) + sizeof(content) - 1), KVS_ERR_PARSE_HDR, ""); 175 176 // truncated records should fail 177 hdr.length -= 3; 178 hdr.crc = crc32(0, (const void*) &hdr, sizeof(hdr) - sizeof(uint32_t)); 179 hdr.crc = crc32(hdr.crc, content, sizeof(content) - 3); 180 memcpy(buffer, &hdr, sizeof(hdr)); 181 memcpy(buffer + sizeof(hdr), content, sizeof(content)); 182 ASSERT_EQ(kvs_load(&kvs, buffer, sizeof(hdr) + sizeof(content) - 3), KVS_ERR_PARSE_REC, ""); 183 184 END_TEST; 185} 186 187BEGIN_TEST_CASE(kvstore_tests) 188RUN_TEST(kvs_bad_args) 189RUN_TEST(kvs_get_put) 190RUN_TEST(kvs_wire_format) 191END_TEST_CASE(kvstore_tests) 192 193int main(int argc, char** argv) { 194 return unittest_run_all_tests(argc, argv) ? 0 : -1; 195} 196