-
Notifications
You must be signed in to change notification settings - Fork 292
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
Introduced TestLogHandler
to simplify how we test logged messages
#1858
Conversation
0ebd176
to
2eb7e58
Compare
ce76cc6
to
d8c54c6
Compare
We had this fragile pattern in several tests: ```swift var loggedMessages = [String]() let originalLogHandler = Logger.logHandler defer { Logger.logHandler = originalLogHandler } Logger.logHandler = { _, message, _, _, _ in loggedMessages.append(message) } ``` Which was too verbose and error prone. This new type works like an RAII type. Its lifetime scopes the messages that are observed, so simply having a reference around for the lifetime of the test allows observing only those messages. For example: ```swift private var testLogHandler: TestLogHandler! override func setUp() { super.setUp() self.testLogHandler = TestLogHandler() } override func tearDown() { self.testLogHandler = nil super.tearDown() } func testExample() { // Run code expect(self.testLogHandler.messages).to(contain(...)) } ``` - Alternatively, `TestLogHandler` can be used locally within a single test: ```swift func testExample() { let logHandler = TestLogHandler() // Run some code expect(logHandler.loggedMessages.onlyElement?.message) == "Expected log" } ```
d8c54c6
to
1472452
Compare
@RevenueCat/core-sdk bump |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a couple of questions, but it's looking great!
|
||
private static let sharedHandler: SharedTestLogHandler = { | ||
let handler = SharedTestLogHandler() | ||
handler.install() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm personally, I don't like that an object contruction such as this has a side effect like this... Could we add a method on the TestLogHandler
so it gets called only on the tests that require it instead? It might be more verbosity on the call side, but I think it makes it clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is done lazily only when an instance is created already (Swift properties like this are lazy)
} | ||
|
||
func install() { | ||
Purchases.verboseLogHandler = self.logHandler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm so if I understand this correctly, when the TestLogHandler
gets released, we remove the observers, but we don't reset the value of verboseLogHandler
. I think the way it is right now, the behavior should be correct, but internally, we will be sharing this logHandler
between tests (unless it gets reconstructed on every test). I wonder if we could reset Purchases.verboseLogHandler
on the deinit
as well? Not sure if there would be any issues with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would have to ensure that there aren't any observers left, which would be extra state. It's possible, but I think it's unnecessary for now, and since this only affects tests I think it's a fair compromise. This class doesn't even get compiled outside the tests.
I'm late to the game but just wanted to say that I love this!! |
😍 |
…count` setting was never explicitly set Fixes [CSDK-454]. This should reduce a lot of the noise during initialization. The internal backing property was already `Bool?`, so we can check if it was ever set, and if not, not log anything. Using `TestLogHandler` introduced in #1858 to verify this behavior.
**This is an automatic release.** ### Bugfixes * `watchOS`: fixed crash when ran on single-target apps with Xcode 14 and before `watchOS 9.0` (#1895) via NachoSoto (@NachoSoto) * `CustomerInfoManager`/`OfferingsManager`: improved display of underlying errors (#1888) via NachoSoto (@NachoSoto) * `Offering`: improved confusing log for `PackageType.custom` (#1884) via NachoSoto (@NachoSoto) * `PurchasesOrchestrator`: don't log warning if `allowSharingAppStoreAccount` setting was never explicitly set (#1885) via NachoSoto (@NachoSoto) * Introduced type-safe `PurchasesError` and fixed some incorrect returned error types (#1879) via NachoSoto (@NachoSoto) * `CustomerInfoManager`: fixed thread-unsafe implementation (#1878) via NachoSoto (@NachoSoto) ### New Features * Disable SK1's `StoreKitWrapper` if SK2 is enabled and available (#1882) via NachoSoto (@NachoSoto) * `Sendable` support (#1795) via NachoSoto (@NachoSoto) ### Other Changes * Renamed `StoreKitWrapper` to `StoreKit1Wrapper` (#1886) via NachoSoto (@NachoSoto) * Enabled `DEAD_CODE_STRIPPING` (#1887) via NachoSoto (@NachoSoto) * `HTTPClient`: added `X-Client-Bundle-ID` and logged on SDK initialization (#1883) via NachoSoto (@NachoSoto) * add link to SDK reference (#1872) via Andy Boedo (@aboedo) * Added `StoreKit2Setting.shouldOnlyUseStoreKit2` (#1881) via NachoSoto (@NachoSoto) * Introduced `TestLogHandler` to simplify how we test logged messages (#1858) via NachoSoto (@NachoSoto) * `Integration Tests`: added test for purchasing `StoreProduct` instead of `Package` (#1875) via NachoSoto (@NachoSoto) * `ErrorUtils`: added test to verify that returned errors can be converted to `ErrorCode` (#1871) via NachoSoto (@NachoSoto)
We had this fragile pattern in several tests:
Which was too verbose and error prone.
This new type works like an RAII type. Its lifetime scopes the messages that are observed, so simply having a reference around for the lifetime of the test allows observing only those messages.
This much simpler abstraction will make it easier for us to test more of what's logged by the SDK.
Examples:
setUp
:TestLogHandler
can be used locally within a single test:Notes:
This implicitly overrides
Purchases.shared.verboseLogHandler
while running tests, but it just wraps it by still invoking the default handler, so logs are still printed in the console.