or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cache-testing.mdconfiguration.mdindex.mdintegration-tests.mdkey-value-stores.mdunit-tests.mdvector-stores.md

key-value-stores.mddocs/

0

# Key-Value Store Testing

1

2

Generic testing suites for key-value store implementations with comprehensive CRUD operations, bulk operations, and both synchronous and asynchronous support. These tests ensure that key-value stores meet LangChain's storage interface requirements.

3

4

## Capabilities

5

6

### Synchronous Key-Value Store Testing

7

8

Comprehensive testing suite for synchronous key-value store implementations.

9

10

```python { .api }

11

from typing import Generic, TypeVar, List

12

from langchain_tests.integration_tests import BaseStoreSyncTests

13

14

V = TypeVar('V')

15

16

class BaseStoreSyncTests(BaseStandardTests, Generic[V]):

17

"""Synchronous key-value store testing suite."""

18

19

# Required fixtures

20

@pytest.fixture

21

def kv_store(self):

22

"""Empty key-value store instance for testing. Must be implemented by test class."""

23

24

@pytest.fixture

25

def three_values(self) -> List[V]:

26

"""Three example values for testing. Must be implemented by test class."""

27

28

# Fixture validation

29

def test_three_values(self) -> None:

30

"""Validate that the three_values fixture provides correct test data."""

31

32

# Store state tests

33

def test_kv_store_is_empty(self) -> None:

34

"""Verify that the key-value store starts empty."""

35

36

def test_store_still_empty(self) -> None:

37

"""Verify that the store is properly cleaned up after tests."""

38

39

# Basic CRUD operations

40

def test_set_and_get_values(self) -> None:

41

"""Test setting and getting values from the store."""

42

43

def test_delete_values(self) -> None:

44

"""Test deleting individual values from the store."""

45

46

def test_delete_bulk_values(self) -> None:

47

"""Test bulk deletion of multiple values."""

48

49

def test_delete_missing_keys(self) -> None:

50

"""Test deletion behavior when keys don't exist."""

51

52

# Idempotency and consistency tests

53

def test_set_values_is_idempotent(self) -> None:

54

"""Test that setting the same key multiple times is idempotent."""

55

56

def test_get_can_get_same_value(self) -> None:

57

"""Test that getting the same key returns consistent values."""

58

59

def test_overwrite_values_by_key(self) -> None:

60

"""Test overwriting existing values with new ones."""

61

62

# Key iteration

63

def test_yield_keys(self) -> None:

64

"""Test iterating over all keys in the store."""

65

```

66

67

#### Usage Example

68

69

```python

70

from typing import List

71

import pytest

72

from langchain_tests.integration_tests import BaseStoreSyncTests

73

from my_integration import MyKeyValueStore

74

75

class TestMyKeyValueStore(BaseStoreSyncTests[str]):

76

@pytest.fixture

77

def kv_store(self):

78

# Create a fresh store instance for each test

79

store = MyKeyValueStore(

80

connection_url="redis://localhost:6379/1",

81

namespace="test_kv"

82

)

83

yield store

84

# Cleanup after test

85

store.clear()

86

87

@pytest.fixture

88

def three_values(self) -> List[str]:

89

return ["value1", "value2", "value3"]

90

```

91

92

### Asynchronous Key-Value Store Testing

93

94

Comprehensive testing suite for asynchronous key-value store implementations.

95

96

```python { .api }

97

from typing import Generic, TypeVar, List

98

from langchain_tests.integration_tests import BaseStoreAsyncTests

99

100

V = TypeVar('V')

101

102

class BaseStoreAsyncTests(BaseStandardTests, Generic[V]):

103

"""Asynchronous key-value store testing suite."""

104

105

# Required fixtures

106

@pytest.fixture

107

async def kv_store(self):

108

"""Empty async key-value store instance for testing. Must be implemented by test class."""

109

110

@pytest.fixture

111

def three_values(self) -> List[V]:

112

"""Three example values for testing. Must be implemented by test class."""

113

114

# Async fixture validation

115

async def test_three_values(self) -> None:

116

"""Validate that the three_values fixture provides correct test data."""

117

118

# Async store state tests

119

async def test_kv_store_is_empty(self) -> None:

120

"""Verify that the async key-value store starts empty."""

121

122

async def test_store_still_empty(self) -> None:

123

"""Verify that the async store is properly cleaned up after tests."""

124

125

# Async CRUD operations

126

async def test_set_and_get_values(self) -> None:

127

"""Test async setting and getting values from the store."""

128

129

async def test_delete_values(self) -> None:

130

"""Test async deletion of individual values from the store."""

131

132

async def test_delete_bulk_values(self) -> None:

133

"""Test async bulk deletion of multiple values."""

134

135

async def test_delete_missing_keys(self) -> None:

136

"""Test async deletion behavior when keys don't exist."""

137

138

# Async idempotency and consistency tests

139

async def test_set_values_is_idempotent(self) -> None:

140

"""Test that async setting the same key multiple times is idempotent."""

141

142

async def test_get_can_get_same_value(self) -> None:

143

"""Test that async getting the same key returns consistent values."""

144

145

async def test_overwrite_values_by_key(self) -> None:

146

"""Test async overwriting existing values with new ones."""

147

148

# Async key iteration

149

async def test_yield_keys(self) -> None:

150

"""Test async iteration over all keys in the store."""

151

```

