internal void BatchIDGeneratorTests( BatchIDGenerator gen, TestClock clock, DateTime now, EventIDGenerator res, EventID id ) { GIVEN["a generator without a last EventID"] = () => { clock = new TestClock(); gen = BatchIDGenerator.Create(clock: clock); }; GIVEN["a preset time"] = () => clock.SetUtcNow(now = DateTime.UtcNow); WHEN["calling GetBatch"] = () => res = gen.GetBatch().Result; AND["getting the first ID"] = () => id = res.Next(); THEN["its event sequence is 1"] = () => id.Sequence.Should().Be(1); AND["its batch sequence is 1"] = () => id.BatchID.Sequence.Should().Be(1); AND["its timestamp is correct"] = () => id.BatchID.Timestamp.Should().BeCloseTo(now, precision: 10); GIVEN["a new time very close to last"] = () => clock.SetUtcNow(now.AddTicks(1)); WHEN["calling GetBatch again"] = () => id = gen.GetBatch().Result.Next(); THEN["the event sequence of first EventID is 1"] = () => id.Sequence.Should().Be(1); AND["its batch sequence is 2"] = () => id.BatchID.Sequence.Should().Be(2); GIVEN["a new time"] = () => clock.SetUtcNow(now = now.AddMilliseconds(10)); WHEN["calling GetBatch"] = () => id = gen.GetBatch().Result.Next(); THEN["the event sequence of first EventID is 1"] = () => id.Sequence.Should().Be(1); AND["its batch sequence is 1"] = () => id.BatchID.Sequence.Should().Be(1); AND["its timestamp is correct"] = () => id.BatchID.Timestamp.Should().BeCloseTo(now, precision: 10); GIVEN["a new time"] = () => clock.SetUtcNow(now = now.AddMilliseconds(10)); THEN["calling GetBatch for 511 times takes less than 10ms"] = () => { Action action = () => Enumerable.Range(1, 511).ForEach(i => res = gen.GetBatch().Result); action.ExecutionTime().Should().BeLessThan(100.Milliseconds()); }; AND["the batch sequence of the first EventID is 511 (max)"] = () => (id = res.Next()).BatchID.Sequence.Should().Be(511); Then["calling GetBatch once more", ThrowsA <EventStoreException>()] = () => gen.GetBatch(); GIVEN["a clock the advances with each call"] = () => clock.SetUtcNow(new PresetTimes(now, now.AddTicks(1), now = now.AddMilliseconds(20))); WHEN["calling GetBatch"] = () => id = gen.GetBatch().Result.Next(); AND["its batch sequence is 1"] = () => id.BatchID.Sequence.Should().Be(1); AND["its timestamp is correct"] = () => id.BatchID.Timestamp.Should().BeCloseTo(now, precision: 10); }
internal void Save( MongoFake db, MongoEventStore store, IEventStoreTransaction tx, PresetIDGenerator generator, EventBatch <Customer> s, BatchID batch ) { GIVEN["a configured store"] = () => store = CreateStore( new List <StreamConfiguration> { new StreamConfiguration(typeof(Customer), "customer"), new StreamConfiguration(typeof(OrderProcessor), "order_processor") }, db = new MongoFake(), generator = new PresetIDGenerator() ); Given["a transaction"] = async() => tx = store.UseTransaction(await db.StartTransactionAsync()); Then["saving an unregistered stream type", ThrowsA <EventStoreConfigurationException>()] = () => tx.Save(CreateStream <Order>(streamID: Guid.NewGuid())); GIVEN["a stream with some events"] = () => s = CreateStream <Customer>( streamID: Guid.NewGuid(), new Customer.Created(), new Customer.Relocated { OldAddress = "ADR 1", NewAddress = "ADR 2" } ); When["saving the stream"] = () => { batch = new BatchID(DateTime.UtcNow); generator.Enqueue(batch); return(tx.Save(s)); }; THEN["an EventID is assigned to each event"] = () => { EventIDGenerator gen = new EventIDGenerator(batch); s.Events.Select(x => x.ID).Should() .AllBeOfType <EventID>().And .ContainInOrder(gen.Next(), gen.Next()); }; AND["the events are persisted properly"] = () => db.Log.Should().BeExactly(b => b .Transaction(t => t .InsertMany("Events", s.Events.ToArray()) // TODO: Better interface on Fake... .Upsert("customer_Info", s.StreamID, new StreamInfo(s.StreamID)) ) ); List <RecordedEvent> act = default; WHEN["getting the saved stream"] = () => act = tx.Get(new StreamLocator <Customer>(s.StreamID)).Result.ToList().Result; THEN["it contains the original events"] = () => act.Should().BeEquivalentTo(s.Events); }