summaryrefslogtreecommitdiff
path: root/tests/storage_test.c
blob: 321709580ccfd98cb9f502ee38980ff683e987f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include "storage/store.h"
#include "sys/system.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int failures;
#define CHECK(value)                                                                               \
  do                                                                                               \
    {                                                                                              \
      if (!(value))                                                                                \
        {                                                                                          \
          fprintf(stderr, "CHECK failed at line %d: %s\n", __LINE__, #value);                      \
          failures++;                                                                              \
        }                                                                                          \
    }                                                                                              \
  while (0)

static char *
duplicate_string(const char *value)
{
  const size_t length = strlen(value);
  char *copy = malloc(length + 1);
  if (copy != NULL)
    {
      memcpy(copy, value, length + 1);
    }
  return copy;
}

int
main(void)
{
  char *temporary_root = tiny_sys_temp_directory_create("tcm");
  char *directory;
  char *log_path;
  char *temporary_path;
  char *lock_path;
  char *snapshot_path;
  tiny_store_t *store = NULL, *second = NULL;
  tiny_message_t input, first, second_message;
  tiny_store_status_t status;
  tiny_sys_file_t log;
  tiny_rebuild_report_t report;
  unsigned char byte;
  uint32_t count;
  tiny_store_health_t health;
  size_t operation;
  static const tiny_sys_test_operation_t rebuild_failures[] = { TINY_SYS_TEST_OPEN,
                                                                TINY_SYS_TEST_RANDOM,
                                                                TINY_SYS_TEST_WRITE,
                                                                TINY_SYS_TEST_FLUSH,
                                                                TINY_SYS_TEST_REPLACE };

  CHECK(tiny_store_open(NULL, "unused") == TINY_STORE_IO_ERROR);
  store = (tiny_store_t *)(uintptr_t)1;
  CHECK(tiny_store_open(&store, NULL) == TINY_STORE_IO_ERROR && store == NULL);
  CHECK(tiny_store_entry_count(NULL) == 0);
  CHECK(tiny_store_entry(NULL, 0) == NULL);
  memset(&health, 0xff, sizeof(health));
  tiny_store_health(NULL, &health);
  CHECK(health.active_messages == 0 && health.log_size == 0);

  CHECK(temporary_root != NULL);
  if (temporary_root == NULL)
    {
      return 1;
    }
  directory = tiny_sys_path_join(temporary_root, "日本語-memory");
  CHECK(directory != NULL && tiny_sys_directory_create(directory) == TINY_SYS_OK);
  if (directory == NULL)
    {
      free(temporary_root);
      return 1;
    }
  log_path = tiny_sys_path_join(directory, "active.log");
  temporary_path = tiny_sys_path_join(directory, "active.tmp");
  lock_path = tiny_sys_path_join(directory, "store.lock");
  snapshot_path = tiny_sys_path_join(directory, "snapshot.bin");
  CHECK(log_path != NULL && temporary_path != NULL && lock_path != NULL && snapshot_path != NULL);

  status = tiny_store_open(&store, directory);
  CHECK(status == TINY_STORE_OK);
  CHECK(tiny_store_open(&second, directory) == TINY_STORE_BUSY);

  tiny_message_init(&input);
  tiny_message_init(&first);
  tiny_message_init(&second_message);
  input.session_id = duplicate_string("unit");
  input.content = duplicate_string("first");
  input.role = TINY_ROLE_USER;
  CHECK(tiny_store_write(store, &input, &first) == TINY_STORE_OK);
  free(input.content);
  input.content = duplicate_string("second");
  CHECK(tiny_store_write(store, &input, &second_message) == TINY_STORE_OK);
  CHECK(strcmp(first.message_id, second_message.message_id) < 0);
  tiny_message_free(&input);
  tiny_message_free(&first);
  tiny_message_free(&second_message);
  tiny_store_close(store);
  store = NULL;

  CHECK(tiny_store_open(&store, directory) == TINY_STORE_OK);
  CHECK(tiny_store_entry_count(store) == 2);
  for (operation = 0; operation < sizeof(rebuild_failures) / sizeof(rebuild_failures[0]);
       ++operation)
    {
      tiny_sys_test_reset();
      CHECK(tiny_sys_test_fail_after(rebuild_failures[operation], 1));
      CHECK(tiny_store_rebuild(store, &report) != TINY_STORE_OK);
      CHECK(tiny_store_entry_count(store) == 2);
      tiny_sys_test_reset();
      (void)tiny_sys_file_remove(temporary_path);
    }
  CHECK(tiny_sys_directory_create(temporary_path) == TINY_SYS_OK);
  CHECK(tiny_store_rebuild(store, &report) == TINY_STORE_IO_ERROR);
  CHECK(tiny_store_entry_count(store) == 2);
  CHECK(tiny_sys_directory_remove(temporary_path));
  tiny_store_close(store);
  store = NULL;

  CHECK(tiny_sys_file_open(&log, log_path, TINY_SYS_FILE_READ_WRITE) == TINY_SYS_OK);
  CHECK(tiny_sys_file_seek(&log, -1, TINY_SYS_SEEK_END));
  CHECK(tiny_sys_file_read(&log, &byte, 1, &count) && count == 1);
  byte ^= 0x5a;
  CHECK(tiny_sys_file_seek(&log, -1, TINY_SYS_SEEK_CURRENT));
  CHECK(tiny_sys_file_write(&log, &byte, 1, &count) && count == 1);
  tiny_sys_file_close(&log);
  CHECK(tiny_store_open(&store, directory) == TINY_STORE_CORRUPT);

  (void)tiny_sys_file_remove(log_path);
  (void)tiny_sys_file_remove(temporary_path);
  (void)tiny_sys_file_remove(lock_path);
  (void)tiny_sys_file_remove(snapshot_path);
  (void)tiny_sys_directory_remove(directory);
  (void)tiny_sys_directory_remove(temporary_root);
  free(snapshot_path);
  free(lock_path);
  free(temporary_path);
  free(log_path);
  free(directory);
  free(temporary_root);
  return failures == 0 ? 0 : 1;
}