152

153

#### Usage Example

154

155

```python

156

from typing import List, Dict, Any

157

import pytest

158

from langchain_tests.integration_tests import BaseStoreAsyncTests

159

from my_integration import MyAsyncKeyValueStore

160

161

class TestMyAsyncKeyValueStore(BaseStoreAsyncTests[Dict[str, Any]]):

162

@pytest.fixture

163

async def kv_store(self):

164

# Create a fresh async store instance for each test

165

store = await MyAsyncKeyValueStore.create(

166

connection_url="redis://localhost:6379/1",

167

namespace="test_async_kv"

168

)

169

yield store

170

# Cleanup after test

171

await store.clear()

172

await store.close()

173

174

@pytest.fixture

175

def three_values(self) -> List[Dict[str, Any]]:

176

return [

177

{"id": 1, "name": "Alice", "role": "admin"},

178

{"id": 2, "name": "Bob", "role": "user"},

179

{"id": 3, "name": "Charlie", "role": "guest"}

180

]

181

```

182

183

## Generic Type Support

184

185

The key-value store testing framework supports generic types, allowing you to test stores with any value type:

186

187

### String Values

188

189

```python

190

class TestStringStore(BaseStoreSyncTests[str]):

191

@pytest.fixture

192

def three_values(self) -> List[str]:

193

return ["hello", "world", "test"]

194

```

195

196

### JSON/Dictionary Values

197

198

```python

199

class TestJSONStore(BaseStoreSyncTests[Dict[str, Any]]):

200

@pytest.fixture

201

def three_values(self) -> List[Dict[str, Any]]:

202

return [

203

{"key": "value1", "count": 1},

204

{"key": "value2", "count": 2},

205

{"key": "value3", "count": 3}

206

]

207

```

208

209

### Custom Object Values

210

211

```python

212

from dataclasses import dataclass

213

214

@dataclass

215

class CustomObject:

216

name: str

217

value: int

218

tags: List[str]

219

220

class TestCustomObjectStore(BaseStoreSyncTests[CustomObject]):

221

@pytest.fixture

222

def three_values(self) -> List[CustomObject]:

223

return [

224

CustomObject("obj1", 100, ["tag1", "tag2"]),

225

CustomObject("obj2", 200, ["tag2", "tag3"]),

226

CustomObject("obj3", 300, ["tag1", "tag3"])

227

]

228

```

229

230

## Key Generation Patterns

231

232

Key-value store implementations typically use string keys. The testing framework validates various key patterns:

233

234

### Simple String Keys

235

236

```python

237

def test_simple_string_keys(self):

238

"""Test with simple alphanumeric keys."""

239

keys = ["key1", "key2", "key3"]

240

```

241

242

### UUID Keys

243

244

```python

245

import uuid

246

247

def test_uuid_keys(self):

248

"""Test with UUID-based keys."""

249

keys = [str(uuid.uuid4()) for _ in range(3)]

250

```

251

252

### Hierarchical Keys

253

254

```python

255

def test_hierarchical_keys(self):

256

"""Test with hierarchical key structures."""

257

keys = ["user:123:profile", "user:123:settings", "user:456:profile"]

258

```

259

260

## Bulk Operations

261

262

The testing framework validates bulk operations for performance:

263

264

### Bulk Set Operations

265

266

```python { .api }

267

def test_bulk_set_operations(self) -> None:

268

"""Test setting multiple key-value pairs in bulk."""

269

270

def test_bulk_get_operations(self) -> None:

271

"""Test getting multiple values in bulk."""

272

273

def test_bulk_delete_operations(self) -> None:

274

"""Test deleting multiple keys in bulk."""

275

```

