Skip to content

Conversation

@josefinalliende
Copy link
Contributor

@josefinalliende josefinalliende commented Aug 29, 2025

Context

The bridge in flutter repo has a getUser method that called find_user_by_pubkey, but actually needed to create users too if not found.

Solution

Make public the User find_or_create_by_pubkey method

Summary by CodeRabbit

  • New Features

    • Automatically create an account when signing in with a new public key; existing accounts continue signing in seamlessly.
    • New accounts trigger background syncing of relay lists and profile metadata; sync failures are logged and do not block sign-in.
  • Tests

    • Added integration scenario and test cases covering existing-user and new-user flows (metadata, relays, and combined).

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 29, 2025

Walkthrough

Adds Whitenoise::find_or_create_user_by_pubkey(pubkey) which delegates to User::find_or_create_by_pubkey, conditionally updates relay lists for newly created users, attempts metadata sync (both log warnings on failure), and returns the User. New integration tests and scenarios exercise the flow.

Changes

Cohort / File(s) Summary
Whitenoise user API extension
src/whitenoise/users.rs
Added pub async fn find_or_create_user_by_pubkey(&self, pubkey: &PublicKey) -> Result<User> in impl Whitenoise. Calls User::find_or_create_by_pubkey(pubkey, &self.database).await; if created, attempts update_relay_lists (warnings on failure); always attempts metadata sync (warnings on failure). Added unit tests for existing/new-user cases.
Integration test registry
src/integration_tests/registry.rs
Registers and runs the new UserDiscoveryScenario as part of ScenarioRegistry::run_all_scenarios so its result is included in the integration summary.
Scenarios module export
src/integration_tests/scenarios/mod.rs
Added pub mod user_discovery; and pub use user_discovery::*; to expose the new scenario.
New integration scenario
src/integration_tests/scenarios/user_discovery.rs
Added UserDiscoveryScenario struct with new(...) and async fn run(&self, ...) executing multiple FindOrCreateUser test cases (no_data, with_metadata, with_relays, with_metadata_and_relays).
Test cases module export
src/integration_tests/test_cases/mod.rs
Added pub mod user_discovery; to include new test cases.
User-discovery test case grouping
src/integration_tests/test_cases/user_discovery/mod.rs
Added pub mod find_or_create_user; and pub use find_or_create_user::*; to expose the new test case.
Find-or-create user test case
src/integration_tests/test_cases/user_discovery/find_or_create_user.rs
New FindOrCreateUserTestCase with constructors for basic/metadata/relays/combined scenarios. Implements TestCase::run, publishing optional metadata/relays, invoking find_or_create_user_by_pubkey, and asserting ID/pubkey stability and metadata/relay expectations.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor TestRunner
  participant W as Whitenoise
  participant U as User(model)
  participant DB as Database
  participant Relay as RelaySync
  participant Meta as MetadataSync

  TestRunner->>W: find_or_create_user_by_pubkey(pubkey)
  W->>U: User::find_or_create_by_pubkey(pubkey, &DB)
  U->>DB: query by pubkey
  alt not found
    DB-->>U: none
    U->>DB: insert new user
    DB-->>U: created user
    U-->>W: (User, created=true)
    W->>Relay: update_relay_lists(&User)  -- warn on failure
  else found
    DB-->>U: existing user
    U-->>W: (User, created=false)
  end
  W->>Meta: sync_metadata(&User)  -- warn on failure
  W-->>TestRunner: Result<User>
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • erskingardner
  • delcin-raj

Poem

I nibble at the pubkey trail,
If no one lives, I dig and hail.
I peek at relays, hum metadata tunes,
Warn if the burrow is missing runes.
Hop home with user saved — carrot, please! 🥕

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/make-user-find-or-create-public

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@josefinalliende josefinalliende force-pushed the feat/make-user-find-or-create-public branch from 064a8eb to 54398dc Compare August 29, 2025 14:58
@josefinalliende
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 29, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/whitenoise/users.rs (3)

385-387: Warm up newly created users in the background

On first create, kick off best-effort background enrichment (relay lists + metadata) so callers immediately benefit from fresher state without extra round-trips.

 pub async fn find_or_create_user_by_pubkey(&self, pubkey: &PublicKey) -> Result<(User, bool)> {
-        User::find_or_create_by_pubkey(pubkey, &self.database).await
+        let (user, was_created) = User::find_or_create_by_pubkey(pubkey, &self.database).await?;
+        if was_created {
+            // Fire-and-forget enrichment; ignore errors.
+            let _ = self.background_fetch_user_data(&user).await;
+        }
+        Ok((user, was_created))
     }

