0df5444669
Multiple round trips + exercise encode/decode
258 lines
8.7 KiB
C
258 lines
8.7 KiB
C
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include "automerge.h"
|
|
|
|
#define BUFSIZE 4096
|
|
|
|
void test_sync_basic() {
|
|
printf("begin sync test - basic\n");
|
|
int len;
|
|
|
|
// In a real application you would need to check to make sure your buffer is large enough for any given read
|
|
char buff[BUFSIZE];
|
|
|
|
Backend * dbA = automerge_init();
|
|
Backend * dbB = automerge_init();
|
|
|
|
SyncState * ssA = automerge_sync_state_init();
|
|
SyncState * ssB = automerge_sync_state_init();
|
|
|
|
len = automerge_generate_sync_message(dbA, ssA);
|
|
// In a real application, we would use `len` to allocate `buff` here
|
|
int len2 = automerge_read_binary(dbA, buff);
|
|
automerge_receive_sync_message(dbB, ssB, buff, len);
|
|
len = automerge_generate_sync_message(dbB, ssB);
|
|
// No more sync messages were generated
|
|
assert(len == 0);
|
|
}
|
|
|
|
void test_sync_encode_decode() {
|
|
printf("begin sync test - encode/decode\n");
|
|
int len;
|
|
|
|
char buff[BUFSIZE];
|
|
char sync_state_buff[BUFSIZE];
|
|
|
|
Backend * dbA = automerge_init();
|
|
Backend * dbB = automerge_init();
|
|
|
|
const char * requestA1 = "{\"actor\":\"111111\",\"seq\":1,\"time\":0,\"deps\":[],\"startOp\":1,\"ops\":[{\"action\":\"set\",\"obj\":\"_root\",\"key\":\"bird\",\"value\":\"magpie\",\"pred\":[]}]}";
|
|
const char * requestB1 = "{\"actor\":\"222222\",\"seq\":1,\"time\":0,\"deps\":[],\"startOp\":1,\"ops\":[{\"action\":\"set\",\"obj\":\"_root\",\"key\":\"bird\",\"value\":\"crow\",\"pred\":[]}]}";
|
|
automerge_apply_local_change(dbA, requestA1);
|
|
automerge_apply_local_change(dbB, requestB1);
|
|
|
|
SyncState * ssA = automerge_sync_state_init();
|
|
SyncState * ssB = automerge_sync_state_init();
|
|
|
|
len = automerge_generate_sync_message(dbA, ssA);
|
|
automerge_read_binary(dbA, buff);
|
|
automerge_receive_sync_message(dbB, ssB, buff, len);
|
|
|
|
len = automerge_generate_sync_message(dbB, ssB);
|
|
automerge_read_binary(dbB, buff);
|
|
automerge_receive_sync_message(dbA, ssA, buff, len);
|
|
|
|
len = automerge_generate_sync_message(dbA, ssA);
|
|
automerge_read_binary(dbA, buff);
|
|
automerge_receive_sync_message(dbB, ssB, buff, len);
|
|
|
|
|
|
len = automerge_generate_sync_message(dbB, ssB);
|
|
automerge_read_binary(dbB, buff);
|
|
automerge_receive_sync_message(dbA, ssA, buff, len);
|
|
|
|
len = automerge_generate_sync_message(dbA, ssA);
|
|
|
|
// Save the sync state
|
|
int encoded_len = automerge_encode_sync_state(dbB, ssB);
|
|
automerge_read_binary(dbB, sync_state_buff);
|
|
// Read it back
|
|
ssB = automerge_decode_sync_state(sync_state_buff, encoded_len);
|
|
|
|
len = automerge_generate_sync_message(dbB, ssB);
|
|
automerge_read_binary(dbB, buff);
|
|
automerge_receive_sync_message(dbA, ssA, buff, len);
|
|
|
|
|
|
len = automerge_generate_sync_message(dbA, ssA);
|
|
assert(len == 0);
|
|
}
|
|
|
|
void test_sync() {
|
|
printf("begin sync test");
|
|
test_sync_basic();
|
|
test_sync_encode_decode();
|
|
}
|
|
|
|
int main() {
|
|
int len;
|
|
|
|
// In a real application you would need to check to make sure your buffer is large enough for any given read
|
|
char buff[BUFSIZE];
|
|
char buff2[BUFSIZE];
|
|
char buff3[BUFSIZE];
|
|
|
|
printf("begin\n");
|
|
|
|
Backend * dbA = automerge_init();
|
|
Backend * dbB = automerge_init();
|
|
|
|
const char * requestA1 = "{\"actor\":\"111111\",\"seq\":1,\"time\":0,\"deps\":[],\"startOp\":1,\"ops\":[{\"action\":\"set\",\"obj\":\"_root\",\"key\":\"bird\",\"value\":\"magpie\",\"pred\":[]}]}";
|
|
const char * requestA2 = "{\"actor\":\"111111\",\"seq\":2,\"time\":0,\"deps\":[],\"startOp\":2,\"ops\":[{\"action\":\"set\",\"obj\":\"_root\",\"key\":\"dog\",\"value\":\"mastiff\",\"pred\":[]}]}";
|
|
const char * requestB1 = "{\"actor\":\"222222\",\"seq\":1,\"time\":0,\"deps\":[],\"startOp\":1,\"ops\":[{\"action\":\"set\",\"obj\":\"_root\",\"key\":\"bird\",\"value\":\"crow\",\"pred\":[]}]}";
|
|
const char * requestB2 = "{\"actor\":\"222222\",\"seq\":2,\"time\":0,\"deps\":[],\"startOp\":2,\"ops\":[{\"action\":\"set\",\"obj\":\"_root\",\"key\":\"cat\",\"value\":\"tabby\",\"pred\":[]}]}";
|
|
|
|
printf("*** requestA1 ***\n\n%s\n\n",requestA1);
|
|
|
|
len = automerge_get_last_local_change(dbA);
|
|
assert(len == -1);
|
|
printf("*** last_local expected error string ** (%s)\n\n",automerge_error(dbA));
|
|
|
|
len = automerge_apply_local_change(dbA, requestA1);
|
|
assert(len <= BUFSIZE);
|
|
automerge_read_json(dbA, buff);
|
|
printf("*** patchA1 ***\n\n%s\n\n",buff);
|
|
|
|
len = automerge_get_last_local_change(dbA);
|
|
assert(len > 0);
|
|
assert(len <= BUFSIZE);
|
|
len = automerge_read_binary(dbA, buff);
|
|
assert(len == 0);
|
|
|
|
len = automerge_apply_local_change(dbA, "{}");
|
|
assert(len == -1);
|
|
printf("*** patchA2 expected error string ** (%s)\n\n",automerge_error(dbA));
|
|
|
|
len = automerge_apply_local_change(dbA, requestA2);
|
|
assert(len <= BUFSIZE);
|
|
automerge_read_json(dbA, buff);
|
|
printf("*** patchA2 ***\n\n%s\n\n",buff);
|
|
|
|
len = automerge_apply_local_change(dbB, requestB1);
|
|
assert(len <= BUFSIZE);
|
|
automerge_read_json(dbB, buff);
|
|
printf("*** patchB1 ***\n\n%s\n\n",buff);
|
|
|
|
len = automerge_apply_local_change(dbB, requestB2);
|
|
assert(len <= BUFSIZE);
|
|
automerge_read_json(dbB, buff);
|
|
printf("*** patchB2 ***\n\n%s\n\n",buff);
|
|
|
|
printf("*** clone dbA -> dbC ***\n\n");
|
|
Backend * dbC = automerge_clone(dbA);
|
|
|
|
len = automerge_get_patch(dbA);
|
|
assert(len <= BUFSIZE);
|
|
automerge_read_json(dbA, buff);
|
|
len = automerge_get_patch(dbC);
|
|
assert(len <= BUFSIZE);
|
|
automerge_read_json(dbC, buff2);
|
|
// the json can serialize in different orders so I can do a stright strcmp()
|
|
printf("*** get_patch of dbA & dbC -- equal? *** --> %s\n\n",strlen(buff) == strlen(buff2) ? "true" : "false");
|
|
assert(strlen(buff) == strlen(buff2));
|
|
|
|
len = automerge_save(dbA);
|
|
assert(len <= BUFSIZE);
|
|
automerge_read_binary(dbA, buff2);
|
|
printf("*** save dbA - %d bytes ***\n\n",len);
|
|
|
|
printf("*** load the save into dbD ***\n\n");
|
|
Backend * dbD = automerge_load(len, buff2);
|
|
len = automerge_get_patch(dbD);
|
|
assert(len <= BUFSIZE);
|
|
automerge_read_json(dbD, buff2);
|
|
printf("*** get_patch of dbA & dbD -- equal? *** --> %s\n\n",strlen(buff) == strlen(buff2) ? "true" : "false");
|
|
assert(strlen(buff) == strlen(buff2));
|
|
|
|
printf("*** copy changes from dbA to B ***\n\n");
|
|
len = automerge_get_changes_for_actor(dbA,"111111");
|
|
while (len > 0) {
|
|
assert(len <= BUFSIZE);
|
|
int nextlen = automerge_read_binary(dbA,buff);
|
|
automerge_write_change(dbB,len,buff);
|
|
|
|
// decode the change for debug
|
|
// encode and decode could happen with either dbA or dbB,
|
|
// however encode needs to be done against dbB instead of dbA
|
|
// only because dbA is in the middle of iterating over some binary results
|
|
// and needs to finish before queuing another
|
|
automerge_decode_change(dbA,len,buff);
|
|
automerge_read_json(dbA, buff2);
|
|
printf("Change decoded to json -- %s\n",buff2);
|
|
automerge_encode_change(dbB,buff2);
|
|
automerge_read_binary(dbB,buff3);
|
|
assert(memcmp(buff,buff3,len) == 0);
|
|
|
|
len = nextlen;
|
|
}
|
|
automerge_apply_changes(dbB);
|
|
|
|
printf("*** get head from dbB ***\n\n");
|
|
int num_heads = 0;
|
|
len = automerge_get_heads(dbB);
|
|
while (len > 0) {
|
|
assert(len == 32);
|
|
int nextlen = automerge_read_binary(dbB,buff3 + (num_heads * 32));
|
|
num_heads++;
|
|
len = nextlen;
|
|
}
|
|
assert(num_heads == 2);
|
|
len = automerge_get_changes(dbB,num_heads,buff3);
|
|
assert(len == 0);
|
|
|
|
printf("*** copy changes from dbB to A ***\n\n");
|
|
len = automerge_get_changes_for_actor(dbB,"222222");
|
|
while (len > 0) {
|
|
assert(len <= BUFSIZE);
|
|
int nextlen = automerge_read_binary(dbB,buff);
|
|
automerge_write_change(dbA,len,buff);
|
|
len = nextlen;
|
|
}
|
|
automerge_apply_changes(dbA);
|
|
|
|
len = automerge_get_patch(dbA);
|
|
assert(len <= BUFSIZE);
|
|
automerge_read_json(dbA, buff);
|
|
len = automerge_get_patch(dbB);
|
|
assert(len <= BUFSIZE);
|
|
automerge_read_json(dbB, buff2);
|
|
printf("*** get_patch of dbA & dbB -- equal? *** --> %s\n\n",strlen(buff) == strlen(buff2) ? "true" : "false");
|
|
assert(strlen(buff) == strlen(buff2));
|
|
|
|
printf("*** copy changes from dbA to E using load ***\n\n");
|
|
Backend * dbE = automerge_init();
|
|
len = automerge_get_changes(dbA,0,NULL);
|
|
while (len > 0) {
|
|
assert(len <= BUFSIZE);
|
|
int nextlen = automerge_read_binary(dbA,buff);
|
|
automerge_write_change(dbE,len,buff);
|
|
len = nextlen;
|
|
}
|
|
automerge_load_changes(dbE);
|
|
|
|
len = automerge_get_patch(dbA);
|
|
assert(len <= BUFSIZE);
|
|
automerge_read_json(dbA, buff);
|
|
len = automerge_get_patch(dbE);
|
|
assert(len <= BUFSIZE);
|
|
automerge_read_json(dbE, buff2);
|
|
printf("*** get_patch of dbA & dbE -- equal? *** --> %s\n\n",strlen(buff) == strlen(buff2) ? "true" : "false");
|
|
assert(strlen(buff) == strlen(buff2));
|
|
|
|
len = automerge_get_missing_deps(dbE, num_heads, buff3);
|
|
automerge_read_json(dbE, buff); // [] - nothing missing
|
|
assert(strlen(buff) == 2);
|
|
|
|
test_sync();
|
|
|
|
printf("free resources\n");
|
|
automerge_free(dbA);
|
|
automerge_free(dbB);
|
|
automerge_free(dbC);
|
|
automerge_free(dbD);
|
|
automerge_free(dbE);
|
|
|
|
printf("end\n");
|
|
}
|