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

Implement Observability #9

Merged
merged 41 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
54deb29
Add observability framework to the project
DevAgani Feb 7, 2024
5896ced
Add ScreenViewEvent and UserActionEvent
DevAgani Feb 7, 2024
7088d82
Test events emission
DevAgani Feb 7, 2024
3cebbed
Rename test file, add tests to verify that events are published
DevAgani Feb 8, 2024
a8f3da7
Add a scanfile and a test lane
DevAgani Feb 8, 2024
7e6e925
Add a github workflow to build and test the app
DevAgani Feb 8, 2024
c6ce12a
Remove coverage data step
DevAgani Feb 8, 2024
5643b44
Add another supported platform
DevAgani Feb 8, 2024
d76b7e4
Add a setup environment step
DevAgani Feb 8, 2024
fbda336
Force installation of gem
DevAgani Feb 8, 2024
2aec0be
Add a bundle exec statement to specify source
DevAgani Feb 8, 2024
b450b9c
Fix closure requirement of explicit use of self
DevAgani Feb 8, 2024
e4c1ea6
Add an explicit return
DevAgani Feb 8, 2024
0756305
fulfill capture semantics requirements
DevAgani Feb 8, 2024
04a123c
Add explicit return statement
DevAgani Feb 8, 2024
7643480
Update journey name
DevAgani Feb 8, 2024
a65583d
Add step to publish code coverage to codecov
DevAgani Feb 8, 2024
d9cc125
Update runner to macos-13
DevAgani Feb 12, 2024
0f9a5ea
Fix version of xcode
DevAgani Feb 12, 2024
dd721bc
Merge branch 'main' into feat/add-observability
DevAgani Feb 12, 2024
77ee5aa
Comment out failing UITests
DevAgani Feb 12, 2024
0bc998e
Remove explicit requirements by the compiler
DevAgani Feb 12, 2024
f84098b
Rever to macos 12
DevAgani Feb 12, 2024
598ab04
Fix xcode version
DevAgani Feb 12, 2024
57e7a08
Revert to macos-12
DevAgani Feb 12, 2024
1e1a122
remove return statements
DevAgani Feb 12, 2024
b3bf495
Fix o11y event name
DevAgani Feb 12, 2024
8078a4b
Remove self
DevAgani Feb 12, 2024
b40c1af
Fix failing test
DevAgani Feb 12, 2024
fcbe64b
Switch to macos-14
DevAgani Feb 12, 2024
38e102a
add platfomr
DevAgani Feb 12, 2024
0ff1dec
Revert to macos-13
DevAgani Feb 12, 2024
59e612d
Add prebuild phase for usecase and app:
DevAgani Feb 14, 2024
b658e5f
Rename observabilityTracker to tracker
DevAgani Feb 19, 2024
4009512
Update observability event publishing to use PassthroughSubjects
DevAgani Feb 20, 2024
f633e2d
Remove slather step for now
DevAgani Feb 20, 2024
f3956b3
Revert to camelCase
DevAgani Feb 20, 2024
e926604
Remove the variable and scope them to the test run
DevAgani Feb 20, 2024
ff7d482
Update AccountsJourneyObservabilityTests.swift
tibor-is-back Feb 20, 2024
dbb0a45
Simplify tests as this is to be used a guide
DevAgani Feb 20, 2024
768cd15
Fix event names, and test for hardcorded strings
DevAgani Feb 20, 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
19 changes: 19 additions & 0 deletions .github/actions/repo-art/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: "Add repo-art"

description: Add repositories from repo.backbase.com

runs:
using: "composite"
steps:
- shell: bash
run: |
echo Adding repository backbase-pods3
bundle exec pod repo-art add backbase-pods3 https://repo.backbase.com/api/pods/ios3
echo Adding repository backbase-pods-retail3
bundle exec pod repo-art add backbase-pods-retail3 https://repo.backbase.com/api/pods/ios-retail3
echo Adding repository backbase-pods-identity
bundle exec pod repo-art add backbase-pods-identity https://repo.backbase.com/api/pods/ios-identity
echo Adding repository backbase-pods-business
bundle exec pod repo-art add backbase-pods-business https://repo.backbase.com/api/pods/ios-business
echo Adding repository backbase-pods-design
bundle exec pod repo-art add backbase-pods-design https://repo.backbase.com/api/pods/design-ios
39 changes: 39 additions & 0 deletions .github/actions/setup-environment/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: "Setup environment"

