@testable import SampleApp import ManageableUsers import VaporTesting import SQLKit import Testing @Suite("App Tests", .serialized) struct AuthorizationTests { private func withApp(_ test: (Application) async throws -> ()) async throws { let app = try await Application.make (.testing) do { setenv ("BASE_URL", "http://localhost", 0) setenv ("EMAIL_SENDER", "nobody@example.com", 0) try await SampleApp.configure (app) let mockDatabase = MockDatabase (eventLoop: app.eventLoopGroup.next()) app.storage[Application.MockDatabaseKey.self] = mockDatabase try await test (app) } catch { try await app.asyncShutdown() throw error } try await app.asyncShutdown() } @Test("Test login redirect") func loginRedirect() async throws { try await withApp { app in try await app.testing().test(.GET, "", afterResponse: { res async in #expect(res.status == .seeOther) #expect(res.headers["Location"] == ["auth/login"]) }) } } @Test("Test login form") func loginForm() async throws { try await withApp { app in try await app.testing().test(.GET, "auth/login", afterResponse: { res async in #expect(res.status == .ok) }) } } @Test("Invalid login") func invalidLogin() async throws { try await withApp { app in app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: ["id": UUID(), "email": "gamma", "full_name": "delta", "password": "$2b$12$4bg4BftSpYAHiQsWjjqj2uZlw.LHbSWUsXA4gBL7njnvONYelCNFC", "active": true, "roles": ["admin"]])]) try await app.testing().test( .POST, "api/auth/login", beforeRequest: { request async in request.headers.contentType = .json request.body = ByteBuffer (string: #"{"email": "foo", "password": "bar"}"#) }, afterResponse: { res async in #expect(res.status == .unauthorized) #expect(res.headers["Location"].isEmpty) }) #expect(app.storage[Application.MockDatabaseKey.self]?.queries.count == 1) } } @Test("Valid login") func validLogin() async throws { try await withApp { app in var session: String? app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: ["id": UUID(), "email": "gamma", "full_name": "delta", "password": "$2b$12$4bg4BftSpYAHiQsWjjqj2uZlw.LHbSWUsXA4gBL7njnvONYelCNFC", "active": true, "roles": Array()])]) app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: ["id": UUID(), "email": "gamma", "full_name": "delta", "password": "$2b$12$4bg4BftSpYAHiQsWjjqj2uZlw.LHbSWUsXA4gBL7njnvONYelCNFC", "active": true, "roles": Array()])]) try await app.testing().test( .POST, "api/auth/login", beforeRequest: { request async in request.headers.contentType = .json request.body = ByteBuffer (string: #"{"email": "gamma", "password": ""}"#) }, afterResponse: { res async in #expect(res.status == .ok) #expect(res.headers["Location"].isEmpty) #expect(res.headers.setCookie?["vapor-session"] != nil) session = res.headers.setCookie?["vapor-session"]?.string }) try await app.testing().test(.GET, "", beforeRequest: { request async in request.headers.cookie = ["vapor-session": HTTPCookies.Value (string: session ?? "")] }, afterResponse: { res async in #expect(res.status == .ok) #expect(res.headers.setCookie?["vapor-session"]?.string == session) }) #expect(app.storage[Application.MockDatabaseKey.self]?.queries.count == 2) } } @Test("Restricted route") func restrictedRoute() async throws { try await withApp { app in var session: String? app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: ["id": UUID(), "email": "gamma", "full_name": "delta", "password": "$2b$12$4bg4BftSpYAHiQsWjjqj2uZlw.LHbSWUsXA4gBL7njnvONYelCNFC", "active": true, "roles": Array()])]) app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: ["id": UUID(), "email": "gamma", "full_name": "delta", "password": "$2b$12$4bg4BftSpYAHiQsWjjqj2uZlw.LHbSWUsXA4gBL7njnvONYelCNFC", "active": true, "roles": Array()])]) try await app.testing().test( .POST, "api/auth/login", beforeRequest: { request async in request.headers.contentType = .json request.body = ByteBuffer (string: #"{"email": "gamma", "password": ""}"#) }, afterResponse: { res async in #expect(res.status == .ok) #expect(res.headers.setCookie?["vapor-session"] != nil) session = res.headers.setCookie?["vapor-session"]?.string }) try await app.testing().test(.GET, "admin", beforeRequest: { request async in request.headers.cookie = ["vapor-session": HTTPCookies.Value (string: session ?? "")] }, afterResponse: { res async in #expect(res.status == .seeOther) #expect(res.headers.setCookie?["vapor-session"]?.string == session) #expect(res.headers["Location"] == ["http://localhost:8080"]) }) #expect(app.storage[Application.MockDatabaseKey.self]?.queries.count == 2) } } @Test("Restricted authorized route") func restrictedAuthorizedRoute() async throws { try await withApp { app in var session: String? app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: ["id": UUID(), "email": "gamma", "full_name": "delta", "password": "$2b$12$4bg4BftSpYAHiQsWjjqj2uZlw.LHbSWUsXA4gBL7njnvONYelCNFC", "active": true, "roles": ["admin"]])]) app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: ["id": UUID(), "email": "gamma", "full_name": "delta", "password": "$2b$12$4bg4BftSpYAHiQsWjjqj2uZlw.LHbSWUsXA4gBL7njnvONYelCNFC", "active": true, "roles": ["admin"]])]) app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: ["name": "admin"])]) try await app.testing().test( .POST, "api/auth/login", beforeRequest: { request async in request.headers.contentType = .json request.body = ByteBuffer (string: #"{"email": "gamma", "password": ""}"#) }, afterResponse: { res async in #expect(res.status == .ok) #expect(res.headers.setCookie?["vapor-session"] != nil) session = res.headers.setCookie?["vapor-session"]?.string }) try await app.testing().test(.GET, "admin", beforeRequest: { request async in request.headers.cookie = ["vapor-session": HTTPCookies.Value (string: session ?? "")] }, afterResponse: { res async in #expect(res.status == .ok) #expect(res.headers.setCookie?["vapor-session"]?.string == session) }) #expect(app.storage[Application.MockDatabaseKey.self]?.queries.count == 3) } } @Test("Forgot password route") func forgotPasswordRoute() async throws { try await withApp { app in app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: [:])]) app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: ["id": UUID(), "email": "a@b", "full_name": "Somebody", "password": "", "active": true, "roles": [""]])]) app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: ["token": "füffe"])]) app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: [:])]) app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: [:])]) try await app.testing().test(.POST, "api/auth/forgot", beforeRequest: { request async throws in try request.content.encode (["email": "gamma"]) }, afterResponse: { res async in #expect(res.status == .ok) }) #expect(app.storage[Application.MockDatabaseKey.self]?.queries.count == 5) } } @Test("Forgot password route without account") func forgotPasswordRouteWithoutAccount() async throws { try await withApp { app in app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: [:])]) app.storage[Application.MockDatabaseKey.self]?.results.append ([]) app.storage[Application.MockDatabaseKey.self]?.results.append ([MockDatabase.Row (values: ["token": "füffe"])]) try await app.testing().test(.POST, "api/auth/forgot", beforeRequest: { request async throws in try request.content.encode (["email": "gamma"]) }, afterResponse: { res async in #expect(res.status == .ok) }) #expect(app.storage[Application.MockDatabaseKey.self]?.queries.count == 3) } } }