mirror of
https://github.com/wnagrodzki/SwiftLogger.git
synced 2025-04-07 13:01:51 +02:00
Merge branch 'feature/code_reorganization' into develop
This commit is contained in:
commit
3bc845ee28
9 changed files with 155 additions and 142 deletions
|
@ -15,14 +15,15 @@
|
||||||
2EBF4B4B2122AF53008E4117 /* ConsoleLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B482122AF53008E4117 /* ConsoleLogger.swift */; };
|
2EBF4B4B2122AF53008E4117 /* ConsoleLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B482122AF53008E4117 /* ConsoleLogger.swift */; };
|
||||||
2EBF4B4C2122AF53008E4117 /* NullLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B492122AF53008E4117 /* NullLogger.swift */; };
|
2EBF4B4C2122AF53008E4117 /* NullLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B492122AF53008E4117 /* NullLogger.swift */; };
|
||||||
2EBF4B572122B598008E4117 /* DiskLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B542122B598008E4117 /* DiskLogger.swift */; };
|
2EBF4B572122B598008E4117 /* DiskLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B542122B598008E4117 /* DiskLogger.swift */; };
|
||||||
2EBF4B582122B598008E4117 /* FileWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B552122B598008E4117 /* FileWriter.swift */; };
|
2EBF4B582122B598008E4117 /* SizeLimitedFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B552122B598008E4117 /* SizeLimitedFile.swift */; };
|
||||||
2EBF4B592122B598008E4117 /* FileRotate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B562122B598008E4117 /* FileRotate.swift */; };
|
2EBF4B592122B598008E4117 /* Logrotate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B562122B598008E4117 /* Logrotate.swift */; };
|
||||||
2ED077D721329CA30058EEFC /* LoggetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED077D621329CA30058EEFC /* LoggetTests.swift */; };
|
2ED077D721329CA30058EEFC /* LoggetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED077D621329CA30058EEFC /* LoggetTests.swift */; };
|
||||||
2ED077D92132A4820058EEFC /* AgregateLoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED077D82132A4820058EEFC /* AgregateLoggerTests.swift */; };
|
2ED077D92132A4820058EEFC /* AgregateLoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED077D82132A4820058EEFC /* AgregateLoggerTests.swift */; };
|
||||||
2ED077DB2132B0320058EEFC /* FileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED077DA2132B0320058EEFC /* FileSystem.swift */; };
|
2ED077DB2132B0320058EEFC /* OSFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED077DA2132B0320058EEFC /* OSFileManager.swift */; };
|
||||||
2ED103E12135C61100EB3683 /* FileRotateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED103E02135C61100EB3683 /* FileRotateTests.swift */; };
|
2ED103E12135C61100EB3683 /* LogrotateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED103E02135C61100EB3683 /* LogrotateTests.swift */; };
|
||||||
2ED103E32135D3FB00EB3683 /* FileWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED103E22135D3FB00EB3683 /* FileWriterTests.swift */; };
|
2ED103E32135D3FB00EB3683 /* SizeLimitedFileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED103E22135D3FB00EB3683 /* SizeLimitedFileTests.swift */; };
|
||||||
2ED103E52138553B00EB3683 /* DiskLoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED103E42138553B00EB3683 /* DiskLoggerTests.swift */; };
|
2ED103E52138553B00EB3683 /* DiskLoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED103E42138553B00EB3683 /* DiskLoggerTests.swift */; };
|
||||||
|
2ED83781236A19A60008C01F /* OSFileHandle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED83780236A19A60008C01F /* OSFileHandle.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
@ -58,14 +59,15 @@
|
||||||
2EBF4B482122AF53008E4117 /* ConsoleLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsoleLogger.swift; sourceTree = "<group>"; };
|
2EBF4B482122AF53008E4117 /* ConsoleLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsoleLogger.swift; sourceTree = "<group>"; };
|
||||||
2EBF4B492122AF53008E4117 /* NullLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NullLogger.swift; sourceTree = "<group>"; };
|
2EBF4B492122AF53008E4117 /* NullLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NullLogger.swift; sourceTree = "<group>"; };
|
||||||
2EBF4B542122B598008E4117 /* DiskLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiskLogger.swift; sourceTree = "<group>"; };
|
2EBF4B542122B598008E4117 /* DiskLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiskLogger.swift; sourceTree = "<group>"; };
|
||||||
2EBF4B552122B598008E4117 /* FileWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileWriter.swift; sourceTree = "<group>"; };
|
2EBF4B552122B598008E4117 /* SizeLimitedFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SizeLimitedFile.swift; sourceTree = "<group>"; };
|
||||||
2EBF4B562122B598008E4117 /* FileRotate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileRotate.swift; sourceTree = "<group>"; };
|
2EBF4B562122B598008E4117 /* Logrotate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logrotate.swift; sourceTree = "<group>"; };
|
||||||
2ED077D621329CA30058EEFC /* LoggetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggetTests.swift; sourceTree = "<group>"; };
|
2ED077D621329CA30058EEFC /* LoggetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggetTests.swift; sourceTree = "<group>"; };
|
||||||
2ED077D82132A4820058EEFC /* AgregateLoggerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgregateLoggerTests.swift; sourceTree = "<group>"; };
|
2ED077D82132A4820058EEFC /* AgregateLoggerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgregateLoggerTests.swift; sourceTree = "<group>"; };
|
||||||
2ED077DA2132B0320058EEFC /* FileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileSystem.swift; sourceTree = "<group>"; };
|
2ED077DA2132B0320058EEFC /* OSFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSFileManager.swift; sourceTree = "<group>"; };
|
||||||
2ED103E02135C61100EB3683 /* FileRotateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileRotateTests.swift; sourceTree = "<group>"; };
|
2ED103E02135C61100EB3683 /* LogrotateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogrotateTests.swift; sourceTree = "<group>"; };
|
||||||
2ED103E22135D3FB00EB3683 /* FileWriterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileWriterTests.swift; sourceTree = "<group>"; };
|
2ED103E22135D3FB00EB3683 /* SizeLimitedFileTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SizeLimitedFileTests.swift; sourceTree = "<group>"; };
|
||||||
2ED103E42138553B00EB3683 /* DiskLoggerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskLoggerTests.swift; sourceTree = "<group>"; };
|
2ED103E42138553B00EB3683 /* DiskLoggerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskLoggerTests.swift; sourceTree = "<group>"; };
|
||||||
|
2ED83780236A19A60008C01F /* OSFileHandle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSFileHandle.swift; sourceTree = "<group>"; };
|
||||||
2EDA8AE8213ACCFF00FE5840 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
2EDA8AE8213ACCFF00FE5840 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
@ -95,8 +97,8 @@
|
||||||
2ED077D621329CA30058EEFC /* LoggetTests.swift */,
|
2ED077D621329CA30058EEFC /* LoggetTests.swift */,
|
||||||
2ED077D82132A4820058EEFC /* AgregateLoggerTests.swift */,
|
2ED077D82132A4820058EEFC /* AgregateLoggerTests.swift */,
|
||||||
2ED103E42138553B00EB3683 /* DiskLoggerTests.swift */,
|
2ED103E42138553B00EB3683 /* DiskLoggerTests.swift */,
|
||||||
2ED103E22135D3FB00EB3683 /* FileWriterTests.swift */,
|
2ED103E22135D3FB00EB3683 /* SizeLimitedFileTests.swift */,
|
||||||
2ED103E02135C61100EB3683 /* FileRotateTests.swift */,
|
2ED103E02135C61100EB3683 /* LogrotateTests.swift */,
|
||||||
2E58D35E21316C3500BEF81A /* Info.plist */,
|
2E58D35E21316C3500BEF81A /* Info.plist */,
|
||||||
);
|
);
|
||||||
path = UnitTests;
|
path = UnitTests;
|
||||||
|
@ -146,9 +148,10 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
2EBF4B542122B598008E4117 /* DiskLogger.swift */,
|
2EBF4B542122B598008E4117 /* DiskLogger.swift */,
|
||||||
2EBF4B552122B598008E4117 /* FileWriter.swift */,
|
2EBF4B552122B598008E4117 /* SizeLimitedFile.swift */,
|
||||||
2EBF4B562122B598008E4117 /* FileRotate.swift */,
|
2EBF4B562122B598008E4117 /* Logrotate.swift */,
|
||||||
2ED077DA2132B0320058EEFC /* FileSystem.swift */,
|
2ED077DA2132B0320058EEFC /* OSFileManager.swift */,
|
||||||
|
2ED83780236A19A60008C01F /* OSFileHandle.swift */,
|
||||||
);
|
);
|
||||||
path = DiskLogger;
|
path = DiskLogger;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -246,10 +249,10 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
2E58D35D21316C3500BEF81A /* LogStringConvertibleTests.swift in Sources */,
|
2E58D35D21316C3500BEF81A /* LogStringConvertibleTests.swift in Sources */,
|
||||||
2ED103E32135D3FB00EB3683 /* FileWriterTests.swift in Sources */,
|
2ED103E32135D3FB00EB3683 /* SizeLimitedFileTests.swift in Sources */,
|
||||||
2ED103E52138553B00EB3683 /* DiskLoggerTests.swift in Sources */,
|
2ED103E52138553B00EB3683 /* DiskLoggerTests.swift in Sources */,
|
||||||
2ED077D92132A4820058EEFC /* AgregateLoggerTests.swift in Sources */,
|
2ED077D92132A4820058EEFC /* AgregateLoggerTests.swift in Sources */,
|
||||||
2ED103E12135C61100EB3683 /* FileRotateTests.swift in Sources */,
|
2ED103E12135C61100EB3683 /* LogrotateTests.swift in Sources */,
|
||||||
2ED077D721329CA30058EEFC /* LoggetTests.swift in Sources */,
|
2ED077D721329CA30058EEFC /* LoggetTests.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -258,14 +261,15 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
2EBF4B582122B598008E4117 /* FileWriter.swift in Sources */,
|
2EBF4B582122B598008E4117 /* SizeLimitedFile.swift in Sources */,
|
||||||
|
2ED83781236A19A60008C01F /* OSFileHandle.swift in Sources */,
|
||||||
2EBF4B572122B598008E4117 /* DiskLogger.swift in Sources */,
|
2EBF4B572122B598008E4117 /* DiskLogger.swift in Sources */,
|
||||||
2EBF4B4C2122AF53008E4117 /* NullLogger.swift in Sources */,
|
2EBF4B4C2122AF53008E4117 /* NullLogger.swift in Sources */,
|
||||||
2EBF4B3E2122AA34008E4117 /* Logger.swift in Sources */,
|
2EBF4B3E2122AA34008E4117 /* Logger.swift in Sources */,
|
||||||
2EBF4B4B2122AF53008E4117 /* ConsoleLogger.swift in Sources */,
|
2EBF4B4B2122AF53008E4117 /* ConsoleLogger.swift in Sources */,
|
||||||
2ED077DB2132B0320058EEFC /* FileSystem.swift in Sources */,
|
2ED077DB2132B0320058EEFC /* OSFileManager.swift in Sources */,
|
||||||
2EBF4B4A2122AF53008E4117 /* AgregateLogger.swift in Sources */,
|
2EBF4B4A2122AF53008E4117 /* AgregateLogger.swift in Sources */,
|
||||||
2EBF4B592122B598008E4117 /* FileRotate.swift in Sources */,
|
2EBF4B592122B598008E4117 /* Logrotate.swift in Sources */,
|
||||||
2EBF4B452122ACD6008E4117 /* LogStringConvertible.swift in Sources */,
|
2EBF4B452122ACD6008E4117 /* LogStringConvertible.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
|
@ -24,23 +24,6 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// Write failed as allowed size limit would be exceeded.
|
|
||||||
public struct SizeLimitedFileQuotaReached: Error {}
|
|
||||||
|
|
||||||
/// Allows writing to a file while respecting allowed size limit.
|
|
||||||
protocol SizeLimitedFile {
|
|
||||||
|
|
||||||
/// Synchronously writes `data` at the end of the file.
|
|
||||||
///
|
|
||||||
/// - Parameter data: The data to be written.
|
|
||||||
/// - Throws: Throws an error if no free space is left on the file system, or if any other writing error occurs.
|
|
||||||
/// Throws `SizeLimitedFileQuotaReached` if allowed size limit would be exceeded.
|
|
||||||
func write(_ data: Data) throws
|
|
||||||
|
|
||||||
/// Writes all in-memory data to permanent storage and closes the file.
|
|
||||||
func synchronizeAndCloseFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
protocol SizeLimitedFileFactory {
|
protocol SizeLimitedFileFactory {
|
||||||
|
|
||||||
/// Returns newly initialized SizeLimitedFile instance.
|
/// Returns newly initialized SizeLimitedFile instance.
|
||||||
|
@ -52,20 +35,6 @@ protocol SizeLimitedFileFactory {
|
||||||
func makeInstance(fileURL: URL, fileSizeLimit: UInt64) throws -> SizeLimitedFile
|
func makeInstance(fileURL: URL, fileSizeLimit: UInt64) throws -> SizeLimitedFile
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows log files rotation.
|
|
||||||
protocol Logrotate {
|
|
||||||
|
|
||||||
/// Rotates log files `rotations` number of times.
|
|
||||||
///
|
|
||||||
/// First deletes file at `<fileURL>.<rotations>`.
|
|
||||||
/// Next moves files located at:
|
|
||||||
///
|
|
||||||
/// `<fileURL>, <fileURL>.1, <fileURL>.2 ... <fileURL>.<rotations - 1>`
|
|
||||||
///
|
|
||||||
/// to `<fileURL>.1, <fileURL>.2 ... <fileURL>.<rotations>`
|
|
||||||
func rotate() throws
|
|
||||||
}
|
|
||||||
|
|
||||||
protocol LogrotateFactory {
|
protocol LogrotateFactory {
|
||||||
|
|
||||||
/// Returns newly initialized Logrotate instance.
|
/// Returns newly initialized Logrotate instance.
|
||||||
|
@ -82,7 +51,7 @@ public final class DiskLogger: Logger {
|
||||||
private let fileURL: URL
|
private let fileURL: URL
|
||||||
private let fileSizeLimit: UInt64
|
private let fileSizeLimit: UInt64
|
||||||
private let rotations: Int
|
private let rotations: Int
|
||||||
private let fileSystem: FileSystem
|
private let fileManager: OSFileManager
|
||||||
private let sizeLimitedFileFactory: SizeLimitedFileFactory
|
private let sizeLimitedFileFactory: SizeLimitedFileFactory
|
||||||
private let logrotateFactory: LogrotateFactory
|
private let logrotateFactory: LogrotateFactory
|
||||||
private let formatter: DateFormatter
|
private let formatter: DateFormatter
|
||||||
|
@ -97,14 +66,14 @@ public final class DiskLogger: Logger {
|
||||||
/// - fileSizeLimit: Maximum size log file can reach in bytes. Attempt to exceeding that limit triggers log files rotation.
|
/// - fileSizeLimit: Maximum size log file can reach in bytes. Attempt to exceeding that limit triggers log files rotation.
|
||||||
/// - rotations: Number of times log files are rotated before being removed.
|
/// - rotations: Number of times log files are rotated before being removed.
|
||||||
public convenience init(fileURL: URL, fileSizeLimit: UInt64, rotations: Int) {
|
public convenience init(fileURL: URL, fileSizeLimit: UInt64, rotations: Int) {
|
||||||
self.init(fileURL: fileURL, fileSizeLimit: fileSizeLimit, rotations: rotations, fileSystem: FileManager.default, sizeLimitedFileFactory: FileWriterFactory(), logrotateFactory: FileRotateFactory())
|
self.init(fileURL: fileURL, fileSizeLimit: fileSizeLimit, rotations: rotations, fileManager: FileManager.default, sizeLimitedFileFactory: SizeLimitedFileFactoryImpl(), logrotateFactory: LogrotateFactoryImpl())
|
||||||
}
|
}
|
||||||
|
|
||||||
init(fileURL: URL, fileSizeLimit: UInt64, rotations: Int, fileSystem: FileSystem, sizeLimitedFileFactory: SizeLimitedFileFactory, logrotateFactory: LogrotateFactory) {
|
init(fileURL: URL, fileSizeLimit: UInt64, rotations: Int, fileManager: OSFileManager, sizeLimitedFileFactory: SizeLimitedFileFactory, logrotateFactory: LogrotateFactory) {
|
||||||
self.fileURL = fileURL
|
self.fileURL = fileURL
|
||||||
self.fileSizeLimit = fileSizeLimit
|
self.fileSizeLimit = fileSizeLimit
|
||||||
self.rotations = rotations
|
self.rotations = rotations
|
||||||
self.fileSystem = fileSystem
|
self.fileManager = fileManager
|
||||||
self.sizeLimitedFileFactory = sizeLimitedFileFactory
|
self.sizeLimitedFileFactory = sizeLimitedFileFactory
|
||||||
self.logrotateFactory = logrotateFactory
|
self.logrotateFactory = logrotateFactory
|
||||||
formatter = DateFormatter()
|
formatter = DateFormatter()
|
||||||
|
@ -144,8 +113,8 @@ public final class DiskLogger: Logger {
|
||||||
|
|
||||||
private func openSizeLimitedFile() throws {
|
private func openSizeLimitedFile() throws {
|
||||||
guard sizeLimitedFile == nil else { return }
|
guard sizeLimitedFile == nil else { return }
|
||||||
if fileSystem.itemExists(at: fileURL) == false {
|
if fileManager.itemExists(at: fileURL) == false {
|
||||||
_ = fileSystem.createFile(at: fileURL)
|
_ = fileManager.createFile(at: fileURL)
|
||||||
}
|
}
|
||||||
sizeLimitedFile = try sizeLimitedFileFactory.makeInstance(fileURL: fileURL, fileSizeLimit: fileSizeLimit)
|
sizeLimitedFile = try sizeLimitedFileFactory.makeInstance(fileURL: fileURL, fileSizeLimit: fileSizeLimit)
|
||||||
}
|
}
|
||||||
|
@ -166,27 +135,20 @@ public final class DiskLogger: Logger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FileRotateFactory: LogrotateFactory {
|
private class LogrotateFactoryImpl: LogrotateFactory {
|
||||||
func makeInstance(fileURL: URL, rotations: Int) -> Logrotate {
|
func makeInstance(fileURL: URL, rotations: Int) -> Logrotate {
|
||||||
return FileRotate(fileURL: fileURL, rotations: rotations, fileSystem: FileManager.default)
|
return LogrotateImpl(fileURL: fileURL, rotations: rotations, fileManager: FileManager.default)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FileWriterFactory: SizeLimitedFileFactory {
|
private class SizeLimitedFileFactoryImpl: SizeLimitedFileFactory {
|
||||||
func makeInstance(fileURL: URL, fileSizeLimit: UInt64) throws -> SizeLimitedFile {
|
func makeInstance(fileURL: URL, fileSizeLimit: UInt64) throws -> SizeLimitedFile {
|
||||||
return try FileWriter(fileURL: fileURL, fileSizeLimit: fileSizeLimit, fileFactory: FileHandleFactory())
|
return try SizeLimitedFileImpl(fileURL: fileURL, fileSizeLimit: fileSizeLimit, fileFactory: FileHandleFactoryImpl())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FileHandleFactory: FileFactory {
|
private class FileHandleFactoryImpl: FileHandleFactory {
|
||||||
func makeInstance(forWritingTo: URL) throws -> File {
|
func makeInstance(forWritingTo: URL) throws -> OSFileHandle {
|
||||||
return try FileHandle(forWritingTo: forWritingTo)
|
return try FileHandle(forWritingTo: forWritingTo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FileHandle: File {
|
|
||||||
|
|
||||||
func swift_write(_ data: Data) throws {
|
|
||||||
try __write(data, error: ())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -24,26 +24,40 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
final class FileRotate {
|
/// Allows log files rotation.
|
||||||
|
protocol Logrotate {
|
||||||
|
|
||||||
|
/// Rotates log files `rotations` number of times.
|
||||||
|
///
|
||||||
|
/// First deletes file at `<fileURL>.<rotations>`.
|
||||||
|
/// Next moves files located at:
|
||||||
|
///
|
||||||
|
/// `<fileURL>, <fileURL>.1, <fileURL>.2 ... <fileURL>.<rotations - 1>`
|
||||||
|
///
|
||||||
|
/// to `<fileURL>.1, <fileURL>.2 ... <fileURL>.<rotations>`
|
||||||
|
func rotate() throws
|
||||||
|
}
|
||||||
|
|
||||||
|
final class LogrotateImpl {
|
||||||
|
|
||||||
private let fileURL: URL
|
private let fileURL: URL
|
||||||
private let rotations: Int
|
private let rotations: Int
|
||||||
private let fileSystem: FileSystem
|
private let fileManager: OSFileManager
|
||||||
|
|
||||||
/// Initializes new Logrotate instance.
|
/// Initializes new Logrotate instance.
|
||||||
///
|
///
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - fileURL: URL of the log file.
|
/// - fileURL: URL of the log file.
|
||||||
/// - rotations: Number of times log files are rotated before being removed.
|
/// - rotations: Number of times log files are rotated before being removed.
|
||||||
init(fileURL: URL, rotations: Int, fileSystem: FileSystem) {
|
init(fileURL: URL, rotations: Int, fileManager: OSFileManager) {
|
||||||
precondition(rotations > 0)
|
precondition(rotations > 0)
|
||||||
self.fileURL = fileURL
|
self.fileURL = fileURL
|
||||||
self.rotations = rotations
|
self.rotations = rotations
|
||||||
self.fileSystem = fileSystem
|
self.fileManager = fileManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FileRotate: Logrotate {
|
extension LogrotateImpl: Logrotate {
|
||||||
|
|
||||||
func rotate() throws {
|
func rotate() throws {
|
||||||
let range = 1...rotations
|
let range = 1...rotations
|
||||||
|
@ -54,12 +68,12 @@ extension FileRotate: Logrotate {
|
||||||
let toDelete = rotatedURLs.last!
|
let toDelete = rotatedURLs.last!
|
||||||
let toMove = zip(allURLs, rotatedURLs).reversed()
|
let toMove = zip(allURLs, rotatedURLs).reversed()
|
||||||
|
|
||||||
if fileSystem.itemExists(at: toDelete) {
|
if fileManager.itemExists(at: toDelete) {
|
||||||
try fileSystem.removeItem(at: toDelete)
|
try fileManager.removeItem(at: toDelete)
|
||||||
}
|
}
|
||||||
for (oldURL, newURL) in toMove {
|
for (oldURL, newURL) in toMove {
|
||||||
guard fileSystem.itemExists(at: oldURL) else { continue }
|
guard fileManager.itemExists(at: oldURL) else { continue }
|
||||||
try fileSystem.moveItem(at: oldURL, to: newURL)
|
try fileManager.moveItem(at: oldURL, to: newURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
23
Logger/Loggers/DiskLogger/OSFileHandle.swift
Normal file
23
Logger/Loggers/DiskLogger/OSFileHandle.swift
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//
|
||||||
|
// OSFileHandle.swift
|
||||||
|
// Logger
|
||||||
|
//
|
||||||
|
// Created by Wojciech Nagrodzki on 30/10/2019.
|
||||||
|
// Copyright © 2019 Wojciech Nagrodzki. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
protocol OSFileHandle {
|
||||||
|
func seekToEndOfFile() -> UInt64
|
||||||
|
func swift_write(_ data: Data) throws
|
||||||
|
func synchronizeFile()
|
||||||
|
func closeFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FileHandle: OSFileHandle {
|
||||||
|
|
||||||
|
func swift_write(_ data: Data) throws {
|
||||||
|
try __write(data, error: ())
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,14 +24,14 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public protocol FileSystem {
|
public protocol OSFileManager {
|
||||||
func itemExists(at URL: URL) -> Bool
|
func itemExists(at URL: URL) -> Bool
|
||||||
func removeItem(at URL: URL) throws
|
func removeItem(at URL: URL) throws
|
||||||
func moveItem(at srcURL: URL, to dstURL: URL) throws
|
func moveItem(at srcURL: URL, to dstURL: URL) throws
|
||||||
func createFile(at URL: URL) -> Bool
|
func createFile(at URL: URL) -> Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FileManager: FileSystem {
|
extension FileManager: OSFileManager {
|
||||||
|
|
||||||
public func itemExists(at URL: URL) -> Bool {
|
public func itemExists(at URL: URL) -> Bool {
|
||||||
return fileExists(atPath: URL.path)
|
return fileExists(atPath: URL.path)
|
|
@ -24,38 +24,48 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
protocol File {
|
protocol FileHandleFactory {
|
||||||
func seekToEndOfFile() -> UInt64
|
func makeInstance(forWritingTo: URL) throws -> OSFileHandle
|
||||||
func swift_write(_ data: Data) throws
|
|
||||||
func synchronizeFile()
|
|
||||||
func closeFile()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol FileFactory {
|
/// Write failed as allowed size limit would be exceeded.
|
||||||
func makeInstance(forWritingTo: URL) throws -> File
|
public struct SizeLimitedFileQuotaReached: Error {}
|
||||||
|
|
||||||
|
/// Allows writing to a file while respecting allowed size limit.
|
||||||
|
protocol SizeLimitedFile {
|
||||||
|
|
||||||
|
/// Synchronously writes `data` at the end of the file.
|
||||||
|
///
|
||||||
|
/// - Parameter data: The data to be written.
|
||||||
|
/// - Throws: Throws an error if no free space is left on the file system, or if any other writing error occurs.
|
||||||
|
/// Throws `SizeLimitedFileQuotaReached` if allowed size limit would be exceeded.
|
||||||
|
func write(_ data: Data) throws
|
||||||
|
|
||||||
|
/// Writes all in-memory data to permanent storage and closes the file.
|
||||||
|
func synchronizeAndCloseFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows writing to a file while respecting allowed size limit.
|
/// Allows writing to a file while respecting allowed size limit.
|
||||||
final class FileWriter {
|
final class SizeLimitedFileImpl {
|
||||||
|
|
||||||
private let file: File
|
private let file: OSFileHandle
|
||||||
private let sizeLimit: UInt64
|
private let sizeLimit: UInt64
|
||||||
private var currentSize: UInt64
|
private var currentSize: UInt64
|
||||||
|
|
||||||
/// Initializes new FileWriter instance.
|
/// Initializes new SizeLimitedFileImpl instance.
|
||||||
///
|
///
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - fileURL: URL of the file.
|
/// - fileURL: URL of the file.
|
||||||
/// - fileSizeLimit: Maximum size the file can reach in bytes.
|
/// - fileSizeLimit: Maximum size the file can reach in bytes.
|
||||||
/// - Throws: An error that may occur while the file is being opened for writing.
|
/// - Throws: An error that may occur while the file is being opened for writing.
|
||||||
init(fileURL: URL, fileSizeLimit: UInt64, fileFactory: FileFactory) throws {
|
init(fileURL: URL, fileSizeLimit: UInt64, fileFactory: FileHandleFactory) throws {
|
||||||
file = try fileFactory.makeInstance(forWritingTo: fileURL)
|
file = try fileFactory.makeInstance(forWritingTo: fileURL)
|
||||||
self.sizeLimit = fileSizeLimit
|
self.sizeLimit = fileSizeLimit
|
||||||
currentSize = file.seekToEndOfFile()
|
currentSize = file.seekToEndOfFile()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FileWriter: SizeLimitedFile {
|
extension SizeLimitedFileImpl: SizeLimitedFile {
|
||||||
|
|
||||||
func write(_ data: Data) throws {
|
func write(_ data: Data) throws {
|
||||||
let dataSize = UInt64(data.count)
|
let dataSize = UInt64(data.count)
|
|
@ -33,13 +33,13 @@ class DiskLoggerTests: XCTestCase {
|
||||||
let expectation = XCTestExpectation(description: "write(_:) was called on SizeLimitedFile")
|
let expectation = XCTestExpectation(description: "write(_:) was called on SizeLimitedFile")
|
||||||
expectation.expectedFulfillmentCount = 1
|
expectation.expectedFulfillmentCount = 1
|
||||||
|
|
||||||
let filesystem = FileSystemStub()
|
let fimeManager = FileManagerStub()
|
||||||
let sizeLimitedFileFactory = SizeLimitedFileMockFactory(writeCall: expectation)
|
let sizeLimitedFileFactory = SizeLimitedFileMockFactory(writeCall: expectation)
|
||||||
let logrotateFactory = LogrotateMockFactory()
|
let logrotateFactory = LogrotateMockFactory()
|
||||||
let logger = DiskLogger(fileURL: logURL,
|
let logger = DiskLogger(fileURL: logURL,
|
||||||
fileSizeLimit: 1024,
|
fileSizeLimit: 1024,
|
||||||
rotations: 1,
|
rotations: 1,
|
||||||
fileSystem: filesystem,
|
fileManager: fimeManager,
|
||||||
sizeLimitedFileFactory: sizeLimitedFileFactory,
|
sizeLimitedFileFactory: sizeLimitedFileFactory,
|
||||||
logrotateFactory: logrotateFactory)
|
logrotateFactory: logrotateFactory)
|
||||||
|
|
||||||
|
@ -61,13 +61,13 @@ class DiskLoggerTests: XCTestCase {
|
||||||
let expectation = XCTestExpectation(description: "write(_:) was called on SizeLimitedFile")
|
let expectation = XCTestExpectation(description: "write(_:) was called on SizeLimitedFile")
|
||||||
expectation.expectedFulfillmentCount = 2
|
expectation.expectedFulfillmentCount = 2
|
||||||
|
|
||||||
let filesystem = FileSystemStub()
|
let fimeManager = FileManagerStub()
|
||||||
let sizeLimitedFileFactory = SizeLimitedFileMockFactory(writeCall: expectation)
|
let sizeLimitedFileFactory = SizeLimitedFileMockFactory(writeCall: expectation)
|
||||||
let logrotateFactory = LogrotateMockFactory()
|
let logrotateFactory = LogrotateMockFactory()
|
||||||
let logger = DiskLogger(fileURL: logURL,
|
let logger = DiskLogger(fileURL: logURL,
|
||||||
fileSizeLimit: 91,
|
fileSizeLimit: 91,
|
||||||
rotations: 1,
|
rotations: 1,
|
||||||
fileSystem: filesystem,
|
fileManager: fimeManager,
|
||||||
sizeLimitedFileFactory: sizeLimitedFileFactory,
|
sizeLimitedFileFactory: sizeLimitedFileFactory,
|
||||||
logrotateFactory: logrotateFactory)
|
logrotateFactory: logrotateFactory)
|
||||||
|
|
||||||
|
@ -90,13 +90,13 @@ class DiskLoggerTests: XCTestCase {
|
||||||
let expectation = XCTestExpectation(description: "write(_:) was called on SizeLimitedFile")
|
let expectation = XCTestExpectation(description: "write(_:) was called on SizeLimitedFile")
|
||||||
expectation.expectedFulfillmentCount = 2
|
expectation.expectedFulfillmentCount = 2
|
||||||
|
|
||||||
let filesystem = FileSystemStub()
|
let fimeManager = FileManagerStub()
|
||||||
let sizeLimitedFileFactory = UnwritableFileStubFactory(writeCall: expectation)
|
let sizeLimitedFileFactory = UnwritableFileStubFactory(writeCall: expectation)
|
||||||
let logrotateFactory = LogrotateMockFactory()
|
let logrotateFactory = LogrotateMockFactory()
|
||||||
let logger = DiskLogger(fileURL: logURL,
|
let logger = DiskLogger(fileURL: logURL,
|
||||||
fileSizeLimit: 91,
|
fileSizeLimit: 91,
|
||||||
rotations: 1,
|
rotations: 1,
|
||||||
fileSystem: filesystem,
|
fileManager: fimeManager,
|
||||||
sizeLimitedFileFactory: sizeLimitedFileFactory,
|
sizeLimitedFileFactory: sizeLimitedFileFactory,
|
||||||
logrotateFactory: logrotateFactory)
|
logrotateFactory: logrotateFactory)
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ class DiskLoggerTests: XCTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FileSystemStub: FileSystem {
|
private class FileManagerStub: OSFileManager {
|
||||||
func itemExists(at URL: URL) -> Bool {
|
func itemExists(at URL: URL) -> Bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import Logger
|
@testable import Logger
|
||||||
|
|
||||||
class FileRotateTests: XCTestCase {
|
class LogrotateTests: XCTestCase {
|
||||||
|
|
||||||
let logURL = URL(fileURLWithPath: "/var/log/application.log")
|
let logURL = URL(fileURLWithPath: "/var/log/application.log")
|
||||||
let log1URL = URL(fileURLWithPath: "/var/log/application.log.1")
|
let log1URL = URL(fileURLWithPath: "/var/log/application.log.1")
|
||||||
|
@ -33,98 +33,98 @@ class FileRotateTests: XCTestCase {
|
||||||
let log3URL = URL(fileURLWithPath: "/var/log/application.log.3")
|
let log3URL = URL(fileURLWithPath: "/var/log/application.log.3")
|
||||||
|
|
||||||
func test_1rotation_0files() {
|
func test_1rotation_0files() {
|
||||||
let fileSystem = FileSystemMock(files: [])
|
let fimeManager = FileManagerMock(files: [])
|
||||||
let logrotate = FileRotate(fileURL: logURL, rotations: 1, fileSystem: fileSystem)
|
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 1, fileManager: fimeManager)
|
||||||
try? logrotate.rotate()
|
try? logrotate.rotate()
|
||||||
|
|
||||||
let actual = fileSystem.files
|
let actual = fimeManager.files
|
||||||
let expected = Set<URL>()
|
let expected = Set<URL>()
|
||||||
XCTAssertEqual(actual, expected)
|
XCTAssertEqual(actual, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_1rotation_1file() {
|
func test_1rotation_1file() {
|
||||||
let fileSystem = FileSystemMock(files: [logURL])
|
let fimeManager = FileManagerMock(files: [logURL])
|
||||||
let logrotate = FileRotate(fileURL: logURL, rotations: 1, fileSystem: fileSystem)
|
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 1, fileManager: fimeManager)
|
||||||
try? logrotate.rotate()
|
try? logrotate.rotate()
|
||||||
|
|
||||||
let actual = fileSystem.files
|
let actual = fimeManager.files
|
||||||
let expected = Set<URL>([log1URL])
|
let expected = Set<URL>([log1URL])
|
||||||
XCTAssertEqual(actual, expected)
|
XCTAssertEqual(actual, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_1rotation_2files() {
|
func test_1rotation_2files() {
|
||||||
let fileSystem = FileSystemMock(files: [logURL, log1URL])
|
let fimeManager = FileManagerMock(files: [logURL, log1URL])
|
||||||
let logrotate = FileRotate(fileURL: logURL, rotations: 1, fileSystem: fileSystem)
|
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 1, fileManager: fimeManager)
|
||||||
try? logrotate.rotate()
|
try? logrotate.rotate()
|
||||||
|
|
||||||
let actual = fileSystem.files
|
let actual = fimeManager.files
|
||||||
let expected = Set<URL>([log1URL])
|
let expected = Set<URL>([log1URL])
|
||||||
XCTAssertEqual(actual, expected)
|
XCTAssertEqual(actual, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_1rotation_3files() {
|
func test_1rotation_3files() {
|
||||||
let fileSystem = FileSystemMock(files: [logURL, log1URL, log2URL])
|
let fimeManager = FileManagerMock(files: [logURL, log1URL, log2URL])
|
||||||
let logrotate = FileRotate(fileURL: logURL, rotations: 1, fileSystem: fileSystem)
|
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 1, fileManager: fimeManager)
|
||||||
try? logrotate.rotate()
|
try? logrotate.rotate()
|
||||||
|
|
||||||
let actual = fileSystem.files
|
let actual = fimeManager.files
|
||||||
let expected = Set<URL>([log1URL, log2URL])
|
let expected = Set<URL>([log1URL, log2URL])
|
||||||
XCTAssertEqual(actual, expected)
|
XCTAssertEqual(actual, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_2rotations_0files() {
|
func test_2rotations_0files() {
|
||||||
let fileSystem = FileSystemMock(files: [])
|
let fimeManager = FileManagerMock(files: [])
|
||||||
let logrotate = FileRotate(fileURL: logURL, rotations: 2, fileSystem: fileSystem)
|
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 2, fileManager: fimeManager)
|
||||||
try? logrotate.rotate()
|
try? logrotate.rotate()
|
||||||
|
|
||||||
let actual = fileSystem.files
|
let actual = fimeManager.files
|
||||||
let expected = Set<URL>()
|
let expected = Set<URL>()
|
||||||
XCTAssertEqual(actual, expected)
|
XCTAssertEqual(actual, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_2rotations_1file() {
|
func test_2rotations_1file() {
|
||||||
let fileSystem = FileSystemMock(files: [logURL])
|
let fimeManager = FileManagerMock(files: [logURL])
|
||||||
let logrotate = FileRotate(fileURL: logURL, rotations: 2, fileSystem: fileSystem)
|
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 2, fileManager: fimeManager)
|
||||||
try? logrotate.rotate()
|
try? logrotate.rotate()
|
||||||
|
|
||||||
let actual = fileSystem.files
|
let actual = fimeManager.files
|
||||||
let expected = Set<URL>([log1URL])
|
let expected = Set<URL>([log1URL])
|
||||||
XCTAssertEqual(actual, expected)
|
XCTAssertEqual(actual, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_2rotations_2files() {
|
func test_2rotations_2files() {
|
||||||
let fileSystem = FileSystemMock(files: [logURL, log1URL])
|
let fimeManager = FileManagerMock(files: [logURL, log1URL])
|
||||||
let logrotate = FileRotate(fileURL: logURL, rotations: 2, fileSystem: fileSystem)
|
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 2, fileManager: fimeManager)
|
||||||
try? logrotate.rotate()
|
try? logrotate.rotate()
|
||||||
|
|
||||||
let actual = fileSystem.files
|
let actual = fimeManager.files
|
||||||
let expected = Set<URL>([log1URL, log2URL])
|
let expected = Set<URL>([log1URL, log2URL])
|
||||||
XCTAssertEqual(actual, expected)
|
XCTAssertEqual(actual, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_2rotations_3files() {
|
func test_2rotations_3files() {
|
||||||
let fileSystem = FileSystemMock(files: [logURL, log1URL, log2URL])
|
let fimeManager = FileManagerMock(files: [logURL, log1URL, log2URL])
|
||||||
let logrotate = FileRotate(fileURL: logURL, rotations: 2, fileSystem: fileSystem)
|
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 2, fileManager: fimeManager)
|
||||||
try? logrotate.rotate()
|
try? logrotate.rotate()
|
||||||
|
|
||||||
let actual = fileSystem.files
|
let actual = fimeManager.files
|
||||||
let expected = Set<URL>([log1URL, log2URL])
|
let expected = Set<URL>([log1URL, log2URL])
|
||||||
XCTAssertEqual(actual, expected)
|
XCTAssertEqual(actual, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_2rotations_4files() {
|
func test_2rotations_4files() {
|
||||||
let fileSystem = FileSystemMock(files: [logURL, log1URL, log2URL, log3URL])
|
let fimeManager = FileManagerMock(files: [logURL, log1URL, log2URL, log3URL])
|
||||||
let logrotate = FileRotate(fileURL: logURL, rotations: 2, fileSystem: fileSystem)
|
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 2, fileManager: fimeManager)
|
||||||
try? logrotate.rotate()
|
try? logrotate.rotate()
|
||||||
|
|
||||||
let actual = fileSystem.files
|
let actual = fimeManager.files
|
||||||
let expected = Set<URL>([log1URL, log2URL, log3URL])
|
let expected = Set<URL>([log1URL, log2URL, log3URL])
|
||||||
XCTAssertEqual(actual, expected)
|
XCTAssertEqual(actual, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testErrorPropagation() {
|
func testErrorPropagation() {
|
||||||
let fileSystem = BrokenFileSystem()
|
let fimeManager = BrokenFileSystem()
|
||||||
let logrotate = FileRotate(fileURL: logURL, rotations: 1, fileSystem: fileSystem)
|
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 1, fileManager: fimeManager)
|
||||||
|
|
||||||
XCTAssertThrowsError(try logrotate.rotate(), "An error when removing or moving an item") { (error) in
|
XCTAssertThrowsError(try logrotate.rotate(), "An error when removing or moving an item") { (error) in
|
||||||
XCTAssertTrue(error is BrokenFileSystem.IOError)
|
XCTAssertTrue(error is BrokenFileSystem.IOError)
|
||||||
|
@ -132,7 +132,7 @@ class FileRotateTests: XCTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FileSystemMock: FileSystem {
|
private class FileManagerMock: OSFileManager {
|
||||||
|
|
||||||
private(set) var files = Set<URL>()
|
private(set) var files = Set<URL>()
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ private class FileSystemMock: FileSystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BrokenFileSystem: FileSystem {
|
private class BrokenFileSystem: OSFileManager {
|
||||||
|
|
||||||
struct IOError: Error { }
|
struct IOError: Error { }
|
||||||
|
|
|
@ -25,20 +25,20 @@
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import Logger
|
@testable import Logger
|
||||||
|
|
||||||
class FileWriterTests: XCTestCase {
|
class SizeLimitedFileTests: XCTestCase {
|
||||||
|
|
||||||
let logURL = URL(fileURLWithPath: "/var/log/application.log")
|
let logURL = URL(fileURLWithPath: "/var/log/application.log")
|
||||||
|
|
||||||
func testFileOpeningFailure() {
|
func testFileOpeningFailure() {
|
||||||
let factory = UnopenableFileFactory()
|
let factory = UnopenableFileFactory()
|
||||||
XCTAssertThrowsError(try FileWriter(fileURL: logURL, fileSizeLimit: 0, fileFactory: factory), "file open failure") { (error) in
|
XCTAssertThrowsError(try SizeLimitedFileImpl(fileURL: logURL, fileSizeLimit: 0, fileFactory: factory), "file open failure") { (error) in
|
||||||
XCTAssertTrue(error is UnopenableFileFactory.OpenFileError)
|
XCTAssertTrue(error is UnopenableFileFactory.OpenFileError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testKeepingFileSizeLimit() throws {
|
func testKeepingFileSizeLimit() throws {
|
||||||
let factory = FileMockFactory()
|
let factory = FileMockFactory()
|
||||||
let writer = try FileWriter(fileURL: logURL, fileSizeLimit: 1, fileFactory: factory)
|
let writer = try SizeLimitedFileImpl(fileURL: logURL, fileSizeLimit: 1, fileFactory: factory)
|
||||||
let data = Data([0])
|
let data = Data([0])
|
||||||
try writer.write(data)
|
try writer.write(data)
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class FileWriterTests: XCTestCase {
|
||||||
|
|
||||||
func testExceedingFileSizeLimit() throws {
|
func testExceedingFileSizeLimit() throws {
|
||||||
let factory = FileMockFactory()
|
let factory = FileMockFactory()
|
||||||
let writer = try FileWriter(fileURL: logURL, fileSizeLimit: 1, fileFactory: factory)
|
let writer = try SizeLimitedFileImpl(fileURL: logURL, fileSizeLimit: 1, fileFactory: factory)
|
||||||
let data = Data([0, 0])
|
let data = Data([0, 0])
|
||||||
|
|
||||||
XCTAssertThrowsError(try writer.write(data), "file size limit exceeded") { (error) in
|
XCTAssertThrowsError(try writer.write(data), "file size limit exceeded") { (error) in
|
||||||
|
@ -59,31 +59,31 @@ class FileWriterTests: XCTestCase {
|
||||||
|
|
||||||
func testSynchronizingAndClosingFile() throws {
|
func testSynchronizingAndClosingFile() throws {
|
||||||
let factory = FileMockFactory()
|
let factory = FileMockFactory()
|
||||||
let writer = try FileWriter(fileURL: logURL, fileSizeLimit: 1, fileFactory: factory)
|
let writer = try SizeLimitedFileImpl(fileURL: logURL, fileSizeLimit: 1, fileFactory: factory)
|
||||||
writer.synchronizeAndCloseFile()
|
writer.synchronizeAndCloseFile()
|
||||||
XCTAssertTrue(factory.mock.synchronizeFileCallCount == 1 && factory.mock.closeFileCallCount == 1)
|
XCTAssertTrue(factory.mock.synchronizeFileCallCount == 1 && factory.mock.closeFileCallCount == 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class UnopenableFileFactory: FileFactory {
|
private class UnopenableFileFactory: FileHandleFactory {
|
||||||
|
|
||||||
struct OpenFileError: Error {}
|
struct OpenFileError: Error {}
|
||||||
|
|
||||||
func makeInstance(forWritingTo: URL) throws -> File {
|
func makeInstance(forWritingTo: URL) throws -> OSFileHandle {
|
||||||
throw OpenFileError()
|
throw OpenFileError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FileMockFactory: FileFactory {
|
private class FileMockFactory: FileHandleFactory {
|
||||||
|
|
||||||
let mock = FileMock()
|
let mock = FileMock()
|
||||||
|
|
||||||
func makeInstance(forWritingTo: URL) throws -> File {
|
func makeInstance(forWritingTo: URL) throws -> OSFileHandle {
|
||||||
return mock
|
return mock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FileMock: File {
|
private class FileMock: OSFileHandle {
|
||||||
|
|
||||||
private(set) var writtenData = Data()
|
private(set) var writtenData = Data()
|
||||||
private(set) var synchronizeFileCallCount = 0
|
private(set) var synchronizeFileCallCount = 0
|
Loading…
Add table
Reference in a new issue