public void FailedWriteDoesNotOverwriteExistingValue() { using (var container = TemporaryDirectory.CreateNew()) { var sut = new AtomicFile <int>(container.File("key-path"), new StubSerialiser()); sut.Write(42); Assume.That(sut.Read(), Is.EqualTo(42)); var failing = new AtomicFile <int>(container.File("key-path"), new RandomlyFailingSerialiser <int>(new StubSerialiser(), 1)); Assume.That(() => failing.Write(23), Throws.InstanceOf <IOException>()); Assert.That(sut.Read(), Is.EqualTo(42)); } }
public void CanDeleteWrittenValue() { using (var container = TemporaryDirectory.CreateNew()) { var sut = new AtomicFile <int>(container.File("key-path"), new StubSerialiser()); sut.Write(42); sut.Delete(); Assert.That(sut.Read(), Is.EqualTo(default(int))); } }
public void CanReplaceWrittenValue() { using (var container = TemporaryDirectory.CreateNew()) { var sut = new AtomicFile <int>(container.File("key-path"), new StubSerialiser()); sut.Write(42); sut.Write(23); var value = sut.Read(); Assert.That(value, Is.EqualTo(23)); } }
public async Task FuzzConcurrentAccess() { const int threadCount = 5; const int iterationCountPerThread = 25; var writtenValues = new List <int>(); var random = new Random(); var failures = new List <Exception>(); using (var container = TemporaryDirectory.CreateNew()) { var path = container.File("key-path"); await ConcurrentOperations.Run(threadCount, () => { var sut = new AtomicFile <int>(path, new RandomlyFailingSerialiser <int>(new StubSerialiser(), 0.05)); for (var i = 0; i < iterationCountPerThread; i++) { try { var value = random.Next(100); sut.Write(value); lock (writtenValues) writtenValues.Add(value); } catch (FileLockedException) { // We expect locking conflicts to represent the bulk of failures. } catch (Exception ex) { lock (failures) failures.Add(ex); } try { sut.Read(); } catch (Exception) { } } }); var finalValue = new AtomicFile <int>(path, new StubSerialiser()).Read(); // At least one write should succeed. Assume.That(writtenValues.Count, Is.GreaterThan(1)); // Due to races it's not guaranteed that the last entry in the list is the last one successfully written. // However, this should be vanishingly unlikely because it would require that another Write call ran to // completion between `sut.Write(value);` and `lock (writtenValues)`. Assert.That(finalValue, Is.EqualTo(writtenValues.Last())); } }
public void CanAccessViaMultipleInstances() { using (var container = TemporaryDirectory.CreateNew()) { var sut1 = new AtomicFile <int>(container.File("key-path"), new StubSerialiser()); var sut2 = new AtomicFile <int>(container.File("key-path"), new StubSerialiser()); var sut3 = new AtomicFile <int>(container.File("key-path"), new StubSerialiser()); sut1.Write(42); sut2.Write(17); sut3.Write(23); var value = sut2.Read(); Assert.That(value, Is.EqualTo(23)); } }