chiark / gitweb /
Basic superblock test.
authorDan Sheppard <dan.sheppard.circle@gmail.com>
Tue, 22 Apr 2025 17:16:12 +0000 (18:16 +0100)
committerDan Sheppard <dan.sheppard.circle@gmail.com>
Tue, 22 Apr 2025 17:16:12 +0000 (18:16 +0100)
.gitignore
Makefile
src/coquet.h
src/superblock.c
src/superblock.h
src/test.c
src/unix.c
testdata/sb1.coquet [new file with mode: 0644]

index 497c04101a0d7cadde42dec02e2044100268790b..2b5e1ba03e545e6f3e11bd2d9ff6201ee51f9a3c 100644 (file)
@@ -1,5 +1,5 @@
 *.o
-*.coquet*
+tmp/*
 a.out
 obj/*
 bin/*
index 9f57f48833532db926737cc22b8b28eef8f3fe62..a5b373f04ce1df7509afe7e578dd0e18995293fb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,43 +6,50 @@ TESTOBJDIR := obj/test
 SRCFILES := unix.c util.c coquet.c superblock.c sha2.c testvfs.c
 
 SRC := $(addprefix $(SRCDIR)/,$(SRCFILES))
-DEPSRC := $(wildcard $(SRCDIR)/*.c)
 
-DEPS = $(DEPSRC:$(SRCDIR)/%.c=$(OBJDIR)/%.d)
-OBJ := $(SRC:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
+CLISRC := $(SRC) $(SRCDIR)/main.c
+TESTSRC := $(SRC) $(SRCDIR)/test.c
 
-TESTDEPS = $(DEPSRC:$(SRCDIR)/%.c=$(TESTOBJDIR)/%.d)
-TESTOBJ := $(SRC:$(SRCDIR)/%.c=$(TESTOBJDIR)/%.o)
+MAINDEPS = $(CLISRC:$(SRCDIR)/%.c=$(OBJDIR)/%.d)
+TESTDEPS = $(TESTSRC:$(SRCDIR)/%.c=$(TESTOBJDIR)/%.d)
+
+CLIOBJ := $(CLISRC:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
+TESTOBJ := $(TESTSRC:$(SRCDIR)/%.c=$(TESTOBJDIR)/%.o)
 
 LIBS =
 CC = gcc
-CFLAGS = -g -Wall --std=c99
+CFLAGS = -Wall --std=c99
+MAINCFLAGS = -O3
+TESTCFLAGS = -g
 
 .PHONY: default all clean test
 
 default: $(BINDIR)/coquet-cli $(BINDIR)/coquet-test
 all: default
 
-obj/test:
-       -mkdir obj/test
+# .c -> .o
 
 $(OBJDIR)/%.o: $(SRCDIR)/%.c
-       $(CC) $(CFLAGS) -c $< -o $@
+       $(CC) $(CFLAGS) $(MAINCFLAGS) -c $< -o $@
+
+$(TESTOBJDIR)/%.o: $(SRCDIR)/%.c
+       $(CC) $(CFLAGS) $(TESTCFLAGS) -DCOQUET_TEST -c $< -o $@
 
-$(TESTOBJDIR)/%.o: $(SRCDIR)/%.c obj/test
-       $(CC) $(CFLAGS) -DCOQUET_TEST -c $< -o $@
+# .c -> .d
 
 $(OBJDIR)/%.d: $(SRCDIR)/%.c
        $(CC) -MM -MP -MT $(@:.d=.o) $< > $@
 
-$(TESTOBJDIR)/%.d: $(SRCDIR)/%.c obj/test
+$(TESTOBJDIR)/%.d: $(SRCDIR)/%.c
        $(CC) -DCOQUET_TEST -MM -MP -MT $(@:.d=.o) $< > $@
 
-$(BINDIR)/coquet-cli: $(OBJ) $(OBJDIR)/main.o
-       $(CC) $(OBJ) $(OBJDIR)/main.o -Wall $(LIBS) -o $@
+# .o -> bin
+
+$(BINDIR)/coquet-cli: $(CLIOBJ)
+       $(CC) $(CLIOBJ) -Wall $(LIBS) -o $@
 
-$(BINDIR)/coquet-test: $(TESTOBJ) $(TESTOBJDIR)/test.o
-       $(CC) $(TESTOBJ) $(TESTOBJDIR)/test.o -Wall $(LIBS) -o $@
+$(BINDIR)/coquet-test: $(TESTOBJ)
+       $(CC) $(TESTOBJ) -Wall $(LIBS) -o $@
 
 # .PRECIOUS: $(TARGET) $(OBJECTS)
 
@@ -51,5 +58,5 @@ clean:
        -rm -f $(TESTOBJDIR)/*
        -rm -f $(BINDIR)/*
 
--include $(DEPS)
+-include $(MAINDEPS)
 -include $(TESTDEPS)
index 9118face23a29020d11f20cf61bebfb76f23fb11..304f1ad68f448752f08b795b110082b3e358c265 100644 (file)
@@ -32,6 +32,8 @@ char * coquet_error_string(coquet_t *cq, int error);
 #ifdef COQUET_TEST
 void test_bail(coquet_t * cq, int error_code);
 void test_unlink(char *path);
+void test_file_compare(char *got, char *expected);
+void test_assert(int is_true, char *msg);
 #endif
 
 #endif
index 3eaa86ed36f6ed06af0b3ceb0a6f41bb6ffc6c89..c901a70f0bf5ed5c659f722e0b6186122ace27c5 100644 (file)
  * +-------------------+
  * | block_size        |   0           1
  * | nursery_size      |   1           1
+ * | unused            |   2         126
  * +-------------------+
- * | unused            |   2         509
+ * | description       | 128         128
  * +-------------------+
- * | reserved          | 511           1
+ * | unused            | 256         256
  * +-------------------+
- * 
- * The reserved byte is to allow locking to work via superblock page.
- * Range must exist to write, hence lock code may write this byte at
- * offset 0x00007FFF
  */
 
 struct cq_super default_super = {
@@ -121,8 +118,8 @@ int cq_super_load(coquet_t *cq, struct cq_super *super, bool_t create) {
         return r;
     }
 
-    r = extract_half(super_bytes,&super_a);
-    r2 = extract_half(super_bytes+HALF_BYTES,&super_b);
+    r = !!extract_half(super_bytes,&super_a);
+    r2 = !!extract_half(super_bytes+HALF_BYTES,&super_b);
     switch(r*2+r2) {
         case 3: /* both valid */
             use_b = (super_b.sb_serial > super_a.sb_serial);
@@ -232,30 +229,69 @@ int cq_super_save(coquet_t *cq, struct cq_super *super, bool_t wait) {
 
 void test_superblock() {
     coquet_t cq;
-    int r;
+    int i,r;
     struct cq_super super;
 
     printf("testing superblock\n");
+
     r = coquet_init(&cq,"tmp/test");
     test_bail(&cq,r);
-    
+    testvfs_fakerandom(cq.vfs_data,0xA5);
+
+    /* simple load/save test to check data is in the right place */
+
     test_unlink("tmp/test.coquet");
+
     r = (cq.vfs_funcs.open)(cq.vfs_data,COQUET_FILE_MAIN,COQUET_CMODE_EITHER);
     test_bail(&cq,r);
 
-    testvfs_fakerandom(cq.vfs_data,0xA5);
     r = cq_super_load(&cq,&super,1);
     test_bail(&cq,r);
 
     cq_super_save(&cq,&super,1);
     test_bail(&cq,r);
-    testvfs_fakerandom(cq.vfs_data,-1);
+
+    super.desired.nursery_size = 11; /* change something for B */
+    cq_super_save(&cq,&super,1);
+    test_bail(&cq,r);
 
     r = (cq.vfs_funcs.close)(cq.vfs_data,COQUET_FILE_MAIN);
     test_bail(&cq,r);
 
+    test_file_compare("tmp/test.coquet","testdata/sb1.coquet");
+
+    /* reopen to check the marshalling */
+    r = (cq.vfs_funcs.open)(cq.vfs_data,COQUET_FILE_MAIN,COQUET_CMODE_EITHER);
+    test_bail(&cq,r);
+
+    r = cq_super_load(&cq,&super,1);
+    test_bail(&cq,r);
+
+    test_assert(super.version == COQUET_VERSION,"version");
+    test_assert(super.sb_serial == 2,"serial");
+    test_assert(super.from_b == 1,"from_b");
+    test_assert(super.current.block_size == 12,"cbsize");
+    test_assert(super.desired.block_size == 12,"dbsize");
+    test_assert(super.current.nursery_size == 10,"cnurs");
+    test_assert(super.desired.nursery_size == 11,"dnurs");
+    for(i=0;i<GLOBAL_IV_LEN;i++)
+        test_assert(super.global_iv[i] == 0xA5,"iv");
+
+    r = (cq.vfs_funcs.close)(cq.vfs_data,COQUET_FILE_MAIN);
+    test_bail(&cq,r);
+
+    testvfs_fakerandom(cq.vfs_data,-1);
     r = coquet_finish(&cq);
     test_bail(&cq,r);
 }
 
+/* To test:
+
+creation
+corruption
+a/b choice
+magic
+
+*/
+
 #endif
index 314e75c533488f6103241783bcef8c25eeb3ae79..a498c8e1ae6551ab5aae0f27575c84d6981c4340 100644 (file)
@@ -6,7 +6,7 @@
 #define HALF_BYTES  2048
 #define SUPER_BYTES (HALF_BYTES*2)
 #define GLOBAL_IV_LEN 32
-#define SUPERBLOCK_LAST_OFFSET (SUPER_BYTES-1)
+#define NUM_LOCKS 32
 
 struct cq_super_config {
     uint8_t block_size; /* log2 bytes */
index e73f8920572d4a312eac640264fb9d154215bab7..63c46a5ef7d1c5b980877f3f56f391bee8a147fb 100644 (file)
@@ -2,9 +2,17 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
+#include <fcntl.h>
 #include "sha2.h"
 #include "superblock.h"
 
+void test_assert(int is_true, char *msg) {
+    if(!is_true) {
+        fprintf(stderr,"assertion '%s' failed\n",msg);
+        exit(1);
+    }
+}
+
 void test_unlink(char *path) {
     int r;
 
@@ -15,6 +23,53 @@ void test_unlink(char *path) {
     }
 }
 
+#define RFBUFLEN 1024
+static void readfile(char *path, char **out, int *len) {
+    int fd, r;
+    char buffer[RFBUFLEN];
+
+    *out = NULL;
+    *len = 0;
+    fd = open(path,O_RDONLY);
+    if(fd<0) {
+        fprintf(stderr,"failed to read '%s': %s\n",path,strerror(errno));
+        exit(1);
+    }
+    while(1) {
+        r = read(fd,buffer,RFBUFLEN);
+        if(r<0) {
+            fprintf(stderr,"failed to read '%s': %s\n",path,strerror(errno));
+            exit(1);
+        } else if(r>0) {
+            *out = realloc(*out,(*len)+r);
+            if(*out == NULL) {
+                fprintf(stderr,"realloc failed\n");
+                exit(1);
+            }
+            memcpy((*out)+(*len),buffer,r);
+            *len += r;
+
+        } else {
+            break;
+        }
+    }
+}
+
+void test_file_compare(char *got, char *expected) {
+    char *got_data, *exp_data;
+    int got_len, exp_len;
+
+    readfile(got,&got_data,&got_len);
+    readfile(expected,&exp_data,&exp_len);
+    if(got_len != exp_len || memcmp(got_data,exp_data,exp_len)) {
+        /* different! */
+        fprintf(stderr,"'%s' (got) and '%s' (expected) differ\n",got,expected);
+        exit(1);
+    }
+    free(got_data);
+    free(exp_data);
+}
+
 void test_bail(coquet_t * cq, int error_code) {
     char *msg;
 
index 87bdd747aa4fb3cfd15f31adc40e5857ff4a1148..6a57c4ddcf4a71bd9638bb5505a91cc412293b16 100644 (file)
@@ -330,7 +330,7 @@ static int unix_lock(void * vfs_data, int which_lock, int lock_mode,
     }
 
     /* Lock region needs to exist. We can append zeroes.*/
-    r = min_size(pd,SUPERBLOCK_LAST_OFFSET);
+    r = min_size(pd,SUPER_BYTES+LOCK_BLOCK*NUM_LOCKS);
     if(r != COQUET_RET_OK) {
         return r;
     }
diff --git a/testdata/sb1.coquet b/testdata/sb1.coquet
new file mode 100644 (file)
index 0000000..669f78d
Binary files /dev/null and b/testdata/sb1.coquet differ