380-384: Docs: remove invalid “public key format” error

The method accepts a typed PublicKey, so format errors cannot occur here. Drop this bullet to avoid confusion.

 /// # Errors
 ///
 /// This method will return an error if:
-/// - There's a database connection or query error
-/// - The public key format is invalid (though this is typically caught at the type level)
+/// - There's a database connection or query error

364-371: Docs: fix example and prevent doctest flakiness

Use from_bech32 (commonly available in nostr-sdk prelude) and mark the block no_run to avoid requiring a real environment during doctests.

-/// ```rust
-/// use nostr_sdk::PublicKey;
+/// ```rust,no_run
+/// use nostr_sdk::prelude::*;
 /// use whitenoise::Whitenoise;
 ///
 /// # async fn example(whitenoise: &Whitenoise) -> Result<(), Box<dyn std::error::Error>> {
-/// let pubkey = PublicKey::parse("npub1...")?;
+/// let pubkey = PublicKey::from_bech32("npub1...")?;
 /// let (user, was_created) = whitenoise.find_or_create_user_by_pubkey(&pubkey).await?;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 064a8eb and 54398dc.

📒 Files selected for processing (1)
  • src/whitenoise/users.rs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/whitenoise/users.rs (1)
src/whitenoise/database/users.rs (1)
  • find_or_create_by_pubkey (92-111)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: check (ubuntu-latest, native)
🔇 Additional comments (2)
src/whitenoise/users.rs (2)

342-387: Verify call-site migration

  • Update the example in src/whitenoise/users.rs (around lines 324–327) to call find_or_create_user_by_pubkey instead of find_user_by_pubkey.
  • Change the integration test in integration_tests/test_cases/subscription_processing/publish_relay_list_update.rs to use find_or_create_user_by_pubkey.
  • Confirm is_following_user in src/whitenoise/follows.rs intentionally uses find_user_by_pubkey (no auto-creation).
  • Manually review your Flutter bridge/FFI layer for any remaining find_user_by_pubkey calls.

342-387: Catch UNIQUE constraint errors in find_or_create_by_pubkey

  • Migration db_migrations/0005_new_tables.sql declares pubkey TEXT NOT NULL UNIQUE, preventing duplicate inserts.
  • In User::find_or_create_by_pubkey, wrap the insert to catch the unique‐constraint violation (e.g. a UniqueViolation variant in WhitenoiseError) and on conflict re-fetch the existing user and return (user, false).
  • Verify that save/insert surfaces unique‐constraint errors and that you handle them as described.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/whitenoise/users.rs (3)

383-403: Tighten log messages: don't say “new user” when the user may already exist.

Small accuracy fix; also include the created flag for context.

