kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 }