From a3369f0ea68b5778c7e943dd406b3f04fcef2db9 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 11 Jun 2025 23:29:24 +0900 Subject: [PATCH 1/4] :card_file_box: chore: adjust SQL schema formatting and add `total_time_in_seconds` to `running_record` table --- src/main/resources/sql/schema.sql | 33 ++++++++++++++++--------------- src/test/resources/sql/schema.sql | 33 ++++++++++++++++--------------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/main/resources/sql/schema.sql b/src/main/resources/sql/schema.sql index dc2e3a2..eeb2385 100644 --- a/src/main/resources/sql/schema.sql +++ b/src/main/resources/sql/schema.sql @@ -25,14 +25,14 @@ CREATE TABLE `users` `public_id` VARCHAR(255), `nickname` VARCHAR(255), `img_url` VARCHAR(255), - `total_distance_in_meters` BIGINT NOT NULL DEFAULT 0, - `total_time_in_seconds` BIGINT NOT NULL DEFAULT 0, + `total_distance_in_meters` BIGINT NOT NULL DEFAULT 0, + `total_time_in_seconds` BIGINT NOT NULL DEFAULT 0, `main_runimo_id` BIGINT, `gender` VARCHAR(24), `role` VARCHAR(24) NOT NULL DEFAULT 'USER', - `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - `deleted_at` TIMESTAMP NULL + `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + `deleted_at` TIMESTAMP NULL ); CREATE TABLE `user_token` @@ -93,7 +93,7 @@ CREATE TABLE `signup_token` CREATE TABLE `running_record` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `user_id` BIGINT NOT NULL, + `user_id` BIGINT NOT NULL, `record_public_id` VARCHAR(255) NOT NULL, `title` VARCHAR(255), `description` VARCHAR(255), @@ -101,6 +101,7 @@ CREATE TABLE `running_record` `started_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `end_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `total_distance` BIGINT, + `total_time_in_seconds` BIGINT, `pace_in_milli_seconds` BIGINT, `is_rewarded` BOOLEAN, `pace_per_km` VARCHAR(10000), @@ -141,8 +142,8 @@ CREATE TABLE `egg_type` CREATE TABLE `item_activity` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `activity_user_id` BIGINT NOT NULL, - `activity_item_id` BIGINT NOT NULL, + `activity_user_id` BIGINT NOT NULL, + `activity_item_id` BIGINT NOT NULL, `activity_event_type` VARCHAR(255) NOT NULL, `quantity` BIGINT, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, @@ -153,9 +154,9 @@ CREATE TABLE `item_activity` CREATE TABLE `user_item` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `user_id` BIGINT NOT NULL, - `item_id` BIGINT NOT NULL, - `quantity` BIGINT NOT NULL, + `user_id` BIGINT NOT NULL, + `item_id` BIGINT NOT NULL, + `quantity` BIGINT NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `deleted_at` TIMESTAMP NULL @@ -164,8 +165,8 @@ CREATE TABLE `user_item` CREATE TABLE `incubating_egg` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `user_id` BIGINT NOT NULL, - `egg_id` BIGINT NOT NULL, + `user_id` BIGINT NOT NULL, + `egg_id` BIGINT NOT NULL, `current_love_point_amount` BIGINT, `hatch_require_amount` BIGINT, `egg_status` VARCHAR(255), @@ -201,9 +202,9 @@ CREATE TABLE `runimo` CREATE TABLE `user_refresh_token` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `user_id` BIGINT NOT NULL UNIQUE , - `refresh_token` TEXT NOT NULL, + `id` BIGINT PRIMARY KEY AUTO_INCREMENT, + `user_id` BIGINT NOT NULL UNIQUE, + `refresh_token` TEXT NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); diff --git a/src/test/resources/sql/schema.sql b/src/test/resources/sql/schema.sql index dc2e3a2..77cf95e 100644 --- a/src/test/resources/sql/schema.sql +++ b/src/test/resources/sql/schema.sql @@ -25,14 +25,14 @@ CREATE TABLE `users` `public_id` VARCHAR(255), `nickname` VARCHAR(255), `img_url` VARCHAR(255), - `total_distance_in_meters` BIGINT NOT NULL DEFAULT 0, - `total_time_in_seconds` BIGINT NOT NULL DEFAULT 0, + `total_distance_in_meters` BIGINT NOT NULL DEFAULT 0, + `total_time_in_seconds` BIGINT NOT NULL DEFAULT 0, `main_runimo_id` BIGINT, `gender` VARCHAR(24), `role` VARCHAR(24) NOT NULL DEFAULT 'USER', - `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - `deleted_at` TIMESTAMP NULL + `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + `deleted_at` TIMESTAMP NULL ); CREATE TABLE `user_token` @@ -93,13 +93,14 @@ CREATE TABLE `signup_token` CREATE TABLE `running_record` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `user_id` BIGINT NOT NULL, + `user_id` BIGINT NOT NULL, `record_public_id` VARCHAR(255) NOT NULL, `title` VARCHAR(255), `description` VARCHAR(255), `img_url` VARCHAR(255), `started_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `end_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + `total_time_in_seconds` BIGINT, `total_distance` BIGINT, `pace_in_milli_seconds` BIGINT, `is_rewarded` BOOLEAN, @@ -141,8 +142,8 @@ CREATE TABLE `egg_type` CREATE TABLE `item_activity` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `activity_user_id` BIGINT NOT NULL, - `activity_item_id` BIGINT NOT NULL, + `activity_user_id` BIGINT NOT NULL, + `activity_item_id` BIGINT NOT NULL, `activity_event_type` VARCHAR(255) NOT NULL, `quantity` BIGINT, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, @@ -153,9 +154,9 @@ CREATE TABLE `item_activity` CREATE TABLE `user_item` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `user_id` BIGINT NOT NULL, - `item_id` BIGINT NOT NULL, - `quantity` BIGINT NOT NULL, + `user_id` BIGINT NOT NULL, + `item_id` BIGINT NOT NULL, + `quantity` BIGINT NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `deleted_at` TIMESTAMP NULL @@ -164,8 +165,8 @@ CREATE TABLE `user_item` CREATE TABLE `incubating_egg` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `user_id` BIGINT NOT NULL, - `egg_id` BIGINT NOT NULL, + `user_id` BIGINT NOT NULL, + `egg_id` BIGINT NOT NULL, `current_love_point_amount` BIGINT, `hatch_require_amount` BIGINT, `egg_status` VARCHAR(255), @@ -201,9 +202,9 @@ CREATE TABLE `runimo` CREATE TABLE `user_refresh_token` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `user_id` BIGINT NOT NULL UNIQUE , - `refresh_token` TEXT NOT NULL, + `id` BIGINT PRIMARY KEY AUTO_INCREMENT, + `user_id` BIGINT NOT NULL UNIQUE, + `refresh_token` TEXT NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); From cc9a4e44c6a53593878bd3acca34ddffde34ae3b Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 11 Jun 2025 23:30:05 +0900 Subject: [PATCH 2/4] :card_file_box: chore: refine SQL formatting and update `running_record` with `total_time_in_seconds` field --- src/test/resources/sql/data.sql | 15 ++++++++ src/test/resources/sql/main_view_data.sql | 13 ++++--- .../resources/sql/user_mypage_test_data.sql | 9 ++--- src/test/resources/sql/weekly_record_data.sql | 35 ++++++++++++------- .../sql/weekly_record_partial_data.sql | 26 +++++++++----- 5 files changed, 68 insertions(+), 30 deletions(-) create mode 100644 src/test/resources/sql/data.sql diff --git a/src/test/resources/sql/data.sql b/src/test/resources/sql/data.sql new file mode 100644 index 0000000..b384b36 --- /dev/null +++ b/src/test/resources/sql/data.sql @@ -0,0 +1,15 @@ +TRUNCATE TABLE item; + +INSERT INTO item (name, item_code, description, item_type, img_url, dtype, egg_type_id, + hatch_require_amount, created_at, + updated_at) +VALUES ('마당알', 'A100', '마당알: 기본 알', 'USABLE', + 'https://runimo.s3.ap-northeast-2.amazonaws.com/R-100_Egg.png', 'EGG', 1, 10, NOW(), + NOW()); + +INSERT INTO item (name, item_code, description, item_type, img_url, dtype, egg_type_id, + hatch_require_amount, created_at, + updated_at) +VALUES ('숲알', 'A101', '숲알: 기본 알', 'USABLE', + 'https://runimo.s3.ap-northeast-2.amazonaws.com/R-110_Egg.png', 'EGG', 2, 20, NOW(), + NOW()); diff --git a/src/test/resources/sql/main_view_data.sql b/src/test/resources/sql/main_view_data.sql index 964e5d9..4e714c7 100644 --- a/src/test/resources/sql/main_view_data.sql +++ b/src/test/resources/sql/main_view_data.sql @@ -20,8 +20,8 @@ VALUES ('마당알', 'A100', '마당알: 기본 알', 'USABLE', 'example.url', ' TRUNCATE TABLE runimo_definition; INSERT INTO runimo_definition (id, name, code, description, img_url, egg_type_id, created_at, updated_at) -VALUES (1, '토끼', 'R-101', '마당-토끼예여', 'http://dummy1', 1, NOW(), NOW()), - (2, '강아지', 'R-102', '마당-강아지예여', 'http://dummy1', 1, NOW(), NOW()), +VALUES (1, '토끼', 'R-101', '마당-토끼예여', 'http://dummy1', 1, NOW(), NOW()), + (2, '강아지', 'R-102', '마당-강아지예여', 'http://dummy1', 1, NOW(), NOW()), (3, '오리', 'R-103', '마당-오리예여', 'http://dummy1', 1, NOW(), NOW()), (4, '고양이', 'R-104', '마당-고양이예여', 'http://dummy1', 1, NOW(), NOW()), (5, '늑대 강아지', 'R-105', '늑대 강아지예여', 'http://dummy2', 2, NOW(), NOW()), @@ -33,10 +33,13 @@ VALUES (1, '토끼', 'R-101', '마당-토끼예여', 'http://dummy1', 1, N TRUNCATE TABLE running_record; INSERT INTO running_record (id, user_id, record_public_id, title, started_at, end_at, - total_distance, pace_in_milli_seconds, is_rewarded, created_at, + total_distance, total_time_in_seconds, pace_in_milli_seconds, + is_rewarded, created_at, updated_at) -VALUES (1, 1, 'record-public-id-1', 'record-title-1', NOW(), NOW(), 1000, 100, false, NOW(), NOW()), - (2, 1, 'record-public-id-2', 'record-title-2', NOW(), NOW(), 2000, 200, false, NOW(), NOW()); +VALUES (1, 1, 'record-public-id-1', 'record-title-1', NOW(), NOW(), 1000, 1000, 100, false, NOW(), + NOW()), + (2, 1, 'record-public-id-2', 'record-title-2', NOW(), NOW(), 2000, 1000, 200, false, NOW(), + NOW()); TRUNCATE TABLE runimo; INSERT INTO runimo (id, user_id, runimo_definition_id, total_run_count, total_distance_in_meters, diff --git a/src/test/resources/sql/user_mypage_test_data.sql b/src/test/resources/sql/user_mypage_test_data.sql index 384d62a..e6f7496 100644 --- a/src/test/resources/sql/user_mypage_test_data.sql +++ b/src/test/resources/sql/user_mypage_test_data.sql @@ -10,7 +10,7 @@ SET FOREIGN_KEY_CHECKS = 1; TRUNCATE TABLE oauth_account; INSERT INTO oauth_account (id, created_at, deleted_at, updated_at, provider, provider_id, user_id) - VALUES (1, NOW(), null, NOW(), 'KAKAO', 1234, 1); +VALUES (1, NOW(), null, NOW(), 'KAKAO', 1234, 1); -- 보유 아이템 TRUNCATE TABLE user_item; @@ -25,10 +25,11 @@ VALUES (1001, 1, 0, NOW(), NOW()); TRUNCATE TABLE running_record; INSERT INTO running_record (id, user_id, record_public_id, title, started_at, end_at, - total_distance, pace_in_milli_seconds, is_rewarded, created_at, + total_distance, total_time_in_seconds, pace_in_milli_seconds, + is_rewarded, created_at, updated_at) VALUES (1, 1, 'record-public-id-1', 'record-title-1', '2025-03-20 13:00:00', '2025-03-20 13:00:00', - 1234, 6666, false, NOW(), NOW()), + 1234, 3600, 6666, false, NOW(), NOW()), (2, 1, 'record-public-id-2', 'record-title-2', '2025-03-29 13:00:00', '2025-03-29 14:00:00', - 2345, 6700, false, NOW(), NOW()); + 2345, 3600, 6700, false, NOW(), NOW()); diff --git a/src/test/resources/sql/weekly_record_data.sql b/src/test/resources/sql/weekly_record_data.sql index 69994f5..cdeb4b3 100644 --- a/src/test/resources/sql/weekly_record_data.sql +++ b/src/test/resources/sql/weekly_record_data.sql @@ -1,22 +1,33 @@ -- 사용자 SET FOREIGN_KEY_CHECKS = 0; TRUNCATE TABLE users; -INSERT INTO users (id, public_id, nickname, img_url, total_distance_in_meters, total_time_in_seconds, created_at, +INSERT INTO users (id, public_id, nickname, img_url, total_distance_in_meters, + total_time_in_seconds, created_at, updated_at) -VALUES (1, 'test-user-uuid-1', 'Daniel', 'https://example.com/images/user1.png', 3000, 3600, NOW(), NOW()); +VALUES (1, 'test-user-uuid-1', 'Daniel', 'https://example.com/images/user1.png', 3000, 3600, NOW(), + NOW()); SET FOREIGN_KEY_CHECKS = 1; TRUNCATE TABLE running_record; -INSERT INTO running_record (id, user_id, record_public_id, title, started_at, end_at, total_distance, pace_in_milli_seconds, is_rewarded, created_at, updated_at) -VALUES - (1, 1, 'record-public-id-1', 'record-title-1', '2025-03-31 10:00:00', '2025-03-31 11:00:00', 1000, 100, false, NOW(), NOW()), - (2, 1, 'record-public-id-2', 'record-title-2', '2025-04-01 10:00:00', '2025-04-01 11:00:00', 2000, 200, false, NOW(), NOW()), - (3, 1, 'record-public-id-3', 'record-title-3', '2025-04-02 10:00:00', '2025-04-02 11:00:00', 3000, 300, false, NOW(), NOW()), - (4, 1, 'record-public-id-4', 'record-title-4', '2025-04-03 10:00:00', '2025-04-03 11:00:00', 4000, 400, false, NOW(), NOW()), - (5, 1, 'record-public-id-5', 'record-title-5', '2025-04-04 10:00:00', '2025-04-04 11:00:00', 5000, 500, false, NOW(), NOW()), - (6, 1, 'record-public-id-6', 'record-title-6', '2025-04-05 10:00:00', '2025-04-05 11:00:00', 6000, 600, false, NOW(), NOW()), - (7, 1, 'record-public-id-7', 'record-title-7', '2025-04-06 10:00:00', '2025-04-06 11:00:00', 7000, 700, false, NOW(), NOW()), - (8, 1, 'record-public-id-8', 'record-title-8', '2025-04-06 10:00:00', '2025-04-06 11:00:00', 7000, 700, false, NOW(), NOW()); +INSERT INTO running_record (id, user_id, record_public_id, title, started_at, end_at, + total_distance, total_time_in_seconds, pace_in_milli_seconds, + is_rewarded, created_at, updated_at) +VALUES (1, 1, 'record-public-id-1', 'record-title-1', '2025-03-31 10:00:00', '2025-03-31 11:00:00', + 1000, 3600, 100, false, NOW(), NOW()), + (2, 1, 'record-public-id-2', 'record-title-2', '2025-04-01 10:00:00', '2025-04-01 11:00:00', + 2000, 3600, 200, false, NOW(), NOW()), + (3, 1, 'record-public-id-3', 'record-title-3', '2025-04-02 10:00:00', '2025-04-02 11:00:00', + 3000, 3600, 300, false, NOW(), NOW()), + (4, 1, 'record-public-id-4', 'record-title-4', '2025-04-03 10:00:00', '2025-04-03 11:00:00', + 4000, 3600, 400, false, NOW(), NOW()), + (5, 1, 'record-public-id-5', 'record-title-5', '2025-04-04 10:00:00', '2025-04-04 11:00:00', + 5000, 3600, 500, false, NOW(), NOW()), + (6, 1, 'record-public-id-6', 'record-title-6', '2025-04-05 10:00:00', '2025-04-05 11:00:00', + 6000, 3600, 600, false, NOW(), NOW()), + (7, 1, 'record-public-id-7', 'record-title-7', '2025-04-06 10:00:00', '2025-04-06 11:00:00', + 7000, 3600, 700, false, NOW(), NOW()), + (8, 1, 'record-public-id-8', 'record-title-8', '2025-04-06 10:00:00', '2025-04-06 11:00:00', + 7000, 3600, 700, false, NOW(), NOW()); diff --git a/src/test/resources/sql/weekly_record_partial_data.sql b/src/test/resources/sql/weekly_record_partial_data.sql index d5d7203..fe175ba 100644 --- a/src/test/resources/sql/weekly_record_partial_data.sql +++ b/src/test/resources/sql/weekly_record_partial_data.sql @@ -1,19 +1,27 @@ -- 사용자 SET FOREIGN_KEY_CHECKS = 0; TRUNCATE TABLE users; -INSERT INTO users (id, public_id, nickname, img_url, total_distance_in_meters, total_time_in_seconds, created_at, +INSERT INTO users (id, public_id, nickname, img_url, total_distance_in_meters, + total_time_in_seconds, created_at, updated_at) -VALUES (1, 'test-user-uuid-1', 'Daniel', 'https://example.com/images/user1.png', 3000, 3600, NOW(), NOW()); +VALUES (1, 'test-user-uuid-1', 'Daniel', 'https://example.com/images/user1.png', 3000, 3600, NOW(), + NOW()); SET FOREIGN_KEY_CHECKS = 1; TRUNCATE TABLE running_record; -INSERT INTO running_record (id, user_id, record_public_id, title, started_at, end_at, total_distance, pace_in_milli_seconds, is_rewarded, created_at, updated_at) -VALUES - (1, 1, 'record-public-id-1', 'record-title-1', '2025-03-31 10:00:00', '2025-03-31 11:00:00', 1000, 100, false, NOW(), NOW()), - (2, 1, 'record-public-id-2', 'record-title-2', '2025-04-01 10:00:00', '2025-04-01 11:00:00', 2000, 200, false, NOW(), NOW()), - (3, 1, 'record-public-id-3', 'record-title-3', '2025-04-04 10:00:00', '2025-04-04 11:00:00', 5000, 500, false, NOW(), NOW()), - (4, 1, 'record-public-id-4', 'record-title-4', '2025-04-05 10:00:00', '2025-04-05 11:00:00', 6000, 600, false, NOW(), NOW()), - (5, 1, 'record-public-id-5', 'record-title-5', '2025-04-06 10:00:00', '2025-04-06 11:00:00', 7000, 700, false, NOW(), NOW()); +INSERT INTO running_record (id, user_id, record_public_id, title, started_at, end_at, + total_distance, total_time_in_seconds, pace_in_milli_seconds, + is_rewarded, created_at, updated_at) +VALUES (1, 1, 'record-public-id-1', 'record-title-1', '2025-03-31 10:00:00', '2025-03-31 11:00:00', + 1000, 3600, 100, false, NOW(), NOW()), + (2, 1, 'record-public-id-2', 'record-title-2', '2025-04-01 10:00:00', '2025-04-01 11:00:00', + 2000, 3600, 200, false, NOW(), NOW()), + (3, 1, 'record-public-id-3', 'record-title-3', '2025-04-04 10:00:00', '2025-04-04 11:00:00', + 5000, 3600, 500, false, NOW(), NOW()), + (4, 1, 'record-public-id-4', 'record-title-4', '2025-04-05 10:00:00', '2025-04-05 11:00:00', + 6000, 3600, 600, false, NOW(), NOW()), + (5, 1, 'record-public-id-5', 'record-title-5', '2025-04-06 10:00:00', '2025-04-06 11:00:00', + 7000, 3600, 700, false, NOW(), NOW()); From 038e8278e28f790aebfbe0575ad38a940caf6670 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 11 Jun 2025 23:31:14 +0900 Subject: [PATCH 3/4] :sparkles: add `total_time_in_seconds` and remove calculating total time logic --- .../records/controller/request/RecordSaveRequest.java | 2 ++ .../runimo/runimo/records/domain/RunningRecord.java | 10 ++++++++-- .../runimo/records/service/RecordCommandService.java | 1 + .../service/usecases/dtos/RecordCreateCommand.java | 2 ++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/runimo/runimo/records/controller/request/RecordSaveRequest.java b/src/main/java/org/runimo/runimo/records/controller/request/RecordSaveRequest.java index 2294e2b..769425c 100644 --- a/src/main/java/org/runimo/runimo/records/controller/request/RecordSaveRequest.java +++ b/src/main/java/org/runimo/runimo/records/controller/request/RecordSaveRequest.java @@ -13,6 +13,8 @@ public record RecordSaveRequest( LocalDateTime endAt, @Schema(description = "달린 거리 (미터)", example = "10000") Long totalDistanceInMeters, + @Schema(description = "달린 시간 (초)", example = "3600000") + Long totalTimeInSeconds, @Schema(description = "평균 페이스 (밀리초)", example = "300000") Long averagePaceInMilliSeconds, @Schema(description = "세그먼트 페이스 리스트") diff --git a/src/main/java/org/runimo/runimo/records/domain/RunningRecord.java b/src/main/java/org/runimo/runimo/records/domain/RunningRecord.java index bc49a9d..c8f91b0 100644 --- a/src/main/java/org/runimo/runimo/records/domain/RunningRecord.java +++ b/src/main/java/org/runimo/runimo/records/domain/RunningRecord.java @@ -10,6 +10,7 @@ import jakarta.persistence.Table; import java.time.Duration; import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Objects; import java.util.UUID; @@ -35,6 +36,7 @@ public class RunningRecord extends BaseEntity { private String imgUrl; private LocalDateTime startedAt; private LocalDateTime endAt; + private Long totalTimeInSeconds; @Embedded @AttributeOverride(name = "amount", column = @Column(name = "total_distance")) private Distance totalDistance; @@ -55,6 +57,7 @@ public RunningRecord( LocalDateTime startedAt, LocalDateTime endAt, Distance totalDistance, + Long totalTimeInSeconds, Pace averagePace, Boolean isRewarded, List pacePerKm) { @@ -67,6 +70,7 @@ public RunningRecord( this.endAt = endAt; this.isRewarded = isRewarded; this.totalDistance = totalDistance; + this.totalTimeInSeconds = totalTimeInSeconds; this.averagePace = averagePace; setTitleIfNull(); } @@ -104,7 +108,7 @@ public Distance getTotalDistance() { } public Duration getRunningTime() { - return Duration.between(startedAt, endAt); + return Duration.of(this.totalTimeInSeconds, ChronoUnit.SECONDS); } @PrePersist @@ -115,7 +119,9 @@ public void generateRecordPublicId() { } private void setTitleIfNull() { - if (this.title != null) return; + if (this.title != null) { + return; + } this.title = DefaultTitle.fromTime(this.startedAt).getTitle(); } diff --git a/src/main/java/org/runimo/runimo/records/service/RecordCommandService.java b/src/main/java/org/runimo/runimo/records/service/RecordCommandService.java index c50c377..218ce40 100644 --- a/src/main/java/org/runimo/runimo/records/service/RecordCommandService.java +++ b/src/main/java/org/runimo/runimo/records/service/RecordCommandService.java @@ -41,6 +41,7 @@ private RunningRecord mapToCreatedRunningRecord(Long id, RecordCreateCommand com .endAt(command.endAt()) .averagePace(command.averagePace()) .totalDistance(command.totalDistance()) + .totalTimeInSeconds(command.totalTimeInSeconds()) .isRewarded(false) .pacePerKm(command.segmentPaces()) .build(); diff --git a/src/main/java/org/runimo/runimo/records/service/usecases/dtos/RecordCreateCommand.java b/src/main/java/org/runimo/runimo/records/service/usecases/dtos/RecordCreateCommand.java index 27a206c..fea98ba 100644 --- a/src/main/java/org/runimo/runimo/records/service/usecases/dtos/RecordCreateCommand.java +++ b/src/main/java/org/runimo/runimo/records/service/usecases/dtos/RecordCreateCommand.java @@ -11,6 +11,7 @@ public record RecordCreateCommand( Long userId, LocalDateTime startedAt, LocalDateTime endAt, + Long totalTimeInSeconds, Pace averagePace, Distance totalDistance, List segmentPaces @@ -21,6 +22,7 @@ public static RecordCreateCommand from(final RecordSaveRequest request, final Lo userId, request.startedAt(), request.endAt(), + request.totalTimeInSeconds(), new Pace(request.averagePaceInMilliSeconds()), new Distance(request.totalDistanceInMeters()), request.segmentPaces() From 7cef14611bf1906434df0b28f7153e0f2f6bb0a1 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 11 Jun 2025 23:32:58 +0900 Subject: [PATCH 4/4] :white_check_mark: test : apply changes to test --- .../runimo/runimo/records/RecordFixtures.java | 1 + .../records/api/RecordAcceptanceTest.java | 662 +++++++++--------- .../org/runimo/runimo/rewards/RewardTest.java | 6 +- .../rewards/api/RewardAcceptanceTest.java | 3 + .../rewards/service/RewardServiceTest.java | 16 +- 5 files changed, 350 insertions(+), 338 deletions(-) diff --git a/src/test/java/org/runimo/runimo/records/RecordFixtures.java b/src/test/java/org/runimo/runimo/records/RecordFixtures.java index e4621d2..b8a8297 100644 --- a/src/test/java/org/runimo/runimo/records/RecordFixtures.java +++ b/src/test/java/org/runimo/runimo/records/RecordFixtures.java @@ -12,6 +12,7 @@ public static RecordSaveRequest createRecordSaveRequest() { LocalDateTime.of(2025, 3, 30, 9, 30, 0), LocalDateTime.of(2025, 3, 30, 10, 0, 0), 5000L, + 1800L, 360000L, List.of(new SegmentPace(1.0, 732000)) ); diff --git a/src/test/java/org/runimo/runimo/records/api/RecordAcceptanceTest.java b/src/test/java/org/runimo/runimo/records/api/RecordAcceptanceTest.java index c9e497b..24145b7 100644 --- a/src/test/java/org/runimo/runimo/records/api/RecordAcceptanceTest.java +++ b/src/test/java/org/runimo/runimo/records/api/RecordAcceptanceTest.java @@ -31,336 +31,336 @@ @ActiveProfiles("test") class RecordAcceptanceTest { - private static final String USER_UUID = "test-user-uuid-1"; - @LocalServerPort - int port; - @Autowired - private ObjectMapper objectMapper; - @Autowired - private CleanUpUtil cleanUpUtil; - - @Autowired - private TokenUtils tokenUtils; - - private String token; - - @BeforeEach - void setUp() { - RestAssured.port = port; - token = tokenUtils.createTokenByUserPublicId(USER_UUID); - } - - @AfterEach - void tearDown() { - cleanUpUtil.cleanUpUserInfos(); - } - - @Test - @Sql(scripts = "/sql/user_item_test_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) - void 달리기_기록_저장_성공_기록_id_반환() throws Exception { - // given - // 구간별 페이스 데이터 - List segmentPaces = List.of( - new SegmentPace(1.0, 732000), - new SegmentPace(2.0, 650000), - new SegmentPace(3.0, 605000), - new SegmentPace(4.0, 615000), - new SegmentPace(0.1, 60000) - ); - - // RecordSaveRequest 객체 생성 - RecordSaveRequest request = new RecordSaveRequest( - LocalDateTime.of(2025, 3, 30, 9, 30, 0), - LocalDateTime.of(2025, 3, 30, 10, 0, 0), - 5000L, - 360000L, - segmentPaces - ); - - // when & then - given() - .header("Authorization", token) - .contentType(ContentType.JSON) - .body(objectMapper.writeValueAsString(request)) - .when() - .post("/api/v1/records") - .then() - .log().all() - .statusCode(201) - .body("payload.saved_id", notNullValue()); - } - - @Test - @Sql(scripts = "/sql/user_item_test_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) - void 달리기_기록_조회_성공_구간별_페이스_포함() throws Exception { - // given - // 선행 조건: 달리기 기록 저장 - List segmentPaces = List.of( - new SegmentPace(1.0, 732000), - new SegmentPace(2.0, 650000), - new SegmentPace(3.0, 605000), - new SegmentPace(4.0, 615000), - new SegmentPace(0.1, 60000) - ); - - RecordSaveRequest request = new RecordSaveRequest( - LocalDateTime.of(2025, 3, 30, 9, 30, 0), - LocalDateTime.of(2025, 3, 30, 10, 0, 0), - 5000L, - 360000L, - segmentPaces - ); - - String recordId = String.valueOf(given() - .header("Authorization", token) - .contentType(ContentType.JSON) - .body(objectMapper.writeValueAsString(request)) - .when() - .post("/api/v1/records") - .then() - .log().all() - .statusCode(201) - .extract() - .path("payload.saved_id") - .toString()); - - // when & then - given() - .header("Authorization", token) - .contentType(ContentType.JSON) - .when() - .get("/api/v1/records/{recordId}", recordId) - .then() - .log().all() - .statusCode(200) - .body("payload.record_id", notNullValue()) - .body("payload.segment_pace_list.size()", greaterThanOrEqualTo(1)) - .body("payload.segment_pace_list[0].distance", equalTo(1.0f)) - .body("payload.segment_pace_list[0].pace", equalTo(732000)); - } - - - @Test - @WithMockUser(username = USER_UUID) - @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) - void 주간_달리기_거리_조회_성공시_정확한_정보를_반환한다() { - // given - // when & then - given() - .header("Authorization", token) - .contentType(ContentType.JSON) - .param("startDate", "2025-03-31") - .param("endDate", "2025-04-06") - .when() - .get("/api/v1/records/stats/weekly") - .then() - .log().all() - .statusCode(200) - .body("code", equalTo("MY_PAGE_DATA_FETCHED")) - .body("payload.daily_stats.size()", equalTo(7)) - .body("payload.daily_stats[0].date", equalTo("2025-03-31")) - .body("payload.daily_stats[0].distance_in_meters", equalTo(1000)) - .body("payload.daily_stats[1].date", equalTo("2025-04-01")) - .body("payload.daily_stats[1].distance_in_meters", equalTo(2000)) - .body("payload.daily_stats[2].date", equalTo("2025-04-02")) - .body("payload.daily_stats[2].distance_in_meters", equalTo(3000)) - .body("payload.daily_stats[3].date", equalTo("2025-04-03")) - .body("payload.daily_stats[3].distance_in_meters", equalTo(4000)) - .body("payload.daily_stats[4].date", equalTo("2025-04-04")) - .body("payload.daily_stats[4].distance_in_meters", equalTo(5000)) - .body("payload.daily_stats[5].date", equalTo("2025-04-05")) - .body("payload.daily_stats[5].distance_in_meters", equalTo(6000)) - .body("payload.daily_stats[6].date", equalTo("2025-04-06")) - .body("payload.daily_stats[6].distance_in_meters", equalTo(14000)); - } - - @Test - @Sql(scripts = "/sql/weekly_record_partial_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) - void 주간_달리기_거리_조회_성공시_일부_날짜에_데이터가_없을때_0을_반환한다() { - // given - // when & then - given() - .header("Authorization", token) - .contentType(ContentType.JSON) - .param("startDate", "2025-03-31") - .param("endDate", "2025-04-06") - .when() - .get("/api/v1/records/stats/weekly") - .then() - .log().ifValidationFails() - .statusCode(200) - .body("code", equalTo("MY_PAGE_DATA_FETCHED")) - .body("payload.simple_stat", notNullValue()) - .body("payload.simple_stat.total_time_in_seconds", equalTo(18000)) - .body("payload.simple_stat.total_running_count", equalTo(5)) - .body("payload.simple_stat.total_distance_in_meters", equalTo(21000)) - .body("payload.daily_stats.size()", equalTo(5)) - .body("payload.daily_stats[0].date", equalTo("2025-03-31")) - .body("payload.daily_stats[0].distance_in_meters", equalTo(1000)) - .body("payload.daily_stats[1].date", equalTo("2025-04-01")) - .body("payload.daily_stats[1].distance_in_meters", equalTo(2000)) - .body("payload.daily_stats[2].date", equalTo("2025-04-04")) - .body("payload.daily_stats[2].distance_in_meters", equalTo(5000)) - .body("payload.daily_stats[3].date", equalTo("2025-04-05")) - .body("payload.daily_stats[3].distance_in_meters", equalTo(6000)) - .body("payload.daily_stats[4].date", equalTo("2025-04-06")) - .body("payload.daily_stats[4].distance_in_meters", equalTo(7000)); - } - - @Test - @WithMockUser(username = USER_UUID) - @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) - void 월간_기록_통계_조회_성공시_정확한_정보를_반환한다() { - // when & then - given() - .header("Authorization", token) - .contentType(ContentType.JSON) - .param("year", 2025) - .param("month", 4) - .when() - .get("/api/v1/records/stats/monthly") - .then() - .log().all() - .statusCode(200) - .body("code", equalTo("MY_PAGE_DATA_FETCHED")) - .body("payload.simple_stat", notNullValue()) - .body("payload.simple_stat.total_time_in_seconds", equalTo(25200)) - .body("payload.simple_stat.total_running_count", equalTo(7)) - .body("payload.simple_stat.total_distance_in_meters", equalTo(34000)) - .body("payload.daily_stats.size()", equalTo(6)) - .body("payload.daily_stats[0].date", equalTo("2025-04-01")) - .body("payload.daily_stats[0].distance_in_meters", equalTo(2000)) - .body("payload.daily_stats[1].date", equalTo("2025-04-02")) - .body("payload.daily_stats[1].distance_in_meters", equalTo(3000)) - .body("payload.daily_stats[5].distance_in_meters", equalTo(14000)); - } - - @Test - @WithMockUser(username = USER_UUID) - @Sql(scripts = "/sql/weekly_record_partial_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) - void 월간_기록_통계_조회_잘못된_요청_데이터() { - // when & then - given() - .header("Authorization", token) - .contentType(ContentType.JSON) - .param("year", 2025) - .param("month", 13) // 잘못된 월 - .when() - .get("/api/v1/records/stats/monthly") - .then() - .log().all() - .statusCode(400); - } - - @Test - @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) - void 월간_기록_통계_조회_인증_실패() { - // when & then - given() - .contentType(ContentType.JSON) - .param("year", 2025) - .param("month", 4) - .when() - .get("/api/v1/records/stats/monthly") - .then() - .log().all() - .statusCode(401); - } - - @Test - @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) - void 사용자_기록_페이지네이션_조회() { - - - given() - .contentType(ContentType.JSON) - .header("Authorization", token) - .param("startDate", "2025-04-01") - .param("endDate", "2025-04-30") - .param("page", 0) - .param("size", 5) - .when() - .get("/api/v1/records/me") - .then() - .log().all() - .statusCode(HttpStatus.OK.value()) - .body("payload.pagination.total_pages", equalTo(2)) - .body("payload.pagination.per_page", equalTo(5)) - .body("payload.pagination.current_page", equalTo(0)) - .body("payload.pagination.total_items", equalTo(7)) - .body("payload.items.size()", equalTo(5)); - } - - @Test - @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) - void 사용자_기록_페이지네이션_조회_결과_없음() { - - - given() - .contentType(ContentType.JSON) - .header("Authorization", token) - .param("startDate", "2010-01-01") - .param("endDate", "2010-01-30") - .param("size", 5) - .when() - .get("/api/v1/records/me") - .then() - .log().all() - .statusCode(HttpStatus.OK.value()) - .body("payload.pagination.total_pages", equalTo(0)) - .body("payload.pagination.per_page", equalTo(5)) - .body("payload.pagination.current_page", equalTo(0)) - .body("payload.pagination.total_items", equalTo(0)) - .body("payload.items.size()", equalTo(0)); - } - - @Test - @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) - void 사용자_기록_페이지네이션_조회_잘못된_요청() { - - given() - .contentType(ContentType.JSON) - .header("Authorization", token) - .param("page", -1) // 잘못된 페이지 번호 - .param("size", 5) - .when() - .get("/api/v1/records/me") - .then() - .log().all() - .statusCode(HttpStatus.BAD_REQUEST.value()); - } - - @Test - @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) - void 사용자_기록_업데이트() throws JsonProcessingException { - RecordUpdateRequest request = new RecordUpdateRequest( - "예시 제목", - "오늘은 올림픽 공원을 달렸어요.", - "https://example.com/image.jpg" - ); - - given() - .contentType(ContentType.JSON) - .header("Authorization", token) - .body(objectMapper.writeValueAsString(request)) - .when() - .patch("/api/v1/records/record-public-id-1") - .then() - .statusCode(HttpStatus.OK.value()); - - given() - .header("Authorization", token) - .contentType(ContentType.JSON) - .when() - .get("/api/v1/records/{recordId}", "record-public-id-1") - .then() - .log().all() - .statusCode(200) - .body("payload.record_id", notNullValue()) - .body("payload.title", equalTo("예시 제목")) - .body("payload.description", equalTo("오늘은 올림픽 공원을 달렸어요.")) - .body("payload.img_url", equalTo("https://example.com/image.jpg")); - - } + private static final String USER_UUID = "test-user-uuid-1"; + @LocalServerPort + int port; + @Autowired + private ObjectMapper objectMapper; + @Autowired + private CleanUpUtil cleanUpUtil; + + @Autowired + private TokenUtils tokenUtils; + + private String token; + + @BeforeEach + void setUp() { + RestAssured.port = port; + token = tokenUtils.createTokenByUserPublicId(USER_UUID); + } + + @AfterEach + void tearDown() { + cleanUpUtil.cleanUpUserInfos(); + } + + @Test + @Sql(scripts = "/sql/user_item_test_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 달리기_기록_저장_성공_기록_id_반환() throws Exception { + // given + // 구간별 페이스 데이터 + List segmentPaces = List.of( + new SegmentPace(1.0, 732000), + new SegmentPace(2.0, 650000), + new SegmentPace(3.0, 605000), + new SegmentPace(4.0, 615000), + new SegmentPace(0.1, 60000) + ); + + // RecordSaveRequest 객체 생성 + RecordSaveRequest request = new RecordSaveRequest( + LocalDateTime.of(2025, 3, 30, 9, 30, 0), + LocalDateTime.of(2025, 3, 30, 10, 0, 0), + 5000L, + 1800L, + 360000L, + segmentPaces + ); + + // when & then + given() + .header("Authorization", token) + .contentType(ContentType.JSON) + .body(objectMapper.writeValueAsString(request)) + .when() + .post("/api/v1/records") + .then() + .log().all() + .statusCode(201) + .body("payload.saved_id", notNullValue()); + } + + @Test + @Sql(scripts = "/sql/user_item_test_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 달리기_기록_조회_성공_구간별_페이스_포함() throws Exception { + // given + // 선행 조건: 달리기 기록 저장 + List segmentPaces = List.of( + new SegmentPace(1.0, 732000), + new SegmentPace(2.0, 650000), + new SegmentPace(3.0, 605000), + new SegmentPace(4.0, 615000), + new SegmentPace(0.1, 60000) + ); + + RecordSaveRequest request = new RecordSaveRequest( + LocalDateTime.of(2025, 3, 30, 9, 30, 0), + LocalDateTime.of(2025, 3, 30, 10, 0, 0), + 5000L, + 1800L, + 360000L, + segmentPaces + ); + + String recordId = String.valueOf(given() + .header("Authorization", token) + .contentType(ContentType.JSON) + .body(objectMapper.writeValueAsString(request)) + .when() + .post("/api/v1/records") + .then() + .log().all() + .statusCode(201) + .extract() + .path("payload.saved_id") + .toString()); + + // when & then + given() + .header("Authorization", token) + .contentType(ContentType.JSON) + .when() + .get("/api/v1/records/{recordId}", recordId) + .then() + .log().all() + .statusCode(200) + .body("payload.record_id", notNullValue()) + .body("payload.segment_pace_list.size()", greaterThanOrEqualTo(1)) + .body("payload.segment_pace_list[0].distance", equalTo(1.0f)) + .body("payload.segment_pace_list[0].pace", equalTo(732000)); + } + + + @Test + @WithMockUser(username = USER_UUID) + @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 주간_달리기_거리_조회_성공시_정확한_정보를_반환한다() { + // given + // when & then + given() + .header("Authorization", token) + .contentType(ContentType.JSON) + .param("startDate", "2025-03-31") + .param("endDate", "2025-04-06") + .when() + .get("/api/v1/records/stats/weekly") + .then() + .log().all() + .statusCode(200) + .body("code", equalTo("MY_PAGE_DATA_FETCHED")) + .body("payload.daily_stats.size()", equalTo(7)) + .body("payload.daily_stats[0].date", equalTo("2025-03-31")) + .body("payload.daily_stats[0].distance_in_meters", equalTo(1000)) + .body("payload.daily_stats[1].date", equalTo("2025-04-01")) + .body("payload.daily_stats[1].distance_in_meters", equalTo(2000)) + .body("payload.daily_stats[2].date", equalTo("2025-04-02")) + .body("payload.daily_stats[2].distance_in_meters", equalTo(3000)) + .body("payload.daily_stats[3].date", equalTo("2025-04-03")) + .body("payload.daily_stats[3].distance_in_meters", equalTo(4000)) + .body("payload.daily_stats[4].date", equalTo("2025-04-04")) + .body("payload.daily_stats[4].distance_in_meters", equalTo(5000)) + .body("payload.daily_stats[5].date", equalTo("2025-04-05")) + .body("payload.daily_stats[5].distance_in_meters", equalTo(6000)) + .body("payload.daily_stats[6].date", equalTo("2025-04-06")) + .body("payload.daily_stats[6].distance_in_meters", equalTo(14000)); + } + + @Test + @Sql(scripts = "/sql/weekly_record_partial_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 주간_달리기_거리_조회_성공시_일부_날짜에_데이터가_없을때_0을_반환한다() { + // given + // when & then + given() + .header("Authorization", token) + .contentType(ContentType.JSON) + .param("startDate", "2025-03-31") + .param("endDate", "2025-04-06") + .when() + .get("/api/v1/records/stats/weekly") + .then() + .log().ifValidationFails() + .statusCode(200) + .body("code", equalTo("MY_PAGE_DATA_FETCHED")) + .body("payload.simple_stat", notNullValue()) + .body("payload.simple_stat.total_time_in_seconds", equalTo(18000)) + .body("payload.simple_stat.total_running_count", equalTo(5)) + .body("payload.simple_stat.total_distance_in_meters", equalTo(21000)) + .body("payload.daily_stats.size()", equalTo(5)) + .body("payload.daily_stats[0].date", equalTo("2025-03-31")) + .body("payload.daily_stats[0].distance_in_meters", equalTo(1000)) + .body("payload.daily_stats[1].date", equalTo("2025-04-01")) + .body("payload.daily_stats[1].distance_in_meters", equalTo(2000)) + .body("payload.daily_stats[2].date", equalTo("2025-04-04")) + .body("payload.daily_stats[2].distance_in_meters", equalTo(5000)) + .body("payload.daily_stats[3].date", equalTo("2025-04-05")) + .body("payload.daily_stats[3].distance_in_meters", equalTo(6000)) + .body("payload.daily_stats[4].date", equalTo("2025-04-06")) + .body("payload.daily_stats[4].distance_in_meters", equalTo(7000)); + } + + @Test + @WithMockUser(username = USER_UUID) + @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 월간_기록_통계_조회_성공시_정확한_정보를_반환한다() { + // when & then + given() + .header("Authorization", token) + .contentType(ContentType.JSON) + .param("year", 2025) + .param("month", 4) + .when() + .get("/api/v1/records/stats/monthly") + .then() + .log().all() + .statusCode(200) + .body("code", equalTo("MY_PAGE_DATA_FETCHED")) + .body("payload.simple_stat", notNullValue()) + .body("payload.simple_stat.total_time_in_seconds", equalTo(25200)) + .body("payload.simple_stat.total_running_count", equalTo(7)) + .body("payload.simple_stat.total_distance_in_meters", equalTo(34000)) + .body("payload.daily_stats.size()", equalTo(6)) + .body("payload.daily_stats[0].date", equalTo("2025-04-01")) + .body("payload.daily_stats[0].distance_in_meters", equalTo(2000)) + .body("payload.daily_stats[1].date", equalTo("2025-04-02")) + .body("payload.daily_stats[1].distance_in_meters", equalTo(3000)) + .body("payload.daily_stats[5].distance_in_meters", equalTo(14000)); + } + + @Test + @WithMockUser(username = USER_UUID) + @Sql(scripts = "/sql/weekly_record_partial_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 월간_기록_통계_조회_잘못된_요청_데이터() { + // when & then + given() + .header("Authorization", token) + .contentType(ContentType.JSON) + .param("year", 2025) + .param("month", 13) // 잘못된 월 + .when() + .get("/api/v1/records/stats/monthly") + .then() + .log().all() + .statusCode(400); + } + + @Test + @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 월간_기록_통계_조회_인증_실패() { + // when & then + given() + .contentType(ContentType.JSON) + .param("year", 2025) + .param("month", 4) + .when() + .get("/api/v1/records/stats/monthly") + .then() + .log().all() + .statusCode(401); + } + + @Test + @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 사용자_기록_페이지네이션_조회() { + + given() + .contentType(ContentType.JSON) + .header("Authorization", token) + .param("startDate", "2025-04-01") + .param("endDate", "2025-04-30") + .param("page", 0) + .param("size", 5) + .when() + .get("/api/v1/records/me") + .then() + .log().all() + .statusCode(HttpStatus.OK.value()) + .body("payload.pagination.total_pages", equalTo(2)) + .body("payload.pagination.per_page", equalTo(5)) + .body("payload.pagination.current_page", equalTo(0)) + .body("payload.pagination.total_items", equalTo(7)) + .body("payload.items.size()", equalTo(5)); + } + + @Test + @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 사용자_기록_페이지네이션_조회_결과_없음() { + + given() + .contentType(ContentType.JSON) + .header("Authorization", token) + .param("startDate", "2010-01-01") + .param("endDate", "2010-01-30") + .param("size", 5) + .when() + .get("/api/v1/records/me") + .then() + .log().all() + .statusCode(HttpStatus.OK.value()) + .body("payload.pagination.total_pages", equalTo(0)) + .body("payload.pagination.per_page", equalTo(5)) + .body("payload.pagination.current_page", equalTo(0)) + .body("payload.pagination.total_items", equalTo(0)) + .body("payload.items.size()", equalTo(0)); + } + + @Test + @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 사용자_기록_페이지네이션_조회_잘못된_요청() { + + given() + .contentType(ContentType.JSON) + .header("Authorization", token) + .param("page", -1) // 잘못된 페이지 번호 + .param("size", 5) + .when() + .get("/api/v1/records/me") + .then() + .log().all() + .statusCode(HttpStatus.BAD_REQUEST.value()); + } + + @Test + @Sql(scripts = "/sql/weekly_record_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 사용자_기록_업데이트() throws JsonProcessingException { + RecordUpdateRequest request = new RecordUpdateRequest( + "예시 제목", + "오늘은 올림픽 공원을 달렸어요.", + "https://example.com/image.jpg" + ); + + given() + .contentType(ContentType.JSON) + .header("Authorization", token) + .body(objectMapper.writeValueAsString(request)) + .when() + .patch("/api/v1/records/record-public-id-1") + .then() + .statusCode(HttpStatus.OK.value()); + + given() + .header("Authorization", token) + .contentType(ContentType.JSON) + .when() + .get("/api/v1/records/{recordId}", "record-public-id-1") + .then() + .log().all() + .statusCode(200) + .body("payload.record_id", notNullValue()) + .body("payload.title", equalTo("예시 제목")) + .body("payload.description", equalTo("오늘은 올림픽 공원을 달렸어요.")) + .body("payload.img_url", equalTo("https://example.com/image.jpg")); + + } } diff --git a/src/test/java/org/runimo/runimo/rewards/RewardTest.java b/src/test/java/org/runimo/runimo/rewards/RewardTest.java index 43b4e70..59daf19 100644 --- a/src/test/java/org/runimo/runimo/rewards/RewardTest.java +++ b/src/test/java/org/runimo/runimo/rewards/RewardTest.java @@ -74,7 +74,8 @@ void setUp() { null, SocialProvider.KAKAO )); - UserSignupCommand command = new UserSignupCommand(registerToken, "name", null, Gender.UNKNOWN); + UserSignupCommand command = new UserSignupCommand(registerToken, "name", null, + Gender.UNKNOWN); Long useId = signUpUsecaseImpl.register(command).userId(); savedUser = userRepository.findById(useId).orElse(null); } @@ -91,6 +92,7 @@ void tearDown() { savedUser.getId(), LocalDateTime.now(), LocalDateTime.now().plusHours(1), + 1800L, new Pace(1909L), new Distance(10000L), List.of() @@ -104,7 +106,7 @@ void tearDown() { findEggByUserIdAndEggCode( savedUser.getId(), rewardResponse.eggCode()) - .get(); + .orElse(null); assertNotNull(rewardResponse.eggCode()); assertNotNull(savedItem); diff --git a/src/test/java/org/runimo/runimo/rewards/api/RewardAcceptanceTest.java b/src/test/java/org/runimo/runimo/rewards/api/RewardAcceptanceTest.java index 12cba0c..cf93586 100644 --- a/src/test/java/org/runimo/runimo/rewards/api/RewardAcceptanceTest.java +++ b/src/test/java/org/runimo/runimo/rewards/api/RewardAcceptanceTest.java @@ -136,6 +136,7 @@ void tearDown() { pivotTime, pivotTime.plusMinutes(20), 1000L, + 1200L, 1000L, null); ValidatableResponse firstRes = given() @@ -157,6 +158,7 @@ void tearDown() { pivotTime.minusDays(1), pivotTime.minusDays(1).plusMinutes(20), 1000L, + 1200L, 1000L, null); given() @@ -231,6 +233,7 @@ void tearDown() { pivotTime, pivotTime.plusMinutes(20), 900L, + 1200L, 1000L, List.of() ); diff --git a/src/test/java/org/runimo/runimo/rewards/service/RewardServiceTest.java b/src/test/java/org/runimo/runimo/rewards/service/RewardServiceTest.java index bfd7467..8c6a2d9 100644 --- a/src/test/java/org/runimo/runimo/rewards/service/RewardServiceTest.java +++ b/src/test/java/org/runimo/runimo/rewards/service/RewardServiceTest.java @@ -48,6 +48,7 @@ private static RunningRecord getRunningRecordWithIds(Long userId, Long recordId, .userId(userId) .isRewarded(isRewarded) .totalDistance(new Distance(1000L)) + .totalTimeInSeconds(1800L) .startedAt(LocalDateTime.now()) .build(); ReflectionTestUtils.setField(runningRecord, "id", recordId); @@ -68,9 +69,11 @@ void setUp() { @Test void 보상을_받지_않은_이번주_첫_기록이라면_알을_지급한다() { RunningRecord unRewardedRecord = getRunningRecordWithIds(1L, 1L, false); - RewardClaimCommand command = new RewardClaimCommand(1L, unRewardedRecord.getRecordPublicId()); + RewardClaimCommand command = new RewardClaimCommand(1L, + unRewardedRecord.getRecordPublicId()); - when(recordFinder.findByPublicId(any())).thenReturn(java.util.Optional.of(unRewardedRecord)); + when(recordFinder.findByPublicId(any())).thenReturn( + java.util.Optional.of(unRewardedRecord)); when(recordFinder.findFirstRunOfCurrentWeek(any())).thenReturn( java.util.Optional.of(unRewardedRecord)); when(eggGrantService.grantRandomEggToUser(any())).thenReturn( @@ -94,7 +97,8 @@ void setUp() { RewardClaimCommand command = new RewardClaimCommand(1L, alreadyRewardedRecord.getRecordPublicId()); - when(recordFinder.findByPublicId(any())).thenReturn(java.util.Optional.of(alreadyRewardedRecord)); + when(recordFinder.findByPublicId(any())).thenReturn( + java.util.Optional.of(alreadyRewardedRecord)); when(recordFinder.findFirstRunOfCurrentWeek(any())).thenReturn( java.util.Optional.of(alreadyRewardedRecord)); when(eggGrantService.grantRandomEggToUser(any())).thenReturn( @@ -113,9 +117,11 @@ void setUp() { void 이번주_첫_기록이_아니면_알을_지급하지_않는다() { RunningRecord unRewardedRecord = getRunningRecordWithIds(1L, 1L, false); RunningRecord anotherRecord = getRunningRecordWithIds(1L, 2L, false); - RewardClaimCommand command = new RewardClaimCommand(1L, unRewardedRecord.getRecordPublicId()); + RewardClaimCommand command = new RewardClaimCommand(1L, + unRewardedRecord.getRecordPublicId()); - when(recordFinder.findByPublicId(any())).thenReturn(java.util.Optional.of(unRewardedRecord)); + when(recordFinder.findByPublicId(any())).thenReturn( + java.util.Optional.of(unRewardedRecord)); when(recordFinder.findFirstRunOfCurrentWeek(any())).thenReturn(Optional.of(anotherRecord)); when(loveGrantService.grantLoveToUserWithDistance(any())).thenReturn(10L);