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

chore: cleanup events and tests #21885

Open
wants to merge 22 commits into
base: develop
Choose a base branch
from

Conversation

seanstrom
Copy link
Member

@seanstrom seanstrom commented Jan 3, 2025

Summary

  • This PR attempts to clean up some of the code related to defining events and the tests we write to confirm their behaviour. Ideally, when we write an event handler we would use data for describing the on-success and on-error handlers instead of functions. This PR tries to find some of the places where we do not follow that convention and update the events and tests with that pattern.
    • Additionally, in some places I've tried updating the event code to migrate from rf/defn towards defn with rf/reg-event-fx.

Platforms

  • Android
  • iOS

Areas that maybe impacted

Functional
  • 1-1 chats
    • Delete Message For Me (with undo)
    • Delete Message for Everyone (with undo)
  • Contacts
    • Sending a contact request
    • Accepting a contact request
    • Dismissing/Declining a contact request
    • Updating a contact nickname
    • Removing a contact

Steps to test

WIP

status: ready

@seanstrom seanstrom self-assigned this Jan 3, 2025
@status-im-auto
Copy link
Member

status-im-auto commented Jan 3, 2025

Jenkins Builds

Click to see older builds (21)
Commit #️⃣ Finished (UTC) Duration Platform Result
76b7123 #1 2025-01-03 15:12:12 ~4 min tests 📄log
✔️ 76b7123 #1 2025-01-03 15:15:54 ~8 min android 🤖apk 📲
✔️ 76b7123 #1 2025-01-03 15:16:21 ~9 min android-e2e 🤖apk 📲
✔️ 76b7123 #1 2025-01-03 15:16:31 ~9 min ios 📱ipa 📲
dc46391 #3 2025-01-03 18:57:17 ~3 min tests 📄log
✔️ dc46391 #3 2025-01-03 19:01:09 ~6 min ios 📱ipa 📲
✔️ dc46391 #3 2025-01-03 19:01:11 ~7 min android 🤖apk 📲
✔️ dc46391 #3 2025-01-03 19:01:57 ~7 min android-e2e 🤖apk 📲
e50ffb4 #4 2025-01-03 19:19:19 ~2 min tests 📄log
✔️ e50ffb4 #4 2025-01-03 19:23:08 ~6 min android 🤖apk 📲
✔️ e50ffb4 #4 2025-01-03 19:23:13 ~6 min ios 📱ipa 📲
✔️ e50ffb4 #4 2025-01-03 19:23:47 ~7 min android-e2e 🤖apk 📲
d0472cb #5 2025-01-03 22:26:18 ~2 min tests 📄log
✔️ d0472cb #5 2025-01-03 22:29:41 ~6 min android-e2e 🤖apk 📲
✔️ d0472cb #5 2025-01-03 22:30:29 ~7 min ios 📱ipa 📲
✔️ d0472cb #5 2025-01-03 22:31:28 ~8 min android 🤖apk 📲
87f0ae8 #6 2025-01-06 19:56:42 ~2 min tests 📄log
f1f8b29 #7 2025-01-06 20:00:06 ~2 min tests 📄log
✔️ f1f8b29 #7 2025-01-06 20:04:58 ~7 min ios 📱ipa 📲
✔️ f1f8b29 #7 2025-01-06 20:05:20 ~8 min android-e2e 🤖apk 📲
✔️ f1f8b29 #7 2025-01-06 20:05:54 ~8 min android 🤖apk 📲
Commit #️⃣ Finished (UTC) Duration Platform Result
7d404b7 #8 2025-01-08 20:01:18 ~5 min tests 📄log
✔️ 7d404b7 #8 2025-01-08 20:03:37 ~8 min ios 📱ipa 📲
✔️ 7d404b7 #8 2025-01-08 20:05:28 ~10 min android-e2e 🤖apk 📲
✔️ accbbe6 #9 2025-01-08 22:21:52 ~4 min tests 📄log
✔️ accbbe6 #9 2025-01-08 22:25:04 ~7 min ios 📱ipa 📲
✔️ accbbe6 #9 2025-01-08 22:25:05 ~7 min android-e2e 🤖apk 📲
✔️ accbbe6 #9 2025-01-08 22:25:36 ~8 min android 🤖apk 📲

Copy link
Member Author

