Skip to content

test(db): cover accounts CRUD + settings_db round-trips#67

Merged
thierryvm merged 2 commits into
mainfrom
test/db-accounts-coverage
May 11, 2026
Merged

test(db): cover accounts CRUD + settings_db round-trips#67
thierryvm merged 2 commits into
mainfrom
test/db-accounts-coverage

Conversation

@thierryvm

@thierryvm thierryvm commented May 11, 2026

Copy link
Copy Markdown
Owner

Coverage audit follow-up

Spotted 8 Rust modules with public functions but no tests. This PR fills the two highest-ROI gaps:

  • db::accounts — security-adjacent OAuth identity store, 8 public fns, 0 tests before this PR
  • db::settings_db — backs active_provider / active_model persistence the AI flow depends on, 2 public fns, 0 tests

Remaining gaps are tracked in the v0.4.x backlog — they'll get covered as we touch those modules.

What's locked in

accounts (+10 tests):

  • Insert + upsert (OAuth re-connection refreshes mutable fields without rotating id)
  • list + get_by_id (with 404 case)
  • update_product_truth / branding / display_handle / visual_profile — all round-trip set→get + clear→None
  • delete cascade: manual NULL-out of post_history.account_id because SQLite forbids FK on ALTER TABLE ADD COLUMN (migration 013 hotfix history). Regression guard against silently dropping the cascade in a future refactor.
  • delete idempotency (race between publish flow and user-clicked disconnect)

settings_db (+5 tests):

  • get None / set+get round trip / set upserts existing key
  • Migration seed verification (active_provider + active_model populated by chain 001/005/006/008/010)
  • Empty-string value accepted (intentional — keeps it a pure key-value store)

Test counts

Rust 221/221 (was 206), clippy + fmt clean. No frontend or sidecar changes.

Why these two first

db::accounts carries Product Truth + brand colours + display handle — content that lands in every generated post and every rendered image. Bugs there mutate the AI output silently. db::settings_db is the persistence layer for the model/provider selection — a broken set/get would mean the user re-picks Claude Sonnet on every launch. Both are foundational without being deeply business-logic, so unit tests carry their weight directly.

🤖 Generated with Claude Code

Résumé par Sourcery

Ajout de tests de base de données axés sur la régression pour la gestion des comptes et la persistance des paramètres.

Tests :

  • Ajout de tests complets de CRUD et de tests de round-trip des champs pour db::accounts, y compris les suppressions en cascade et les suppressions idempotentes.
  • Ajout de tests settings_db couvrant le comportement de get/set, les valeurs par défaut fournies par les migrations et l’acceptation des valeurs de chaîne vide.
Original summary in English

Summary by Sourcery

Add regression-focused database tests for account management and settings persistence.

Tests:

  • Add comprehensive CRUD and field round-trip tests for db::accounts, including delete cascades and idempotent deletes.
  • Add settings_db tests covering get/set behavior, migration-provided defaults, and acceptance of empty-string values.

Two modules with zero coverage flagged by the coverage audit
(2026-05-11). Both are foundational — accounts handles OAuth-linked
identities + Product Truth (security-adjacent), settings_db backs
the active_provider / active_model persistence the AI flow depends
on. Tests use the same fresh in-memory pool pattern as history
and groups.

## db::accounts (+10 tests)

- upsert_inserts_new_account_and_returns_it
- upsert_on_existing_account_updates_in_place
- list_returns_all_accounts_ordered_by_created_at
- get_by_id_returns_account_and_404s_on_missing
- update_product_truth_round_trips_and_clears
- update_branding_sets_both_colors_atomically (partial-clear case)
- update_display_handle_overrides_and_clears (migration 016
  regression guard for LinkedIn full-name vs brand handle)
- update_visual_profile_round_trips_and_clears
- delete_removes_account_and_nulls_post_references (manual cascade
  enforced in app code because SQLite forbids FK on ALTER ADD)
- delete_is_idempotent_on_missing_account (race between publish
  flow and disconnect must not panic)

## db::settings_db (+5 tests)

- get_returns_none_for_unknown_key
- set_then_get_round_trips
- set_on_existing_key_upserts_the_value (refresh-model flow)
- migrations_seed_default_provider_and_model (consumer-POV
  smoke for the migrations chain 001/005/006/008/010)
- set_accepts_empty_string_value (intentional — keeps the
  function pure key-value, no business-rule pollution)

Total: Rust 221/221 (was 206), clippy + fmt clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented May 11, 2026

Copy link
Copy Markdown

🧙 Sourcery a terminé la revue de votre pull request !


Conseils et commandes

Interagir avec Sourcery

  • Lancer une nouvelle revue : Commentez @sourcery-ai review sur la pull request.
  • Poursuivre les discussions : Répondez directement aux commentaires de revue de Sourcery.
  • Générer un ticket GitHub à partir d’un commentaire de revue : Demandez à Sourcery de créer un
    ticket à partir d’un commentaire de revue en répondant à celui-ci. Vous pouvez également répondre à un
    commentaire de revue avec @sourcery-ai issue pour créer un ticket à partir de celui-ci.
  • Générer un titre de pull request : Écrivez @sourcery-ai n’importe où dans le titre de la pull
    request pour générer un titre à tout moment. Vous pouvez également commenter
    @sourcery-ai title sur la pull request pour (re)générer le titre à tout moment.
  • Générer un résumé de pull request : Écrivez @sourcery-ai summary n’importe où dans
    le corps de la pull request pour générer un résumé de PR à tout moment exactement à l’endroit
    où vous le souhaitez. Vous pouvez également commenter @sourcery-ai summary sur la pull request pour
    (re)générer le résumé à tout moment.
  • Générer un guide pour les reviewers : Commentez @sourcery-ai guide sur la pull
    request pour (re)générer le guide du reviewer à tout moment.
  • Résoudre tous les commentaires Sourcery : Commentez @sourcery-ai resolve sur la
    pull request pour résoudre tous les commentaires Sourcery. Utile si vous avez déjà
    traité tous les commentaires et ne souhaitez plus les voir.
  • Ignorer toutes les revues Sourcery : Commentez @sourcery-ai dismiss sur la pull
    request pour ignorer toutes les revues Sourcery existantes. Particulièrement utile si vous
    souhaitez repartir de zéro avec une nouvelle revue – n’oubliez pas de commenter
    @sourcery-ai review pour lancer une nouvelle revue !

