Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat]: Add CI workflow to run tests #62

Merged
merged 53 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
5f82211
[feat]: Add CI workflow to run tests
johnkodes Jan 17, 2024
b8f60c0
[feat]: Fix macOS versions
johnkodes Jan 17, 2024
1cae19b
[feat]: Update versions
johnkodes Jan 17, 2024
9516ed2
[feat]: Test formatting tool
johnkodes Jan 17, 2024
b8f6ca4
[feat]: Split reports
johnkodes Jan 18, 2024
71fe137
[feat]: Turn on test coverage
johnkodes Jan 18, 2024
3a73813
[feat]: Test speed of macOS tests via xcodebuild
johnkodes Jan 18, 2024
a23e8a6
[feat]: Try different Xcode to solve “Segmentation fault” error
johnkodes Jan 18, 2024
180e9c4
[feat]: try xcode 15.2 again for macOSě
johnkodes Jan 19, 2024
3ee87c0
[feat]: test xcresults without matrix
johnkodes Jan 19, 2024
93547a6
[feat]: Set correct simulators
johnkodes Jan 19, 2024
2fbdef3
[feat]: Change name
johnkodes Jan 19, 2024
c6f0235
[feat]: Split xcodebuild to build + test
johnkodes Jan 19, 2024
6b00693
[feat]: change results bundle
johnkodes Jan 19, 2024
2813225
[feat]: Trying to fix the missing package error
johnkodes Jan 19, 2024
a609ac5
[feat]: Change Xcode version
johnkodes Jan 19, 2024
e4cd644
[feat]: Fix checkout
johnkodes Jan 19, 2024
c065981
[feat]: Use lower Xcode for macOS
johnkodes Jan 19, 2024
4501d9c
[feat]: try something else
johnkodes Jan 20, 2024
a74d496
[feat]: Revert back
johnkodes Jan 20, 2024
4f577de
[feat]: Upload logs
johnkodes Jan 21, 2024
ffeb9f7
[feat]: Upload logs
johnkodes Jan 21, 2024
b53904c
[feat]: If failure or success
johnkodes Jan 21, 2024
041e709
Merge branch 'master' into feat/ci-workflow
johnkodes Jan 21, 2024
de9e9e7
[feat]: Remove result bundle
johnkodes Jan 21, 2024
70e9b99
[feat]: disable swiftlint
johnkodes Jan 21, 2024
cf8635e
[feat]: Remove workspace
johnkodes Jan 21, 2024
3bd4c44
Revert "[feat]: Remove workspace"
johnkodes Jan 21, 2024
958f5d3
[feat]: Revert swiftlint
johnkodes Jan 21, 2024
fd26d0a
[feat]: Change Xcode to 15.0.1
johnkodes Jan 21, 2024
b673d89
[feat]: Add back result bundle
johnkodes Jan 21, 2024
88baabd
[feat]: Increase timeout
johnkodes Jan 22, 2024
aa82148
[feat]: Remove Task.sleeps in tests
johnkodes Jan 23, 2024
26403b6
[feat]: Bring back skipped tests
johnkodes Jan 24, 2024
8995951
[feat]: Try latest Xcode for macOS tests
johnkodes Jan 24, 2024
ce5394b
[feat]: Rename MockResponseProvider to StoredResponseProvider
johnkodes Jan 24, 2024
032023f
[feat]: Add FileDataWriter
johnkodes Jan 25, 2024
28779d6
[feat]: Randomize and parallelize tests
johnkodes Jan 25, 2024
b8efb10
[eat]: remove duplicate files
johnkodes Jan 25, 2024
ef0ef9b
[feat]: Increase timeouts
johnkodes Jan 25, 2024
8ec2ba0
[chore]: Update GA upload-artifact
johnkodes Jan 25, 2024
3374cc7
[chore]: Turn parallel testing
johnkodes Jan 25, 2024
6d8ab0c
[feat]: Add documentation
johnkodes Jan 25, 2024
6501bad
[feat]: Increase priority
johnkodes Jan 25, 2024
0a10d96
[feat]: Make class final
johnkodes Jan 29, 2024
fe1b1df
[feat]: Rework FileManager + tests
johnkodes Feb 1, 2024
a90c35c
[feat]: Use latest GA runner
johnkodes Feb 1, 2024
a79c45c
[feat]: Increase timeouts
johnkodes Feb 1, 2024
5ffc432
[feat]: Revert back to macos-13
johnkodes Feb 1, 2024
dfb5564
[feat]: Remove write in mock
johnkodes Feb 1, 2024
0d581a8
[feat]: Use macos-14
johnkodes Feb 1, 2024
820b8f3
[feat]: Remove unused file
johnkodes Feb 5, 2024
b2deb96
[feat]: Assert received URLs
johnkodes Feb 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: "Networking CI"

