cas_test.c (4894B)
1 /* cas_test -- public <kit/cas.h> by-id blob read surface. 2 * 3 * Run by: make test-cas-api 4 */ 5 6 #include <kit/cas.h> 7 #include <kit/core.h> 8 #include <errno.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <sys/stat.h> 13 #include <sys/types.h> 14 15 #include "lib/kit_unit.h" 16 17 static KitUnit g_u; 18 #define EXPECT(c, ...) CU_EXPECT(&g_u, c, __VA_ARGS__) 19 20 typedef struct CasTestWriter { 21 KitWriter w; 22 FILE* f; 23 } CasTestWriter; 24 25 static KitStatus cas_test_writer_write(KitWriter* w, const void* data, 26 size_t n) { 27 CasTestWriter* cw = (CasTestWriter*)w; 28 return fwrite(data, 1, n, cw->f) == n ? KIT_OK : KIT_IO; 29 } 30 31 static KitStatus cas_test_writer_seek(KitWriter* w, uint64_t offset) { 32 CasTestWriter* cw = (CasTestWriter*)w; 33 return fseek(cw->f, (long)offset, SEEK_SET) == 0 ? KIT_OK : KIT_IO; 34 } 35 36 static uint64_t cas_test_writer_tell(KitWriter* w) { 37 CasTestWriter* cw = (CasTestWriter*)w; 38 long pos = ftell(cw->f); 39 return pos < 0 ? 0 : (uint64_t)pos; 40 } 41 42 static KitStatus cas_test_writer_status(KitWriter* w) { 43 CasTestWriter* cw = (CasTestWriter*)w; 44 return ferror(cw->f) ? KIT_IO : KIT_OK; 45 } 46 47 static void cas_test_writer_close(KitWriter* w) { 48 CasTestWriter* cw = (CasTestWriter*)w; 49 if (cw->f) fclose(cw->f); 50 free(cw); 51 } 52 53 static KitStatus cas_test_read_all(void* user, const char* path, 54 KitFileData* out) { 55 FILE* f; 56 long end; 57 uint8_t* data; 58 (void)user; 59 out->data = NULL; 60 out->size = 0; 61 out->token = NULL; 62 f = fopen(path, "rb"); 63 if (!f) return KIT_NOT_FOUND; 64 if (fseek(f, 0, SEEK_END) != 0) { 65 fclose(f); 66 return KIT_IO; 67 } 68 end = ftell(f); 69 if (end < 0 || fseek(f, 0, SEEK_SET) != 0) { 70 fclose(f); 71 return KIT_IO; 72 } 73 data = (uint8_t*)malloc((size_t)end ? (size_t)end : 1u); 74 if (!data) { 75 fclose(f); 76 return KIT_NOMEM; 77 } 78 if ((size_t)end && 79 fread(data, 1, (size_t)end, f) != (size_t)end) { 80 free(data); 81 fclose(f); 82 return KIT_IO; 83 } 84 fclose(f); 85 out->data = data; 86 out->size = (size_t)end; 87 out->token = data; 88 return KIT_OK; 89 } 90 91 static void cas_test_release(void* user, KitFileData* fd) { 92 (void)user; 93 free(fd->token); 94 fd->data = NULL; 95 fd->size = 0; 96 fd->token = NULL; 97 } 98 99 static KitStatus cas_test_open_writer(void* user, const char* path, 100 KitWriter** out) { 101 CasTestWriter* cw; 102 (void)user; 103 *out = NULL; 104 cw = (CasTestWriter*)calloc(1, sizeof *cw); 105 if (!cw) return KIT_NOMEM; 106 cw->f = fopen(path, "wb"); 107 if (!cw->f) { 108 free(cw); 109 return KIT_IO; 110 } 111 cw->w.write = cas_test_writer_write; 112 cw->w.seek = cas_test_writer_seek; 113 cw->w.tell = cas_test_writer_tell; 114 cw->w.status = cas_test_writer_status; 115 cw->w.close = cas_test_writer_close; 116 *out = &cw->w; 117 return KIT_OK; 118 } 119 120 static int cas_test_mkdir_p(void* user, const char* path) { 121 char buf[1024]; 122 size_t i, n; 123 (void)user; 124 n = strlen(path); 125 if (n == 0 || n >= sizeof buf) return 1; 126 memcpy(buf, path, n + 1u); 127 for (i = 1; i <= n; ++i) { 128 if (buf[i] != '/' && buf[i] != '\0') continue; 129 { 130 char save = buf[i]; 131 buf[i] = '\0'; 132 if (mkdir(buf, 0777) != 0 && errno != EEXIST) return 1; 133 buf[i] = save; 134 } 135 } 136 return 0; 137 } 138 139 int main(void) { 140 static const uint8_t data[] = "config=debug\n"; 141 static const char root[] = "build/test/cas_api_test_store"; 142 KitFileIO fio; 143 KitCasHost host; 144 KitCas* cas = NULL; 145 KitBlobInfo info; 146 KitFileData fd; 147 uint8_t missing[KIT_CAS_HASH_LEN]; 148 149 kit_unit_init(&g_u); 150 memset(&fio, 0, sizeof fio); 151 fio.read_all = cas_test_read_all; 152 fio.release = cas_test_release; 153 fio.open_writer = cas_test_open_writer; 154 memset(&host, 0, sizeof host); 155 host.file_io = &fio; 156 host.mkdir_p = cas_test_mkdir_p; 157 158 EXPECT(kit_cas_open(&g_u.ctx, &host, root, &cas) == KIT_OK, "open CAS"); 159 EXPECT(kit_cas_add_blob(cas, data, sizeof data - 1u, &info) == KIT_OK, 160 "add blob"); 161 EXPECT(kit_cas_has_blob(cas, info.id) == KIT_OK, "has added blob"); 162 163 memset(&fd, 0, sizeof fd); 164 EXPECT(kit_cas_get_blob(cas, info.id, &fd) == KIT_OK, "get added blob"); 165 EXPECT(fd.size == sizeof data - 1u, "blob size matches"); 166 EXPECT(memcmp(fd.data, data, sizeof data - 1u) == 0, "blob bytes match"); 167 kit_cas_release(cas, &fd); 168 kit_cas_release(cas, &fd); 169 EXPECT(fd.data == NULL && fd.size == 0 && fd.token == NULL, 170 "release is idempotent"); 171 172 memset(missing, 0, sizeof missing); 173 EXPECT(kit_cas_has_blob(cas, missing) == KIT_NOT_FOUND, 174 "has missing blob reports not found"); 175 memset(&fd, 0xff, sizeof fd); 176 EXPECT(kit_cas_get_blob(cas, missing, &fd) == KIT_NOT_FOUND, 177 "get missing blob reports not found"); 178 EXPECT(fd.data == NULL && fd.size == 0 && fd.token == NULL, 179 "miss leaves output empty"); 180 181 kit_cas_close(cas); 182 kit_unit_summary(&g_u, "cas_test"); 183 return kit_unit_status(&g_u); 184 }