Skip to content

Conversation

@ekgns33
Copy link
Contributor

@ekgns33 ekgns33 commented Jul 9, 2025

작업 내역

  • 알림 수신 활성화/비활성화 API 생성
  • 테스트코드 작성

Summary by CodeRabbit

  • New Features

    • Added API endpoints for users to view and update their notification permission settings.
    • Users can now manage notification allowance and device token information.
  • Bug Fixes

    • Enforced uniqueness of device tokens to prevent duplicates.
  • Documentation

    • Enhanced API documentation for notification permission endpoints and request/response structures.
  • Tests

    • Introduced comprehensive tests for notification permission APIs, including state changes and error handling.
    • Added unit tests verifying creation and update logic for notification settings.
  • Chores

    • Updated test utilities to support cleanup of device token data.
    • Added database migration scripts for new constraints.

@ekgns33 ekgns33 requested a review from Copilot July 9, 2025 12:18
@ekgns33 ekgns33 self-assigned this Jul 9, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 9, 2025

"""

Walkthrough

This update introduces API endpoints and supporting logic for managing user notification permissions. It adds PATCH and GET endpoints for updating and querying notification allowance, implements related service interfaces and classes, updates the domain model, adds database constraints, and extends acceptance and unit tests to cover these new features.

Changes

File(s) Change Summary
.../controller/MyPageController.java Added PATCH and GET endpoints for user notification permission; integrated new service dependencies.
.../controller/request/UpdateNotificationAllowedRequst.java Introduced a new request record for updating notification permission.
.../service/dto/command/UpdateNotificationAllowedCommand.java Added a command record with a factory method for notification permission updates.
.../service/dto/response/NotificationAllowedResponse.java Added a response record for notification permission queries.
.../service/usecases/UpdateUserDetailUsecase.java
.../UpdateUserDetailUsecaseImpl.java
Introduced interface and implementation for updating user notification permissions.
.../service/usecases/query/UserInfoQueryUsecase.java
.../UserInfoQueryUsecaseImpl.java
Added interface and implementation for querying user notification permissions.
.../domain/UserDeviceToken.java Added methods for updating notification permission and device token, with validation.
.../repository/UserDeviceTokenRepository.java Added method to find device token by user ID.
.../service/UserFinder.java Added dependency and method for retrieving user device token by user ID.
.../enums/UserHttpResponseCode.java Added response codes for notification permission and device token not found.
.../resources/application.yml Added Flyway migration settings for the dev profile.
.../resources/db/migration/V202050709__add_unique_constraint_to_device_token.sql Added SQL migration to enforce unique device tokens.
.../test/java/org/runimo/runimo/CleanUpUtil.java Included "user_token" table in test cleanup utility.
.../test/java/org/runimo/runimo/user/api/MyPageAcceptanceTest.java Added acceptance tests for notification permission API, covering update, query, and error cases.
.../test/java/org/runimo/runimo/user/controller/MyPageControllerTest.java Added mocks for new use cases to controller tests.
.../test/resources/db/migration/h2/V202050709__add_unique_constraint_to_device_token.sql Added H2 migration for unique device token constraint in tests.
.../test/resources/sql/all_user_notification.sql Added test data for active and deleted users with device tokens for notification testing.
.../test/resources/sql/inactive_user_notification.sql Added test data for active and inactive users with notification-allowed tokens.
.../test/resources/sql/user_device_token_test_data.sql Added baseline test data for user, OAuth account, and device token.
.../test/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecaseImplTest.java Added unit tests for updating user notification permissions with and without existing tokens.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant MyPageController
    participant UpdateUserDetailUsecase
    participant UserFinder
    participant UserDeviceTokenRepository

    Client->>MyPageController: PATCH /notifications/permission
    MyPageController->>UpdateUserDetailUsecase: updateUserNotificationAllowed(command)
    UpdateUserDetailUsecase->>UserFinder: findUserDeviceTokenByUserId(userId)
    alt DeviceToken exists
        UpdateUserDetailUsecase->>UserDeviceTokenRepository: update device token and permission
    else DeviceToken missing
        UpdateUserDetailUsecase->>UserFinder: findUserById(userId)
        UpdateUserDetailUsecase->>UserDeviceTokenRepository: save new device token
    end
    MyPageController-->>Client: 200 OK (SuccessResponse)

    Client->>MyPageController: GET /notifications/permission
    MyPageController->>UserInfoQueryUsecase: getUserNotificationAllowed(userId)
    UserInfoQueryUsecase->>UserFinder: findUserById(userId)
    UserInfoQueryUsecase->>UserFinder: findUserDeviceTokenByUserId(userId)
    alt DeviceToken exists
        UserInfoQueryUsecase-->>MyPageController: NotificationAllowedResponse
        MyPageController-->>Client: 200 OK (SuccessResponse)
    else DeviceToken missing
        UserInfoQueryUsecase-->>MyPageController: DEVICE_TOKEN_NOT_FOUND error
        MyPageController-->>Client: 404 Not Found
    end
Loading

Possibly related PRs

  • Run-Us/Runimo#104: Introduced foundational device token management, which this PR extends for notification permission handling.

Suggested labels

:rocket: feature :rocket:

Suggested reviewers

  • jeeheaG

Poem

A rabbit hopped through fields of code,
Bringing endpoints new to lighten the load.
With tokens unique and permissions in hand,
Notifications now obey your command!
Tests abound to keep bugs at bay—
Hooray for features that brighten our day!
🐇✨
"""


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cdb22d6 and 97f5646.