-        if created {
-            if let Err(e) = user.update_relay_lists(self).await {
+        if created {
+            if let Err(e) = user.update_relay_lists(self).await {
                 tracing::warn!(
                     target: "whitenoise::users::find_or_create_user_by_pubkey",
-                    "Failed to update relay lists for new user {}: {}",
-                    user.pubkey,
-                    e
+                    "Failed to update relay lists for user {} (created=true): {}",
+                    user.pubkey,
+                    e
                 );
             }
         }
-        if let Err(e) = user.sync_metadata(self).await {
+        if let Err(e) = user.sync_metadata(self).await {
             tracing::warn!(
                 target: "whitenoise::users::find_or_create_user_by_pubkey",
-                "Failed to sync metadata for new user {}: {}",
-                user.pubkey,
-                e
+                "Failed to sync metadata for user {} (created={}): {}",
+                user.pubkey,
+                created,
+                e
             );
         }

383-403: Consider offloading network I/O to the existing background task.

To reduce latency for callers (e.g., Flutter bridge getUser), schedule relay/metadata fetch via background_fetch_user_data and return the User immediately. Adjust only if the UI doesn’t require synchronous metadata.

-        if created {
-            if let Err(e) = user.update_relay_lists(self).await {
-                tracing::warn!(target: "whitenoise::users::find_or_create_user_by_pubkey", "Failed to update relay lists for user {} (created=true): {}", user.pubkey, e);
-            }
-        }
-        if let Err(e) = user.sync_metadata(self).await {
-            tracing::warn!(target: "whitenoise::users::find_or_create_user_by_pubkey", "Failed to sync metadata for user {} (created={}): {}", user.pubkey, created, e);
-        }
+        if let Err(e) = self.background_fetch_user_data(&user).await {
+            tracing::warn!(
+                target: "whitenoise::users::find_or_create_user_by_pubkey",
+                "Failed to schedule background fetch for user {} (created={}): {}",
+                user.pubkey,
+                created,
+                e
+            );
+        }

Would the Flutter side benefit from lower latency here, or does it rely on immediate metadata? If immediate data is required, keep the current await-based flow.


365-375: Doc example API name may be wrong for “npub” strings.

PublicKey::parse might not accept bech32 npub strings. PublicKey::from_bech32 tends to be the correct API; if not, annotate the example with no_run to avoid CI doc-test failures.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 54398dc and b5e6a87.

📒 Files selected for processing (1)
  • src/whitenoise/users.rs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/whitenoise/users.rs (2)
src/whitenoise/database/users.rs (1)
  • find_or_create_by_pubkey (92-111)
src/whitenoise/mod.rs (2)
  • create_mock_whitenoise (376-435)
  • new (55-69)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: check (macos-14, native)
  • GitHub Check: check (ubuntu-latest, native)
🔇 Additional comments (3)
src/whitenoise/users.rs (3)

342-403: Behavior matches prior feedback for the created path.

Updating relays (created=true) and attempting metadata sync aligns with earlier review guidance.


676-705: Tests: existing-user path looks good.

Validates no mutation of identity/metadata when user already exists.


708-729: Tests: new-user path covers the creation happy-path.

Asserts persistence and default metadata state. Consider asserting that a subsequent find returns the same id (already done).

@josefinalliende
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 30, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@josefinalliende
Copy link
Contributor Author

I changed the method and added some unit and integrations tests too :)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/whitenoise/users.rs (1)

342-376: Docs still misstate behavior; fix example and clarify when updates occur.

  • Text says "updates the created user's relay lists and metadata" but code syncs metadata for all users, not only newly created.
  • Example still uses PublicKey::parse(...); prefer from_bech32(...) and mark block no_run for stability.

Apply:

-    /// If the user doesn't exist, it creates a new user record with default metadata.
-    /// It also updates the created user's relay lists and metadata.
+    /// If the user doesn't exist, it creates a new user record with default metadata.
+    /// If created, it updates the user's relay lists; in all cases, it best-effort
+    /// attempts to sync the user's metadata.

-    /// ```rust
+    /// ```no_run
     /// use nostr_sdk::PublicKey;
     /// use whitenoise::Whitenoise;
     ///
     /// # async fn example(whitenoise: &Whitenoise) -> Result<(), Box<dyn std::error::Error>> {
-    /// let pubkey = PublicKey::parse("npub1...")?;
+    /// let pubkey = PublicKey::from_bech32("npub1...")?;
     /// let user = whitenoise.find_or_create_user_by_pubkey(&pubkey).await?;
     /// println!("Found user: {:?}", user.metadata.name);
     /// # Ok(())
     /// # }
     /// ```
🧹 Nitpick comments (9)
src/whitenoise/users.rs (2)

394-401: Log message says “new user” even when user already existed.

Use a context string or make the message generic.

Apply:

-        if let Err(e) = user.sync_metadata(self).await {
-            tracing::warn!(
-                target: "whitenoise::users::find_or_create_user_by_pubkey",
-                "Failed to sync metadata for new user {}: {}",
-                user.pubkey,
-                e
-            );
-        }
+        if let Err(e) = user.sync_metadata(self).await {
+            let ctx = if created { "new user" } else { "user" };
+            tracing::warn!(
+                target: "whitenoise::users::find_or_create_user_by_pubkey",
+                "Failed to sync metadata for {} {}: {}",
+                ctx,
+                user.pubkey,
+                e
+            );
+        }

383-403: Consider deferring network I/O for existing users to reduce latency.

You could run relay/metadata sync in the background for non-created users (keep synchronous for created users if you want immediate initialization).

If desired, I can propose a small wrapper using background_fetch_user_data here.

src/integration_tests/scenarios/user_discovery.rs (2)

10-14: Consider relaxing the 'static requirement

Accepting &'static Whitenoise may overconstrain callers. If feasible, switch to a generic lifetime (&'a Whitenoise).


24-24: Add a tracing span to group scenario logs

Helpful when many scenarios run in the same process.

Apply this diff:

-        tracing::info!("=== Starting Find Or Create User Scenario ===");
+        let _span = tracing::info_span!("scenario", name = "find_or_create_user").entered();
+        tracing::info!("=== Starting Find Or Create User Scenario ===");
src/integration_tests/test_cases/user_discovery/find_or_create_user.rs (5)

112-113: Make the stabilization delay configurable to reduce flakiness

Use an env override instead of a hardcoded 500ms.

Apply this diff:

-        tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
+        let delay_ms = std::env::var("WN_TEST_STABILIZATION_MS")
+            .ok()
+            .and_then(|v| v.parse::<u64>().ok())
+            .unwrap_or(500);
+        tokio::time::sleep(tokio::time::Duration::from_millis(delay_ms)).await;

45-47: Avoid unwrap() in tests; prefer expect() with context

Improves debuggability on malformed URLs.

Apply this diff:

-            RelayUrl::parse("ws://localhost:8080").unwrap(),
-            RelayUrl::parse("ws://localhost:7777").unwrap(),
+            RelayUrl::parse("ws://localhost:8080").expect("invalid test relay URL"),
+            RelayUrl::parse("ws://localhost:7777").expect("invalid test relay URL"),
-            RelayUrl::parse("ws://localhost:8080").unwrap(),
-            RelayUrl::parse("ws://localhost:7777").unwrap(),
+            RelayUrl::parse("ws://localhost:8080").expect("invalid test relay URL"),
+            RelayUrl::parse("ws://localhost:7777").expect("invalid test relay URL"),

Also applies to: 67-69


155-175: Also assert nip05 when metadata is expected

Covers the with_metadata_and_relays case and tightens validation.

Apply this diff:

                 assert_eq!(
                     user.metadata.about, expected_metadata.about,
                     "Metadata about should match published data"
                 );
+
+                assert_eq!(
+                    user.metadata.nip05, expected_metadata.nip05,
+                    "Metadata nip05 should match published data"
+                );

192-199: Avoid temporary allocation when checking relay membership

Use iterator any() instead of collecting a Vec.

Apply this diff:

-            let relay_urls: Vec<&RelayUrl> = user_relays.iter().map(|r| &r.url).collect();
-            for expected_relay in &self.test_relays {
-                assert!(
-                    relay_urls.contains(&expected_relay),
-                    "User should have relay {} that was published",
-                    expected_relay
-                );
-            }
+            for expected_relay in &self.test_relays {
+                assert!(
+                    user_relays.iter().any(|r| &r.url == expected_relay),
+                    "User should have relay {} that was published",
+                    expected_relay
+                );
+            }

80-116: Ensure logout on early errors with a simple guard

If publish fails midway, logout is skipped. A small RAII guard can enforce cleanup.

Example helper (outside this block):

struct LogoutGuard<'a> { wn: &'a Whitenoise, pk: &'a nostr_sdk::PublicKey }
impl<'a> Drop for LogoutGuard<'a> {
    fn drop(&mut self) { let _ = futures::executor::block_on(self.wn.logout(self.pk)); }
}

Use it right after login to guarantee logout even if an await returns Err.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b5e6a87 and a3bed97.

📒 Files selected for processing (7)
  • src/integration_tests/registry.rs (1 hunks)
  • src/integration_tests/scenarios/mod.rs (2 hunks)
  • src/integration_tests/scenarios/user_discovery.rs (1 hunks)
  • src/integration_tests/test_cases/mod.rs (1 hunks)
  • src/integration_tests/test_cases/user_discovery/find_or_create_user.rs (1 hunks)
  • src/integration_tests/test_cases/user_discovery/mod.rs (1 hunks)
  • src/whitenoise/users.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/integration_tests/**

📄 CodeRabbit inference engine (.cursor/rules/mls-protocol-docs.mdc)

Place MLS integration tests under src/integration_tests

Files:

  • src/integration_tests/test_cases/mod.rs
  • src/integration_tests/test_cases/user_discovery/mod.rs
  • src/integration_tests/registry.rs
  • src/integration_tests/scenarios/mod.rs
  • src/integration_tests/test_cases/user_discovery/find_or_create_user.rs
  • src/integration_tests/scenarios/user_discovery.rs
🧬 Code graph analysis (4)
src/integration_tests/registry.rs (2)
src/integration_tests/scenarios/user_discovery.rs (1)
  • run_scenario (23-45)
src/integration_tests/core/traits.rs (1)
  • run_scenario (31-31)
src/integration_tests/test_cases/user_discovery/find_or_create_user.rs (2)
src/whitenoise/accounts.rs (1)
  • metadata (189-192)
src/whitenoise/database/accounts.rs (1)
  • user (152-159)
src/integration_tests/scenarios/user_discovery.rs (1)
src/integration_tests/test_cases/user_discovery/find_or_create_user.rs (4)
  • no_data (15-24)
  • with_metadata (26-40)
  • with_relays (42-56)
  • with_metadata_and_relays (58-78)
src/whitenoise/users.rs (3)
src/whitenoise/database/users.rs (1)
  • find_or_create_by_pubkey (92-111)
src/whitenoise/mod.rs (2)
  • create_mock_whitenoise (376-435)
  • new (55-69)
src/whitenoise/accounts.rs (2)
  • new (51-70)
  • metadata (189-192)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: check (ubuntu-latest, native)
🔇 Additional comments (8)
src/whitenoise/users.rs (2)

677-705: Unit test for existing-user path looks solid.

Covers ID stability and metadata preservation.


707-729: Unit test for new-user path is clear and deterministic.

Good check that creation occurs and record is persisted.

src/integration_tests/test_cases/mod.rs (1)

9-9: Expose user_discovery test cases — LGTM.

Module surface matches the new scenario wiring.

src/integration_tests/registry.rs (1)

34-34: Added UserDiscoveryScenario to run order — LGTM.

Placement at the end is reasonable given network interactions.

src/integration_tests/scenarios/mod.rs (2)

9-9: New user_discovery scenario module — LGTM.


19-19: Public re-export — LGTM.

src/integration_tests/test_cases/user_discovery/mod.rs (1)

1-3: Module + re-export wiring — LGTM.

Follows the test-case pattern and placement guideline under src/integration_tests.

src/integration_tests/scenarios/user_discovery.rs (1)

23-45: Scenario flow looks solid

Sequentially exercising all four cases with proper error propagation. LGTM.

Copy link
Contributor

@jgmontoya jgmontoya left a comment

Choose a reason for hiding this comment

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

Nice, love to see the integration tests expanding ♥️ ! Just a couple of comments 🙏

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
src/integration_tests/test_cases/user_discovery/find_or_create_user.rs (3)

48-66: Ensure logout even on failure; avoid leaking temp sessions

If update_metadata fails, logout is skipped. Wrap the work, always attempt logout, then return the inner result.

Apply this diff:

     async fn publish_metadata(&self, context: &ScenarioContext) -> Result<(), WhitenoiseError> {
         let temp_account = context
             .whitenoise
             .login(self.test_keys.secret_key().to_secret_hex())
             .await?;
-
-        if let Some(metadata) = &self.test_metadata {
-            tracing::info!("Publishing test metadata for test pubkey");
-            temp_account
-                .update_metadata(metadata, context.whitenoise)
-                .await?;
-        }
-
-        tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
-        context.whitenoise.logout(&temp_account.pubkey).await?;
-
-        Ok(())
+        let pubkey = temp_account.pubkey.clone();
+        let res = async {
+            if let Some(metadata) = &self.test_metadata {
+                tracing::info!("Publishing test metadata for test pubkey");
+                temp_account
+                    .update_metadata(metadata, context.whitenoise)
+                    .await?;
+            }
+            tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
+            Ok::<(), WhitenoiseError>(())
+        }
+        .await;
+        let _ = context.whitenoise.logout(&pubkey).await;
+        res
     }

Optional: replace the fixed sleep with a small poll + timeout to reduce flakiness. I can propose a helper if you want.


67-92: Mirror the logout safety for relay publishing; consider retry instead of fixed sleep

Same concern: ensure logout runs even if any add_relay call fails. Keeping the sleep but wrapping in a result makes this robust.

Apply this diff:

     async fn publish_relays_data(&self, context: &ScenarioContext) -> Result<(), WhitenoiseError> {
         let temp_account = context
             .whitenoise
             .login(self.test_keys.secret_key().to_secret_hex())
             .await?;
-
-        tracing::info!("Publishing test relay list for test pubkey");
-        for relay_url in &self.test_relays {
-            let relay = context
-                .whitenoise
-                .find_or_create_relay_by_url(relay_url)
-                .await?;
-            temp_account
-                .add_relay(
-                    &relay,
-                    crate::whitenoise::relays::RelayType::Nip65,
-                    context.whitenoise,
-                )
-                .await?;
-        }
-
-        tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
-        context.whitenoise.logout(&temp_account.pubkey).await?;
-
-        Ok(())
+        let pubkey = temp_account.pubkey.clone();
+        let res = async {
+            tracing::info!("Publishing test relay list for test pubkey");
+            for relay_url in &self.test_relays {
+                let relay = context
+                    .whitenoise
+                    .find_or_create_relay_by_url(relay_url)
+                    .await?;
+                temp_account
+                    .add_relay(
+                        &relay,
+                        crate::whitenoise::relays::RelayType::Nip65,
+                        context.whitenoise,
+                    )
+                    .await?;
+            }
+            tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
+            Ok::<(), WhitenoiseError>(())
+        }
+        .await;
+        let _ = context.whitenoise.logout(&pubkey).await;
+        res
     }

Optional: as suggested in earlier feedback, consider using create_test_client instead of logging in a temp account to avoid test cross-talk.


100-105: Don’t treat any error as “not found”; match the specific variant

Using .is_ok() can hide real failures (DB/network). Match Err(WhitenoiseError::UserNotFound), panic on Ok, and bubble up other errors.

Apply this diff:

-        let user_exists = context
-            .whitenoise
-            .find_user_by_pubkey(&test_pubkey)
-            .await
-            .is_ok();
-        assert!(!user_exists, "User should not exist initially");
+        let res = context.whitenoise.find_user_by_pubkey(&test_pubkey).await;
+        match res {
+            Ok(_) => panic!("User should not exist initially"),
+            Err(WhitenoiseError::UserNotFound) => {}
+            Err(e) => return Err(e),
+        }

Run to confirm the exact error variant name and the function signature:

#!/bin/bash
rg -nP -C3 'enum\s+WhitenoiseError\b' src
rg -nP '\bUserNotFound\b' -C2 src
rg -nP '\bfind_user_by_pubkey\s*\(' -n -C2 src
🧹 Nitpick comments (2)
src/integration_tests/test_cases/user_discovery/find_or_create_user.rs (2)

157-162: Tighten the “no metadata” assertion

Avoid allowing empty-string sentinels unless the system truly emits them. Assert None for clarity.

Apply this diff:

-            assert!(
-                user.metadata.name.is_none() || user.metadata.name == Some(String::new()),
-                "User should have empty/no name when no metadata published"
-            );
+            assert!(
+                user.metadata.name.is_none(),
+                "User should have no name when no metadata was published"
+            );

172-179: Use a set for faster, order-agnostic relay checks

Minor: HashSet avoids O(n^2) contains and reads cleaner.

Apply this diff:

-            let relay_urls: Vec<&RelayUrl> = user_relays.iter().map(|r| &r.url).collect();
-            for expected_relay in &self.test_relays {
+            use std::collections::HashSet;
+            let relay_urls: HashSet<&RelayUrl> = user_relays.iter().map(|r| &r.url).collect();
+            for expected_relay in &self.test_relays {
                 assert!(
                     relay_urls.contains(&expected_relay),
                     "User should have relay {} that was published",
                     expected_relay
                 );
             }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a3bed97 and f860bc3.

📒 Files selected for processing (3)
  • src/integration_tests/scenarios/user_discovery.rs (1 hunks)
  • src/integration_tests/test_cases/user_discovery/find_or_create_user.rs (1 hunks)
  • src/whitenoise/users.rs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/integration_tests/scenarios/user_discovery.rs
  • src/whitenoise/users.rs
🧰 Additional context used
📓 Path-based instructions (1)
src/integration_tests/**

📄 CodeRabbit inference engine (.cursor/rules/mls-protocol-docs.mdc)

Place MLS integration tests under src/integration_tests

Files:

  • src/integration_tests/test_cases/user_discovery/find_or_create_user.rs
🧬 Code graph analysis (1)
src/integration_tests/test_cases/user_discovery/find_or_create_user.rs (2)
src/whitenoise/accounts.rs (1)
  • metadata (189-192)
src/whitenoise/database/accounts.rs (1)
  • user (152-159)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: check (ubuntu-latest, native)
🔇 Additional comments (1)
src/integration_tests/test_cases/user_discovery/find_or_create_user.rs (1)

26-46: Builder-style chaining looks good

Returning Self from with_metadata and with_relays enables clean chaining as requested by prior feedback. No change needed.

@josefinalliende josefinalliende merged commit 24763a5 into master Aug 30, 2025
3 checks passed
@github-project-automation github-project-automation bot moved this from In progress to Done in White Noise Aug 30, 2025
@josefinalliende josefinalliende deleted the feat/make-user-find-or-create-public branch August 30, 2025 01:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants