Skip to content

Add RSpec test suite for existing functionality - #2

Merged
lloydwatkin merged 2 commits into
mainfrom
add-rspec-specs
Aug 14, 2026
Merged

Add RSpec test suite for existing functionality#2
lloydwatkin merged 2 commits into
mainfrom
add-rspec-specs

Conversation

@lloydwatkin

Copy link
Copy Markdown
Member

Summary

The gem had no test infrastructure. This sets up RSpec from scratch and adds coverage for the existing pure-Ruby and model-level units — 46 examples, all passing.

Run with bundle exec rspec.

What's covered

Unit Tests
Configuration defaults, mount_strategy= validation (raises + lists valid values), authentication_enabled?
ActiveAdminMcp module config memoization, configure yields and persists
RequestHandler JSON-RPC dispatch (initialize, ping, tools/list, notifications/initialized→nil, unknown method→-32601), both tools, limit defaulting/capping (25/100), empty-Ransack default, resource-not-found, unknown-tool
ResourceRegistry sensitive-attribute filtering, skipping non-existent tables / non-Ransackable models, missing :admin namespace, ActiveAdmin undefined, find hits/misses
ApiToken digest, token generation + digest-only storage, validations, find_by_raw_token (match/miss/blank), touch_last_used! throttle

Setup

  • Added rspec and sqlite3 as dev dependencies.
  • ApiToken specs run against an in-memory SQLite schema; everything else is pure unit tests with stubs/doubles.
  • spec_helper resets the memoized global config between examples so config-touching specs don't leak state.

Notes / gaps

  • No McpController or Engine request-level specs — those need a full Rails/ActiveAdmin host app to test meaningfully. The controller's auth path is indirectly covered by the ApiToken and Configuration unit tests. Worth adding a dummy-app-backed request spec later for end-to-end coverage of the Bearer-token flow.

🤖 Generated with Claude Code

lloydwatkin and others added 2 commits August 14, 2026 16:00
Set up RSpec from scratch (the gem had no test infrastructure) and cover
the pure-Ruby and model-level units:

- Configuration: defaults, mount_strategy validation, authentication_enabled?
- ActiveAdminMcp module: config memoization and configure
- RequestHandler: JSON-RPC dispatch, both tools, limit capping, error paths
- ResourceRegistry: sensitive-attribute filtering, resource discovery guards
- ApiToken: digest/token generation, validations, find_by_raw_token, throttle

ApiToken specs run against an in-memory SQLite schema; everything else is
pure unit tests with stubs. Controller/engine request specs are omitted as
they require a full Rails/ActiveAdmin host app.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Runs bundle exec rspec on push to main and on pull requests, across
Ruby 3.1–3.4.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lloydwatkin
lloydwatkin merged commit 9015a2c into main Aug 14, 2026
4 checks passed
@lloydwatkin
lloydwatkin deleted the add-rspec-specs branch August 14, 2026 15:03
lloydwatkin added a commit that referenced this pull request Aug 14, 2026
## Summary

Adds a basic `update` MCP tool — the first write operation — that
modifies a single record while enforcing the **same three rules as the
ActiveAdmin UI**:

1. **Editable resources only** — refused unless the resource exposes the
`:update` action (`resource.defined_actions`). Resources registered
`actions :index, :show` stay read-only.
2. **Authorization** — the update runs through the resource namespace's
authorization adapter (`adapter.new(config,
current_user).authorized?(:update, record)`), so CanCanCan/Pundit rules
apply for the authenticated MCP user.
3. **Permitted fields only** — attributes are filtered through the
resource's `permit_params` by driving ActiveAdmin's own
`permitted_params`, so only fields the admin form accepts are written.
Anything else is dropped (fails closed if permit params can't be
resolved).

Validation failures return the record's `full_messages`; unknown
resource / missing record / missing args return clear errors.

## Usage

```
update(resource: "User", id: 42, attributes: { name: "New name" })
```

## Changes

- `lib/active_admin_mcp/record_updater.rb` *(new)* — the gating + update
logic
- `lib/active_admin_mcp/request_handler.rb` — new `update` tool schema +
dispatch; threads `current_user` in via the constructor
- `lib/active_admin_mcp/resource_registry.rb` — `find` now also returns
the ActiveAdmin resource `config` so the updater can inspect
actions/authorization
- `app/controllers/active_admin_mcp/mcp_controller.rb` — passes
`current_mcp_user` to the handler
- `README.md` — documents the tool and its rules

## Tests

**59 examples, 0 failures.**

- New `record_updater_spec.rb` (8 examples) covering each gate,
validation failures, permitted-field filtering, and an
`error`-named-attribute regression
- Updated `request_handler_spec.rb` — `tools/list` now includes
`update`, plus dispatch coverage; updated `resource_registry_spec.rb`
for the new `find` contract

## Note — stacked on #2

This branch is built on top of the RSpec suite from #2, so the diff
currently also includes those spec-infrastructure commits. Once #2 is
merged to `main`, this diff will reduce to just the `update` feature.
Please merge #2 first.

## Follow-up

The permit-params path is unit-tested against a controller double, not a
live ActiveAdmin controller (booting a full AA dummy app is a larger
lift and needs its own harness). A dummy-app-backed integration spec for
`permitted_params` and the end-to-end update flow is a sensible
follow-up before relying on this in production.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
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