inputs:
bb_artifactory_ios_username:
description: "Backbase repo username"
required: true
bb_artifactory_ios_password:
description: "Backbase repo password"
required: true

description: Build and Run

runs:
using: "composite"
steps:
- uses: actions/cache@v2
with:
path: Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-

- uses: actions/cache@v2
with:
path: vendor/bundle
key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gem-

- name: Setup repository credentials
shell: bash
run: |
echo Adding credentials to ~/.netrc file
echo -e "machine repo.backbase.com\nlogin ${{ inputs.bb_artifactory_ios_username }}\npassword ${{ inputs.bb_artifactory_ios_password }}" > ~/.netrc
echo Changing ~/.netrc file permissions
chmod -R 0600 ~/.netrc

- name: Add repositories from repo.backbase.com
uses: ./.github/actions/repo-art
40 changes: 40 additions & 0 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Build and Test GoldenSampeApp
on:
push:
branches: [main]
paths-ignore:
- "**.md"
pull_request:
branches: [main]
paths-ignore:
- "**.md"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-and-tests:
runs-on: macos-13
steps:
- name: Check out repository
uses: actions/checkout@v3
- name: Install Gems
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Setup environment
uses: ./.github/actions/setup-environment
with:
bb_artifactory_ios_username: ${{ secrets.REPO_USERNAME }}
bb_artifactory_ios_password: ${{ secrets.REPO_PASSWORD }}
- name: Xcode Select Version
uses: mobiledevops/xcode-select-version-action@v1
with:
xcode-select-version: 15.2
- name: Generate the project file
run: bundle exec fastlane setup
- name: Run tests
run: bundle exec fastlane test
# - name: Upload coverage reports to Codecov
# uses: codecov/codecov-action@v3
# env:
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
1 change: 1 addition & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ excluded:
- .build
- Tests
- vendor
- DerivedData
line_length:
warning: 160
error: 200
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ gem "cocoapods", "~> 1.13"
gem "cocoapods-art", "~> 1.1"
gem "fastlane", "~> 2.216"
gem "activesupport", "~> 7.0", "<= 7.0.8"
gem "slather"

plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)
15 changes: 15 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ GEM
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
clamp (1.3.2)
cocoapods (1.13.0)
addressable (~> 2.8)
claide (>= 1.0.2, < 2.0)
Expand Down Expand Up @@ -219,10 +220,15 @@ GEM
nap (1.1.0)
naturally (2.2.1)
netrc (0.11.0)
nokogiri (1.16.2-arm64-darwin)
racc (~> 1.4)
nokogiri (1.16.2-x86_64-darwin)
racc (~> 1.4)
optparse (0.1.1)
os (1.1.4)
plist (3.7.0)
public_suffix (4.0.7)
racc (1.7.3)
rake (13.0.6)
representable (3.2.0)
declarative (< 0.1.0)
Expand All @@ -243,6 +249,12 @@ GEM
simctl (1.6.10)
CFPropertyList
naturally
slather (2.8.0)
CFPropertyList (>= 2.2, < 4)
activesupport
clamp (~> 1.3)
nokogiri (>= 1.14.3)
xcodeproj (~> 1.21)
terminal-notifier (2.0.0)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
Expand Down Expand Up @@ -275,6 +287,8 @@ GEM
xcpretty (~> 0.2, >= 0.0.7)

PLATFORMS
arm64-darwin-22
x86_64-darwin-20
x86_64-darwin-21
x86_64-darwin-22

Expand All @@ -284,6 +298,7 @@ DEPENDENCIES
cocoapods-art (~> 1.1)
fastlane (~> 2.216)
fastlane-plugin-xcodegen
slather

BUNDLED WITH
2.3.14
1 change: 1 addition & 0 deletions Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ abstract_target 'Common' do
pod 'ArrangementsClient2Gen2','~> 1.2.1'
pod 'Resolver', $resolverVersion
pod 'SwiftLint'
pod 'BackbaseObservability', '~> 1.0'

target 'AccountsJourney' do
end
Expand Down
9 changes: 5 additions & 4 deletions Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ PODS:

