-
Notifications
You must be signed in to change notification settings - Fork 90
Expand file tree
/
Copy pathEnvironmentTests.cs
More file actions
406 lines (333 loc) · 13.1 KB
/
EnvironmentTests.cs
File metadata and controls
406 lines (333 loc) · 13.1 KB
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
using System;
using System.IO;
using Shouldly;
namespace LightningDB.Tests;
public class EnvironmentTests : TestBase
{
public void can_get_environment_version()
{
using var env = CreateEnvironment();
var version = env.Version;
version.ShouldNotBeNull();
version.Minor.ShouldBeGreaterThan(0);
}
public void environment_should_be_created_if_without_flags()
{
using var env = CreateEnvironment();
env.Open();
}
public void environment_created_from_config()
{
const int mapExpected = 1024*1024*20;
const int maxDatabaseExpected = 2;
const int maxReadersExpected = 3;
var config = new EnvironmentConfiguration {MapSize = mapExpected, MaxDatabases = maxDatabaseExpected, MaxReaders = maxReadersExpected};
using var env = CreateEnvironment(config: config);
env.MapSize.ShouldBe(mapExpected);
env.MaxDatabases.ShouldBe(maxDatabaseExpected);
env.MaxReaders.ShouldBe(maxReadersExpected);
}
public void starting_transaction_before_environment_open()
{
using var env = CreateEnvironment();
Should.Throw<InvalidOperationException>(() => env.BeginTransaction());
}
public void can_get_environment_info()
{
const long mapSize = 1024 * 1024 * 200;
using var env = CreateEnvironment(config: new EnvironmentConfiguration
{
MapSize = mapSize
});
env.Open();
var info = env.Info;
info.MapSize.ShouldBe(env.MapSize);
}
public void can_get_large_environment_info_only_on_64bit_platform()
{
const long mapSize = 1024 * 1024 * 1024 * 3L;
using var env = CreateEnvironment(config: new EnvironmentConfiguration
{
MapSize = mapSize
});
env.Open();
var info = env.Info;
env.MapSize.ShouldBe(info.MapSize);
}
public void max_databases_works_through_config_issue_62()
{
var config = new EnvironmentConfiguration { MaxDatabases = 2 };
using var env = CreateEnvironment(config: config);
env.Open();
using (var tx = env.BeginTransaction())
{
using var db = tx.OpenDatabase("db1", new DatabaseConfiguration {Flags = DatabaseOpenFlags.Create});
using var db2 = tx.OpenDatabase("db2", new DatabaseConfiguration {Flags = DatabaseOpenFlags.Create});
tx.Commit();
}
env.MaxDatabases.ShouldBe(2);
}
public void can_load_and_dispose_multiple_environments()
{
var env = CreateEnvironment();
env.Dispose();
using var env2 = CreateEnvironment();
}
public void environment_should_be_created_if_read_only()
{
var env = CreateEnvironment();
env.Open(); //readonly requires environment to have been created at least once before
env.Dispose();
env = CreateEnvironment(env.Path);
using(env)
env.Open(EnvironmentOpenFlags.ReadOnly);
}
public void environment_should_be_opened()
{
using var env = CreateEnvironment();
env.Open();
env.IsOpened.ShouldBeTrue();
}
public void environment_should_be_closed()
{
var env = CreateEnvironment();
env.Open();
env.Dispose();
env.IsOpened.ShouldBeFalse();
}
public void can_put_multiple_key_value_pairs_and_flush_successfully()
{
using var env = CreateEnvironment();
env.Open();
using var tx = env.BeginTransaction();
using var db = tx.OpenDatabase(new DatabaseConfiguration { Flags = DatabaseOpenFlags.Create });
for (int i = 0; i < 5; i++)
{
var key = BitConverter.GetBytes(i);
var value = BitConverter.GetBytes(i * 10);
tx.Put(db, key, value);
}
tx.Commit();
var result = env.Flush(force: true);
result.ShouldBe(MDBResultCode.Success);
}
public void environment_should_be_copied()
{
void CopyTest(bool compact)
{
using var env = CreateEnvironment();
env.Open();
var newPath = TempPath();
env.CopyTo(newPath, compact).ThrowOnError();
(Directory.GetFiles(newPath).Length == 0)
.ShouldBeFalse("Copied files doesn't exist");
}
CopyTest(true);
CopyTest(false);
}
public void environment_should_fail_copy_if_path_is_file()
{
using var env = CreateEnvironment();
env.Open();
var filePath = Path.Combine(TempPath(), "test.txt");
File.WriteAllBytes(filePath, Array.Empty<byte>());
MDBResultCode result = env.CopyTo(filePath);
result.ShouldNotBe(MDBResultCode.Success);
}
public void can_open_environment_more_than_50mb()
{
using var env = CreateEnvironment();
env.MapSize = 55 * 1024 * 1024;
env.Open();
}
public void can_open_environment_with_special_characters()
{
//all include special character now
using var env = CreateEnvironment(TempPath("ß"));
env.Open();
}
public void can_get_and_set_flags()
{
using var env = CreateEnvironment();
env.Open();
var flags = env.Flags;
env.Flags = flags;
env.Flags = EnvironmentOpenFlags.None;
env.Flags.ShouldBe(EnvironmentOpenFlags.None);
env.Flags = EnvironmentOpenFlags.NoSync;
env.Flags.ShouldBe(EnvironmentOpenFlags.NoSync);
env.Flags = EnvironmentOpenFlags.NoSync | EnvironmentOpenFlags.NoMetaSync;
env.Flags.ShouldBe(EnvironmentOpenFlags.NoSync | EnvironmentOpenFlags.NoMetaSync);
env.Flags.HasFlag(EnvironmentOpenFlags.NoSync).ShouldBeTrue();
env.Flags.HasFlag(EnvironmentOpenFlags.NoMetaSync).ShouldBeTrue();
env.Flags = flags;
env.Flags.ShouldBe(flags);
}
public void can_check_stale_readers()
{
using var env = CreateEnvironment();
env.Open();
var staleReaders = env.CheckStaleReaders();
staleReaders.ShouldBeGreaterThanOrEqualTo(0); // Should be 0 if no stale readers
}
public void should_get_version_info()
{
using var env = CreateEnvironment();
var versionInfo = env.Version;
// Verify version info properties are valid
versionInfo.ShouldNotBeNull();
versionInfo.Major.ShouldBeGreaterThanOrEqualTo(0);
versionInfo.Minor.ShouldBeGreaterThan(0);
versionInfo.Patch.ShouldBeGreaterThanOrEqualTo(0);
}
public void should_get_version_string()
{
using var env = CreateEnvironment();
var versionInfo = env.Version;
// LightningVersionInfo doesn't override ToString(), so it returns the type name
// Just check that it returns a non-empty string
var versionString = versionInfo.ToString();
versionString.ShouldNotBeNullOrEmpty();
}
public void should_get_version_description()
{
using var env = CreateEnvironment();
var versionInfo = env.Version;
var versionDesc = versionInfo.Version;
versionDesc.ShouldNotBeNullOrEmpty();
// Version description should contain the library name and version
versionDesc.ToLowerInvariant().ShouldContain("lmdb");
}
public void can_copy_to_file_stream()
{
// Setup a source environment with some data
using var sourceEnv = CreateEnvironment();
sourceEnv.Open();
// Add some data to the source environment
using (var tx = sourceEnv.BeginTransaction())
using (var db = tx.OpenDatabase(new DatabaseConfiguration { Flags = DatabaseOpenFlags.Create }))
{
for (int i = 0; i < 5; i++)
{
tx.Put(db, $"key{i}", $"value{i}");
}
tx.Commit();
}
// Create a temporary file for the copy
var tempFilePath = Path.Combine(TempPath(), "env_copy.mdb");
// Ensure directory exists
Directory.CreateDirectory(Path.GetDirectoryName(tempFilePath)!);
// Create a FileStream to the destination file
using (var fileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.ReadWrite))
{
// Copy the environment to the FileStream
var result = sourceEnv.CopyToStream(fileStream);
result.ShouldBe(MDBResultCode.Success);
}
// Verify the file exists and has content
File.Exists(tempFilePath).ShouldBeTrue("Destination file should exist");
new FileInfo(tempFilePath).Length.ShouldBeGreaterThan(0, "Destination file should have content");
}
public void can_copy_with_compaction_to_file_stream()
{
// Setup a source environment with some data
using var sourceEnv = CreateEnvironment();
sourceEnv.Open();
// Add some data to the source environment and then delete half of it to create free space
using (var tx = sourceEnv.BeginTransaction())
using (var db = tx.OpenDatabase(new DatabaseConfiguration { Flags = DatabaseOpenFlags.Create }))
{
for (int i = 0; i < 10; i++)
{
tx.Put(db, $"key{i}", $"value{i}");
}
tx.Commit();
}
// Delete some entries to create free space for compaction
using (var tx = sourceEnv.BeginTransaction())
using (var db = tx.OpenDatabase())
{
for (int i = 0; i < 5; i++)
{
tx.Delete(db, $"key{i}");
}
tx.Commit();
}
// Create a temporary file for the copy
var tempFilePath = Path.Combine(TempPath(), "env_copy_compact.mdb");
// Ensure directory exists
Directory.CreateDirectory(Path.GetDirectoryName(tempFilePath)!);
// Create a FileStream to the destination file
using (var fileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.ReadWrite))
{
// Copy the environment to the FileStream with compaction
var result = sourceEnv.CopyToStream(fileStream, compact: true);
result.ShouldBe(MDBResultCode.Success);
}
// Verify the file exists and has content
File.Exists(tempFilePath).ShouldBeTrue("Destination file should exist");
new FileInfo(tempFilePath).Length.ShouldBeGreaterThan(0, "Destination file should have content");
}
public void can_get_environment_file_stream()
{
// Skip this test on platforms where SafeFileHandle creation might not be supported
using var env = CreateEnvironment();
env.Open();
// Add some data to make sure the file has content
using (var tx = env.BeginTransaction())
using (var db = tx.OpenDatabase(new DatabaseConfiguration { Flags = DatabaseOpenFlags.Create }))
{
tx.Put(db, "testkey", "testvalue");
tx.Commit();
}
// Try to get a FileStream for the environment
using var fileStream = env.GetFileStream();
// Verify the FileStream is valid
fileStream.ShouldNotBeNull();
fileStream.CanRead.ShouldBeTrue();
// Should be able to read data from the beginning of the file
fileStream.Position = 0;
var buffer = new byte[16];
int bytesRead = fileStream.Read(buffer, 0, buffer.Length);
// We should have read some data (the exact content depends on LMDB format)
bytesRead.ShouldBeGreaterThan(0);
}
public void stream_throws_exception_for_null_argument()
{
using var env = CreateEnvironment();
env.Open();
// Null FileStream - intentionally passing null to verify exception behavior
Should.Throw<ArgumentNullException>(() => env.CopyToStream(null!));
}
public void stream_throws_exception_for_read_only_file_stream()
{
using var env = CreateEnvironment();
env.Open();
// Create a temporary file
var tempFilePath = Path.Combine(TempPath(), "temp.txt");
File.WriteAllText(tempFilePath, "test");
// Open as read-only and verify it throws the expected exception
using var readOnlyStream = new FileStream(tempFilePath, FileMode.Open, FileAccess.Read);
Should.Throw<ArgumentException>(() => env.CopyToStream(readOnlyStream));
}
public void can_get_max_key_size()
{
using var env = CreateEnvironment();
env.Open();
// Get the maximum key size
var maxKeySize = env.MaxKeySize;
// The default max key size for LMDB is typically 511 bytes for non-dupsort databases
// But we'll just verify it's a reasonable, positive value
maxKeySize.ShouldBeGreaterThan(0);
// Typical value is 511 or 511 * 4 (for larger page sizes)
// Let's verify it's at least 100 bytes, which should be true for all configurations
maxKeySize.ShouldBeGreaterThanOrEqualTo(100);
}
public void max_key_size_throws_when_environment_not_opened()
{
using var env = CreateEnvironment();
// Don't open the environment
// Attempting to get MaxKeySize should throw, as the environment must be opened
Should.Throw<InvalidOperationException>(() => { _ = env.MaxKeySize; });
}
}