📒 Files selected for processing (1)
  • src/test/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecaseImplTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/test/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecaseImplTest.java
⏰ 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: Build and analyze
✨ Finishing Touches
  • 📝 Generate Docstrings

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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai 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

Documentation and Community

  • 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.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Adds endpoints and persistence logic to enable/disable user notification permissions and stores device tokens.

  • Introduce Flyway migrations and config for a unique constraint on user_token.device_token
  • Implement new service use cases, DTOs, repository methods, domain updates, and controller endpoints for notification permission
  • Add acceptance tests for the new PATCH/GET notification-permission API and register mocks in the controller unit test

Reviewed Changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/main/resources/db/migration/V202050709__add_unique_constraint_to_device_token.sql Add unique constraint on user_token.device_token
src/test/resources/db/migration/h2/V202050709__add_unique_constraint_to_device_token.sql Same constraint for H2 test migrations
src/main/resources/application.yml Enable Flyway and point to MySQL migration path
src/test/java/org/runimo/runimo/CleanUpUtil.java Include user_token in the test-cleanup table list
src/main/java/org/runimo/runimo/user/domain/UserDeviceToken.java Add methods to update device token and notification flag
src/main/java/org/runimo/runimo/user/repository/UserDeviceTokenRepository.java Add findByUserId method
src/main/java/org/runimo/runimo/user/service/UserFinder.java Add finder for UserDeviceToken
src/main/java/org/runimo/runimo/user/service/dto/command/UpdateNotificationAllowedCommand.java Command mapping for notification updates
src/main/java/org/runimo/runimo/user/service/dto/response/NotificationAllowedResponse.java Response DTO for notification-allowed
src/main/java/org/runimo/runimo/user/service/usecases/query/UserInfoQueryUsecase*.java Interface and implementation to fetch permission
src/main/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecase*.java Interface and implementation to update permission
src/main/java/org/runimo/runimo/user/enums/UserHttpResponseCode.java Add response codes NOTIFICATION_ALLOW_* and DEVICE_TOKEN_NOT_FOUND
src/main/java/org/runimo/runimo/user/controller/MyPageController.java Add PATCH and GET endpoints under /notifications/permission
src/test/java/org/runimo/runimo/user/controller/MyPageControllerTest.java Register new use-case beans (missing endpoint tests)
src/test/java/org/runimo/runimo/user/api/MyPageAcceptanceTest.java Add acceptance tests for notification permission flows
Comments suppressed due to low confidence (3)

src/main/java/org/runimo/runimo/user/controller/request/UpdateNotificationAllowedRequst.java:6

  • The class name UpdateNotificationAllowedRequst is misspelled and should be UpdateNotificationAllowedRequest (and update all references accordingly).
