import Configuration import Infrastructure import Persistence import Testing @testable import Website @testable import WebsiteLibrary @Suite("ConfigReader properties") struct ConfigReaderPropertiesTests { // MARK: Functional tests @Test func `analytics to be omitted by default`() { // The template ships no website identifier, so an unconfigured deployment embeds no tracker at all. #expect(.Analytics.websiteID == "") #expect(reader().analytics == nil) } @Test func `analytics to be enabled by setting the website id alone`() throws { let analytics = try #require(reader(values: [ .Analytics.websiteID: "0000-website-id" ]).analytics) #expect(analytics.scriptURL == .Analytics.scriptURL) #expect(analytics.websiteID == "0000-website-id") #expect(analytics.domains.isEmpty) #expect(analytics.excludeHash) #expect(analytics.doNotTrack) #expect(analytics.performance) #expect(!analytics.recorder) } @Test func `analytics to switch recorder mode on when configured`() throws { // Session recording is the most invasive thing the tracker does, so it is opted into rather than out of. let analytics = try #require(reader(values: [ .Analytics.websiteID: "0000-website-id", .Analytics.recorder: true ]).analytics) #expect(analytics.recorder) } @Test func `analytics to override the website id and domains when configured`() throws { let analytics = try #require(reader(values: [ .Analytics.websiteID: "custom-website-id", .Analytics.domains: "staging.example.com" ]).analytics) #expect(analytics.websiteID == "custom-website-id") #expect(analytics.domains == "staging.example.com") #expect(analytics.scriptURL == .Analytics.scriptURL) } @Test func `analytics to be omitted when the website id is cleared`() { #expect(reader(values: [.Analytics.websiteID: ""]).analytics == nil) } @Test(arguments: [ "shared.css", "shared.js", "milker-400.woff2", "booth.mp4", "portrait.jpg", "portrait.webp" ]) func `cache control to mark the fingerprinted media immutable`( file: String ) throws { let header = try #require(reader().cacheControl.getCacheControlHeader(for: file)) #expect(header.contains("immutable")) } @Test(arguments: [ // The icons are exempt: a browser fetches `/favicon.ico` unversioned whatever the markup says, and the manifest names the PNGs. "favicon.ico", "icon-192.png", "icon.svg" ]) func `cache control to leave the unversioned images mutable`( file: String ) throws { let header = try #require(reader().cacheControl.getCacheControlHeader(for: file)) #expect(!header.contains("immutable")) } @Test func `cache control to have the unversioned text revalidate`() throws { let header = try #require(reader().cacheControl.getCacheControlHeader(for: "robots.txt")) #expect(header.contains("must-revalidate")) #expect(!header.contains("immutable")) } @Test func `driver to default to the in-memory database`() throws { guard case .inMemory = try reader().driver else { Issue.record("Expected the in-memory driver when 'database.driver' is unset.") return } } @Test func `driver to select postgres when configured`() throws { guard case .postgres = try reader(values: [.Database.driver: "postgres"]).driver else { Issue.record("Expected the postgres driver when 'database.driver' selects it.") return } } @Test func `driver to throw on an unknown token`() { // A silent fallback would run the deployment on the ephemeral database and discard every write on restart. #expect(throws: ConfigError.unknownDatabaseDriver("mariadb")) { _ = try reader(values: [.Database.driver: "mariadb"]).driver } } @Test(arguments: [ String.Database.tlsOff, String.Database.tlsPrefer, String.Database.tlsRequire ]) func `driver to accept a recognized tls token`(token: String) throws { let reader = reader(values: [ .Database.driver: .init(stringLiteral: .Database.driverPostgres), .Database.tls: .init(stringLiteral: token) ]) guard case .postgres = try reader.driver else { Issue.record("Expected the postgres driver for the '\(token)' TLS token.") return } } @Test func `driver to throw on an unknown tls token`() { // A silent fallback to `prefer` hands the password over in plaintext when the upgrade is stripped. #expect(throws: ConfigError.unknownDatabaseTLS("required")) { _ = try reader(values: [ .Database.driver: .init(stringLiteral: .Database.driverPostgres), .Database.tls: "required" ]).driver } } } // MARK: - Helpers private extension ConfigReaderPropertiesTests { // MARK: Methods /// Builds a configuration reader over the given in-memory values alone. func reader( values: [AbsoluteConfigKey: ConfigValue] = [:] ) -> ConfigReader { ConfigReader(providers: [ InMemoryProvider(values: values) ]) } }