AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <stdio.h>6 7/* The target function is static; use the provided global wrapper. */8extern int test_memdbLock(sqlite3_file *pFile, int eLock);9 10/* Ensure sqlite3MemdbInit is visible */11extern int sqlite3MemdbInit(void);12 13static int g_memdb_inited = 0;14 15static void open_shared_memdb(const char *name, sqlite3 **pDb, sqlite3_file **ppFile){16 int rc;17 char uri[256];18 sqlite3 *db = 0;19 sqlite3_file *pFile = 0;20 21 /* Construct a shared-memdb URI: leading slash makes it shared */22 sqlite3_snprintf(sizeof(uri), uri, "file:/%s?vfs=memdb", name);23 rc = sqlite3_open_v2(uri, &db,24 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI,25 NULL);26 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "Failed to open shared memdb database");27 TEST_ASSERT_NOT_NULL(db);28 29 rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &pFile);30 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "SQLITE_FCNTL_FILE_POINTER failed");31 TEST_ASSERT_NOT_NULL(pFile);32 33 *pDb = db;34 *ppFile = pFile;35}36 37static void close_db(sqlite3 *db){38 if( db ){39 sqlite3_close(db);40 }41}42 43static void open_readonly_deserialized_memdb(sqlite3 **pDb, sqlite3_file **ppFile){44 /* Create a separate memdb via sqlite3_deserialize with READONLY */45 int rc;46 sqlite3 *db = 0;47 sqlite3_file *pFile = 0;48 const sqlite3_int64 szDb = 0; /* 0-byte db content is fine for our locking tests */49 const sqlite3_int64 szBuf = 1024; /* backing buffer size */50 unsigned char *pData = (unsigned char*)sqlite3_malloc((int)szBuf);51 TEST_ASSERT_NOT_NULL_MESSAGE(pData, "sqlite3_malloc failed for deserialize buffer");52 memset(pData, 0, (size_t)szBuf);53 54 rc = sqlite3_open(":memory:", &db);55 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "Failed to open :memory:");56 57 /* READONLY plus FREEONCLOSE so buffer is freed on close */58 rc = sqlite3_deserialize(db, "main", pData, szDb, szBuf,59 SQLITE_DESERIALIZE_READONLY | SQLITE_DESERIALIZE_FREEONCLOSE);60 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_deserialize failed");61 62 rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &pFile);63 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "SQLITE_FCNTL_FILE_POINTER failed after deserialize");64 TEST_ASSERT_NOT_NULL(pFile);65 66 *pDb = db;67 *ppFile = pFile;68}69 70void setUp(void) {71 if( !g_memdb_inited ){72 int rc = sqlite3MemdbInit();73 /* sqlite3MemdbInit may be called multiple times; first must succeed */74 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3MemdbInit failed");75 g_memdb_inited = 1;76 }77}78 79void tearDown(void) {80 /* Nothing to do */81}82 83/* Test 1: Acquire SHARED lock on a fresh handle succeeds */84void test_memdbLock_shared_ok(void){85 sqlite3 *db = 0;86 sqlite3_file *pFile = 0;87 int rc;88 89 open_shared_memdb("t1_shared_ok", &db, &pFile);90 91 rc = test_memdbLock(pFile, SQLITE_LOCK_SHARED);92 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);93 94 /* Cleanup: unlock back to NONE */95 pFile->pMethods->xUnlock(pFile, SQLITE_LOCK_NONE);96 close_db(db);97}98 99/* Test 2: Two readers -> EXCLUSIVE on one should be SQLITE_BUSY */100void test_memdbLock_two_readers_then_exclusive_busy(void){101 sqlite3 *db1 = 0, *db2 = 0;102 sqlite3_file *f1 = 0, *f2 = 0;103 int rc;104 105 open_shared_memdb("t2_two_readers", &db1, &f1);106 open_shared_memdb("t2_two_readers", &db2, &f2);107 108 rc = test_memdbLock(f1, SQLITE_LOCK_SHARED);109 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);110 111 rc = test_memdbLock(f2, SQLITE_LOCK_SHARED);112 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);113 114 rc = test_memdbLock(f1, SQLITE_LOCK_EXCLUSIVE);115 TEST_ASSERT_EQUAL_INT(SQLITE_BUSY, rc);116 117 /* Cleanup: unlock both back to NONE */118 f1->pMethods->xUnlock(f1, SQLITE_LOCK_NONE);119 f2->pMethods->xUnlock(f2, SQLITE_LOCK_NONE);120 close_db(db1);121 close_db(db2);122}123 124/* Test 3: Writer reserved lock blocks new readers */125void test_memdbLock_reserved_blocks_new_shared(void){126 sqlite3 *db1 = 0, *db2 = 0;127 sqlite3_file *f1 = 0, *f2 = 0;128 int rc;129 130 open_shared_memdb("t3_reserved_blocks", &db1, &f1);131 open_shared_memdb("t3_reserved_blocks", &db2, &f2);132 133 rc = test_memdbLock(f1, SQLITE_LOCK_SHARED);134 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);135 136 rc = test_memdbLock(f1, SQLITE_LOCK_RESERVED);137 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);138 139 rc = test_memdbLock(f2, SQLITE_LOCK_SHARED);140 TEST_ASSERT_EQUAL_INT(SQLITE_BUSY, rc);141 142 /* Cleanup: release writer and close */143 f1->pMethods->xUnlock(f1, SQLITE_LOCK_NONE);144 f2->pMethods->xUnlock(f2, SQLITE_LOCK_NONE);145 close_db(db1);146 close_db(db2);147}148 149/* Test 4: Single reader can upgrade SHARED -> RESERVED -> EXCLUSIVE */150void test_memdbLock_upgrade_to_exclusive_single_reader_ok(void){151 sqlite3 *db = 0;152 sqlite3_file *f = 0;153 int rc;154 155 open_shared_memdb("t4_upgrade_ok", &db, &f);156 157 rc = test_memdbLock(f, SQLITE_LOCK_SHARED);158 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);159 160 rc = test_memdbLock(f, SQLITE_LOCK_RESERVED);161 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);162 163 rc = test_memdbLock(f, SQLITE_LOCK_EXCLUSIVE);164 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);165 166 /* Cleanup */167 f->pMethods->xUnlock(f, SQLITE_LOCK_NONE);168 close_db(db);169}170 171/* Test 5: Read-only store allows SHARED but refuses RESERVED/EXCLUSIVE */172void test_memdbLock_readonly_refuses_upgrades(void){173 sqlite3 *db = 0;174 sqlite3_file *f = 0;175 int rc;176 177 open_readonly_deserialized_memdb(&db, &f);178 179 rc = test_memdbLock(f, SQLITE_LOCK_SHARED);180 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);181 182 rc = test_memdbLock(f, SQLITE_LOCK_RESERVED);183 TEST_ASSERT_EQUAL_INT(SQLITE_READONLY, rc);184 185 rc = test_memdbLock(f, SQLITE_LOCK_EXCLUSIVE);186 TEST_ASSERT_EQUAL_INT(SQLITE_READONLY, rc);187 188 /* Cleanup */189 f->pMethods->xUnlock(f, SQLITE_LOCK_NONE);190 close_db(db);191}192 193/* Test 6: Idempotent / non-decreasing requests are OK */194void test_memdbLock_same_or_lower_level_ok(void){195 sqlite3 *db = 0;196 sqlite3_file *f = 0;197 int rc;198 199 open_shared_memdb("t6_idempotent", &db, &f);200 201 rc = test_memdbLock(f, SQLITE_LOCK_SHARED);202 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);203 204 /* Request same level again */205 rc = test_memdbLock(f, SQLITE_LOCK_SHARED);206 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);207 208 /* Request lower level (NONE) – should be OK (no-op inside memdbLock) */209 rc = test_memdbLock(f, SQLITE_LOCK_NONE);210 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);211 212 /* Cleanup */213 f->pMethods->xUnlock(f, SQLITE_LOCK_NONE);214 close_db(db);215}216 217int main(void){218 UNITY_BEGIN();219 RUN_TEST(test_memdbLock_shared_ok);220 RUN_TEST(test_memdbLock_two_readers_then_exclusive_busy);221 RUN_TEST(test_memdbLock_reserved_blocks_new_shared);222 RUN_TEST(test_memdbLock_upgrade_to_exclusive_single_reader_ok);223 RUN_TEST(test_memdbLock_readonly_refuses_upgrades);224 RUN_TEST(test_memdbLock_same_or_lower_level_ok);225 return UNITY_END();226}