@seanstrom seanstrom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self Review 📚

Comment on lines +132 to +133
:json-rpc/call
:fx})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needed to be added while running tests locally, otherwise the rf/merge function wouldn't return a merged collection of effects.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch!

Comment on lines 97 to 107
:on-error [:contacts/send-contact-request-error id]
:on-success [:transport/message-sent]}]]]}))

(rf/reg-event-fx :contact.ui/send-contact-request send-contact-request)

(defn send-contact-request-failure
(defn send-contact-request-error
[_ [id error]]
(log/error "Failed to send contact request"
{:error error
:event :contact.ui/send-contact-request
:id id}))
{:id id
:error error
:event :contact.ui/send-contact-request}))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a pattern for the error handlers that has been introduced in other areas. Here we're creating an explicit error handler instead of inlining a function. This way it's more straightforward to unit test this code because it's all data.

Comment on lines +111 to +126
(defn remove-contact
"Remove a contact from current account's contact list"
{:events [:contact.ui/remove-contact-pressed]}
[{:keys [db]} {:keys [public-key]}]
{:db (-> db
(assoc-in [:contacts/contacts public-key :added?] false)
(assoc-in [:contacts/contacts public-key :active?] false)
(assoc-in [:contacts/contacts public-key :contact-request-state]
constants/contact-request-state-none))
:json-rpc/call [{:method "wakuext_retractContactRequest"
:params [{:id public-key}]
:js-response true
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to remove contact" public-key %)}]})

(rf/defn update-nickname
{:events [:contacts/update-nickname]}
[_ public-key nickname]
{:json-rpc/call [{:method "wakuext_setContactLocalNickname"
:params [{:id public-key :nickname nickname}]
:js-response true
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to set contact nickname " public-key nickname %)}]})
[{:keys [db]} [{:keys [public-key]}]]
{:db (-> db
(assoc-in [:contacts/contacts public-key :added?] false)
(assoc-in [:contacts/contacts public-key :active?] false)
(assoc-in [:contacts/contacts public-key :contact-request-state]
constants/contact-request-state-none))
:fx [[:json-rpc/call
[{:method "wakuext_retractContactRequest"
:params [{:id public-key}]
:js-response true
:on-success [:sanitize-messages-and-process-response]
:on-error [:contacts/remove-contact-error public-key]}]]]})

(rf/reg-event-fx :contact.ui/remove-contact-pressed remove-contact)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we're also migrating towards using the :fx key for re-frame effects.

Comment on lines +159 to +157
(fn [cofx]
(delete-for-me/sync-all cofx))
(fn [cofx]
(delete-message/send-all cofx))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Here we're wrapping these functions because delete-for-me/sync-all and delete-message/send-all are no longer defined with rf/defn.
    • It seems by default that functions defined with rf/defn are composable with rf/merge (when we don't pass all the arguments I think), and rf/merge likes to compose these functions by passing a cofx object.
    • So instead we just manually wrap the function, which seems to have the same behaviour as before.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct @seanstrom. I had to do this a few times in the past.

Comment on lines 75 to 79
(i18n/label :t/contact-request-chat-pending)

contact-request-dismissed?
(i18n/label :t/contact-request-chat-add {:name primary-name}))}]]))

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a label because we were not handling the dismissed state and that was causing some schema errors

Comment on lines +141 to +146
(let [pending-sync-messages (reduce-kv filter-pending-sync-messages [] (:messages db))
pending-effects (map (fn [message]
(fn [cofx]
(delete-and-sync cofx [message true])))
pending-sync-messages)]
(apply rf/merge cofx pending-effects)))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we're needing to wrap the call to delete-and-sync because rf/merge is expecting a sequence of functions that receive a cofx object. Normally this behaviour is handled by rf/defn but delete-and-sync no longer uses that for defining its logic.

Comment on lines 13 to 14
(testing "foo"
(is (= 1 1)))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops 🙈

Comment on lines +132 to +133
:json-rpc/call
:fx})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch!

Comment on lines +159 to +157
(fn [cofx]
(delete-for-me/sync-all cofx))
(fn [cofx]
(delete-message/send-all cofx))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct @seanstrom. I had to do this a few times in the past.


