| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- using Application.Helpers;
- namespace Application.Tests;
- [TestClass]
- public sealed class KrxBackfillTests
- {
- private static IReadOnlySet<DateOnly> NoHolidays => new HashSet<DateOnly>();
- [TestMethod]
- public async Task RunAsync_IteratesBusinessDays_RecentFirst_SkippingWeekends()
- {
- // 2025-01-06(월) ~ 2025-01-10(금) 은 평일 5일, 2025-01-11(토)/12(일) 은 주말.
- // endDate=일(12), startDate=토(11 하루 전 없음) → 창을 넓게 잡고 주말이 제외되는지 확인.
- var start = new DateOnly(2025, 1, 6); // 월
- var end = new DateOnly(2025, 1, 12); // 일
- var fetchedDays = new List<DateOnly>();
- var count = await KrxBackfill.RunAsync(
- existsForDate: (_, _) => Task.FromResult(false),
- fetchAndUpsertForDate: (day, _) => { fetchedDays.Add(day); return Task.CompletedTask; },
- startDate: start,
- endDate: end,
- holidays: NoHolidays,
- maxPerRun: 100,
- delayMs: 0,
- ct: CancellationToken.None);
- // 주말(11 토, 12 일) 제외 → 평일 5일 (10 금 → 6 월 순, recent-first)
- Assert.AreEqual(5, count);
- CollectionAssert.AreEqual(
- new[]
- {
- new DateOnly(2025, 1, 10),
- new DateOnly(2025, 1, 9),
- new DateOnly(2025, 1, 8),
- new DateOnly(2025, 1, 7),
- new DateOnly(2025, 1, 6)
- },
- fetchedDays,
- "endDate 부터 과거로(recent-first), 주말은 건너뛴다");
- }
- [TestMethod]
- public async Task RunAsync_SkipsHolidays()
- {
- var start = new DateOnly(2025, 1, 6); // 월
- var end = new DateOnly(2025, 1, 10); // 금
- var holidays = new HashSet<DateOnly> { new(2025, 1, 8) }; // 수 휴장
- var fetchedDays = new List<DateOnly>();
- var count = await KrxBackfill.RunAsync(
- existsForDate: (_, _) => Task.FromResult(false),
- fetchAndUpsertForDate: (day, _) => { fetchedDays.Add(day); return Task.CompletedTask; },
- startDate: start,
- endDate: end,
- holidays: holidays,
- maxPerRun: 100,
- delayMs: 0,
- ct: CancellationToken.None);
- Assert.AreEqual(4, count, "휴장일(8 수) 제외 → 4일");
- CollectionAssert.DoesNotContain(fetchedDays, new DateOnly(2025, 1, 8));
- }
- [TestMethod]
- public async Task RunAsync_SkipsAlreadyExistingDays_Resumable()
- {
- var start = new DateOnly(2025, 1, 6); // 월
- var end = new DateOnly(2025, 1, 10); // 금
- // 8 수, 9 목 은 이미 적재됨 → skip
- var existing = new HashSet<DateOnly> { new(2025, 1, 8), new(2025, 1, 9) };
- var fetchedDays = new List<DateOnly>();
- var count = await KrxBackfill.RunAsync(
- existsForDate: (day, _) => Task.FromResult(existing.Contains(day)),
- fetchAndUpsertForDate: (day, _) => { fetchedDays.Add(day); return Task.CompletedTask; },
- startDate: start,
- endDate: end,
- holidays: NoHolidays,
- maxPerRun: 100,
- delayMs: 0,
- ct: CancellationToken.None);
- Assert.AreEqual(3, count, "이미 적재된 2일 제외 → 3일 (resumable)");
- CollectionAssert.AreEqual(
- new[]
- {
- new DateOnly(2025, 1, 10),
- new DateOnly(2025, 1, 7),
- new DateOnly(2025, 1, 6)
- },
- fetchedDays);
- }
- [TestMethod]
- public async Task RunAsync_StopsAfterMaxPerRun()
- {
- // 넉넉한 창(3주) 에서 상한 3 으로 잘리는지
- var start = new DateOnly(2025, 1, 1);
- var end = new DateOnly(2025, 1, 21);
- var fetchedDays = new List<DateOnly>();
- var count = await KrxBackfill.RunAsync(
- existsForDate: (_, _) => Task.FromResult(false),
- fetchAndUpsertForDate: (day, _) => { fetchedDays.Add(day); return Task.CompletedTask; },
- startDate: start,
- endDate: end,
- holidays: NoHolidays,
- maxPerRun: 3,
- delayMs: 0,
- ct: CancellationToken.None);
- Assert.AreEqual(3, count, "maxPerRun 도달 시 즉시 멈춤");
- Assert.AreEqual(3, fetchedDays.Count);
- // recent-first: 21(화),20(월),17(금) — 18/19 는 주말
- CollectionAssert.AreEqual(
- new[]
- {
- new DateOnly(2025, 1, 21),
- new DateOnly(2025, 1, 20),
- new DateOnly(2025, 1, 17)
- },
- fetchedDays);
- }
- [TestMethod]
- public async Task RunAsync_MaxPerRunZeroOrNegative_FetchesNothing()
- {
- var fetched = 0;
- var count = await KrxBackfill.RunAsync(
- existsForDate: (_, _) => Task.FromResult(false),
- fetchAndUpsertForDate: (_, _) => { fetched++; return Task.CompletedTask; },
- startDate: new DateOnly(2025, 1, 1),
- endDate: new DateOnly(2025, 1, 31),
- holidays: NoHolidays,
- maxPerRun: 0,
- delayMs: 0,
- ct: CancellationToken.None);
- Assert.AreEqual(0, count);
- Assert.AreEqual(0, fetched, "maxPerRun<=0 이면 fetch 호출 자체가 없다");
- }
- [TestMethod]
- public async Task RunAsync_EmptyWindow_WhenStartAfterEnd_FetchesNothing()
- {
- var fetched = 0;
- var count = await KrxBackfill.RunAsync(
- existsForDate: (_, _) => Task.FromResult(false),
- fetchAndUpsertForDate: (_, _) => { fetched++; return Task.CompletedTask; },
- startDate: new DateOnly(2025, 2, 1),
- endDate: new DateOnly(2025, 1, 1), // start > end
- holidays: NoHolidays,
- maxPerRun: 100,
- delayMs: 0,
- ct: CancellationToken.None);
- Assert.AreEqual(0, count);
- Assert.AreEqual(0, fetched);
- }
- }
|