on:
push:
branches:
- master
pull_request:
branches:
- '*'

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
unit-tests:
name: ${{ matrix.name }}
runs-on: ${{ matrix.runsOn }}
env:
DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- name: 'iOS 17.2'
destination: 'OS=17.2,name=iPhone 15 Pro'
xcode: 'Xcode_15.2'
runsOn: macos-13
# - name: 'iOS 16.4'
# destination: 'OS=16.4,name=iPhone 14 Pro'
# xcode: 'Xcode_14.3.1'
# runsOn: macos-13
- name: 'macOS 13, Xcode 15.2'
destination: 'platform=macOS'
xcode: 'Xcode_15.2'
runsOn: macos-13
steps:
- uses: actions/checkout@v4

- name: 'Running unit tests on ${{ matrix.name }}'
run: |
set -o pipefail && \
xcodebuild clean test -resultBundlePath "TestResults-${{ matrix.name }}" -skipPackagePluginValidation -scheme "Networking" -destination "${{ matrix.destination }}" | tee "build-log-${{ matrix.name }}.txt" | xcpretty

- uses: kishikawakatsumi/xcresulttool@v1
with:
path: 'TestResults-${{ matrix.name }}.xcresult'
title: '${{ matrix.name }} Test Results'
if: success() || failure()

