Skip to content

Commit

Permalink
fix: EventHandler has no state
Browse files Browse the repository at this point in the history
Signed-off-by: Fabrizio Demaria <[email protected]>
  • Loading branch information
fabriziodemaria committed Sep 5, 2024
1 parent ee94d8a commit 4dac6c6
Show file tree
Hide file tree
Showing 10 changed files with 16 additions and 126 deletions.
17 changes: 6 additions & 11 deletions Sources/OpenFeature/EventHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,24 @@ import Combine
import Foundation

public class EventHandler: EventSender, EventPublisher {
private let eventState: CurrentValueSubject<ProviderEvent, Never>
private let lastSentEvent = PassthroughSubject<ProviderEvent?, Never>()

convenience init() {
self.init(.notReady)
public init() {
}

public init(_ state: ProviderEvent) {
eventState = CurrentValueSubject<ProviderEvent, Never>(state)
}

public func observe() -> AnyPublisher<ProviderEvent, Never> {
return eventState.eraseToAnyPublisher()
public func observe() -> AnyPublisher<ProviderEvent?, Never> {
return lastSentEvent.eraseToAnyPublisher()
}

public func send(
_ event: ProviderEvent
) {
eventState.send(event)
lastSentEvent.send(event)
}
}

public protocol EventPublisher {
func observe() -> AnyPublisher<ProviderEvent, Never>
func observe() -> AnyPublisher<ProviderEvent?, Never>
}

public protocol EventSender {
Expand Down
4 changes: 2 additions & 2 deletions Sources/OpenFeature/OpenFeatureAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,15 @@ public class OpenFeatureAPI {
self.hooks.removeAll()
}

public func observe() -> AnyPublisher<ProviderEvent, Never> {
public func observe() -> AnyPublisher<ProviderEvent?, Never> {
return providerSubject.map { provider in
if let provider = provider {
let test = provider.observe()
.append(self.eventHandler.observe())
.eraseToAnyPublisher()
return test
} else {
return Empty<ProviderEvent, Never>()
return Empty<ProviderEvent?, Never>()
.eraseToAnyPublisher()
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/OpenFeature/Provider/NoOpProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class NoOpProvider: FeatureProvider {
value: defaultValue, variant: NoOpProvider.passedInDefault, reason: Reason.defaultReason.rawValue)
}

func observe() -> AnyPublisher<ProviderEvent, Never> {
func observe() -> AnyPublisher<ProviderEvent?, Never> {
return eventHandler.observe()
}
}
Expand Down
15 changes: 3 additions & 12 deletions Tests/OpenFeatureTests/DeveloperExperienceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,9 @@ final class DeveloperExperienceTests: XCTestCase {
}

func testObserveGlobalEvents() {
let notReadyExpectation = XCTestExpectation(description: "NotReady")
let readyExpectation = XCTestExpectation(description: "Ready")
var eventState = OpenFeatureAPI.shared.observe().sink { event in
switch event {
case .notReady:
notReadyExpectation.fulfill()
case .ready:
readyExpectation.fulfill()
default:
Expand All @@ -47,14 +44,12 @@ final class DeveloperExperienceTests: XCTestCase {
}

func testSetProviderAndWait() async {
let notReadyExpectation = XCTestExpectation(description: "NotReady")
let readyExpectation = XCTestExpectation(description: "Ready")
let errorExpectation = XCTestExpectation(description: "Error")
withExtendedLifetime(

Check warning on line 50 in Tests/OpenFeatureTests/DeveloperExperienceTests.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Vertical Whitespace after Opening Braces Violation: Don't include vertical whitespace (empty line) after opening braces (vertical_whitespace_opening_braces)
OpenFeatureAPI.shared.observe().sink { event in
switch event {
case .notReady:
notReadyExpectation.fulfill()
case .ready:
readyExpectation.fulfill()
case .error:
Expand All @@ -64,17 +59,15 @@ final class DeveloperExperienceTests: XCTestCase {
}
}
) {

Check warning on line 62 in Tests/OpenFeatureTests/DeveloperExperienceTests.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Vertical Whitespace after Opening Braces Violation: Don't include vertical whitespace (empty line) after opening braces (vertical_whitespace_opening_braces)
let initCompleteExpectation = XCTestExpectation()

let eventHandler = EventHandler()
let provider = InjectableEventHandlerProvider(eventHandler: eventHandler)
let provider = DoSomethingProvider()
Task {
await OpenFeatureAPI.shared.setProviderAndWait(provider: provider)
wait(for: [readyExpectation], timeout: 1)
initCompleteExpectation.fulfill()
}
wait(for: [notReadyExpectation], timeout: 1)
eventHandler.send(.ready)
wait(for: [initCompleteExpectation], timeout: 1)

let errorProviderExpectation = XCTestExpectation()
Expand All @@ -84,8 +77,6 @@ final class DeveloperExperienceTests: XCTestCase {
wait(for: [errorExpectation], timeout: 2)
errorProviderExpectation.fulfill()
}

eventHandler.send(.error(errorCode: nil, message: nil))
wait(for: [errorProviderExpectation], timeout: 2)
}
}
Expand Down
16 changes: 0 additions & 16 deletions Tests/OpenFeatureTests/FlagEvaluationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,11 @@ final class FlagEvaluationTests: XCTestCase {

func testSimpleFlagEvaluation() {
let provider = DoSomethingProvider()
let notReadyExpectation = XCTestExpectation(description: "NotReady")
let readyExpectation = XCTestExpectation(description: "Ready")
let errorExpectation = XCTestExpectation(description: "Error")
let staleExpectation = XCTestExpectation(description: "Stale")
let eventState = provider.observe().sink { event in
switch event {
case .notReady:
notReadyExpectation.fulfill()
case .ready:
readyExpectation.fulfill()
case .error:
Expand All @@ -72,7 +69,6 @@ final class FlagEvaluationTests: XCTestCase {
}
}

wait(for: [notReadyExpectation], timeout: 5)
OpenFeatureAPI.shared.setProvider(provider: provider)
wait(for: [readyExpectation], timeout: 5)
let client = OpenFeatureAPI.shared.getClient()
Expand Down Expand Up @@ -112,12 +108,9 @@ final class FlagEvaluationTests: XCTestCase {

func testDetailedFlagEvaluation() async {
let provider = DoSomethingProvider()
let notReadyExpectation = XCTestExpectation(description: "NotReady")
let readyExpectation = XCTestExpectation(description: "Ready")
let eventState = provider.observe().sink { event in
switch event {
case .notReady:
notReadyExpectation.fulfill()
case .ready:
readyExpectation.fulfill()
default:
Expand Down Expand Up @@ -175,12 +168,9 @@ final class FlagEvaluationTests: XCTestCase {

func testHooksAreFired() async {
let provider = NoOpProvider()
let notReadyExpectation = XCTestExpectation(description: "NotReady")
let readyExpectation = XCTestExpectation(description: "Ready")
let eventState = provider.observe().sink { event in
switch event {
case .notReady:
notReadyExpectation.fulfill()
case .ready:
readyExpectation.fulfill()
default:
Expand Down Expand Up @@ -209,14 +199,11 @@ final class FlagEvaluationTests: XCTestCase {

func testBrokenProvider() {
let provider = AlwaysBrokenProvider()
let notReadyExpectation = XCTestExpectation(description: "NotReady")
let readyExpectation = XCTestExpectation(description: "Ready")
let errorExpectation = XCTestExpectation(description: "Error")
let staleExpectation = XCTestExpectation(description: "Stale")
let eventState = provider.observe().sink { event in
switch event {
case .notReady:
notReadyExpectation.fulfill()
case .ready:
readyExpectation.fulfill()
case .error:
Expand Down Expand Up @@ -248,9 +235,6 @@ final class FlagEvaluationTests: XCTestCase {

let eventState = provider.observe().sink { event in
switch event {
case .notReady:
// The provider starts in this state.
return
case .error:
fatalExpectation.fulfill()
default:
Expand Down
2 changes: 1 addition & 1 deletion Tests/OpenFeatureTests/Helpers/AlwaysBrokenProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class AlwaysBrokenProvider: FeatureProvider {
throw OpenFeatureError.flagNotFoundError(key: key)
}

func observe() -> AnyPublisher<ProviderEvent, Never> {
func observe() -> AnyPublisher<ProviderEvent?, Never> {
eventHandler.observe()
}
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/OpenFeatureTests/Helpers/DoSomethingProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import OpenFeature

class DoSomethingProvider: FeatureProvider {
public static let name = "Something"
private let eventHandler = EventHandler(.notReady)
private let eventHandler = EventHandler()
private var holdit: AnyCancellable?

func onContextSet(oldContext: OpenFeature.EvaluationContext?, newContext: OpenFeature.EvaluationContext) {
Expand Down Expand Up @@ -59,7 +59,7 @@ class DoSomethingProvider: FeatureProvider {
return ProviderEvaluation(value: .null, flagMetadata: DoSomethingProvider.flagMetadataMap)
}

func observe() -> AnyPublisher<ProviderEvent, Never> {
func observe() -> AnyPublisher<ProviderEvent?, Never> {
eventHandler.observe()
}

Expand Down

This file was deleted.

2 changes: 1 addition & 1 deletion Tests/OpenFeatureTests/Helpers/ThrowingProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class ThrowingProvider: FeatureProvider {
throw OpenFeatureError.flagNotFoundError(key: key)
}

func observe() -> AnyPublisher<ProviderEvent, Never> {
func observe() -> AnyPublisher<ProviderEvent?, Never> {
eventHandler.observe()
}
}
Expand Down
9 changes: 0 additions & 9 deletions Tests/OpenFeatureTests/HookSpecTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@ import XCTest
final class HookSpecTests: XCTestCase {
func testNoErrorHookCalled() {
let provider = NoOpProvider()
let notReadyExpectation = XCTestExpectation(description: "NotReady")
let readyExpectation = XCTestExpectation(description: "Ready")
let eventState = provider.observe().sink { event in
switch event {
case .notReady:
notReadyExpectation.fulfill()
case .ready:
readyExpectation.fulfill()
default:
Expand Down Expand Up @@ -39,13 +36,10 @@ final class HookSpecTests: XCTestCase {

func testErrorHookButNoAfterCalled() {
let provider = AlwaysBrokenProvider()
let notReadyExpectation = XCTestExpectation(description: "NotReady")
let readyExpectation = XCTestExpectation(description: "Ready")
let errorExpectation = XCTestExpectation(description: "Error")
let eventState = provider.observe().sink { event in
switch event {
case .notReady:
notReadyExpectation.fulfill()
case .ready:
readyExpectation.fulfill()
case .error:
Expand Down Expand Up @@ -81,12 +75,9 @@ final class HookSpecTests: XCTestCase {
let providerMock = NoOpProviderMock(hooks: [
BooleanHookMock(prefix: "provider", addEval: addEval)
])
let notReadyExpectation = XCTestExpectation(description: "NotReady")
let readyExpectation = XCTestExpectation(description: "Ready")
let eventState = providerMock.observe().sink { event in
switch event {
case .notReady:
notReadyExpectation.fulfill()
case .ready:
readyExpectation.fulfill()
default:
Expand Down

0 comments on commit 4dac6c6

Please sign in to comment.