DEPENDENCIES:
- ArrangementsClient2Gen2 (~> 1.2.1)
- Backbase (>= 10.0)
- Backbase (= 10.1.0)
- BackbaseObservability (~> 1.0)
- BusinessWorkspacesJourney
- BusinessWorkspacesJourneyWorkspacesUseCase2
- IdentityAuthenticationJourney
Expand All @@ -99,7 +100,7 @@ DEPENDENCIES:
SPEC REPOS:
https://repo.backbase.com/api/pods/design-ios:
- BackbaseCountryCore
https://repo.backbase.com/api/pods/ios-business/:
https://repo.backbase.com/api/pods/ios-business:
- BackbaseObservability
- BusinessDesign
- BusinessJourneyCommon
Expand Down Expand Up @@ -153,6 +154,6 @@ SPEC CHECKSUMS:
SnapKit: e01d52ebb8ddbc333eefe2132acf85c8227d9c25
SwiftLint: 5ce4d6a8ff83f1b5fd5ad5dbf30965d35af65e44

PODFILE CHECKSUM: bbf64b9052c3d48518b0863ad398b8c06037b8d1
PODFILE CHECKSUM: ad03def58cc094e2876713a7073d488dc29c1f60

COCOAPODS: 1.14.3
COCOAPODS: 1.13.0
DevAgani marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import XCTest
import Combine
import Resolver
import BackbaseObservability
@testable import AccountsJourney

final class AccountsJourneyObservabilityTests: XCTestCase {

private var userActionSpy: TrackerSpy<UserActionEvent>?
DevAgani marked this conversation as resolved.
Show resolved Hide resolved
private var screenViewEventsSpy: TrackerSpy<ScreenViewEvent>?

override func setUp() {
super.setUp()
let accountsJourneyConfig = AccountsJourney.Configuration()
Resolver.register { accountsJourneyConfig }
Resolver.register { DummyAccountsListUseCase() as AccountsListUseCase }
Resolver.register { DummyAccountDetailsUseCase() as AccountDetailsUseCase }
}

override func tearDown() {
super.tearDown()
userActionSpy = nil
screenViewEventsSpy = nil
}

//MARK: - AccountsList Events

func test_noUserActionEventIsPublished_whenAccountsListViewModel_is_initialized() {
userActionSpy = TrackerSpy<UserActionEvent>()
expect(userActionSpy!, toReceive: [], when: {
_ = AccountsListViewModel()
})
}

func test_noScreenViewEventIsPublished_whenAccountListViewModel_is_initialized() {
screenViewEventsSpy = TrackerSpy<ScreenViewEvent>()
expect(screenViewEventsSpy!, toReceive: [], when: {
_ = AccountsListViewModel()
})
}

func test_accountsScreenEventIsPublished_whenTheAccountsViewLoads() {
screenViewEventsSpy = TrackerSpy<ScreenViewEvent>()

expect(screenViewEventsSpy!, toReceive: [ScreenViewEvent(.accounts_list)], when: {
AccountsListViewModel().onEvent(.getAccounts)
let viewDidAppearSubject = PassthroughSubject<Void, Never>()
let userActionEventSubject = PassthroughSubject<UserActionEvent, Never>()
let viewModel = AccountsListViewModel()
viewModel.bind(viewDidAppearPublisher: viewDidAppearSubject.eraseToAnyPublisher(), userActionEventPublisher: userActionEventSubject.eraseToAnyPublisher())
viewDidAppearSubject.send()
})
}

func test_refresh_accountsUserActionEvent_isPublished_whenTheRefreshEventIsEmitted() {
userActionSpy = TrackerSpy<UserActionEvent>()

expect(userActionSpy!, toReceive: [UserActionEvent(.refresh_accounts)], when: {

let viewDidAppearSubject = PassthroughSubject<Void, Never>()
let userActionEventSubject = PassthroughSubject<UserActionEvent, Never>()
let viewModel = AccountsListViewModel()
viewModel.bind(viewDidAppearPublisher: viewDidAppearSubject.eraseToAnyPublisher(), userActionEventPublisher: userActionEventSubject.eraseToAnyPublisher())
userActionEventSubject.send(UserActionEvent(.refresh_accounts))
})
}


// MARK: - AccountDetails Tests
func test_noUserActionEventIsPublished_whenAccountDetailsViewModel_is_initialized() {
userActionSpy = TrackerSpy<UserActionEvent>()
expect(userActionSpy!, toReceive: [], when: {
_ = AccountDetailsViewModel()
})
}

func test_noScreenViewEventIsPublished_whenAccountDetailsViewModel_is_initialized() {
screenViewEventsSpy = TrackerSpy<ScreenViewEvent>()
expect(screenViewEventsSpy!, toReceive: [], when: {
_ = AccountDetailsViewModel()
})
}

func test_accountsDetailsScreenEventIsPublished_whenTheAccountsDetailsViewLoads() {
screenViewEventsSpy = TrackerSpy<ScreenViewEvent>()

expect(screenViewEventsSpy!, toReceive: [ScreenViewEvent(.account_details)], when: {
let valueSubject = PassthroughSubject<Void, Never>()
let viewModel = AccountDetailsViewModel()
viewModel.bind(viewDidAppear: valueSubject.eraseToAnyPublisher())
valueSubject.send()
})
}

// MARK: - Private

private class TrackerSpy<S>: NSObject, Tracker {
tibor-is-back marked this conversation as resolved.
Show resolved Hide resolved
private(set) var publishedEvents = [S?]()

func publish<T>(event: T) {
publishedEvents.append(event as? S)
}

func subscribe<T>(subscriber: AnyHashable, eventClass: T.Type, completion: @escaping (T) -> Void) {}
func unsubscribe(subscriber: AnyHashable) {}
}

private func expect<S>(_ sut: TrackerSpy<S>, toReceive events: [S?], when action: () -> Void, file: StaticString = #file, line: UInt = #line) where S: Equatable {
let spy = TrackerSpy<S>()
Resolver.register { spy as Tracker }

action()

XCTAssertEqual(spy.publishedEvents, events, file: file, line: line)
}

}
extension ScreenViewEvent: Equatable {
public static func == (lhs: ScreenViewEvent, rhs: ScreenViewEvent) -> Bool {
(lhs.name == rhs.name) && (lhs.journey == rhs.journey)
}
}

