0

Here is a simple Logger class I've written:

public class Logger : ILogger
{
    private readonly string logFilePath;
    private readonly object threadLock;

    public Logger(string filePath, string fileName)
    {
        this.logFilePath = Path.Combine(filePath, fileName);
        this.threadLock = new object();
    }

    #region ILogger

    void ILogger.Log(string message) => this.DoLog(message);

    void ILogger.DeleteLog() => this.DoDelete();

    #endregion

    [Conditional("DEBUG")]
    private void DoLog(string message)
    {
        //lock (this.threadLock)
        //{
            string dateTime = DateTime.UtcNow.ToString("O", System.Globalization.CultureInfo.InvariantCulture); // See https://stackoverflow.com/questions/1728404/date-format-yyyy-mm-ddthhmmssz
            string logMessage = string.Format("{0} {1}{2}", dateTime, message, Environment.NewLine);
            File.AppendAllText(this.logFilePath, logMessage);
        //}
    }

    [Conditional("DEBUG")]
    private void DoDelete()
    {
        //lock (this.threadLock)
        //{
            File.Delete(this.logFilePath);
        //}
    }
}

and I'd like to get File.Delete to fail before I add a lock around that.

I tried this unit test:

    [Test]
    public void TestMultithreadingDeleteLog()
    {
        Thread thread1 = new Thread(this.DoLog);
        Thread thread2 = new Thread(this.DoDeleteLog);
        this.logger.Log("TestMultithreadingDeleteLog");
        //
        thread1.Start();
        thread2.Start();
        //
        thread1.Join(); // Blocks the current thread until thread1 completes or aborts)
        thread2.Join();
    }

    private void DoLog()
    {
        for (int x = 0; x < 100; x++)
        {
            this.logger.Log("ABC");
        }
    }

    private void DoDeleteLog()
    {
        for (int x = 0; x < 100; x++)
        {
            this.logger.DeleteLog();
        }
    }

but it always passes, even with much larger numbers.

How can I get File.Delete to throw an exception so I can then add the lock and check that fixes it?

Bbx
  • 3,184
  • 3
  • 22
  • 33
  • 1
    File system should be treated as a 3rd party dependency and abstracted out to avoid tight coupling. – Nkosi Mar 02 '21 at 16:46
  • Why don't you create a new class the wraps `File` and exposes only the methods you need? then you could mock that class – Bargros Mar 02 '21 at 16:49
  • @Nkosi and Bargros. Good points. But what I really want to prove is if File.Delete and File.AppendAllText are actually thread safe or not. Maybe they implement a lock themselves, in which case I would not need locks in the Logger class. – Bbx Mar 02 '21 at 17:00
  • 1
    They do not implement locks. https://source.dot.net/#System.IO.FileSystem/System/IO/File.cs,1c7421e464f67b7e,references – Nkosi Mar 02 '21 at 17:16

0 Answers0