Personnaliser votre expérience

Accédez à votre dashboard pour :

  • Activer ou désactiver des fonctionnalités de revue comme le résumé de pull request
    généré par Sourcery, le guide du reviewer, et d’autres.
  • Modifier la langue de la revue.
  • Ajouter, supprimer ou modifier des instructions de revue personnalisées.
  • Ajuster d’autres paramètres de revue.

Obtenir de l’aide

Original review guide in English

🧙 Sourcery has finished reviewing your pull request!


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Salut - j’ai laissé quelques retours généraux :

  • Le helper fresh_pool est maintenant dupliqué dans plusieurs modules de tests de la base de données ; envisage d’extraire une utilité de test partagée (par ex. db::test_utils::fresh_pool()) pour centraliser la configuration du pool en mémoire initialisé par les migrations.
  • Le test list_returns_all_accounts_ordered_by_created_at suppose actuellement que l’ordre d’insertion est égal à l’ordre de created_at ; si l’implémentation change un jour les timestamps (par ex. avec des insertions anté-datées), cela pourrait devenir fragile, donc tu pourrais vouloir vérifier l’ordre via des timestamps explicites ou clarifier que l’ordre d’insertion fait partie du contrat.
Prompt pour agents IA
Veuillez traiter les commentaires de cette revue de code :

## Commentaires généraux
- Le helper `fresh_pool` est maintenant dupliqué dans plusieurs modules de tests de la base de données ; envisage d’extraire une utilité de test partagée (par ex. `db::test_utils::fresh_pool()`) pour centraliser la configuration du pool en mémoire initialisé par les migrations.
- Le test `list_returns_all_accounts_ordered_by_created_at` suppose actuellement que l’ordre d’insertion est égal à l’ordre de `created_at` ; si l’implémentation change un jour les timestamps (par ex. avec des insertions anté-datées), cela pourrait devenir fragile, donc vous pourriez vouloir vérifier l’ordre via des timestamps explicites ou clarifier que l’ordre d’insertion fait partie du contrat.

Sourcery est gratuit pour l’open source - si vous appréciez nos revues, pensez à les partager ✨
Aidez-moi à être plus utile ! Veuillez cliquer sur 👍 ou 👎 sur chaque commentaire et j’utiliserai vos retours pour améliorer vos revues.
Original comment in English

Hey - I've left some high level feedback:

  • The fresh_pool helper is now duplicated across multiple DB test modules; consider extracting a shared test utility (e.g., db::test_utils::fresh_pool()) to centralize the migration-bootstrapped in-memory pool setup.
  • The list_returns_all_accounts_ordered_by_created_at test currently assumes insertion order equals created_at order; if the implementation ever changes timestamps (e.g., with backdated inserts), this could become fragile, so you might want to assert ordering via explicit timestamps or clarify that insertion order is a contract.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `fresh_pool` helper is now duplicated across multiple DB test modules; consider extracting a shared test utility (e.g., `db::test_utils::fresh_pool()`) to centralize the migration-bootstrapped in-memory pool setup.
- The `list_returns_all_accounts_ordered_by_created_at` test currently assumes insertion order equals `created_at` order; if the implementation ever changes timestamps (e.g., with backdated inserts), this could become fragile, so you might want to assert ordering via explicit timestamps or clarify that insertion order is a contract.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Continuing the coverage audit started on this branch. `sidecar.rs`
has 3 public functions but they're all process-spawn / async IO —
true integration territory. What IS testable cleanly without a real
Python install is the SERDE contract of the IPC types, and that's
exactly the layer where silent cross-language drift hits the user
the hardest.

- sidecar_request_serialises_with_all_fields — every Python-side
  field present in the wire JSON. Renaming a Rust field without
  updating the sidecar would silently break generation.
- sidecar_request_serialises_api_key_none_as_null — SECURITY:
  Ollama / local flows pass None; serde must emit `null`, not
  omit. Skipping would let the sidecar fall back to an env-var
  read on the Python side.
- sidecar_data_deserialises_with_usage_field — cost tracker
  contract for the `usage` token counts.
- sidecar_data_deserialises_without_usage_for_legacy_sidecars —
  `#[serde(default)] Option<TokenUsage>` keeps stale sidecars
  parseable instead of breaking every BYOK user on update lag.
- token_usage_defaults_to_zero_when_field_missing — verify the
  `#[serde(default)]` on TokenUsage fields so a future refactor
  that drops the attribute is caught.

Total: Rust 226/226 (was 221), clippy + fmt clean.

Process-spawn coverage stays in the integration tier — out of
scope for `cargo test --lib` and tracked for a future end-to-end
suite once we have Python available in CI.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@thierryvm thierryvm merged commit 76d140e into main May 11, 2026
5 checks passed
@thierryvm thierryvm deleted the test/db-accounts-coverage branch May 11, 2026 19:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant