From 1abb4eea2559c38a27248debe4681048332e2f19 Mon Sep 17 00:00:00 2001
From: tpgus2603 <kakaneymar2424@gmail.com>
Date: Fri, 22 Nov 2024 21:23:39 +0900
Subject: [PATCH] =?UTF-8?q?test:=20=EB=B0=94=EB=80=90=20=EC=8A=A4=EC=BC=80?=
 =?UTF-8?q?=EC=A5=B4=20=EC=84=9C=EB=B9=84=EC=8A=A4=EB=A1=9C=EC=A7=81=20?=
 =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=99=84=EB=A3=8C(#13)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 services/schedule.test.js   | 390 ++++++++++++++++++++++++------------
 services/scheduleService.js |   4 +-
 2 files changed, 261 insertions(+), 133 deletions(-)

diff --git a/services/schedule.test.js b/services/schedule.test.js
index b5d5626..a8df82b 100644
--- a/services/schedule.test.js
+++ b/services/schedule.test.js
@@ -1,237 +1,367 @@
-// test/schedule.test.js
-const sequelize = require('../config/sequelize');
-const {User, Friend, Schedule,} = require('../models'); 
-const scheduleService = require('../services/scheduleService'); // 경로 수정
+// test/scheduleService.test.js
+const sequelize = require('../config/sequelize'); // 실제 경로에 맞게 수정
+const { Schedule, User } = require('../models');
+const ScheduleService = require('../services/scheduleService'); // Uppercase 'S'로 가져오기
+const ScheduleResponseDTO = require('../dtos/ScheduleResponseDTO');
 
 beforeAll(async () => {
+    // 테스트 스위트가 시작되기 전에 데이터베이스를 동기화합니다.
     await sequelize.sync({ force: true });
+});
+
+beforeEach(async () => {
+    // 각 테스트가 시작되기 전에 기존 데이터를 삭제합니다.
+    await Schedule.destroy({ where: {} });
+    await User.destroy({ where: {} });
 
     // 더미 사용자 생성
     await User.bulkCreate([
         { id: 1, name: 'Alice', email: 'alice@example.com' },
         { id: 2, name: 'Bob', email: 'bob@example.com' },
+        { id: 3, name: 'Charlie', email: 'charlie@example.com' },
     ]);
 
-    // 더미 친구 관계 생성
-    await Friend.create({
-        id: 1,
-        requester_id: 1,
-        receiver_id: 2,
-        status: 'ACCEPTED',
-    });
-
-    // 더미 스케줄 생성 (day_of_week과 TIME 형식 사용)
-    await Schedule.create({
-        id: 1,
-        user_id: 1,
-        title: 'Alice\'s Fixed Schedule',
-        day_of_week: 'Monday',
-        start_time: '09:00:00', // 'HH:MM:SS' 형식
-        end_time: '10:00:00',
-        is_fixed: true,
-    });
-
-    await Schedule.create({
-        id: 2,
-        user_id: 1,
-        title: 'Alice\'s Flexible Schedule',
-        day_of_week: 'Tuesday',
-        start_time: '11:00:00',
-        end_time: '12:00:00',
-        is_fixed: false,
-    });
+    // 더미 스케줄 생성
+    await Schedule.bulkCreate([
+        { id: 1, user_id: 1, title: 'Alice Fixed Schedule 1', time_idx: 36, is_fixed: true },
+        { id: 2, user_id: 1, title: 'Alice Flexible Schedule 1', time_idx: 44, is_fixed: false },
+        { id: 3, user_id: 2, title: 'Bob Fixed Schedule 1', time_idx: 60, is_fixed: true },
+        { id: 4, user_id: 2, title: 'Bob Flexible Schedule 1', time_idx: 61, is_fixed: false },
+        { id: 5, user_id: 3, title: 'Charlie Fixed Schedule 1', time_idx: 100, is_fixed: true },
+    ]);
 });
 
 afterAll(async () => {
-    // 데이터베이스 연결 종료
+    // 모든 테스트가 끝난 후 데이터베이스 연결을 종료합니다.
     await sequelize.close();
 });
 
-describe('Schedule Service', () => {
+describe('ScheduleService', () => {
     describe('createSchedules', () => {
-        test('should create new fixed schedules successfully', async () => {
+        test('should create multiple new fixed schedules successfully', async () => {
             const scheduleData = {
-                userId: 2,
-                title: 'Bob\'s Fixed Schedule',
+                userId: 1,
+                title: 'Alice Fixed Schedule Bulk',
                 is_fixed: true,
                 events: [
-                    {
-                        day_of_week: 'Wednesday',
-                        start_time: '14:00:00',
-                        end_time: '15:00:00',
-                    },
+                    { time_idx: 50 }, // Valid time_idx
+                    { time_idx: 51 },
                 ],
             };
 
-            const schedules = await scheduleService.createSchedules(scheduleData);
+            const schedules = await ScheduleService.createSchedules(scheduleData);
 
             expect(schedules).toBeDefined();
             expect(Array.isArray(schedules)).toBe(true);
-            expect(schedules.length).toBe(1);
-
-            const schedule = schedules[0];
-            expect(schedule.user_id).toBe(2);
-            expect(schedule.title).toBe('Bob\'s Fixed Schedule');
-            expect(schedule.is_fixed).toBe(true);
-            expect(schedule.day_of_week).toBe('Wednesday');
-            expect(schedule.start_time).toBe('14:00');
-            expect(schedule.end_time).toBe('15:00');
+            expect(schedules.length).toBe(2);
+
+            schedules.forEach((schedule, index) => {
+                expect(schedule.user_id).toBe(1);
+                expect(schedule.title).toBe('Alice Fixed Schedule Bulk');
+                expect(schedule.is_fixed).toBe(true);
+                expect(schedule.time_idx).toBe(scheduleData.events[index].time_idx);
+            });
+
+            // 데이터베이스에 실제로 추가되었는지 확인
+            const dbSchedules = await Schedule.findAll({
+                where: { user_id: 1, title: 'Alice Fixed Schedule Bulk' },
+            });
+            expect(dbSchedules.length).toBe(2);
         });
 
-        test('should create new flexible schedules successfully', async () => {
+        test('should create multiple new flexible schedules successfully', async () => {
             const scheduleData = {
                 userId: 2,
-                title: 'Bob\'s Flexible Schedule',
+                title: 'Bob Flexible Schedule Bulk',
                 is_fixed: false,
                 events: [
-                    {
-                        day_of_week: 'Thursday',
-                        start_time: '16:00:00',
-                        end_time: '17:00:00',
-                    },
+                    { time_idx: 62 },
+                    { time_idx: 63 },
                 ],
             };
 
-            const schedules = await scheduleService.createSchedules(scheduleData);
+            const schedules = await ScheduleService.createSchedules(scheduleData);
 
             expect(schedules).toBeDefined();
             expect(Array.isArray(schedules)).toBe(true);
-            expect(schedules.length).toBe(1);
-
-            const schedule = schedules[0];
-            expect(schedule.user_id).toBe(2);
-            expect(schedule.title).toBe('Bob\'s Flexible Schedule');
-            expect(schedule.is_fixed).toBe(false);
-            expect(schedule.day_of_week).toBe('Thursday');
-            expect(schedule.start_time).toBe('16:00');
-            expect(schedule.end_time).toBe('17:00');
+            expect(schedules.length).toBe(2);
+
+            schedules.forEach((schedule, index) => {
+                expect(schedule.user_id).toBe(2);
+                expect(schedule.title).toBe('Bob Flexible Schedule Bulk');
+                expect(schedule.is_fixed).toBe(false);
+                expect(schedule.time_idx).toBe(scheduleData.events[index].time_idx);
+            });
+
+            // 데이터베이스에 실제로 추가되었는지 확인
+            const dbSchedules = await Schedule.findAll({
+                where: { user_id: 2, title: 'Bob Flexible Schedule Bulk' },
+            });
+            expect(dbSchedules.length).toBe(2);
         });
 
-        test('should throw error when schedule times overlap with existing schedule', async () => {
+        test('should throw error when creating schedules with overlapping time_idx', async () => {
             const scheduleData = {
                 userId: 1,
-                title: 'Alice\'s Overlapping Schedule',
+                title: 'Alice Overlapping Schedule',
                 is_fixed: false,
                 events: [
-                    {
-                        day_of_week: 'Monday', // 기존 스케줄과 동일한 요일
-                        start_time: '09:30:00', // 기존 스케줄과 겹치는 시간
-                        end_time: '10:30:00',
-                    },
+                    { time_idx: 36 }, // Existing schedule for Alice
                 ],
             };
 
-            await expect(scheduleService.createSchedules(scheduleData))
+            await expect(ScheduleService.createSchedules(scheduleData))
                 .rejects
-                .toThrow('Schedule overlaps with existing schedule on Monday');
+                .toThrow('Schedule overlaps with existing schedule at time_idx 36');
         });
 
-        test('should throw error when start_time is after end_time', async () => {
+        test('should throw error when creating schedules with invalid time_idx', async () => {
             const scheduleData = {
                 userId: 1,
-                title: 'Invalid Schedule',
+                title: 'Alice Invalid Schedule',
                 is_fixed: false,
                 events: [
-                    {
-                        day_of_week: 'Friday',
-                        start_time: '18:00:00',
-                        end_time: '17:00:00', // start_time이 더 늦음
-                    },
+                    { time_idx: 700 }, // Invalid time_idx
                 ],
             };
 
-            await expect(scheduleService.createSchedules(scheduleData))
+            await expect(ScheduleService.createSchedules(scheduleData))
                 .rejects
-                .toThrow('Start time must be before end time');
+                .toThrow('Validation error: Validation max on time_idx failed');
         });
     });
 
-    describe('updateSchedule', () => {
-        test('should update an existing schedule successfully', async () => {
+    describe('updateSchedules', () => {
+        test('should update multiple existing schedules successfully', async () => {
             const updateData = {
-                title: 'Alice\'s Updated Flexible Schedule',
-                start_time: '11:30:00',
-                end_time: '12:30:00',
+                updates: [
+                    { time_idx: 36, title: 'Alice Updated Fixed Schedule', is_fixed: true },
+                    { time_idx: 44, title: 'Alice Updated Flexible Schedule', is_fixed: false },
+                ],
             };
 
-            const updatedSchedule = await scheduleService.updateSchedule(2, 1, updateData);
+            const updatedSchedules = await ScheduleService.updateSchedules(1, updateData.updates);
+
+            expect(updatedSchedules).toBeDefined();
+            expect(Array.isArray(updatedSchedules)).toBe(true);
+            expect(updatedSchedules.length).toBe(2);
+
+            updatedSchedules.forEach((schedule, index) => {
+                expect(schedule.title).toBe(updateData.updates[index].title);
+                expect(schedule.is_fixed).toBe(updateData.updates[index].is_fixed);
+                expect(schedule.time_idx).toBe(updateData.updates[index].time_idx);
+            });
 
-            expect(updatedSchedule).toBeDefined();
-            expect(updatedSchedule.title).toBe('Alice\'s Updated Flexible Schedule');
-            expect(updatedSchedule.start_time).toBe('11:30');
-            expect(updatedSchedule.end_time).toBe('12:30');
+            // 데이터베이스에서 업데이트 확인
+            const dbSchedule1 = await Schedule.findOne({ where: { user_id: 1, time_idx: 36 } });
+            const dbSchedule2 = await Schedule.findOne({ where: { user_id: 1, time_idx: 44 } });
+
+            expect(dbSchedule1.title).toBe('Alice Updated Fixed Schedule');
+            expect(dbSchedule2.title).toBe('Alice Updated Flexible Schedule');
         });
 
         test('should throw error when updating a non-existing schedule', async () => {
             const updateData = {
-                title: 'Non-existing Schedule',
-                start_time: '10:00:00',
-                end_time: '11:00:00',
+                updates: [
+                    { time_idx: 999, title: 'Non-existing Schedule' },
+                ],
             };
 
-            await expect(scheduleService.updateSchedule(999, 1, updateData))
+            await expect(ScheduleService.updateSchedules(1, updateData.updates))
                 .rejects
-                .toThrow('Schedule not found');
+                .toMatchObject({ message: 'Schedule not found at time_idx 999' });
         });
 
-        test('should throw error when updated schedule overlaps with existing schedule', async () => {
-            const updateData = {
-                title: 'Alice\'s Overlapping Update',
-                start_time: '09:30:00', // 기존 스케줄과 겹침
-                end_time: '10:30:00',
+        test('should throw error when creating schedules with overlapping time_idx', async () => {
+            // 먼저, 새로운 스케줄을 생성하여 time_idx 50을 사용
+            await ScheduleService.createSchedules({
+                userId: 1,
+                title: 'Alice Another Schedule',
+                is_fixed: false,
+                events: [
+                    { time_idx: 50 },
+                ],
+            });
+
+            // 동일한 time_idx로 스케줄을 생성하려 할 때 오류가 발생하는지 테스트
+            const scheduleData = {
+                userId: 1,
+                title: 'Alice Overlapping Schedule',
+                is_fixed: false,
+                events: [
+                    { time_idx: 50 }, // 이미 존재하는 time_idx
+                ],
             };
 
-            await expect(scheduleService.updateSchedule(2, 1, updateData))
+            await expect(ScheduleService.createSchedules(scheduleData))
                 .rejects
-                .toThrow('Schedule overlaps with existing schedule');
+                .toThrow('Schedule overlaps with existing schedule at time_idx 50');
         });
     });
 
-    describe('deleteSchedule', () => {
-        test('should delete an existing schedule successfully', async () => {
-            const result = await scheduleService.deleteSchedule(2, 1);
+    describe('deleteSchedules', () => {
+        test('should delete multiple existing schedules successfully', async () => {
+            // 먼저, 스케줄 생성
+            await ScheduleService.createSchedules({
+                userId: 1,
+                title: 'Alice Bulk Delete Schedule 1',
+                is_fixed: false,
+                events: [
+                    { time_idx: 70 },
+                    { time_idx: 71 },
+                ],
+            });
+
+            const deleteData = {
+                time_idxs: [70, 71],
+            };
+
+            const result = await ScheduleService.deleteSchedules(1, deleteData.time_idxs);
 
-            expect(result).toEqual({ message: 'Schedule successfully deleted' });
+            expect(result).toBeDefined();
+            expect(result.deleted_time_idxs).toContain(70);
+            expect(result.deleted_time_idxs).toContain(71);
 
-            // 삭제된 스케줄이 실제로 삭제되었는지 확인
-            const schedule = await Schedule.findByPk(2);
-            expect(schedule).toBeNull();
+            // 데이터베이스에서 삭제 확인
+            const dbSchedule1 = await Schedule.findOne({ where: { user_id: 1, time_idx: 70 } });
+            const dbSchedule2 = await Schedule.findOne({ where: { user_id: 1, time_idx: 71 } });
+
+            expect(dbSchedule1).toBeNull();
+            expect(dbSchedule2).toBeNull();
         });
 
         test('should throw error when deleting a non-existing schedule', async () => {
-            await expect(scheduleService.deleteSchedule(999, 1))
+            const deleteData = {
+                time_idxs: [999],
+            };
+
+            await expect(ScheduleService.deleteSchedules(1, deleteData.time_idxs))
                 .rejects
-                .toThrow('Schedule not found');
+                .toThrow('Schedule not found at time_idx 999');
         });
     });
 
     describe('getAllSchedules', () => {
-        test('should retrieve all valid schedules for a user', async () => {
-            // 사용자 Alice의 모든 스케줄 조회 (user_id: 1)
-            const schedules = await scheduleService.getAllSchedules(1);
+        test('should retrieve all schedules for a user', async () => {
+            // Update schedules first
+            const updateData = {
+                updates: [
+                    { time_idx: 36, title: 'Alice Updated Fixed Schedule', is_fixed: true },
+                    { time_idx: 44, title: 'Alice Updated Flexible Schedule', is_fixed: false },
+                ],
+            };
+
+            await ScheduleService.updateSchedules(1, updateData.updates);
+
+            const schedules = await ScheduleService.getAllSchedules(1);
 
             expect(schedules).toBeDefined();
             expect(Array.isArray(schedules)).toBe(true);
-            expect(schedules.length).toBe(1); // id=1 스케줄은 is_fixed=true
-            expect(schedules[0].title).toBe('Alice\'s Fixed Schedule');
-            expect(schedules[0].day_of_week).toBe('Monday');
+
+            // 현재 Alice는 id=1, time_idx=36 (fixed), time_idx=44 (flexible)이 존재
+            expect(schedules.length).toBe(2);
+
+            const schedule1 = schedules.find(s => s.time_idx === 36);
+            const schedule2 = schedules.find(s => s.time_idx === 44);
+
+            expect(schedule1).toBeDefined();
+            expect(schedule1.title).toBe('Alice Updated Fixed Schedule');
+
+            expect(schedule2).toBeDefined();
+            expect(schedule2.title).toBe('Alice Updated Flexible Schedule');
+        });
+
+        test('should retrieve one schedule when user has only one', async () => {
+            const schedules = await ScheduleService.getAllSchedules(3); // Charlie has id=3 and only one fixed schedule
+
+            expect(schedules).toBeDefined();
+            expect(Array.isArray(schedules)).toBe(true);
+            expect(schedules.length).toBe(1);
+
+            expect(schedules[0].title).toBe('Charlie Fixed Schedule 1');
         });
     });
 
-    describe('getScheduleById', () => {
-        test('should retrieve a specific schedule by ID', async () => {
-            const schedule = await scheduleService.getScheduleById(1, 1);
+    describe('getScheduleByTimeIdx', () => {
+        test('should retrieve a specific schedule by time_idx', async () => {
+            // Update schedule first
+            const updateData = {
+                updates: [
+                    { time_idx: 36, title: 'Alice Updated Fixed Schedule', is_fixed: true },
+                ],
+            };
+
+            await ScheduleService.updateSchedules(1, updateData.updates);
+
+            const schedule = await ScheduleService.getScheduleByTimeIdx(1, 36);
 
             expect(schedule).toBeDefined();
-            expect(schedule.title).toBe('Alice\'s Fixed Schedule');
-            expect(schedule.day_of_week).toBe('Monday');
+            expect(schedule.title).toBe('Alice Updated Fixed Schedule');
+            expect(schedule.time_idx).toBe(36);
         });
 
         test('should throw error when retrieving a non-existing schedule', async () => {
-            await expect(scheduleService.getScheduleById(999, 1))
+            await expect(ScheduleService.getScheduleByTimeIdx(1, 999))
                 .rejects
                 .toThrow('Schedule not found');
         });
     });
 
+    describe('cleanExpiredSchedules', () => {
+        test('should delete all flexible schedules', async () => {
+            // 먼저, 여러 유동 스케줄을 생성
+            await ScheduleService.createSchedules({
+                userId: 1,
+                title: 'Alice Flexible Schedule 2',
+                is_fixed: false,
+                events: [
+                    { time_idx: 80 },
+                    { time_idx: 81 },
+                ],
+            });
+
+            await ScheduleService.createSchedules({
+                userId: 2,
+                title: 'Bob Flexible Schedule 2',
+                is_fixed: false,
+                events: [
+                    { time_idx: 90 },
+                    { time_idx: 91 },
+                ],
+            });
+
+            // 유동 스케줄 삭제
+            await ScheduleService.cleanExpiredSchedules();
+
+            // 데이터베이스에서 유동 스케줄이 모두 삭제되었는지 확인
+            const remainingFlexibleSchedules = await Schedule.findAll({
+                where: { is_fixed: false },
+            });
+
+            expect(remainingFlexibleSchedules.length).toBe(0);
+        });
+
+        test('should not delete fixed schedules', async () => {
+            // 먼저, 여러 고정 스케줄을 생성
+            await ScheduleService.createSchedules({
+                userId: 3,
+                title: 'Charlie Fixed Schedule 2',
+                is_fixed: true,
+                events: [
+                    { time_idx: 120 },
+                    { time_idx: 121 },
+                ],
+            });
+
+            // 유동 스케줄 삭제
+            await ScheduleService.cleanExpiredSchedules();
+
+            // 데이터베이스에서 고정 스케줄이 유지되었는지 확인
+            const remainingFixedSchedules = await Schedule.findAll({
+                where: { user_id: 3, is_fixed: true },
+            });
+
+            expect(remainingFixedSchedules.length).toBe(3); // 기존 1개 + 2개 추가
+        });
+    });
 });
diff --git a/services/scheduleService.js b/services/scheduleService.js
index 419b49a..65f4b0d 100644
--- a/services/scheduleService.js
+++ b/services/scheduleService.js
@@ -60,9 +60,7 @@ class ScheduleService {
                     throw { code: 'SCHEDULE_NOT_FOUND', message: `Schedule not found at time_idx ${time_idx}` };
                 }
 
-                // 중복 스케줄 검사 (time_idx는 고유하므로 필요 없음)
-                // 만약 다른 필드를 기반으로 중복을 검사한다면 추가 로직 필요
-
+            
                 const updatedData = {};
                 if (title !== undefined) updatedData.title = title;
                 if (is_fixed !== undefined) updatedData.is_fixed = is_fixed;
-- 
GitLab