276

277

## Error Handling

278

279

Key-value store tests verify proper error handling:

280

281

### Connection Errors

282

283

```python { .api }

284

def test_connection_error_handling(self) -> None:

285

"""Test behavior when store backend is unavailable."""

286

287

def test_timeout_handling(self) -> None:

288

"""Test handling of operation timeouts."""

289

```

290

291

### Serialization Errors

292

293

```python { .api }

294

def test_serialization_error_handling(self) -> None:

295

"""Test handling of values that cannot be serialized."""

296

297

def test_deserialization_error_handling(self) -> None:

298

"""Test handling of corrupted data during retrieval."""

299

```

300

301

### Key Validation

302

303

```python { .api }

304

def test_invalid_key_handling(self) -> None:

305

"""Test handling of invalid key formats."""

306

307

def test_empty_key_handling(self) -> None:

308

"""Test handling of empty or null keys."""

309

```

310

311

## Performance Testing

312

313

Key-value store tests include performance benchmarks:

314

315

### Latency Tests

316

317

```python { .api }

318

def test_get_latency(self) -> None:

319

"""Benchmark get operation latency."""

320

321

def test_set_latency(self) -> None:

322

"""Benchmark set operation latency."""

323

324

def test_delete_latency(self) -> None:

325

"""Benchmark delete operation latency."""

326

```

327

328

### Throughput Tests

329

330

```python { .api }

331

def test_bulk_operation_throughput(self) -> None:

332

"""Benchmark bulk operation throughput."""

333

334

def test_concurrent_access_performance(self) -> None:

335

"""Test performance under concurrent access."""

336

```

337

338

## Memory Management

339

340

Tests for memory-efficient implementations:

341

342

```python { .api }

343

def test_memory_usage_patterns(self) -> None:

344

"""Test memory usage with large datasets."""

345

346

def test_garbage_collection_behavior(self) -> None:

347

"""Test proper cleanup of resources."""

348

```

349

350

## Concurrency Testing

351

352

For thread-safe implementations:

353

354

### Thread Safety

355

356

```python { .api }

357

def test_concurrent_reads(self) -> None:

358

"""Test concurrent read operations."""

359

360

def test_concurrent_writes(self) -> None:

361

"""Test concurrent write operations."""

362

363

def test_read_write_consistency(self) -> None:

364

"""Test consistency between concurrent reads and writes."""

365

```

366

367

### Lock-Free Operations

368

369

```python { .api }

370

def test_lock_free_operations(self) -> None:

371

"""Test lock-free operation patterns."""

372

373

def test_atomic_operations(self) -> None:

374

"""Test atomic read-modify-write operations."""

375

```

376

377

## Persistence and Durability

378

379

For persistent store implementations:

380

381

### Data Persistence

382

383

```python { .api }

384

def test_data_persistence(self) -> None:

385

"""Test that data survives store restart."""

386

387

def test_crash_recovery(self) -> None:

388

"""Test recovery from unexpected shutdown."""

389

```

390

391

### Backup and Restore

392

393

```python { .api }

394

def test_backup_functionality(self) -> None:

395

"""Test data backup capabilities."""

396

397

def test_restore_functionality(self) -> None:

398

"""Test data restore capabilities."""

399

```

400

401

## Namespace and Isolation

402

403

For multi-tenant implementations:

404

405

### Namespace Separation

406

407

```python { .api }

408

def test_namespace_isolation(self) -> None:

409

"""Test that different namespaces are isolated."""

410

411

def test_namespace_cleanup(self) -> None:

412

"""Test proper cleanup of namespace data."""

413

```

414

415

## Configuration Testing

416

417

Validate that stores respect configuration parameters:

418

419

### Connection Parameters

420

421

```python { .api }

422

def test_connection_string_parsing(self) -> None:

423

"""Test parsing of connection strings."""

424

425

def test_connection_pool_management(self) -> None:

426

"""Test connection pool behavior."""

427

```

428

429

### Serialization Options

430

431

```python { .api }

432

def test_json_serialization(self) -> None:

433

"""Test JSON serialization of values."""

434

435

def test_pickle_serialization(self) -> None:

436

"""Test pickle serialization of Python objects."""

437

438

def test_custom_serialization(self) -> None:

439

"""Test custom serialization schemes."""

440

```

441

442

The key-value store testing framework provides comprehensive validation of storage implementations, ensuring they meet LangChain's requirements for reliability, performance, and consistency across both synchronous and asynchronous usage patterns.