public record UpdateNotificationAllowedRequst(

src/test/java/org/runimo/runimo/user/controller/MyPageControllerTest.java:41

  • Unit tests for the new PATCH /notifications/permission and GET endpoints are missing. Add controller tests that mock UpdateUserDetailUsecase and UserInfoQueryUsecase to verify each mapping and response.
    private UserInfoQueryUsecase userInfoQueryUsecase;

Copy link

@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: 3

🧹 Nitpick comments (4)
src/main/java/org/runimo/runimo/user/controller/request/UpdateNotificationAllowedRequst.java (1)

8-11: Consider adding validation annotations for required fields.

The deviceToken and platform fields might benefit from validation annotations to ensure they're not null or empty when required.

Consider adding validation annotations:

+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+
 @Schema(description = "알림 허용 여부 업데이트 요청")
 public record UpdateNotificationAllowedRequst(
     @Schema(description = "알림 허용 여부", example = "true")
+    @NotNull
     boolean allowed,
+    @NotBlank
     String deviceToken,
+    @NotBlank
     String platform
 ) {
src/main/java/org/runimo/runimo/user/service/dto/response/NotificationAllowedResponse.java (1)

7-8: Consider removing the userId field for security and simplicity.

Since this response is typically returned for authenticated users querying their own notification settings, including the userId field might be redundant and could potentially expose user IDs unnecessarily.

Consider simplifying the response:

 @Schema(description = "알림 허용 여부 응답")
 public record NotificationAllowedResponse(
-    @Schema(description = "사용자 ID", example = "1")
-    Long userId,
     @Schema(description = "알림 허용 여부", example = "true")
     boolean allowed
 ) {

This would make the API more focused and reduce potential information disclosure.

src/main/java/org/runimo/runimo/user/domain/UserDeviceToken.java (1)

70-74: Remove unused parameter or document its purpose.

The platform parameter is not used in the validation logic. If it's intended for future extensibility, consider adding a comment explaining its purpose.

-    private void validateDeviceToken(String deviceToken, DevicePlatform platform) {
+    private void validateDeviceToken(String deviceToken) {
        if (deviceToken == null || deviceToken.trim().isEmpty()) {
            throw new IllegalArgumentException("디바이스 토큰은 필수입니다");
        }
    }

And update the caller:

-        validateDeviceToken(deviceToken, this.platform);
+        validateDeviceToken(deviceToken);
src/main/java/org/runimo/runimo/user/service/usecases/query/UserInfoQueryUsecaseImpl.java (1)

16-24: Consider optimizing the user validation logic.

The current implementation performs two separate lookups:

  1. Check if user exists (line 18)
  2. Get user device token (line 21)

This could be optimized by directly querying for the device token and handling the user-not-found case within the device token lookup, reducing database calls.

Consider this optimization:

@Override
public NotificationAllowedResponse getUserNotificationAllowed(Long userId) {
-    if (userFinder.findUserById(userId).isEmpty()) {
-        throw UserException.of(UserHttpResponseCode.USER_NOT_FOUND);
-    }
-    var userDeviceToken = userFinder.findUserDeviceTokenByUserId(userId)
-        .orElseThrow(() -> UserException.of(UserHttpResponseCode.DEVICE_TOKEN_NOT_FOUND));
+    var userDeviceToken = userFinder.findUserDeviceTokenByUserId(userId)
+        .orElseThrow(() -> {
+            // Check if user exists to provide more specific error
+            if (userFinder.findUserById(userId).isEmpty()) {
+                return UserException.of(UserHttpResponseCode.USER_NOT_FOUND);
+            }
+            return UserException.of(UserHttpResponseCode.DEVICE_TOKEN_NOT_FOUND);
+        });
    return new NotificationAllowedResponse(userId, userDeviceToken.getNotificationAllowed());
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 39e739e and ed95476.

📒 Files selected for processing (18)
  • src/main/java/org/runimo/runimo/user/controller/MyPageController.java (3 hunks)
  • src/main/java/org/runimo/runimo/user/controller/request/UpdateNotificationAllowedRequst.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/domain/UserDeviceToken.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/enums/UserHttpResponseCode.java (2 hunks)
  • src/main/java/org/runimo/runimo/user/repository/UserDeviceTokenRepository.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/service/UserFinder.java (3 hunks)
  • src/main/java/org/runimo/runimo/user/service/dto/command/UpdateNotificationAllowedCommand.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/service/dto/response/NotificationAllowedResponse.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecase.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecaseImpl.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/service/usecases/query/UserInfoQueryUsecase.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/service/usecases/query/UserInfoQueryUsecaseImpl.java (1 hunks)
  • src/main/resources/application.yml (1 hunks)
  • src/main/resources/db/migration/V202050709__add_unique_constraint_to_device_token.sql (1 hunks)
  • src/test/java/org/runimo/runimo/CleanUpUtil.java (1 hunks)
  • src/test/java/org/runimo/runimo/user/api/MyPageAcceptanceTest.java (1 hunks)
  • src/test/java/org/runimo/runimo/user/controller/MyPageControllerTest.java (2 hunks)
  • src/test/resources/db/migration/h2/V202050709__add_unique_constraint_to_device_token.sql (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/main/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecaseImpl.java (1)
src/main/java/org/runimo/runimo/user/exception/UserException.java (1)
  • UserException (6-19)
src/main/java/org/runimo/runimo/user/service/usecases/query/UserInfoQueryUsecaseImpl.java (1)
src/main/java/org/runimo/runimo/user/exception/UserException.java (1)
  • UserException (6-19)
src/test/java/org/runimo/runimo/user/api/MyPageAcceptanceTest.java (1)
performance/src/lib/api-client.ts (2)
  • patch (45-78)
  • get (14-43)
🪛 GitHub Actions: development-ci
src/main/java/org/runimo/runimo/user/controller/MyPageController.java

[error] 35-35: NoSuchElementException: User not found.

src/test/java/org/runimo/runimo/user/api/MyPageAcceptanceTest.java

[error] 1-1: Cannot read SQL script from class path resource [sql/user_device_token_test_data.sql]. File not found, causing test failure.

🔇 Additional comments (32)
src/test/resources/db/migration/h2/V202050709__add_unique_constraint_to_device_token.sql (1)

1-2: LGTM! Database constraint properly implemented.

The unique constraint on device_token ensures data integrity for the notification permission feature. The constraint name follows naming conventions and the SQL syntax is correct.

src/main/resources/db/migration/V202050709__add_unique_constraint_to_device_token.sql (1)

1-2: LGTM! Consistent with H2 migration script.

The MySQL migration script is identical to the H2 version, ensuring consistency between test and production environments. The unique constraint will properly enforce device token uniqueness.

src/test/java/org/runimo/runimo/CleanUpUtil.java (1)

18-18: LGTM! Proper test cleanup support for new table.

Adding "user_token" to the cleanup utility is necessary to ensure test isolation for the new notification permission feature. The table will be properly reset between test runs.

src/main/resources/application.yml (1)

120-124: LGTM! Appropriate Flyway configuration for development.

The Flyway configuration is properly set up for the dev profile with standard settings. The baseline-on-migrate: true and clean-disabled: false settings are appropriate for development environment.

src/main/java/org/runimo/runimo/user/repository/UserDeviceTokenRepository.java (2)

3-3: LGTM! Proper import for Optional return type.

The import is correctly added to support the Optional return type in the new repository method.


11-11: LGTM! Repository method follows Spring Data JPA conventions.

The findByUserId method properly follows Spring Data JPA naming conventions and returns an Optional<UserDeviceToken> to handle potential null results. This enables querying device tokens by user ID for the notification permission feature.

src/main/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecase.java (1)

5-8: Clean interface design following SOLID principles.

The interface follows good design patterns with single responsibility and appropriate command pattern usage.

src/main/java/org/runimo/runimo/user/service/usecases/query/UserInfoQueryUsecase.java (1)

5-9: Good separation of query operations using CQRS pattern.

The interface appropriately separates query operations from commands and uses clear naming conventions.

src/main/java/org/runimo/runimo/user/service/UserFinder.java (3)

7-7: LGTM: Clean import additions.

The imports are necessary for the new functionality and follow the existing import organization.

Also applies to: 9-9


20-20: LGTM: Repository dependency added correctly.

The field follows the existing pattern and is properly used in the new method.


37-40: LGTM: Well-implemented finder method.

The method follows the established patterns in the class with proper transaction annotation and consistent Optional return type.

src/main/java/org/runimo/runimo/user/domain/UserDeviceToken.java (2)

60-62: LGTM: Simple and effective update method.

The method correctly updates the notification allowed flag with proper encapsulation.


64-68: LGTM: Good practice with validation and timestamp update.

The method properly validates the device token and updates the lastUsedAt timestamp, which is good for tracking token usage.

src/main/java/org/runimo/runimo/user/enums/UserHttpResponseCode.java (2)

17-18: LGTM: Well-defined response codes for notification features.

The new enum values follow the established pattern with appropriate HTTP status codes and consistent Korean messages.


32-33: LGTM: Proper enum syntax and new error code.

The comma addition to USER_NOT_FOUND and the new DEVICE_TOKEN_NOT_FOUND enum value are correctly implemented.

src/main/java/org/runimo/runimo/user/service/dto/command/UpdateNotificationAllowedCommand.java (2)

6-11: LGTM: Well-structured command record.

The record definition is clean with appropriate fields for the notification update operation.


13-17: LGTM: Good factory method design.

The static factory method provides a clean conversion from request to command with proper platform enum conversion.

src/main/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecaseImpl.java (3)

18-19: LGTM: Clean dependency injection setup.

The required dependencies are properly injected following the established patterns.


23-29: LGTM: Solid transaction handling with find-or-create pattern.

The method correctly handles both existing and new device tokens. The updateDeviceToken call on existing tokens is appropriate for updating the lastUsedAt timestamp.


31-43: LGTM: Proper user validation and token creation.

The method correctly validates user existence and creates a new device token using the builder pattern. The exception handling with the appropriate error code is well-implemented.

src/main/java/org/runimo/runimo/user/controller/MyPageController.java (6)

3-5: LGTM - Proper Swagger imports added.

The new Swagger imports are correctly added to support the API documentation for the new endpoints.


8-8: LGTM - New class imports are properly organized.

The new imports for request/response DTOs and use cases are correctly added and follow the existing package structure.

Also applies to: 10-10, 12-12, 15-15


18-21: LGTM - Required annotations imported for new endpoints.

The new annotations @PatchMapping and @RequestBody are correctly imported for the new PATCH endpoint functionality.


29-30: LGTM - New dependencies properly injected.

The new use case dependencies are correctly injected using constructor injection pattern consistent with the existing code.


40-54: LGTM - Well-structured PATCH endpoint with proper documentation.

The notification permission update endpoint is well-implemented with:

  • Comprehensive Swagger documentation
  • Proper request/response handling
  • Appropriate HTTP status codes
  • Consistent error response patterns

56-68: LGTM - Well-structured GET endpoint with proper documentation.

The notification permission query endpoint is well-implemented with:

  • Comprehensive Swagger documentation
  • Proper response handling
  • Appropriate HTTP status codes
  • Consistent error response patterns
src/main/java/org/runimo/runimo/user/service/usecases/query/UserInfoQueryUsecaseImpl.java (1)

1-14: LGTM - Proper class structure and dependencies.

The service implementation is correctly structured with:

  • Proper package declaration
  • Required imports
  • Spring annotations
  • Constructor injection via Lombok
src/test/java/org/runimo/runimo/user/api/MyPageAcceptanceTest.java (5)

76-111: LGTM - Comprehensive test for updating existing notification permission.

The test properly validates:

  • PATCH request with existing device token
  • Response status and message
  • State verification with GET request
  • Proper JSON structure and content type

113-148: LGTM - Good test coverage for new token creation.

The test correctly validates the scenario where a user without a device token creates a new one, including proper verification of the created state.


150-186: LGTM - Proper test for token update scenario.

The test correctly handles the case where an existing user's device token information is updated, including platform and token value changes.


188-210: LGTM - Proper error handling test for invalid platform.

The test correctly validates that invalid platform values result in a 400 Bad Request response, which is appropriate for client-side validation errors.


212-227: LGTM - Proper test for missing device token scenario.

The test correctly validates the 404 Not Found response when querying notification permission for a user without a device token.

@pull-request-size pull-request-size bot added size/XL and removed size/L labels Jul 9, 2025
Copy link

@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: 3

🧹 Nitpick comments (1)
src/test/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecaseImplTest.java (1)

36-76: Consider adding edge case tests.

The current tests cover the main scenarios well, but consider adding tests for edge cases such as:

  • Invalid user ID
  • Null or empty device token
  • Invalid platform enum values
  • Exception handling scenarios

This would provide more comprehensive coverage of the use case behavior.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e84ad04 and cdb22d6.

📒 Files selected for processing (1)
  • src/test/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecaseImplTest.java (1 hunks)
⏰ 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: Build and analyze
🔇 Additional comments (1)
src/test/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecaseImplTest.java (1)

23-34: LGTM - Well-structured test setup.

The test setup properly initializes mocks and the use case instance using dependency injection. The use of MockitoAnnotations.openMocks(this) follows best practices.

import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.runimo.runimo.user.UserFixtures;
import org.runimo.runimo.user.controller.request.UpdateNotificationAllowedRequst;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typo in class name.

There's a typo in the imported class name - UpdateNotificationAllowedRequst should be UpdateNotificationAllowedRequest (missing 'e').

-import org.runimo.runimo.user.controller.request.UpdateNotificationAllowedRequst;
+import org.runimo.runimo.user.controller.request.UpdateNotificationAllowedRequest;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import org.runimo.runimo.user.controller.request.UpdateNotificationAllowedRequst;
import org.runimo.runimo.user.controller.request.UpdateNotificationAllowedRequest;
🤖 Prompt for AI Agents
In
src/test/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecaseImplTest.java
at line 14, fix the typo in the import statement by changing the class name from
UpdateNotificationAllowedRequst to UpdateNotificationAllowedRequest, adding the
missing 'e' to correct the class name.

Comment on lines 57 to 76
@Test
void 토큰_있으면_생성안함() {
given(userDeviceTokenRepository.findByUserId(any()))
.willReturn(
Optional.ofNullable(UserDeviceToken.from("token", DevicePlatform.APNS, true)));
given(userFinder.findUserById(any()))
.willReturn(Optional.ofNullable(UserFixtures.getDefaultUser()));
given(userDeviceTokenRepository.save(any()))
.willReturn(UserDeviceToken.from("token", DevicePlatform.APNS, true));
var command = UpdateNotificationAllowedCommand.of(
1L,
new UpdateNotificationAllowedRequst(true, "token", "APNS")
);

// when
updateUserDetailUsecase.updateUserNotificationAllowed(command);

// then
verify(userDeviceTokenRepository, times(0)).save(any());
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typo and remove unnecessary mock setup.

The test logic is correct but has the same typo. Additionally, the mock setup for userDeviceTokenRepository.save() is unnecessary since the test expects it to never be called.

-        var command = UpdateNotificationAllowedCommand.of(
-            1L,
-            new UpdateNotificationAllowedRequst(true, "token", "APNS")
-        );
+        var command = UpdateNotificationAllowedCommand.of(
+            1L,
+            new UpdateNotificationAllowedRequest(true, "token", "APNS")
+        );

Optional cleanup: Remove the unnecessary mock setup since save() should never be called:

-        given(userDeviceTokenRepository.save(any()))
-            .willReturn(UserDeviceToken.from("token", DevicePlatform.APNS, true));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Test
void 토큰_있으면_생성안함() {
given(userDeviceTokenRepository.findByUserId(any()))
.willReturn(
Optional.ofNullable(UserDeviceToken.from("token", DevicePlatform.APNS, true)));
given(userFinder.findUserById(any()))
.willReturn(Optional.ofNullable(UserFixtures.getDefaultUser()));
given(userDeviceTokenRepository.save(any()))
.willReturn(UserDeviceToken.from("token", DevicePlatform.APNS, true));
var command = UpdateNotificationAllowedCommand.of(
1L,
new UpdateNotificationAllowedRequst(true, "token", "APNS")
);
// when
updateUserDetailUsecase.updateUserNotificationAllowed(command);
// then
verify(userDeviceTokenRepository, times(0)).save(any());
}
@Test
void 토큰_있으면_생성안함() {
given(userDeviceTokenRepository.findByUserId(any()))
.willReturn(
Optional.ofNullable(UserDeviceToken.from("token", DevicePlatform.APNS, true)));
given(userFinder.findUserById(any()))
.willReturn(Optional.ofNullable(UserFixtures.getDefaultUser()));
var command = UpdateNotificationAllowedCommand.of(
1L,
new UpdateNotificationAllowedRequest(true, "token", "APNS")
);
// when
updateUserDetailUsecase.updateUserNotificationAllowed(command);
// then
verify(userDeviceTokenRepository, times(0)).save(any());
}
🤖 Prompt for AI Agents
In
src/test/java/org/runimo/runimo/user/service/usecases/UpdateUserDetailUsecaseImplTest.java
around lines 57 to 76, fix the typo in the class name
UpdateNotificationAllowedRequst to UpdateNotificationAllowedRequest. Also,
remove the mock setup for userDeviceTokenRepository.save() since the test
verifies that save() is never called, making this setup unnecessary.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Jul 9, 2025

@ekgns33 ekgns33 merged commit 7e38fd2 into main Jul 9, 2025
3 checks passed
@ekgns33 ekgns33 deleted the feat/change-notification-permission branch July 9, 2025 13:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants