Index: Application/Ringtoets/src/Application.Ringtoets/App.xaml.cs =================================================================== diff -u -r82b94cbd467ad3e7e5adb525d57b7233a963a726 -r72da35fee21360783bf87322879144f16d7e7589 --- Application/Ringtoets/src/Application.Ringtoets/App.xaml.cs (.../App.xaml.cs) (revision 82b94cbd467ad3e7e5adb525d57b7233a963a726) +++ Application/Ringtoets/src/Application.Ringtoets/App.xaml.cs (.../App.xaml.cs) (revision 72da35fee21360783bf87322879144f16d7e7589) @@ -185,40 +185,15 @@ /// private void DeleteOldLogFiles() { - string settingsDirectory = GetLogFileDirectory(); - if (string.IsNullOrWhiteSpace(settingsDirectory)) - { - return; - } - foreach (string logFile in Directory.GetFiles(settingsDirectory, "*.log")) - { - if ((DateTime.Now - File.GetCreationTime(logFile)).TotalDays > numberOfDaysToKeepLogFiles) - { - File.Delete(logFile); - } - } - } - - private string GetLogFileDirectory() - { - var fileAppender = LogManager.GetAllRepositories() - .SelectMany(r => r.GetAppenders()) - .OfType() - .FirstOrDefault(); - if (fileAppender == null) - { - return string.Empty; - } - try { - return Path.GetDirectoryName(fileAppender.File); + FileUtils.DeleteOldFiles(GetLogFileDirectory(), "*.log", numberOfDaysToKeepLogFiles); } - catch (Exception exception) + catch (Exception e) { - if (exception is ArgumentException || exception is PathTooLongException) + if (e is ArgumentException || e is IOException) { - return string.Empty; + return; } throw; } @@ -414,5 +389,19 @@ Thread.CurrentThread.CurrentCulture = cultureInfo; } } + + private static string GetLogFileDirectory() + { + var fileAppender = LogManager.GetAllRepositories() + .SelectMany(r => r.GetAppenders()) + .OfType() + .FirstOrDefault(); + if (fileAppender == null || string.IsNullOrWhiteSpace(fileAppender.File)) + { + return string.Empty; + } + + return Path.GetDirectoryName(fileAppender.File); + } } } \ No newline at end of file Index: Core/Common/src/Core.Common.Gui/Properties/Resources.Designer.cs =================================================================== diff -u -r82b94cbd467ad3e7e5adb525d57b7233a963a726 -r72da35fee21360783bf87322879144f16d7e7589 --- Core/Common/src/Core.Common.Gui/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 82b94cbd467ad3e7e5adb525d57b7233a963a726) +++ Core/Common/src/Core.Common.Gui/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 72da35fee21360783bf87322879144f16d7e7589) @@ -1,4 +1,25 @@ -//------------------------------------------------------------------------------ +// Copyright (C) Stichting Deltares 2016. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 @@ -1299,6 +1320,16 @@ } /// + /// Looks up a localized string similar to De map '{0}' kan niet aangemaakt worden.. + /// + public static string SettingsHelper_GetApplicationLocalUserSettingsDirectory_Folder_0_Cannot_be_created { + get { + return ResourceManager.GetString("SettingsHelper_GetApplicationLocalUserSettingsDirectory_Folder_0_Cannot_be_create" + + "d", resourceCulture); + } + } + + /// /// Looks up a localized string similar to Website. /// public static string SplashScreen_SupportEmail { Index: Core/Common/src/Core.Common.Gui/Properties/Resources.resx =================================================================== diff -u -r82b94cbd467ad3e7e5adb525d57b7233a963a726 -r72da35fee21360783bf87322879144f16d7e7589 --- Core/Common/src/Core.Common.Gui/Properties/Resources.resx (.../Resources.resx) (revision 82b94cbd467ad3e7e5adb525d57b7233a963a726) +++ Core/Common/src/Core.Common.Gui/Properties/Resources.resx (.../Resources.resx) (revision 72da35fee21360783bf87322879144f16d7e7589) @@ -568,4 +568,7 @@ Start + + De map '{0}' kan niet aangemaakt worden. + \ No newline at end of file Index: Core/Common/src/Core.Common.Gui/Settings/SettingsHelper.cs =================================================================== diff -u -r82b94cbd467ad3e7e5adb525d57b7233a963a726 -r72da35fee21360783bf87322879144f16d7e7589 --- Core/Common/src/Core.Common.Gui/Settings/SettingsHelper.cs (.../SettingsHelper.cs) (revision 82b94cbd467ad3e7e5adb525d57b7233a963a726) +++ Core/Common/src/Core.Common.Gui/Settings/SettingsHelper.cs (.../SettingsHelper.cs) (revision 72da35fee21360783bf87322879144f16d7e7589) @@ -21,6 +21,7 @@ using System; using System.IO; +using Core.Common.Gui.Properties; using Core.Common.Utils.Reflection; namespace Core.Common.Gui.Settings @@ -30,6 +31,8 @@ /// public static class SettingsHelper { + private static readonly string localSettingsDirectoryPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + /// /// Initializes the static properties. /// @@ -56,16 +59,27 @@ /// /// The postfix path to use after the local application data folder (if any). /// Directory path where the user settings can be found. + /// Thown when the application local user settings directory could not be created. public static string GetApplicationLocalUserSettingsDirectory(string postfix) { - var localSettingsDirectoryPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); var appSettingsDirectoryPath = string.IsNullOrWhiteSpace(postfix) ? localSettingsDirectoryPath : Path.Combine(localSettingsDirectoryPath, postfix); if (!Directory.Exists(appSettingsDirectoryPath)) { - Directory.CreateDirectory(appSettingsDirectoryPath); + try + { + Directory.CreateDirectory(appSettingsDirectoryPath); + } + catch (Exception e) + { + if (e is ArgumentException || e is IOException || e is NotSupportedException || e is UnauthorizedAccessException) + { + var message = string.Format(Resources.SettingsHelper_GetApplicationLocalUserSettingsDirectory_Folder_0_Cannot_be_created, appSettingsDirectoryPath); + throw new IOException(message, e); + } + throw; + } } - return appSettingsDirectoryPath; } } Index: Core/Common/src/Core.Common.Utils/FileUtils.cs =================================================================== diff -u -rdd2a90e1f1fb2cc5fc0474d48ea3914228514a49 -r72da35fee21360783bf87322879144f16d7e7589 --- Core/Common/src/Core.Common.Utils/FileUtils.cs (.../FileUtils.cs) (revision dd2a90e1f1fb2cc5fc0474d48ea3914228514a49) +++ Core/Common/src/Core.Common.Utils/FileUtils.cs (.../FileUtils.cs) (revision 72da35fee21360783bf87322879144f16d7e7589) @@ -21,6 +21,7 @@ using System; using System.IO; +using System.Linq; using Core.Common.Utils.Builders; using Core.Common.Utils.Properties; @@ -94,5 +95,44 @@ } return true; } + + /// + /// Searches the files in that match and + /// deletes the files older than days. + /// + /// The directory to search. + /// The search string to match against the names of files in path. + /// The maximum number days since the creation of the file. + /// Thrown when of is null, is a zero-length string, + /// contains only white space, or contains one or more invalid characters. + /// Thrown when an error occured trying to search and delete files in . + public static void DeleteOldFiles(string path, string searchPattern, int numberOfDaysToKeepFiles) + { + if (string.IsNullOrWhiteSpace(path)) + { + throw new ArgumentException(@"No valid value for 'path'.", "path"); + } + if (string.IsNullOrWhiteSpace(searchPattern)) + { + throw new ArgumentException(@"No valid value for 'searchPattern'.", "searchPattern"); + } + try + { + foreach (string logFile in Directory.GetFiles(path, searchPattern).Where( + l => (DateTime.Now - File.GetCreationTime(l)).TotalDays > numberOfDaysToKeepFiles)) + { + File.Delete(logFile); + } + } + catch (Exception e) + { + if (e is ArgumentException || e is IOException || e is NotSupportedException || e is UnauthorizedAccessException) + { + var message = string.Format(Resources.FileUtils_DeleteOldFiles_Error_occured_deleting_files_in_folder_0, path); + throw new IOException(message, e); + } + throw; + } + } } } \ No newline at end of file Index: Core/Common/src/Core.Common.Utils/Properties/Resources.Designer.cs =================================================================== diff -u -r16d6d5ad38a45e4e0e8b3a9b41b3383d31595a36 -r72da35fee21360783bf87322879144f16d7e7589 --- Core/Common/src/Core.Common.Utils/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 16d6d5ad38a45e4e0e8b3a9b41b3383d31595a36) +++ Core/Common/src/Core.Common.Utils/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 72da35fee21360783bf87322879144f16d7e7589) @@ -1,4 +1,25 @@ -//------------------------------------------------------------------------------ +// Copyright (C) Stichting Deltares 2016. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 @@ -151,6 +172,15 @@ } /// + /// Looks up a localized string similar to Er is een fout opgetreden bij het verwijderen van bestanden in de map '{0}'.. + /// + public static string FileUtils_DeleteOldFiles_Error_occured_deleting_files_in_folder_0 { + get { + return ResourceManager.GetString("FileUtils_DeleteOldFiles_Error_occured_deleting_files_in_folder_0", resourceCulture); + } + } + + /// /// Looks up a localized string similar to op regel {0}. /// public static string TextFile_On_LineNumber_0_ { Index: Core/Common/src/Core.Common.Utils/Properties/Resources.resx =================================================================== diff -u -r16d6d5ad38a45e4e0e8b3a9b41b3383d31595a36 -r72da35fee21360783bf87322879144f16d7e7589 --- Core/Common/src/Core.Common.Utils/Properties/Resources.resx (.../Resources.resx) (revision 16d6d5ad38a45e4e0e8b3a9b41b3383d31595a36) +++ Core/Common/src/Core.Common.Utils/Properties/Resources.resx (.../Resources.resx) (revision 72da35fee21360783bf87322879144f16d7e7589) @@ -153,4 +153,7 @@ op regel {0} + + Er is een fout opgetreden bij het verwijderen van bestanden in de map '{0}'. + \ No newline at end of file Index: Core/Common/test/Core.Common.Gui.Test/Settings/SettingsHelperTest.cs =================================================================== diff -u -r82b94cbd467ad3e7e5adb525d57b7233a963a726 -r72da35fee21360783bf87322879144f16d7e7589 --- Core/Common/test/Core.Common.Gui.Test/Settings/SettingsHelperTest.cs (.../SettingsHelperTest.cs) (revision 82b94cbd467ad3e7e5adb525d57b7233a963a726) +++ Core/Common/test/Core.Common.Gui.Test/Settings/SettingsHelperTest.cs (.../SettingsHelperTest.cs) (revision 72da35fee21360783bf87322879144f16d7e7589) @@ -21,15 +21,26 @@ using System; using System.IO; +using System.Reflection; +using System.Security.AccessControl; +using System.Security.Principal; using Core.Common.Gui.Settings; +using Core.Common.TestUtil; using Core.Common.Utils.Reflection; +using log4net; using NUnit.Framework; namespace Core.Common.Gui.Test.Settings { [TestFixture] public class SettingsHelperTest { + [TearDown] + public void TearDown() + { + SetLocalSettingsDirectoryPath(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)); + } + [Test] public void ApplicationName_ReturnsProductNameOfExecutingAssembly() { @@ -55,7 +66,7 @@ [TestCase("")] [TestCase(" ")] [TestCase("some directory name")] - public void GetApplicationLocalUserSettingsDirectory_VariousInfixes_ReturnsApplicationLocalUserSettingsDirectory(string postfix) + public void GetApplicationLocalUserSettingsDirectory_VariousPostfixes_ReturnsApplicationLocalUserSettingsDirectory(string postfix) { // Setup var localSettingsDirectoryPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); @@ -67,5 +78,93 @@ // Assert Assert.AreEqual(appSettingsDirectoryPath, pathFromSettings); } + + [Test] + public void GetApplicationLocalUserSettingsDirectory_ValidPathFileExistsDirectoryNotWritable_ThrowsIOException() + { + // Setup + var workingDirectory = TestHelper.GetTestDataPath(TestDataPath.Core.Common.Gui, "SettingsHelper"); + Directory.CreateDirectory(workingDirectory); + var notWritableFolder = "notWritable"; + + DenyDirectoryRight(workingDirectory, FileSystemRights.Write); + + SetLocalSettingsDirectoryPath(workingDirectory); + + // Call + TestDelegate test = () => SettingsHelper.GetApplicationLocalUserSettingsDirectory(notWritableFolder); + + try + { + // Assert + var notWritableDirectory = Path.Combine(workingDirectory, notWritableFolder); + var expectedMessage = string.Format("De map '{0}' kan niet aangemaakt worden.", notWritableDirectory); + var message = Assert.Throws(test).Message; + Assert.AreEqual(expectedMessage, message); + } + finally + { + RevertDenyDirectoryRight(workingDirectory, FileSystemRights.FullControl); + Directory.Delete(workingDirectory, true); + } + + } + + /// + /// Adds a of type to the access + /// rule set for the file at . + /// + /// The path of the file to change the right for. + /// The right to deny. + private static void DenyDirectoryRight(string filePath, FileSystemRights rights) + { + var sid = GetSecurityIdentifier(); + + DirectoryInfo directoryInfo = new DirectoryInfo(filePath); + DirectorySecurity directorySecurity = directoryInfo.GetAccessControl(); + + directorySecurity.AddAccessRule(new FileSystemAccessRule(sid, rights, AccessControlType.Deny)); + + directoryInfo.SetAccessControl(directorySecurity); + } + + /// + /// Removes a of type from the + /// access rule set for the file at . + /// + /// The path of the file to change the right for. + /// The right to revert. + private static void RevertDenyDirectoryRight(string filePath, FileSystemRights rights) + { + var sid = GetSecurityIdentifier(); + + DirectoryInfo directoryInfo = new DirectoryInfo(filePath); + DirectorySecurity directorySecurity = directoryInfo.GetAccessControl(); + + directorySecurity.RemoveAccessRule(new FileSystemAccessRule(sid, rights, AccessControlType.Deny)); + + directoryInfo.SetAccessControl(directorySecurity); + } + + private static SecurityIdentifier GetSecurityIdentifier() + { + SecurityIdentifier id = WindowsIdentity.GetCurrent().User.AccountDomainSid; + return new SecurityIdentifier(WellKnownSidType.WorldSid, id); + } + + private static void SetLocalSettingsDirectoryPath(string nonExistingFolder) + { + string localSettingsDirectoryPath = "localSettingsDirectoryPath"; + Type settingsHelperType = typeof(SettingsHelper); + FieldInfo fieldInfo = settingsHelperType.GetField(localSettingsDirectoryPath, BindingFlags.NonPublic | BindingFlags.Static); + if (fieldInfo == null) + { + Assert.Fail("Unable to find private field '{0}'", localSettingsDirectoryPath); + } + else + { + fieldInfo.SetValue(null, nonExistingFolder); + } + } } } \ No newline at end of file Index: Core/Common/test/Core.Common.Utils.Test/FileUtilsTest.cs =================================================================== diff -u -r151bab16a7ebc1bffc0621ab56c6dc219db1e90f -r72da35fee21360783bf87322879144f16d7e7589 --- Core/Common/test/Core.Common.Utils.Test/FileUtilsTest.cs (.../FileUtilsTest.cs) (revision 151bab16a7ebc1bffc0621ab56c6dc219db1e90f) +++ Core/Common/test/Core.Common.Utils.Test/FileUtilsTest.cs (.../FileUtilsTest.cs) (revision 72da35fee21360783bf87322879144f16d7e7589) @@ -143,5 +143,73 @@ // Assert Assert.IsFalse(valid); } + + [Test] + [TestCase(null)] + [TestCase("")] + [TestCase(" ")] + public void DeleteOldFiles_InvalidEmptyPath_ThrowsArgumentException(string invalidPath) + { + // Call + TestDelegate call = () => FileUtils.DeleteOldFiles(invalidPath,"",0); + + // Assert + string invalidParameterName = Assert.Throws(call).ParamName; + Assert.AreEqual("path", invalidParameterName); + } + + [Test] + [TestCase(null)] + [TestCase("")] + [TestCase(" ")] + public void DeleteOldFiles_PathDoesNotExist_ThrowsArgumentException(string invalidSearchPattern) + { + // Setup + var path = TestHelper.GetTestDataPath(TestDataPath.Core.Common.Utils); + + // Call + TestDelegate call = () => FileUtils.DeleteOldFiles(path, invalidSearchPattern, 0); + + // Assert + string invalidParameterName = Assert.Throws(call).ParamName; + Assert.AreEqual("searchPattern", invalidParameterName); + } + + [Test] + public void DeleteOldFiles_PathDoesNotExist_ThrowsIOException() + { + // Setup + var path = TestHelper.GetTestDataPath(TestDataPath.Core.Common.Utils, "doesNotExist"); + + // Precondition + Assert.IsFalse(Directory.Exists(path)); + + // Call + TestDelegate call = () => FileUtils.DeleteOldFiles(path, "*.log", 0); + + // Assert + IOException exception = Assert.Throws(call); + var message = string.Format("Er is een fout opgetreden bij het verwijderen van bestanden in de map '{0}'.", path); + Assert.AreEqual(message, exception.Message); + Assert.IsInstanceOf(exception.InnerException); + } + + [Test] + public void DeleteOldFiles_ValidPathWithFile_DeletesFile() + { + // Setup + var path = TestHelper.GetTestDataPath(TestDataPath.Core.Common.Utils); + var filePath = Path.Combine(path, "fileToDelete.log"); + + using (new FileDisposeHelper(filePath)) + { + + // Call + FileUtils.DeleteOldFiles(path, "*.log", 0); + + // Assert + Assert.IsFalse(File.Exists(filePath)); + } + } } } \ No newline at end of file