private final class DummyAccountsListUseCase: AccountsListUseCase {
func getAccountSummary(_ completion: @escaping (Result<AccountsJourney.AccountsSummary, AccountsJourney.ErrorResponse>) -> Void) {

}
}

private final class DummyAccountDetailsUseCase: AccountDetailsUseCase {
func getAccountDetail(arrangementId: String, _ completion: @escaping (Result<AccountsJourney.AccountDetailsModel, AccountsJourney.ErrorResponse>) -> Void) {

}
}
Empty file.
31 changes: 31 additions & 0 deletions accounts-journey/Extensions/O11YEvents.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// O11YEvents.swift
// AccountsJourney
//
// Created by George Nyakundi on 07/02/2024.
//

import Foundation
import BackbaseObservability

extension ScreenViewEvent {
enum ScreenName: String {
case accounts_list = "accounts-list"
case account_details = "account-details"
DevAgani marked this conversation as resolved.
Show resolved Hide resolved
}

init(_ screenName: ScreenName, addition: String? = nil) {
self.init(name: screenName.rawValue, journey: "accounts-transactions", addition: addition)
}
}

extension UserActionEvent {

enum EventName: String {
case refresh_accounts = "refresh-accounts"
DevAgani marked this conversation as resolved.
Show resolved Hide resolved
}

convenience init(_ eventName: EventName, attributes: [String: BackbaseObservability.BasicEventData] = [:]) {
self.init(name: eventName.rawValue, journey: "accounts-transactions", attributes: attributes)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ extension AccountsList {
case .noAccounts:
DesignSystem.Assets.icStateViewNoWifi
default:
DesignSystem.Assets.icStateViewLoadingFailed
DesignSystem.Assets.icStateViewLoadingFailed
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ extension AccountsList {
public var errorRetryButtonTitle: ErrorFormatter<LocalizedString?> = { error in
switch error {
case .loadingFailure:
return localized(key: "errors.loadingFailure.actionButton")
localized(key: "errors.loadingFailure.actionButton")
default:
return nil
nil
}
}

Expand Down
Loading
Loading