2026-06-04 02:29:23 -07:00
|
|
|
@testable import ForgejoKit
|
2026-02-28 11:10:51 -08:00
|
|
|
import Foundation
|
|
|
|
|
import Testing
|
|
|
|
|
|
|
|
|
|
struct URLSessionManagerTests {
|
|
|
|
|
// MARK: - trustedHost scoping
|
|
|
|
|
|
|
|
|
|
@Test func selfSignedWithoutTrustedHostAcceptsAny() {
|
|
|
|
|
let manager = URLSessionManager(allowSelfSignedCertificates: true, trustedHost: nil)
|
|
|
|
|
#expect(manager.allowSelfSignedCertificates == true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test func selfSignedWithTrustedHostIsSet() {
|
|
|
|
|
let manager = URLSessionManager(allowSelfSignedCertificates: true, trustedHost: "forgejo.example.com")
|
|
|
|
|
#expect(manager.allowSelfSignedCertificates == true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test func selfSignedDisabledByDefault() {
|
|
|
|
|
let manager = URLSessionManager()
|
|
|
|
|
#expect(manager.allowSelfSignedCertificates == false)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test func sessionIsCreatedWithConfiguration() {
|
|
|
|
|
let manager = URLSessionManager(allowSelfSignedCertificates: false)
|
|
|
|
|
let session = manager.session
|
|
|
|
|
#expect(session.configuration.timeoutIntervalForRequest == 30)
|
|
|
|
|
#expect(session.configuration.timeoutIntervalForResource == 300)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: - Trust disposition logic
|
|
|
|
|
|
|
|
|
|
@Test func selfSignedDisabledReturnsDefaultHandling() {
|
|
|
|
|
let manager = URLSessionManager(allowSelfSignedCertificates: false)
|
|
|
|
|
let disposition = manager.trustDisposition(for: "forgejo.example.com")
|
|
|
|
|
#expect(disposition == .performDefaultHandling)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test func selfSignedEnabledWithNilTrustedHostReturnsDefaultHandling() {
|
|
|
|
|
let manager = URLSessionManager(allowSelfSignedCertificates: true, trustedHost: nil)
|
|
|
|
|
let disposition = manager.trustDisposition(for: "forgejo.example.com")
|
|
|
|
|
#expect(disposition == .performDefaultHandling)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test func selfSignedEnabledWithMatchingHostReturnsUseCredential() {
|
|
|
|
|
let manager = URLSessionManager(allowSelfSignedCertificates: true, trustedHost: "forgejo.example.com")
|
|
|
|
|
let disposition = manager.trustDisposition(for: "forgejo.example.com")
|
|
|
|
|
#expect(disposition == .useCredential)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test func selfSignedEnabledWithMismatchedHostReturnsDefaultHandling() {
|
|
|
|
|
let manager = URLSessionManager(allowSelfSignedCertificates: true, trustedHost: "forgejo.example.com")
|
|
|
|
|
let disposition = manager.trustDisposition(for: "evil.example.com")
|
|
|
|
|
#expect(disposition == .performDefaultHandling)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test func selfSignedTrustMatchesCaseInsensitive() {
|
|
|
|
|
let manager = URLSessionManager(allowSelfSignedCertificates: true, trustedHost: "Forgejo.Example.COM")
|
|
|
|
|
let disposition = manager.trustDisposition(for: "forgejo.example.com")
|
|
|
|
|
#expect(disposition == .useCredential)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ForgejoClientHostMatchTests {
|
|
|
|
|
// MARK: - Auth header host matching
|
|
|
|
|
|
2026-06-04 02:29:23 -07:00
|
|
|
@Test func authenticatedRequestIncludesAuthForMatchingHost() throws {
|
2026-02-28 11:10:51 -08:00
|
|
|
let client = ForgejoClient(
|
|
|
|
|
serverURL: "https://forgejo.example.com",
|
|
|
|
|
username: "user",
|
2026-06-04 02:29:23 -07:00
|
|
|
password: "pass",
|
2026-02-28 11:10:51 -08:00
|
|
|
)
|
2026-06-04 02:29:23 -07:00
|
|
|
let url = try #require(URL(string: "https://forgejo.example.com/api/v1/user"))
|
2026-02-28 11:10:51 -08:00
|
|
|
let request = client.authenticatedRequest(url: url)
|
|
|
|
|
#expect(request.value(forHTTPHeaderField: "Authorization") != nil)
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-04 02:29:23 -07:00
|
|
|
@Test func authenticatedRequestOmitsAuthForDifferentHost() throws {
|
2026-02-28 11:10:51 -08:00
|
|
|
let client = ForgejoClient(
|
|
|
|
|
serverURL: "https://forgejo.example.com",
|
|
|
|
|
username: "user",
|
2026-06-04 02:29:23 -07:00
|
|
|
password: "pass",
|
2026-02-28 11:10:51 -08:00
|
|
|
)
|
2026-06-04 02:29:23 -07:00
|
|
|
let url = try #require(URL(string: "https://evil.example.com/api/v1/user"))
|
2026-02-28 11:10:51 -08:00
|
|
|
let request = client.authenticatedRequest(url: url)
|
|
|
|
|
#expect(request.value(forHTTPHeaderField: "Authorization") == nil)
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-04 02:29:23 -07:00
|
|
|
@Test func authenticatedRequestMatchesCaseInsensitiveHost() throws {
|
2026-02-28 11:10:51 -08:00
|
|
|
let client = ForgejoClient(
|
|
|
|
|
serverURL: "https://Forgejo.Example.COM",
|
|
|
|
|
username: "user",
|
2026-06-04 02:29:23 -07:00
|
|
|
password: "pass",
|
2026-02-28 11:10:51 -08:00
|
|
|
)
|
2026-06-04 02:29:23 -07:00
|
|
|
let url = try #require(URL(string: "https://forgejo.example.com/api/v1/repos"))
|
2026-02-28 11:10:51 -08:00
|
|
|
let request = client.authenticatedRequest(url: url)
|
|
|
|
|
#expect(request.value(forHTTPHeaderField: "Authorization") != nil)
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-04 02:29:23 -07:00
|
|
|
@Test func authenticatedRequestSetsMethodAndBody() throws {
|
2026-02-28 11:10:51 -08:00
|
|
|
let client = ForgejoClient(
|
|
|
|
|
serverURL: "https://forgejo.example.com",
|
|
|
|
|
username: "user",
|
2026-06-04 02:29:23 -07:00
|
|
|
password: "pass",
|
2026-02-28 11:10:51 -08:00
|
|
|
)
|
2026-06-04 02:29:23 -07:00
|
|
|
let url = try #require(URL(string: "https://forgejo.example.com/api/v1/repos"))
|
2026-02-28 11:10:51 -08:00
|
|
|
let body = Data("{\"name\":\"test\"}".utf8)
|
|
|
|
|
let request = client.authenticatedRequest(url: url, method: "POST", body: body)
|
|
|
|
|
#expect(request.httpMethod == "POST")
|
|
|
|
|
#expect(request.httpBody == body)
|
|
|
|
|
#expect(request.value(forHTTPHeaderField: "Content-Type") == "application/json")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test func makeURLConstructsValidURL() throws {
|
|
|
|
|
let client = ForgejoClient(
|
|
|
|
|
serverURL: "https://forgejo.example.com",
|
|
|
|
|
username: "user",
|
2026-06-04 02:29:23 -07:00
|
|
|
password: "pass",
|
2026-02-28 11:10:51 -08:00
|
|
|
)
|
|
|
|
|
let url = try client.makeURL(path: "/api/v1/user")
|
|
|
|
|
#expect(url.absoluteString == "https://forgejo.example.com/api/v1/user")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test func makeURLWithQueryItems() throws {
|
|
|
|
|
let client = ForgejoClient(
|
|
|
|
|
serverURL: "https://forgejo.example.com",
|
|
|
|
|
username: "user",
|
2026-06-04 02:29:23 -07:00
|
|
|
password: "pass",
|
2026-02-28 11:10:51 -08:00
|
|
|
)
|
|
|
|
|
let url = try client.makeURL(path: "/api/v1/repos/search", queryItems: [
|
|
|
|
|
URLQueryItem(name: "q", value: "test"),
|
2026-06-04 02:29:23 -07:00
|
|
|
URLQueryItem(name: "page", value: "2"),
|
2026-02-28 11:10:51 -08:00
|
|
|
])
|
|
|
|
|
#expect(url.absoluteString.contains("q=test"))
|
|
|
|
|
#expect(url.absoluteString.contains("page=2"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test func clientExtractsHostForTrustedCert() {
|
|
|
|
|
// Verify that the client passes the right host to URLSessionManager
|
|
|
|
|
let client = ForgejoClient(
|
|
|
|
|
serverURL: "https://my-forgejo.local:3000",
|
|
|
|
|
username: "user",
|
|
|
|
|
password: "pass",
|
2026-06-04 02:29:23 -07:00
|
|
|
allowSelfSignedCertificates: true,
|
2026-02-28 11:10:51 -08:00
|
|
|
)
|
|
|
|
|
// The session should be created with self-signed support
|
|
|
|
|
#expect(client.serverURL == "https://my-forgejo.local:3000")
|
|
|
|
|
}
|
|
|
|
|
}
|