Add comprehensive API controller test coverage and serializer model tests#2250
Merged
Conversation
Tests cover all 12 UserController endpoints: - GetCurrentUser (me), GetById, GetByOrganization - Patch/Put user updates - DeleteCurrentUser, Delete (admin) - UpdateEmailAddress, VerifyEmail, ResendVerification - UnverifyEmailAddress (admin) - AddAdminRole, DeleteAdminRole (admin) Each endpoint tested for happy path, unauthorized access, and forbidden access (non-admin on admin endpoints). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ests Controller tests: - UserControllerTests: 22 tests covering all 12 endpoints - UtilityControllerTests: 5 tests for search/validate endpoint - StripeControllerTests: 3 tests for webhook error cases - StackControllerTests: ~20 new tests (ChangeStatus, Delete, GetAll, GetAsync, GetByOrganization, GetByProject, MarkCritical, MarkNotCritical, RemoveLink, Snooze) - StatusControllerTests: ~9 new tests (GetAbout, QueueStats, SystemNotification CRUD) Serializer model tests (ported from feature/system-text-json-v2): - TokenSerializerTests: roundtrip and snake_case deserialization - OrganizationSerializerTests: core properties, invites, suspension - LocationSerializerTests: full, partial, unicode roundtrip - MethodSerializerTests: all properties, minimal, snake_case - InnerErrorSerializerTests: nested errors, stack traces - ManualStackingInfoSerializerTests: signature data, special chars - SubmissionClientSerializerTests: IPv4, IPv6, minimal - UserDescriptionSerializerTests: data dictionary, minimal - SavedViewSerializerTests: columns, filters, minimal All tests use 3-part naming (Method_Scenario_Expected) with Arrange/Act/Assert pattern, inserted alphabetically. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds new integration tests for multiple API controllers and ports several serializer roundtrip / snake_case deserialization tests from feature/system-text-json-v2 to increase regression coverage ahead of future controller refactors (e.g., minimal API migration).
Changes:
- Added serializer model tests validating snake_case deserialization + roundtrip serialization for several core models.
- Added new integration test suites for
UserController,UtilityController, andStripeController. - Expanded existing controller test coverage for
StatusControllerandStackControllerwith additional endpoint scenarios.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Exceptionless.Tests/Serializer/Models/UserDescriptionSerializerTests.cs | Adds snake_case + roundtrip tests for UserDescription. |
| tests/Exceptionless.Tests/Serializer/Models/TokenSerializerTests.cs | Adds snake_case + roundtrip tests for Token variations and flags. |
| tests/Exceptionless.Tests/Serializer/Models/SubmissionClientSerializerTests.cs | Adds snake_case + roundtrip tests for SubmissionClient (IPv4/IPv6/minimal). |
| tests/Exceptionless.Tests/Serializer/Models/SavedViewSerializerTests.cs | Adds snake_case + roundtrip tests for SavedView including columns/filter data. |
| tests/Exceptionless.Tests/Serializer/Models/OrganizationSerializerTests.cs | Adds snake_case + roundtrip tests for Organization core fields/invites/suspension. |
| tests/Exceptionless.Tests/Serializer/Models/MethodSerializerTests.cs | Adds snake_case + roundtrip tests for Method including params/generics. |
| tests/Exceptionless.Tests/Serializer/Models/ManualStackingInfoSerializerTests.cs | Adds snake_case + roundtrip tests for ManualStackingInfo signature data. |
| tests/Exceptionless.Tests/Serializer/Models/LocationSerializerTests.cs | Adds snake_case + roundtrip tests for Location including unicode. |
| tests/Exceptionless.Tests/Serializer/Models/InnerErrorSerializerTests.cs | Adds snake_case + roundtrip tests for InnerError including nested inner errors. |
| tests/Exceptionless.Tests/Controllers/UtilityControllerTests.cs | Adds integration coverage for search/validate scenarios (auth/valid/invalid/premium). |
| tests/Exceptionless.Tests/Controllers/UserControllerTests.cs | Adds integration coverage for UserController endpoints (authz + basic success paths). |
| tests/Exceptionless.Tests/Controllers/StripeControllerTests.cs | Adds integration coverage for Stripe webhook error paths. |
| tests/Exceptionless.Tests/Controllers/StatusControllerTests.cs | Extends integration coverage for /about, /queue-stats, and system notification CRUD. |
| tests/Exceptionless.Tests/Controllers/StackControllerTests.cs | Extends integration coverage for stack status changes, delete/get, critical flags, links, and snoozing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Add PatchAsync tests to OrganizationControllerTests: UpdateName, NonExistent, Anonymous, EmptyName validation - Add SemanticVersionParserTests: standard semver, pre-release, wildcard, cache - Add EnumerableExtensionsTests: CollectionEquals order/equality, GetCollectionHashCode - Add DictionaryExtensionsTests: CollectionEquals, AddRange, ContainsKeyWithValue - Fix inverted logic in EnumerableExtensions.CollectionEquals (returned false for equal elements) - Fix inverted logic in DictionaryExtensions.CollectionEquals (returned false for equal values, early-returned true on first null pair) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ller ProjectController - new tests: - DeleteAsync: existing project removal, non-existent returns 404 - DeleteDataAsync: removes data key, invalid key returns 400, not found - GetAllAsync: returns user projects, respects limit parameter - GetByOrganizationAsync: returns org projects, invalid org returns 404 - GetConfigAsync: by project ID returns config - GetV2ConfigAsync: client auth returns config - GetNotificationSettingsAsync: admin gets all, user gets own - IsNameAvailableAsync: taken name returns 204, new name returns 201, org-scoped - PatchAsync: name change persists and preserves other fields, not found, extra props - PostDataAsync: valid persists, empty/dash key returns 400, not found - ResetDataAsync: clears stacks and events - SetNotificationSettingsAsync: persists settings, null removes settings AdminController - new tests: - GetSettings: returns app options, forbidden for non-admin, unauthorized - EchoRequest: returns headers/IP, forbidden, unauthorized - GetAssemblies: returns assembly list, forbidden, unauthorized - ChangePlanAsync: valid plan changes org, invalid plan fails, forbidden - SetBonusAsync: applies bonus, with expiration, invalid org returns 422, forbidden Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add 14 new TokenController tests (delete, get by org/project, patch, auth) - Add 10 new WebHookController tests (CRUD, unsubscribe, auth) - Add StringExtensions unit tests (28 tests) - Add HashExtensions unit tests (11 tests) - Add JsonExtensions unit tests (11 tests) - Fix double blank lines in serializer test files - Clean up whitespace in Status/Stripe/User controller tests - Add content-unchanged assertions on error responses Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
niemyjski
commented
May 22, 2026
niemyjski
commented
May 22, 2026
niemyjski
commented
May 22, 2026
niemyjski
commented
May 22, 2026
niemyjski
commented
May 22, 2026
niemyjski
commented
May 22, 2026
niemyjski
commented
May 22, 2026
niemyjski
commented
May 22, 2026
niemyjski
commented
May 22, 2026
niemyjski
commented
May 22, 2026
niemyjski
commented
May 22, 2026
…, and IDisposable - AdminControllerTests: remove System.Text.Json import, add private DTOs (AppSettingsDto, EchoResult, AssemblyInfo, ChangePlanResult), fix DateTime.UtcNow -> TimeProvider.GetUtcNow() in SetBonusAsync_WithExpiration - ProjectControllerTests: use TryGetValue instead of ContainsKey+indexer - StackControllerTests: rename now->utcNow/snoozeUntil->snoozeUntilUtc, add content-unchanged assertion after bad request - StatusControllerTests: restore System.Net import for HttpStatusCode - StripeControllerTests: using var StringContent, String.Empty, remove import - UtilityControllerTests: fix premium query to use tags:error (free field fix) - WebHookControllerTests: remove spurious RefreshDataAsync before GetByIdAsync - DictionaryExtensionsTests: fix 2-part names to 3-part - SemanticVersionParserTests: implement IDisposable for LoggerFactory Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…-setter deserialization - Fix IsNameAvailable tests: 204=available, 201=taken (not reversed) - Remove Assert.Single(Workers) from DeleteAsync test (project delete has no work items) - Fix PatchAsync_EmptyName: expects 400 BadRequest (not 422 UnprocessableEntity) - Fix GetCurrentUserAsync: remove IsEmailAddressVerified assertion (not set in sample data) - Fix GetByOrganizationAsync invalid org: GlobalAdmin gets 200 empty list (not 404) - Fix WebHook GetByProject: add RefreshDataAsync() before search-based GET - Fix WebHook Unsubscribe: add RefreshDataAsync() before unsubscribe (search-dependent) - Fix GetAssemblies: parse JSON directly (AssemblyDetail has private setters, STJ can't deserialize) - Add StatusCodeShouldBeNoContent() extension method Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
niemyjski
commented
May 22, 2026
niemyjski
commented
May 22, 2026
niemyjski
commented
May 22, 2026
niemyjski
commented
May 22, 2026
niemyjski
commented
May 23, 2026
niemyjski
commented
May 23, 2026
niemyjski
commented
May 23, 2026
niemyjski
commented
May 23, 2026
niemyjski
commented
May 23, 2026
The NewToken model's ProjectId property is now non-nullable, and the API schema is updated to reflect `project_id` as a required field. This change enforces explicit project association for all new tokens. When both `ProjectId` and `DefaultProjectId` are provided during token creation, `DefaultProjectId` will now be cleared. Attempts to create a token without a `ProjectId` will result in a validation error.
Refactor `ProjectController.PatchAsync` tests to send raw JSON payloads using `snake_case` property names. New assertions verify: - Read-only fields are ignored during patch updates. - Updatable fields are correctly applied while preserving others. - The API response consistently uses `snake_case` property naming, preventing potential serialization drift back to `PascalCase`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds broad API controller coverage, ports serializer model contract tests from
feature/system-text-json-v2, and includes the small production seams/fixes needed to make those API and billing paths testable.Controller Tests Added
Serializer Model Tests Ported
Ported from
feature/system-text-json-v2with roundtrip, snake_case deserialization, and explicit wire-name assertions:Production Changes
NewTokento the project-owned contract:ProjectIdis required andNewTokenimplementsIOwnedByOrganizationAndProjectdirectly.NewToken.project_idis required andViewToken.project_idremains required.IStripeBillingClient/StripeBillingClientso controller and service billing flows can be tested without hitting Stripe.StripeBillingClientinstead of recreating the client for each operation.SubscribeDatefor existing-customer paid-plan changes when it was previously null orDateTime.MinValue.Conventions
MethodUnderTest_Scenario_ExpectedBehavior.