(defn delete-and-send-error
[_ [message-id error]]
(log/error "failed to delete message "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the purist, log calls are stateful and could be re-frame effects. When I see these wrapper functions for log calls I remember we could create a custom log effect and avoid the imperative calls to log. We used to do that in another re-frame project.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about this too, and I had commit for defining events and effects for call the log functions. Here's the commit: b4b808d

When you have chance, let me know what you think, I would definitely like to use log effects for this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's pretty much what I had in mind too @seanstrom. I would consider using a shorter name. For the event, could be :log/error (reads a bit better to be in the singular, but it's personal preference). And then just register other events for the other commonly supported levels we use, like debug, warn, and info.

The event :logs/log-and-attach-error I would skip to keep things plain simple. Some other app contexts could then build their own effects abstracting logs, in case a strong pattern emerges in how certain errors are logged (for example for WalletConnect).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides the PR reviewers, @clauxx @smohamedjavid what are your thoughts on this topic?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a developer, I don't need to add logs for every RPC call's on-error. In fact, the on-error or on-success should be defined ONLY if the client/UI will take any action (UI or app-db changes) based on it. Not to mention the user won't see our polite log message failed to do X/Y/Z.

I felt we have subconsciously created a pattern for RPC calls in our codebase to add logging on error and it's been followed everywhere (:on-error #(log/error "failed to do X/Y/Z")).

Now, with this PR, this might probably evolve to :on-error [:chat/delete-and-send-error] or :on-error [:log/error]

IMO, the logs should be added in the error handling part of the json-rpc call method (centralised place).

(let [error (transforms/js->clj error)]
(if (vector? on-error)
(rf/dispatch (conj on-error error))
(on-error error)))

We could log just the method name and error response, optionally params, as we have sensitive data such as passwords or private keys.

The log structure can be something like:

[json-rpc] [wallet] {:name "wallet_fetchOrGetCachedWalletBalances" :error "<ERROR_RESPONSE_GOES_HERE>"}
[json-rpc] [chat] {:name "chat_editChat" :error "..."}
[json-rpc] [wakuext] {:name "wakuext_createGroupChatWithMembers" :error "..."}

The above would help devs to search for any RPC errors in the logs by their context (e.g. searching [wallet]).

The above are just my thoughts 😅

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @smohamedjavid. I see your point and I agree with the observation that logs shouldn't ideally be polluting so many of our event handlers. Usually in past projects I used to work with 2 layers:

  1. The generic request abstraction (in our case the :json/rpc-call effect)
  2. A domain/context specific abstraction for making requests. This layer we don't have in status-mobile. This is the layer where we would log and sometimes handle errors in a particular way.

We could log just the method name and error response, optionally params, as we have sensitive data such as passwords or private keys.

I think that's the problem of having only one general abstraction such as :json/rpc-call. It shouldn't know what to log because it lacks context by definition of being generic. And logging too much is risky.

One solution is to have a separate namespace(s) defining custom effects for all RPC endpoints. These effects can safely decide what to log and the generic :json/rpc-call we would gradually stop using. They wouldn't be tied to any UI concerns. This is a sensible approach to implement, low risk as well. Would give us a central place to apply malli schemas in and out as well.

The above would help devs to search for any RPC errors in the logs by their context (e.g. searching [wallet]).

Nice idea about log groups. In status-go there's work in progress to support log namespaces, similar idea.

Anyway, I also just shared a few thoughts. Seems like we could take this discussion outside the PR since there are different ideas to explore. Maybe the DX call?

@seanstrom seanstrom force-pushed the seanstrom/cleanup-events-and-tests branch 2 times, most recently from 767ab80 to dc46391 Compare January 3, 2025 18:53
@@ -38,3 +38,75 @@
:logs/set-level
(fn [level]
(setup level)))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love this!

@vkjr
Copy link
Contributor

vkjr commented Jan 6, 2025

Thanks for the cleanup, @seanstrom! 🎉

@seanstrom seanstrom force-pushed the seanstrom/cleanup-events-and-tests branch 2 times, most recently from 87f0ae8 to f1f8b29 Compare January 6, 2025 19:57
@seanstrom seanstrom force-pushed the seanstrom/cleanup-events-and-tests branch from f1f8b29 to 7d404b7 Compare January 8, 2025 19:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: REVIEW
Development

Successfully merging this pull request may close these issues.

5 participants