From f3f9d085d10b745d6f15775f145be81db34eb900 Mon Sep 17 00:00:00 2001 From: Robert Dailey Date: Sat, 15 May 2021 14:39:23 -0500 Subject: [PATCH] fix: handle invalid cache data If cache data is invalid, catch the exception and log an error. But the app should continue and not stop there. Just proceed without cache. --- CHANGELOG.md | 5 +++++ src/Trash.Tests/Cache/ServiceCacheTest.cs | 16 +++++++++++++++- src/Trash/Cache/ServiceCache.cs | 19 +++++++++++++++++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2548ca53..a56ed23e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Invalid cache data files no longer cause the program to exit. An error is printed and the + application continues as if there was no cache at all. + ### Changed - The log message listing custom formats without scores in the guide now prints information one per diff --git a/src/Trash.Tests/Cache/ServiceCacheTest.cs b/src/Trash.Tests/Cache/ServiceCacheTest.cs index b992102e..ec105e91 100644 --- a/src/Trash.Tests/Cache/ServiceCacheTest.cs +++ b/src/Trash.Tests/Cache/ServiceCacheTest.cs @@ -5,6 +5,7 @@ using FluentAssertions; using Newtonsoft.Json; using NSubstitute; using NUnit.Framework; +using Serilog; using Trash.Cache; using Trash.Config; @@ -21,7 +22,7 @@ namespace Trash.Tests.Cache Filesystem = fs ?? Substitute.For(); StoragePath = Substitute.For(); ServiceConfig = Substitute.For(); - Cache = new ServiceCache(Filesystem, StoragePath, ServiceConfig); + Cache = new ServiceCache(Filesystem, StoragePath, ServiceConfig, Substitute.For()); } public ServiceCache Cache { get; } @@ -141,5 +142,18 @@ namespace Trash.Tests.Cache .Throw() .WithMessage("CacheObjectNameAttribute is missing*"); } + + [Test] + public void When_cache_file_is_empty_do_not_throw() + { + var ctx = new Context(); + ctx.Filesystem.File.Exists(Arg.Any()).Returns(true); + ctx.Filesystem.File.ReadAllText(Arg.Any()) + .Returns(_ => ""); + + Action act = () => ctx.Cache.Load(); + + act.Should().NotThrow(); + } } } diff --git a/src/Trash/Cache/ServiceCache.cs b/src/Trash/Cache/ServiceCache.cs index bcdaa010..4cd79202 100644 --- a/src/Trash/Cache/ServiceCache.cs +++ b/src/Trash/Cache/ServiceCache.cs @@ -7,6 +7,7 @@ using System.Text; using System.Text.RegularExpressions; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Serilog; using Trash.Config; namespace Trash.Cache @@ -19,14 +20,18 @@ namespace Trash.Cache private readonly IFNV1a _hash; private readonly ICacheStoragePath _storagePath; - public ServiceCache(IFileSystem fileSystem, ICacheStoragePath storagePath, IServiceConfiguration config) + public ServiceCache(IFileSystem fileSystem, ICacheStoragePath storagePath, IServiceConfiguration config, + ILogger log) { _fileSystem = fileSystem; _storagePath = storagePath; _config = config; + Log = log; _hash = FNV1aFactory.Instance.Create(FNVConfig.GetPredefinedConfig(32)); } + private ILogger Log { get; } + public T? Load() where T : class { var path = PathFromAttribute(); @@ -36,7 +41,17 @@ namespace Trash.Cache } var json = _fileSystem.File.ReadAllText(path); - return JObject.Parse(json).ToObject(); + + try + { + return JObject.Parse(json).ToObject(); + } + catch (JsonException e) + { + Log.Error("Failed to read cache data, will proceed without cache. Reason: {Msg}", e.Message); + } + + return null; } public void Save(T obj) where T : class