/// <summary> /// Creates a new log file for reading and writing and populates it with the specified message set. /// Throws an exception, if the file exists already. /// </summary> /// <param name="path">Log file to open/create.</param> /// <param name="purpose"> /// Purpose of the log file determining whether the log file is primarily used for recording or for analysis /// (does not have any effect, if the log file exists already). /// </param> /// <param name="writeMode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <exception cref="LogFileException">Opening the log file failed (see message and inner exception for details).</exception> private LogFile( string path, LogFilePurpose purpose, LogFileWriteMode writeMode) : this(path, true, false, purpose, writeMode, false, null, null) { mMessageCollection = new FileBackedLogMessageCollection(this); }
/// <summary> /// Creates a <see cref="FileBackedLogMessageCollection"/> backed by the specified log file. /// The log file is created, if it does not exist, yet. /// </summary> /// <param name="path">Path of the log file to open/create.</param> /// <param name="purpose"> /// Purpose of the log file determining whether the log file is primarily used for recording or for analysis /// (does not have any effect, if the log file exists already). /// </param> /// <param name="mode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <exception cref="LogFileException">Opening the log file failed (see message and inner exception for details).</exception> public static FileBackedLogMessageCollection OpenOrCreate( string path, LogFilePurpose purpose, LogFileWriteMode mode) { return(LogFile.OpenOrCreate(path, purpose, mode).Messages); }
/// <summary> /// Opens an existing log file in read/write mode, creates a new log file, if the file does not exist, yet. /// </summary> /// <param name="path">Log file to open/create.</param> /// <param name="purpose"> /// Purpose of the log file determining whether the log file is primarily used for recording or for analysis /// (does not have any effect, if the log file exists already). /// </param> /// <param name="writeMode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <exception cref="LogFileException">Opening the log file failed (see message and inner exception for details).</exception> public static LogFile OpenOrCreate( string path, LogFilePurpose purpose, LogFileWriteMode writeMode) { return(new LogFile(path, purpose, writeMode)); }
private void OpenReadOnly(LogFilePurpose purpose, LogFileWriteMode writeMode) { string path = purpose == LogFilePurpose.Recording ? Fixture.GetCopyOfFile_Recording_RandomMessages_10K() : Fixture.GetCopyOfFile_Analysis_RandomMessages_10K(); try { Assert.True(File.Exists(path)); using (var collection = FileBackedLogMessageCollection.OpenReadOnly(path)) { Assert.True(File.Exists(path)); Assert.Equal(path, collection.FilePath); TestCollectionPropertyDefaults(collection, 10000, true); } // the file should persist after disposing the collection Assert.True(File.Exists(path)); } finally { // remove temporary log file to avoid polluting the output directory File.Delete(path); } }
private void OpenOrCreate_NewFile(LogFilePurpose purpose, LogFileWriteMode writeMode) { string backingFilePath = Path.Combine(Environment.CurrentDirectory, "FileBackedLogMessageCollectionBuffer.gplog"); // delete the file to work with to ensure that the collection creates a new one File.Delete(backingFilePath); Assert.False(File.Exists(backingFilePath)); try { using (var collection = FileBackedLogMessageCollection.OpenOrCreate(backingFilePath, purpose, writeMode)) { Assert.True(File.Exists(backingFilePath)); Assert.Equal(backingFilePath, collection.FilePath); TestCollectionPropertyDefaults(collection, 0, false); } // the file should persist after disposing the collection Assert.True(File.Exists(backingFilePath)); } finally { File.Delete(backingFilePath); } }
/// <summary> /// Creates a <see cref="FileBackedLogMessageCollection"/> backed by the specified log file and populates it with the specified messages. /// The log file must not exist, yet. /// </summary> /// <param name="path">Path of the log file to create.</param> /// <param name="purpose">Purpose of the log file determining whether the log file is primarily used for recording or for analysis.</param> /// <param name="mode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <param name="messages">Messages to populate the log file with (may be null).</param> /// <exception cref="LogFileException">Creating the log file failed (see message and inner exception for details).</exception> public static FileBackedLogMessageCollection Create( string path, LogFilePurpose purpose, LogFileWriteMode mode, IEnumerable <ILogMessage> messages = null) { return(LogFile.Create(path, purpose, mode, messages).Messages); }
/// <summary> /// Creates a new log file. /// </summary> /// <param name="path">Log file to create.</param> /// <param name="purpose">Purpose of the log file determining whether the log file is primarily used for recording or for analysis.</param> /// <param name="writeMode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <param name="messages">Messages to populate the log file with.</param> /// <exception cref="LogFileException">Opening the log file failed (see message and inner exception for details).</exception> private LogFile( string path, LogFilePurpose purpose, LogFileWriteMode writeMode, IEnumerable <ILogMessage> messages) : this(path, true, true, purpose, writeMode, false, null, messages) { mMessageCollection = new FileBackedLogMessageCollection(this); }
/// <summary> /// Creates a new log file and populates it with the specified log messages. /// </summary> /// <param name="path">Log file to create.</param> /// <param name="purpose">Purpose of the log file determining whether the log file is primarily used for recording or for analysis.</param> /// <param name="writeMode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <param name="messages">Messages to populate the new log file with (may be null).</param> /// <exception cref="LogFileException">Creating the log file failed (see message and inner exception for details).</exception> public static LogFile Create( string path, LogFilePurpose purpose, LogFileWriteMode writeMode, IEnumerable <ILogMessage> messages = null) { return(new LogFile(path, purpose, writeMode, messages)); }
/// <summary> /// Initializes an instance of the <see cref="FileBackedLogMessageCollectionTests_Base"/> class. /// </summary> /// <param name="fixture">Fixture providing static test data.</param> /// <param name="useReadOnlyCollection">Indicates whether the collection used for the test is read-only or not.</param> /// <param name="purpose">The log file purpose to test.</param> /// <param name="writeMode">The log file write mode to test.</param> protected SelectableFileBackedLogMessageFilterTests_Base( LogFileTestsFixture fixture, bool useReadOnlyCollection, LogFilePurpose purpose, LogFileWriteMode writeMode) { Fixture = fixture; LogFilePurposeToTest = purpose; LogFileWriteModeToTest = writeMode; CollectionIsReadOnly = useReadOnlyCollection; }
/// <summary> /// Creates a new instance of the <see cref="FileBackedLogMessageCollection"/> with a file in the temporary directory /// optionally marking the file for auto-deletion. /// </summary> /// <param name="deleteAutomatically"> /// true to delete the file automatically when the collection is disposed (or the next time, a temporary collection is created in the same directory); /// false to keep it after the collection is disposed. /// </param> /// <param name="temporaryDirectoryPath"> /// Path of the temporary directory to use; /// null to use the default temporary directory (default). /// </param> /// <param name="purpose"> /// Purpose of the log file determining whether the log file is primarily used for recording or for analysis (default). /// </param> /// <param name="mode"> /// Write mode determining whether to open the log file in 'robust' or 'fast' mode (default). /// </param> /// <param name="messages">Messages to populate the temporary collection with (may be null).</param> /// <returns>The created collection.</returns> public static FileBackedLogMessageCollection CreateTemporaryCollection( bool deleteAutomatically, string temporaryDirectoryPath = null, LogFilePurpose purpose = LogFilePurpose.Analysis, LogFileWriteMode mode = LogFileWriteMode.Fast, IEnumerable <ILogMessage> messages = null) { string path = TemporaryFileManager.GetTemporaryFileName(deleteAutomatically, temporaryDirectoryPath); var file = LogFile.Create(path, purpose, mode, messages); file.Messages.AutoDelete = deleteAutomatically; return(file.Messages); }
private void Create_ExistingFile(LogFilePurpose purpose, LogFileWriteMode writeMode, bool populate) { string backingFilePath = purpose == LogFilePurpose.Recording ? Fixture.GetCopyOfFile_Recording_RandomMessages_10K() : Fixture.GetCopyOfFile_Analysis_RandomMessages_10K(); var messages = populate ? Fixture.GetLogMessages_Random_10K() : null; try { Assert.Throws <LogFileException>(() => FileBackedLogMessageCollection.Create(backingFilePath, purpose, writeMode, messages)); } finally { // remove temporary log file to avoid polluting the output directory File.Delete(backingFilePath); } }
/// <summary> /// Creates a new instance of the collection class to test, pre-populated with the specified number of random log messages. /// The collection should be disposed at the end to avoid generating orphaned log files. /// </summary> /// <param name="count">Number of random log messages the collection should contain.</param> /// <param name="purpose">Purpose of the log file backing the collection.</param> /// <param name="writeMode">Write mode of the log file backing the collection.</param> /// <param name="isReadOnly"><c>true</c> to create a read-only log file; otherwise <c>false</c>.</param> /// <param name="messages">Receives messages that have been put into the collection.</param> /// <returns>A new instance of the collection class to test.</returns> private static FileBackedLogMessageCollection CreateCollection( int count, LogFilePurpose purpose, LogFileWriteMode writeMode, bool isReadOnly, out LogMessage[] messages) { string path = Guid.NewGuid().ToString("D") + ".gplog"; // create a collection backed by a new file using (var file1 = LogFile.OpenOrCreate(path, purpose, writeMode)) { // generate the required number of log message and add them to the collection var fileLogMessages = LoggingTestHelpers.GetTestMessages <LogFileMessage>(count); for (long i = 0; i < fileLogMessages.Length; i++) { fileLogMessages[i].Id = i; } messages = fileLogMessages.Cast <LogMessage>().ToArray(); if (count > 0) { file1.Write(messages); } } // open the created log file again as expected for the test var file2 = isReadOnly ? LogFile.OpenReadOnly(path) : LogFile.Open(path, writeMode); // let the collection delete the log file on its disposal file2.Messages.AutoDelete = true; // the collection should now contain the messages written into it // (the file-backed collection assigns message ids on its own, but they should be the same as the ids assigned to the test set) Assert.Equal(messages, file2.Messages.ToArray()); // the test assumes that the collection uses single-item notifications file2.Messages.UseMultiItemNotifications = false; return(file2.Messages); }
private void CreateTemporaryCollection( string temporaryDirectoryPath, bool deleteAutomatically, LogFilePurpose purpose, LogFileWriteMode mode) { string effectiveTemporaryFolderPath = temporaryDirectoryPath ?? Path.GetTempPath().TrimEnd(Path.DirectorySeparatorChar); string backingFilePath; using (var collection = FileBackedLogMessageCollection.CreateTemporaryCollection(deleteAutomatically, temporaryDirectoryPath, purpose, mode)) { Assert.True(File.Exists(collection.FilePath)); Assert.Equal(effectiveTemporaryFolderPath, Path.GetDirectoryName(collection.FilePath)); TestCollectionPropertyDefaults(collection, 0, false); backingFilePath = collection.FilePath; } // the file should not persist after disposing the collection, if auto-deletion is enabled Assert.Equal(deleteAutomatically, !File.Exists(backingFilePath)); }
private void Create_NewFile(LogFilePurpose purpose, LogFileWriteMode writeMode, bool populate) { string backingFilePath = Path.Combine(Environment.CurrentDirectory, "FileBackedLogMessageCollectionBuffer.gplog"); // delete the file to work with to ensure that the collection creates a new one File.Delete(backingFilePath); Assert.False(File.Exists(backingFilePath)); try { var messages = populate ? Fixture.GetLogMessages_Random_10K() : null; using (var collection = FileBackedLogMessageCollection.Create(backingFilePath, purpose, writeMode, messages)) { Assert.True(File.Exists(backingFilePath)); Assert.Equal(backingFilePath, collection.FilePath); TestCollectionPropertyDefaults(collection, populate ? messages.Length : 0, false); if (populate) { Assert.Equal(messages, collection); Assert.Equal(messages, collection.LogFile.Read(0, messages.Length + 1)); } else { Assert.Empty(collection); Assert.Equal(0, collection.LogFile.MessageCount); } } // the file should persist after disposing the collection Assert.True(File.Exists(backingFilePath)); } finally { File.Delete(backingFilePath); } }
private void CreateTemporaryCollection( string temporaryDirectoryPath, bool deleteAutomatically, LogFilePurpose purpose, LogFileWriteMode mode, bool populate) { string effectiveTemporaryFolderPath = temporaryDirectoryPath ?? Path.GetTempPath().TrimEnd(Path.DirectorySeparatorChar); string backingFilePath; var messages = populate ? mFixture.GetLogMessages_Random_10K() : null; using (var collection = FileBackedLogMessageCollection.CreateTemporaryCollection(deleteAutomatically, temporaryDirectoryPath, purpose, mode, messages)) { Assert.True(File.Exists(collection.FilePath)); Assert.Equal(effectiveTemporaryFolderPath, Path.GetDirectoryName(collection.FilePath)); using (var eventWatcher = collection.AttachEventWatcher()) { // check collection specific properties // --------------------------------------------------------------------------------------------------------------- Assert.Equal(20, collection.MaxCachePageCount); Assert.Equal(100, collection.CachePageCapacity); if (messages != null) { Assert.Equal(messages.Length, collection.Count); Assert.Equal(messages, collection); } else { Assert.Equal(0, collection.Count); Assert.Empty(collection); } // check log file specific properties // --------------------------------------------------------------------------------------------------------------- Assert.NotNull(collection.LogFile); Assert.NotNull(collection.FilePath); Assert.Equal(collection.LogFile.FilePath, collection.FilePath); // check properties exposed by IList implementation // --------------------------------------------------------------------------------------------------------------- { var list = (IList)collection; Assert.False(list.IsReadOnly); Assert.False(list.IsFixedSize); Assert.False(list.IsSynchronized); Assert.NotSame(collection, list.SyncRoot); // sync root must not be the same as the collection to avoid deadlocks if (messages != null) { Assert.Equal(messages.Length, list.Count); Assert.Equal(messages, list); } else { Assert.Equal(0, list.Count); Assert.Empty(collection); } } // check properties exposed by IList<T> implementation // --------------------------------------------------------------------------------------------------------------- { var list = (IList <LogMessage>)collection; Assert.False(list.IsReadOnly); if (messages != null) { Assert.Equal(messages.Length, list.Count); Assert.Equal(messages, list.Cast <LogFileMessage>()); } else { Assert.Equal(0, list.Count); Assert.Empty(collection); } } // no events should have been raised eventWatcher.CheckInvocations(); } backingFilePath = collection.FilePath; } // the file should not persist after disposing the collection, if auto-deletion is enabled Assert.Equal(deleteAutomatically, !File.Exists(backingFilePath)); // delete the file, if it still exists to avoid polluting the output directory File.Delete(backingFilePath); }
/// <summary> /// Constructor providing functionality common to other constructors (for internal use only). /// </summary> /// <param name="path">Log file to open/create.</param> /// <param name="createIfNotExist"> /// true to create the specified log file, if it does not exist, yet; /// false to throw an exception, if the file does not exist. /// </param> /// <param name="fileMustNotExist"> /// <c>true</c> if the specified file must not exist; otherwise <c>false</c>. /// </param> /// <param name="purpose">Purpose of the log file determining whether the log file is primarily used for recording or for analysis.</param> /// <param name="writeMode">Write mode determining whether to open the log file in 'robust' or 'fast' mode.</param> /// <param name="isReadOnly"> /// true to open the log file in read-only mode; /// false to open the log file in read/write mode. /// </param> /// <param name="collection">Collection that works upon the log file.</param> /// <param name="messages">Messages to put into the log file (should only be used for new files).</param> /// <exception cref="FileNotFoundException"><paramref name="createIfNotExist"/> is <c>false</c> and the specified file does not exist.</exception> /// <exception cref="LogFileException">Opening/Creating the log file failed.</exception> internal LogFile( string path, bool createIfNotExist, bool fileMustNotExist, LogFilePurpose purpose, LogFileWriteMode writeMode, bool isReadOnly, FileBackedLogMessageCollection collection, IEnumerable <ILogMessage> messages) { if (path == null) { throw new ArgumentNullException(nameof(path)); } // initialize information about the operating mode mFilePath = Path.GetFullPath(path); mMessageCollection = collection; // check whether the log file exists already bool fileExists = File.Exists(mFilePath); // abort, if the file does not exist and creating a new file is not allowed if (!fileExists && !createIfNotExist) { throw new FileNotFoundException($"Log file ({path}) does not exist."); } // abort, if the file exists, but the caller expects it does not if (fileExists && fileMustNotExist) { throw new LogFileException("Log file ({path}) exists already, but it should not."); } // abort, if the file exists, but an initial message set is specified (internal error) if (fileExists && messages != null) { throw new InvalidOperationException("Log file ({path}) exists already, but it should not as an initial message set is specified."); } SQLiteConnection connection = null; try { // open database file (creates a new one, if it does not exist) connection = new SQLiteConnection($"Data Source={mFilePath};Version=3;Read Only={isReadOnly}"); connection.Open(); // open/create the database if (fileExists) { // check application id ulong applicationId = DatabaseAccessor.GetApplicationId(connection); if (applicationId != DatabaseAccessor.LogFileApplicationId) { throw new InvalidLogFileFormatException($"Application id in the sqlite database is 0x{applicationId:08x}, expecting not 0x{DatabaseAccessor.LogFileApplicationId:08x}"); } // check user version // (indicates its purpose, directly corresponds to the database schema) ulong userVersion = DatabaseAccessor.GetSchemaVersion(connection); switch (userVersion) { case 1: mDatabaseAccessor = new RecordingDatabaseAccessor(connection, writeMode, isReadOnly, false); break; case 2: mDatabaseAccessor = new AnalysisDatabaseAccessor(connection, writeMode, isReadOnly, false); break; default: throw new FileVersionNotSupportedException(); } } else { switch (purpose) { case LogFilePurpose.Recording: mDatabaseAccessor = new RecordingDatabaseAccessor(connection, writeMode, isReadOnly, true, messages); break; case LogFilePurpose.Analysis: mDatabaseAccessor = new AnalysisDatabaseAccessor(connection, writeMode, isReadOnly, true, messages); break; default: throw new NotSupportedException($"The specified purpose ({purpose}) is not supported."); } } } catch (SQLiteException ex) { Dispose(); connection?.Dispose(); throw new LogFileException( $"Opening/Creating the log file failed: {ex.Message}", ex); } catch (Exception) { Dispose(); connection?.Dispose(); throw; } }