- name: 'Upload Build Log'
uses: actions/upload-artifact@v4
with:
name: 'build-log-${{ matrix.name }}'
path: 'build-log-${{ matrix.name }}.txt'
if: success() || failure()
16 changes: 14 additions & 2 deletions .swiftpm/xcode/xcshareddata/xcschemes/Networking.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,22 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES"
onlyGenerateCoverageForSpecifiedTargets = "YES">
<CodeCoverageTargets>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Networking"
BuildableName = "Networking"
BlueprintName = "Networking"
ReferencedContainer = "container:">
</BuildableReference>
</CodeCoverageTargets>
<Testables>
<TestableReference
skipped = "NO">
skipped = "NO"
testExecutionOrdering = "random">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "NetworkingTests"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ final class SampleAuthorizationManager: AuthorizationManaging {
/// We use mock data to simulate real API requests here
private let apiManager: APIManager = {
APIManager(
responseProvider: MockResponseProvider(with: Bundle.main, sessionId: "2023-01-31T15:08:08Z"),
responseProvider: StoredResponseProvider(with: Bundle.main, sessionId: "2023-01-31T15:08:08Z"),
requestAdapters: [LoggingInterceptor.shared],
responseProcessors: [
LoggingInterceptor.shared,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ final class AuthorizationViewModel: ObservableObject {
#endif

return APIManager(
responseProvider: MockResponseProvider(with: Bundle.main, sessionId: "2023-01-31T15:08:08Z"),
responseProvider: StoredResponseProvider(with: Bundle.main, sessionId: "2023-01-31T15:08:08Z"),
requestAdapters: [
LoggingInterceptor.shared,
authorizationInterceptor
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// MockResponseProvider.swift
// StoredResponseProvider.swift
//
//
// Created by Matej Molnár on 04.01.2023.
Expand All @@ -14,10 +14,8 @@ import Foundation
import UIKit
#endif

// MARK: - MockResponseProvider definition

/// A response provider which creates responses for requests from corresponding data files stored in Assets.
open class MockResponseProvider: ResponseProviding {
open class StoredResponseProvider: ResponseProviding {
private let bundle: Bundle
private let sessionId: String
private let requestCounter = Counter()
Expand All @@ -36,7 +34,7 @@ open class MockResponseProvider: ResponseProviding {
/// - Parameter request: URL request.
public func response(for request: URLRequest) async throws -> Response {
guard let model = try? await loadModel(for: request) else {
throw NetworkError.underlying(error: MockResponseProviderError.unableToLoadAssetData)
throw NetworkError.underlying(error: StoredResponseProviderError.unableToLoadAssetData)
}

guard
Expand All @@ -49,7 +47,7 @@ open class MockResponseProvider: ResponseProviding {
headerFields: model.responseHeaders
)
else {
throw NetworkError.underlying(error: MockResponseProviderError.unableToConstructResponse)
throw NetworkError.underlying(error: StoredResponseProviderError.unableToConstructResponse)
}

return Response(model.responseBody ?? Data(), httpResponse)
Expand All @@ -58,7 +56,7 @@ open class MockResponseProvider: ResponseProviding {

// MARK: Private helper functions

private extension MockResponseProvider {
private extension StoredResponseProvider {
/// Loads a corresponding file from Assets for a given ``URLRequest`` and decodes the data to `EndpointRequestStorageModel`.
func loadModel(for request: URLRequest) async throws -> EndpointRequestStorageModel? {
// counting from 0, check storage request processing
Expand Down
16 changes: 16 additions & 0 deletions Sources/Networking/Misc/StoredResponseProviderError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// StoredResponseProvider.swift
//
//
// Created by Matej Molnár on 04.01.2023.
//

import Foundation

/// An error that occurs during loading a ``Response`` from assets by `StoredResponseProvider`.
enum StoredResponseProviderError: Error {
/// An indication that there was a problem with loading or decoding data from assets.
case unableToLoadAssetData
/// An indication that it was not possible to construct a `Response` from the loaded data.
case unableToConstructResponse
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ open class EndpointRequestStorageProcessor: ResponseProcessing, ErrorProcessing
// MARK: Private variables
private let fileManager: FileManager
private let jsonEncoder: JSONEncoder
private let fileDataWriter: FileDataWriting
private let config: Config

private lazy var responsesDirectory = fileManager.temporaryDirectory.appendingPathComponent("responses")
Expand Down Expand Up @@ -51,13 +52,15 @@ open class EndpointRequestStorageProcessor: ResponseProcessing, ErrorProcessing

public init(
fileManager: FileManager = .default,
fileDataWriter: FileDataWriting = FileDataWriter(),
jsonEncoder: JSONEncoder? = nil,
config: Config = .default
) {
self.fileManager = fileManager
self.fileDataWriter = fileDataWriter
self.jsonEncoder = jsonEncoder ?? .default
self.config = config

deleteStoredSessionsExceedingLimit()
}

Expand Down Expand Up @@ -138,7 +141,7 @@ private extension EndpointRequestStorageProcessor {
endpointRequest: EndpointRequest,
urlRequest: URLRequest
) {
Task(priority: .background) { [weak self] in
Task.detached(priority: .utility) { [weak self] in
cejanen marked this conversation as resolved.
Show resolved Hide resolved
guard let self else {
return
}
Expand Down Expand Up @@ -214,7 +217,7 @@ private extension EndpointRequestStorageProcessor {
func store(_ model: EndpointRequestStorageModel, fileUrl: URL) {
do {
let jsonData = try jsonEncoder.encode(model)
try jsonData.write(to: fileUrl)
try fileDataWriter.write(jsonData, to: fileUrl)
os_log("🎈 Response saved %{public}@ bytes at %{public}@", type: .info, "\(jsonData.count)", fileUrl.path)
} catch {
os_log("❌ Can't store response %{public}@ %{public}@ %{public}@", type: .error, model.method, model.path, error.localizedDescription)
Expand Down
29 changes: 29 additions & 0 deletions Sources/Networking/Utils/FileDataWriter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// FileWriter.swift
//
//
// Created by Jan Kodeš on 24.01.2024.
//

import Foundation

/// A protocol defining an interface for writing data to a file.
public protocol FileDataWriting {
/// Writes the given data to the specified URL.
///
/// - Parameters:
/// - data: The `Data` object that needs to be written to the file.
/// - url: The destination `URL` where the data should be written.
/// - Throws: An error if the data cannot be written to the URL.
func write(_ data: Data, to url: URL) throws
}


/// A class that implements data writing functionality.
public class FileDataWriter: FileDataWriting {
public init() {}

public func write(_ data: Data, to url: URL) throws {
try data.write(to: url)
}
}
Loading
Loading