public void TestFlush1() { var collection = new LogSourceListenerCollection(new Mock <ILogSource>().Object); var listener = new Mock <ILogSourceListener>(); var modifications = new List <LogSourceModification>(); listener.Setup(x => x.OnLogFileModified(It.IsAny <ILogSource>(), It.IsAny <LogSourceModification>())) .Callback((ILogSource file, LogSourceModification y) => modifications.Add(y)); collection.AddListener(listener.Object, TimeSpan.FromHours(1), 1000); collection.OnRead(1); modifications.Should().Equal(new object[] { LogSourceModification.Reset() }); collection.Flush(); modifications.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1) }, "Because Flush() should force calling the OnLogFileModified method"); }
public void TestTail_WriteOneLineTwoFlushes_Changes3() { var encoding = Encoding.UTF8; var fileName = GetUniqueNonExistingFileName(); var linePart1 = "The sky"; var linePart2 = " Crawlers"; using (var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read)) using (var writer = new StreamWriter(stream, encoding)) using (var logFile = Create(fileName, encoding)) { var changes = AddListener(logFile, 1000); changes.Should().Equal(new object[] { LogSourceModification.Reset() }); writer.Write(linePart1); writer.Flush(); _taskScheduler.RunOnce(); changes.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1) }, "because the file consists of one line"); writer.Write(linePart2); writer.Flush(); _taskScheduler.RunOnce(); changes.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1), LogSourceModification.Removed(0, 1), LogSourceModification.Appended(0, 1) }); } }
public void TestReadOneLine4() { _streamWriter.Write("A"); _streamWriter.Flush(); _taskScheduler.RunOnce(); _streamWriter.Write("B"); _streamWriter.Flush(); _taskScheduler.RunOnce(); _streamWriter.Write("C"); _streamWriter.Flush(); _taskScheduler.RunOnce(); _modifications.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1), LogSourceModification.Removed(0, 1), LogSourceModification.Appended(0, 1), LogSourceModification.Removed(0, 1), LogSourceModification.Appended(0, 1) }, "because the log file should've sent invalidations for the 2nd and 3rd read (because the same line was modified)"); _source.GetProperty(Properties.LogEntryCount).Should().Be(1); var entry = _source.GetEntry(0); entry.Index.Should().Be(0); entry.LogEntryIndex.Should().Be(0); entry.RawContent.Should().Be("ABC"); }
public void TestTail_WriteTwoLines_Changes1() { var encoding = Encoding.UTF8; var fileName = GetUniqueNonExistingFileName(); var line1 = "The sky crawlers"; var line2 = "is awesome!"; using (var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read)) using (var writer = new StreamWriter(stream, encoding)) using (var logFile = Create(fileName, encoding)) { var changes = AddListener(logFile, 1000); changes.Should().Equal(new object[] { LogSourceModification.Reset() }); writer.Write(line1 + "\r\n"); writer.Flush(); _taskScheduler.RunOnce(); changes.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1), LogSourceModification.Appended(1, 1) }, "because the file consists of two lines, one being totally empty"); writer.Write(line2 + "\r\n"); writer.Flush(); _taskScheduler.RunOnce(); changes.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1), LogSourceModification.Appended(1, 1), LogSourceModification.Removed(1, 1), LogSourceModification.Appended(1, 2) }); } }
public void TestTail_WriteTwoLines_Changes2() { var encoding = Encoding.UTF8; var fileName = GetUniqueNonExistingFileName(); var line1 = "The sky crawlers"; var line2 = "is awesome!"; using (var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read)) using (var writer = new StreamWriter(stream, encoding)) using (var logFile = Create(fileName, encoding)) { var changes = AddListener(logFile, 1000); changes.Should().Equal(new object[] { LogSourceModification.Reset() }); writer.Write(line1); writer.Flush(); _taskScheduler.RunOnce(); changes.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1) }, "because the file consists of one line"); writer.Write("\n" + line2); writer.Flush(); _taskScheduler.RunOnce(); //changes.Should().Equal(new object[] {LogSourceModification.Reset(), new LogFileSection(0, 1), new LogFileSection(1, 1)}); // The current behavior won't cause wrong behavior in upstream listeners, but it will cause them unnecessary work. changes.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1), LogSourceModification.Removed(0, 1), LogSourceModification.Appended(0, 2) }); } }
public void TestInvokeListenerEventually() { var line = "Hello, World!"; var fileName = GetUniqueNonExistingFileName(); using (var stream = File.OpenWrite(fileName)) using (var writer = new StreamWriter(stream)) { writer.Write(line); } var logFile = Create(fileName, new UTF8Encoding(true)); var listener = new Mock <ILogSourceListener>(); var modifications = new List <LogSourceModification>(); listener.Setup(x => x.OnLogFileModified(logFile, It.IsAny <LogSourceModification>())) .Callback((ILogSource _, LogSourceModification modification) => { modifications.Add(modification); }); var maxWaitTime = TimeSpan.FromMilliseconds(500); logFile.AddListener(listener.Object, maxWaitTime, 500); modifications.Should().Equal(new object[] { LogSourceModification.Reset() }); _taskScheduler.RunOnce(); logFile.GetProperty(Properties.LogEntryCount).Should().Be(1, "because there's one log entry in the file"); modifications.Should().Equal(new object[] { LogSourceModification.Reset() }, "because not enough time has elapsed and thus the log source may not have notified the listener just yet"); Thread.Sleep(maxWaitTime); _taskScheduler.RunOnce(); logFile.GetProperty(Properties.LogEntryCount).Should().Be(1, "because there's still one log entry in the file"); modifications.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1) }, "because enough time has passed for the log file to notify us at this point in time"); }
public void AddListener(ILogSourceListener listener, TimeSpan maximumWaitTime, int maximumLineCount) { if (_listeners.Add(listener)) { listener.OnLogFileModified(this, LogSourceModification.Reset()); } }
public void TestFilter2() { using (var file = Create(File20Mb)) { file.Property(x => x.GetProperty(Properties.LogEntryCount)).ShouldAfter(TimeSpan.FromSeconds(10)).Be(165342); using (FilteredLogSource filtered = file.AsFiltered(_taskScheduler, null, Filter.Create("info"))) { var listener = new Mock <ILogSourceListener>(); var modifications = new List <LogSourceModification>(); listener.Setup(x => x.OnLogFileModified(It.IsAny <ILogSource>(), It.IsAny <LogSourceModification>())) .Callback((ILogSource logFile, LogSourceModification modification) => modifications.Add(modification)); filtered.Property(x => x.GetProperty(Properties.LogEntryCount)).ShouldAfter(TimeSpan.FromSeconds(5)).Be(5); filtered.AddListener(listener.Object, TimeSpan.Zero, 1); modifications.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1), LogSourceModification.Appended(1, 1), LogSourceModification.Appended(2, 1), LogSourceModification.Appended(3, 1), LogSourceModification.Appended(4, 1) }); } } }
public void TestClear() { var collection = new LogSourceListenerCollection(new Mock <ILogSource>().Object); var listener = new Mock <ILogSourceListener>(); var modifications = new List <LogSourceModification>(); listener.Setup(x => x.OnLogFileModified(It.IsAny <ILogSource>(), It.IsAny <LogSourceModification>())) .Callback((ILogSource file, LogSourceModification y) => modifications.Add(y)); collection.AddListener(listener.Object, TimeSpan.FromHours(1), 1000); collection.OnRead(1); collection.Flush(); modifications.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1), }); collection.Clear(); modifications.Clear(); collection.OnRead(2); collection.Flush(); modifications.Should() .BeEmpty("because the collection should have removed all listeners and thus we may not have been notified anymore"); }
public void TestMergeResetOneSource() { var source1 = new InMemoryLogSource(); var source2 = new InMemoryLogSource(); var merged = new MergedLogSource(_taskScheduler, TimeSpan.Zero, source1, source2); var entries = Listen(merged); var changes = ListenToChanges(merged, 100); source2.AddEntry("a", LevelFlags.Warning, new DateTime(2021, 2, 28, 22, 15, 0)); source1.AddEntry("b", LevelFlags.Info, new DateTime(2021, 2, 28, 22, 16, 0)); source2.AddEntry("c", LevelFlags.Error, new DateTime(2021, 2, 28, 22, 17, 0)); _taskScheduler.RunOnce(); merged.GetProperty(Core.Properties.PercentageProcessed).Should().Be(Percentage.HundredPercent); entries.Count.Should().Be(3); changes.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 3) }); source1.Clear(); _taskScheduler.RunOnce(); entries.Count.Should().Be(2, "because the one entry from source should have been removed from the merged source"); changes.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 3), LogSourceModification.Removed(1, 2), LogSourceModification.Appended(1, 1) }); }
public void TestOneSourceAppendReset() { var source1 = new InMemoryLogSource(); source1.AddEntry("A", LevelFlags.Other, new DateTime(2019, 5, 28, 00, 34, 0)); var index = new MergedLogSourceIndex(source1); var changes = index.Process(new MergedLogSourcePendingModification(source1, LogSourceModification.Appended(0, 1))); changes.Should().Equal(new object[] { LogSourceModification.Appended(0, 1) }); changes = index.Process(new MergedLogSourcePendingModification(source1, LogSourceModification.Reset())); changes.Should().Equal(new object[] { LogSourceModification.Reset() }); index.Count.Should().Be(0); index.Get(new LogSourceSection(0, 1)).Should().Equal(new object[] { MergedLogLineIndex.Invalid }); }
public void TestEquality() { var appendModification = LogSourceModification.Appended(10, 41); var equalAppendModification = LogSourceModification.Appended(10, 41); var anotherAppendModification = LogSourceModification.Appended(9, 41); appendModification.Should().Be(equalAppendModification); equalAppendModification.Should().Be(appendModification); appendModification.Should().NotBe(anotherAppendModification); anotherAppendModification.Should().NotBe(equalAppendModification); var removedModification = LogSourceModification.Removed(10, 41); appendModification.Should().NotBe(removedModification); equalAppendModification.Should().NotBe(removedModification); anotherAppendModification.Should().NotBe(removedModification); var anotherRemovedModification = LogSourceModification.Removed(9, 41); removedModification.Should().NotBe(anotherRemovedModification); anotherRemovedModification.Should().NotBe(anotherAppendModification); appendModification.Should().NotBe(LogSourceModification.Reset()); appendModification.Should().NotBe(LogSourceModification.PropertiesChanged()); removedModification.Should().NotBe(LogSourceModification.Reset()); removedModification.Should().NotBe(LogSourceModification.PropertiesChanged()); }
public void TestClear2() { const string fname = "TestClear2.log"; using (FileStream stream = File.OpenWrite(fname)) using (var writer = new StreamWriter(stream)) { stream.SetLength(0); writer.WriteLine("Test"); } using (var logFile = Create(fname)) { var listener = new Mock <ILogSourceListener>(); var modifications = new List <LogSourceModification>(); listener.Setup(x => x.OnLogFileModified(It.IsAny <ILogSource>(), It.IsAny <LogSourceModification>())) .Callback((ILogSource log, LogSourceModification modification) => modifications.Add(modification)); logFile.AddListener(listener.Object, TimeSpan.Zero, 2); logFile.Property(x => x.GetProperty(Properties.LogEntryCount)).ShouldAfter(TimeSpan.FromSeconds(5)).Be(1); using (var stream = new FileStream(fname, FileMode.Open, FileAccess.Write, FileShare.ReadWrite)) { stream.SetLength(0); logFile.Property(x => x.GetProperty(Properties.LogEntryCount)).ShouldAfter(TimeSpan.FromSeconds(5)).Be(0); modifications.Should().EndWith(LogSourceModification.Reset()); } } }
public void TestAddListener1() { var logFile = new InMemoryLogSource(); logFile.AddListener(_listener.Object, TimeSpan.Zero, 1); _modifications.Should().Equal(new object[] { LogSourceModification.Reset() }); }
public void TestAddListener() { var logFile = new EmptyLogSource(); var listener = new Mock <ILogSourceListener>(); logFile.AddListener(listener.Object, TimeSpan.Zero, 0); listener.Verify(x => x.OnLogFileModified(logFile, LogSourceModification.Reset()), Times.Once); }
public void TestSplitReset([Values(1, 99, 100)] int maxCount) { var section = LogSourceModification.Reset(); section.Split(maxCount).Should().Equal(new[] { section }, "because resets are NEVER split up"); }
public void TestCurrentLineChanged6() { var notifier = new LogSourceListenerNotifier(_logFile.Object, _listener.Object, TimeSpan.FromHours(1), 1000); notifier.OnRead(-1); _modifications.Should().Equal(new[] { LogSourceModification.Reset() }); }
public LogSourceListenerNotifier(ILogSource logSource, ILogSourceListener listener, TimeSpan maximumTime, int maximumCount) { _logSource = logSource ?? throw new ArgumentNullException(nameof(logSource)); _listener = listener ?? throw new ArgumentNullException(nameof(listener)); _maximumTime = maximumTime; _maximumCount = maximumCount; Reset(); _listener.OnLogFileModified(logSource, LogSourceModification.Reset()); }
public void TestClear4() { var logFile = new InMemoryLogSource(); logFile.AddEntry("Hi", LevelFlags.Info); logFile.GetProperty(TextProperties.MaxCharactersInLine).Should().Be(2); logFile.AddListener(_listener.Object, TimeSpan.Zero, 1); logFile.Clear(); _modifications.Should().EndWith(LogSourceModification.Reset()); }
public void TestInvalidate5() { var notifier = new LogSourceListenerNotifier(_logFile.Object, _listener.Object, TimeSpan.FromMilliseconds(100), 100); notifier.OnRead(1); notifier.OnRead(-1); _modifications.Should().Equal(new[] { LogSourceModification.Reset() }); notifier.OnRead(-1); _modifications.Should().Equal(new[] { LogSourceModification.Reset() }); notifier.OnRead(-1); _modifications.Should().Equal(new[] { LogSourceModification.Reset() }); }
public void TestAddListener2() { var logFile = new InMemoryLogSource(); logFile.AddEntry("Foo", LevelFlags.Other); logFile.AddListener(_listener.Object, TimeSpan.Zero, 1); _modifications.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1) }); }
public void TestListen4() { using (var proxy = new LogSourceProxy(_taskScheduler, TimeSpan.Zero, _logFile.Object)) { proxy.AddListener(_listener.Object, TimeSpan.Zero, 1000); new Action(() => proxy.OnLogFileModified(new Mock <ILogSource>().Object, LogSourceModification.Appended(0, 1))).Should().NotThrow(); _modifications.Should().Equal(new[] { LogSourceModification.Reset() }, "because the OnLogFileModified shouldn't have been forwarded since it's from the wrong source"); new Action(() => proxy.OnLogFileModified(null, LogSourceModification.Appended(0, 1))).Should().NotThrow(); _modifications.Should().Equal(new[] { LogSourceModification.Reset() }, "because the OnLogFileModified shouldn't have been forwarded since it's from the wrong source"); } }
public void TestRead2LogEntries() { using (var file = Create(File2Entries)) { var listener = new Mock <ILogSourceListener>(); var modifications = new List <LogSourceModification>(); listener.Setup(x => x.OnLogFileModified(It.IsAny <ILogSource>(), It.IsAny <LogSourceModification>())) .Callback((ILogSource logFile, LogSourceModification modification) => modifications.Add(modification)); file.AddListener(listener.Object, TimeSpan.Zero, 1); modifications.Property(x => x.Count).ShouldAfter(TimeSpan.FromSeconds(5)).Be(7); modifications.Should().Equal(new[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1), LogSourceModification.Appended(1, 1), LogSourceModification.Appended(2, 1), LogSourceModification.Appended(3, 1), LogSourceModification.Appended(4, 1), LogSourceModification.Appended(5, 1) }); var entries = file.GetEntries(new LogSourceSection(0, 6)); entries[0].Index.Should().Be(0); entries[0].LogEntryIndex.Should().Be(0); entries[0].RawContent.Should().Be("2015-10-07 19:50:58,982 [8092, 1] INFO SharpRemote.Hosting.OutOfProcessSiloServer (null) - Silo Server starting, args (1): \"14056\", without custom type resolver"); entries[1].Index.Should().Be(1); entries[1].LogEntryIndex.Should().Be(1); entries[1].RawContent.Should().Be("Foobar"); entries[2].Index.Should().Be(2); entries[2].LogEntryIndex.Should().Be(2); entries[2].RawContent.Should().Be("Some more info"); entries[3].Index.Should().Be(3); entries[3].LogEntryIndex.Should().Be(3); entries[3].RawContent.Should().Be("2015-10-07 19:50:58,998 [8092, 1] DEBUG SharpRemote.Hosting.OutOfProcessSiloServer (null) - Args.Length: 1"); entries[4].Index.Should().Be(4); entries[4].LogEntryIndex.Should().Be(4); entries[4].RawContent.Should().Be("Hey look at me"); entries[5].Index.Should().Be(5); entries[5].LogEntryIndex.Should().Be(5); entries[5].RawContent.Should().Be("dwadawdadw"); } }
public void TestOptimizeOneSourceAppendReset() { var source = new Mock <ILogSource>(); var input = new[] { new MergedLogSourcePendingModification(source.Object, LogSourceModification.Appended(1, 2)), new MergedLogSourcePendingModification(source.Object, LogSourceModification.Reset()) }; MergedLogSourcePendingModification.Optimize(input).Should().Equal(new object[] { new MergedLogSourcePendingModification(source.Object, LogSourceModification.Reset()) }); }
public void TestInvalidate1() { var notifier = new LogSourceListenerNotifier(_logFile.Object, _listener.Object, TimeSpan.Zero, 1); notifier.OnRead(1); notifier.Remove(0, 1); _modifications.Should().Equal(new[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1), LogSourceModification.Removed(0, 1) }); notifier.LastNumberOfLines.Should().Be(0); }
public void TestTail_WriteLinesClearWriteLines() { var encoding = new UTF8Encoding(false); var fileName = GetUniqueNonExistingFileName(); using (var logFile = Create(fileName, encoding)) { var line1 = "The sky"; var line2 = "Crawlers"; using (var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read)) using (var writer = new StreamWriter(stream, encoding)) { var changes = AddListener(logFile, 1000); changes.Should().Equal(new object[] { LogSourceModification.Reset() }); writer.WriteLine(line1); writer.Flush(); _taskScheduler.RunOnce(); logFile.GetProperty(Properties.LogEntryCount).Should().Be(2); var index = logFile.GetColumn(new LogSourceSection(0, 2), StreamingTextLogSource.LineOffsetInBytes); index[0].Should().Be(0); index[1].Should().Be(9); writer.WriteLine(line2); writer.Flush(); _taskScheduler.RunOnce(); logFile.GetProperty(Properties.LogEntryCount).Should().Be(3); index = logFile.GetColumn(new LogSourceSection(0, 3), StreamingTextLogSource.LineOffsetInBytes); index[0].Should().Be(0); index[1].Should().Be(9); index[2].Should().Be(19); } using (var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read)) using (var writer = new StreamWriter(stream, encoding)) { writer.WriteLine("A"); writer.WriteLine("B"); writer.Flush(); _taskScheduler.RunOnce(); logFile.GetProperty(Properties.LogEntryCount).Should().Be(3); var index = logFile.GetColumn(new LogSourceSection(0, 3), StreamingTextLogSource.LineOffsetInBytes); index[0].Should().Be(0); index[1].Should().Be(3); index[2].Should().Be(6); } } }
public void TestListen1() { using (var proxy = new LogSourceProxy(_taskScheduler, TimeSpan.Zero, _logFile.Object)) { proxy.AddListener(_listener.Object, TimeSpan.FromSeconds(1), 1000); proxy.OnLogFileModified(_logFile.Object, LogSourceModification.Appended(0, 1)); _modifications.Property(x => x.Count).ShouldEventually().Be(2); _modifications.Should().Equal(new[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 1) }); } }
public void TestReset() { var modification = LogSourceModification.Reset(); modification.IsReset().Should().BeTrue(); modification.ToString().Should().Be("Reset"); modification.IsRemoved(out var removedSection).Should().BeFalse(); removedSection.Should().Equal(new LogSourceSection()); modification.IsAppended(out var appendedSection).Should().BeFalse(); appendedSection.Should().Equal(new LogSourceSection()); modification.IsPropertiesChanged().Should().BeFalse(); }
public void TestAddMultilineEntry4() { var logFile = new InMemoryLogSource(); logFile.AddListener(_listener.Object, TimeSpan.Zero, 2); var t1 = new DateTime(2017, 11, 26, 11, 56, 0); logFile.AddMultilineEntry(LevelFlags.Info, t1, "foo", "bar"); _modifications.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, 2) }); }
public void TestManySources2() { const int sourceCount = 100; var sources = new InMemoryLogSource[sourceCount]; for (int i = 0; i < sourceCount; ++i) { sources[i] = new InMemoryLogSource(); } var merged = new MergedLogSource(_taskScheduler, TimeSpan.Zero, sources); var end = new DateTime(2017, 11, 26, 17, 56, 0); for (int i = 0; i < sourceCount; ++i) { // Sources are modified in reverse order: This is the worst case. // Reality is somewhere in between... sources[i].AddEntry(i.ToString(), LevelFlags.Info, end - TimeSpan.FromSeconds(i)); } var changes = ListenToChanges(merged, sourceCount); _taskScheduler.RunOnce(); // For once, we expect the content of the merged data source to be as expected... merged.GetProperty(Core.Properties.LogEntryCount).Should().Be(sourceCount, "because every source added one line"); var entries = merged.GetEntries(new LogSourceSection(0, sourceCount)); for (int i = 0; i < sourceCount; ++i) { var entry = entries[i]; entry.Index.Should().Be(i); entry.LogEntryIndex.Should().Be(i); int idx = sourceCount - i - 1; entry.SourceId.Should().Be(new LogEntrySourceId((byte)idx)); entry.RawContent.Should().Be(idx.ToString()); entry.LogLevel.Should().Be(LevelFlags.Info); entry.Timestamp.Should().Be(end - TimeSpan.FromSeconds(idx)); } // But then it should also have fired as few changes as possible! changes.Should().Equal(new object[] { LogSourceModification.Reset(), LogSourceModification.Appended(0, sourceCount) }); }