Skip to content

Commit dc625ec

Browse files
committed
Implement tests
- Add unit tests - Add integration tests
1 parent 86d8aa0 commit dc625ec

41 files changed

Lines changed: 862 additions & 49 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Package.resolved

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ let package = Package(
1919
dependencies: [
2020
.package(url: "https://github.com/space-code/atomic", .upToNextMajor(from: "1.0.0")),
2121
.package(url: "https://github.com/space-code/typhoon", .upToNextMajor(from: "1.0.0")),
22+
.package(url: "https://github.com/WeTransfer/Mocker", .upToNextMajor(from: "3.0.1")),
2223
],
2324
targets: [
2425
.target(
@@ -39,7 +40,11 @@ let package = Package(
3940
name: "NetworkLayerTests",
4041
dependencies: [
4142
"NetworkLayer",
43+
.product(name: "Mocker", package: "Mocker"),
4244
.product(name: "Typhoon", package: "typhoon"),
45+
],
46+
resources: [
47+
.copy("Resources"),
4348
]
4449
),
4550
]

Package@swift-5.7.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ let package = Package(
1818
dependencies: [
1919
.package(url: "https://github.com/space-code/atomic", .upToNextMajor(from: "1.0.0")),
2020
.package(url: "https://github.com/space-code/typhoon", .upToNextMajor(from: "1.0.0")),
21+
.package(url: "https://github.com/WeTransfer/Mocker", .upToNextMajor(from: "3.0.1")),
2122
],
2223
targets: [
2324
.target(
@@ -30,13 +31,19 @@ let package = Package(
3031
),
3132
.target(
3233
name: "NetworkLayerInterfaces",
33-
dependencies: []
34+
dependencies: [
35+
.product(name: "Typhoon", package: "typhoon"),
36+
]
3437
),
3538
.testTarget(
3639
name: "NetworkLayerTests",
3740
dependencies: [
3841
"NetworkLayer",
42+
.product(name: "Mocker", package: "Mocker"),
3943
.product(name: "Typhoon", package: "typhoon"),
44+
],
45+
resources: [
46+
.copy("Resources"),
4047
]
4148
),
4249
]

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
<p align="center">
44
<a href="https://github.com/space-code/network-layer/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/github/license/space-code/network-layer?style=flat"></a>
5-
<a href="https://developer.apple.com/swift"><img alt="5.7" src="https://img.shields.io/badge/language-Swift5.7-orange.svg"/></a>
5+
<a href="https://swiftpackageindex.com/space-code/network-layer"><img alt="Swift Compability" src="https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fspace-code%2Fnetwork-layer%2Fbadge%3Ftype%3Dswift-versions"/></a>
6+
<a href="https://swiftpackageindex.com/space-code/network-layer"><img alt="Platform Compability" src="https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fspace-code%2Fnetwork-layer%2Fbadge%3Ftype%3Dplatforms"/></a>
67
<a href="https://github.com/space-code/network-layer"><img alt="CI" src="https://github.com/space-code/network-layer/actions/workflows/ci.yml/badge.svg?branch=main"></a>
78
<a href="https://github.com/apple/swift-package-manager" alt="network-layer on Swift Package Manager" title="network-layer on Swift Package Manager"><img src="https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg" /></a>
9+
<a href="https://codecov.io/gh/space-code/network-layer" > <img src="https://codecov.io/gh/space-code/network-layer/graph/badge.svg?token=lWsPUf5nPL"/></a>
810
</p>
911

1012
## Description
@@ -53,4 +55,4 @@ Please feel free to help out with this project! If you see something that could
5355
Nikita Vasilev, nv3212@gmail.com
5456

5557
## License
56-
network-layer is available under the MIT license. See the LICENSE file for more info.
58+
network-layer is available under the MIT license. See the LICENSE file for more info.

Sources/NetworkLayer/Classes/Core/Authentification/AuthenticatorInterceptor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public final class AuthenticatorInterceptor<Authenticator: IAuthenticator>: IAut
2828

2929
// MARK: IAuthentificatorInterceptor
3030

31-
public func adapt(request: URLRequest, for session: URLSession) async throws {
31+
public func adapt(request: inout URLRequest, for session: URLSession) async throws {
3232
guard let credential else {
3333
throw AuthenticatorInterceptorError.missingCredential
3434
}

Sources/NetworkLayer/Classes/Core/Builders/RequestBuilder/RequestParameterEncoder/RequestParametersEncoder.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ struct RequestParametersEncoder: IRequestParametersEncoder {
1111
throw URLError(.badURL)
1212
}
1313

14+
if parameters.isEmpty {
15+
return
16+
}
17+
1418
let queries = parameters.map { URLQueryItem(name: $0.key, value: $0.value) }
1519
var urlComponents = URLComponents(string: url.absoluteString)
1620

Sources/NetworkLayer/Classes/Core/Services/DataRequestHandler/DataRequestHandler.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ final class DataRequestHandler: NSObject {
3535
extension DataRequestHandler: IDataRequestHandler {
3636
func startDataTask(
3737
_ task: URLSessionDataTask,
38-
session _: URLSession,
3938
delegate: URLSessionDelegate?
4039
) async throws -> Response<Data> {
4140
try await withTaskCancellationHandler(operation: {

Sources/NetworkLayer/Classes/Core/Services/RequestProcessor/RequestProcessor.swift

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ actor RequestProcessor {
5151
self.retryPolicyService = retryPolicyService
5252
self.delegate = delegate
5353
self.interceptor = interceptor
54+
self.dataRequestHandler.urlSessionDelegate = configuration.sessionDelegate
5455
session = URLSession(
5556
configuration: configuration.sessionConfiguration,
5657
delegate: dataRequestHandler,
@@ -76,19 +77,19 @@ actor RequestProcessor {
7677
delegate: URLSessionDelegate?,
7778
configure: ((inout URLRequest) throws -> Void)?
7879
) async throws -> Response<Data> {
79-
guard let urlRequest = try requestBuilder.build(request, configure) else {
80+
guard var urlRequest = try requestBuilder.build(request, configure) else {
8081
throw NetworkLayerError.badURL
8182
}
8283

83-
try await adapt(request, urlRequest: urlRequest, session: session)
84+
try await adapt(request, urlRequest: &urlRequest, session: session)
8485

8586
return try await performRequest(strategy: strategy) {
8687
try await self.delegate?.requestProcessor(self, willSendRequest: urlRequest)
8788

8889
let task = session.dataTask(with: urlRequest)
8990

9091
do {
91-
let response = try await dataRequestHandler.startDataTask(task, session: session, delegate: delegate)
92+
let response = try await dataRequestHandler.startDataTask(task, delegate: delegate)
9293

9394
if request.requiresAuthentication {
9495
let isRefreshedCredential = try await refresh(
@@ -102,18 +103,34 @@ actor RequestProcessor {
102103
}
103104
}
104105

106+
try self.validate(response)
107+
105108
return response
106109
} catch {
107110
throw error
108111
}
109112
}
110113
}
111114

112-
private func adapt<T: IRequest>(_ request: T, urlRequest: URLRequest, session: URLSession) async throws {
115+
/// Adapts an initial request.
116+
///
117+
/// - Parameters:
118+
/// - request: The request model.
119+
/// - urlRequest: The request that needs to be authenticated.
120+
/// - session: The URLSession for which the request is being refreshed.
121+
private func adapt<T: IRequest>(_ request: T, urlRequest: inout URLRequest, session: URLSession) async throws {
113122
guard request.requiresAuthentication else { return }
114-
try await interceptor?.adapt(request: urlRequest, for: session)
123+
try await interceptor?.adapt(request: &urlRequest, for: session)
115124
}
116125

126+
/// Refreshes credential.
127+
///
128+
/// - Parameters:
129+
/// - urlRequest: The request that needs to be authenticated.
130+
/// - response: The metadata associated with the response to an HTTP protocol URL load request.
131+
/// - session: The URLSession for which the request is being refreshed.
132+
///
133+
/// - Returns: `true` if the request's token is refreshed, false otherwise.
117134
private func refresh<T>(
118135
urlRequest: URLRequest,
119136
response: Response<T>,
@@ -146,6 +163,11 @@ actor RequestProcessor {
146163
return try await retryPolicyService.retry(strategy: strategy, send)
147164
}
148165
}
166+
167+
private func validate(_ response: Response<Data>) throws {
168+
guard let urlResponse = response.response as? HTTPURLResponse else { return }
169+
try delegate?.requestProcessor(self, validateResponse: urlResponse, data: response.data, task: response.task)
170+
}
149171
}
150172

151173
// MARK: IRequestProcessor

Sources/NetworkLayerInterfaces/Classes/Core/Authenticator/IAuthenticatorInterceptor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public protocol IAuthenticatorInterceptor {
1212
/// - Parameters:
1313
/// - request: The URLRequest to be adapted.
1414
/// - session: The URLSession for which the request is being adapted.
15-
func adapt(request: URLRequest, for session: URLSession) async throws
15+
func adapt(request: inout URLRequest, for session: URLSession) async throws
1616

1717
/// Refreshes credential for the request.
1818
///

Sources/NetworkLayerInterfaces/Classes/Core/Services/IDataRequestHandler.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ import Foundation
77

88
/// A protocol for handling data requests.
99
public protocol IDataRequestHandler: URLSessionTaskDelegate & URLSessionDataDelegate {
10+
var urlSessionDelegate: URLSessionDelegate? { get set }
11+
1012
/// Starts a data task for handling network requests.
1113
///
1214
/// - Parameters:
1315
/// - task: The `URLSessionDataTask` representing the network task to be initiated.
14-
/// - session: The `URLSession` to use for the data task.
1516
/// - delegate: An optional `URLSessionDelegate` for handling `URLSession` events and callbacks. Pass `nil` if not needed.
1617
///
1718
/// - Returns: An asynchronous task that will result in a Response object containing data when the request is completed.
1819
func startDataTask(
1920
_ task: URLSessionDataTask,
20-
session: URLSession,
2121
delegate: URLSessionDelegate?
2222
) async throws -> Response<Data>
2323
}

0 commit comments

Comments
 (0)