diff --git a/fruitshorts-app-api/src/test/java/com/fruitshorts/playback/service/WatchProgressServiceTest.java b/fruitshorts-app-api/src/test/java/com/fruitshorts/playback/service/WatchProgressServiceTest.java index e117279..1892886 100644 --- a/fruitshorts-app-api/src/test/java/com/fruitshorts/playback/service/WatchProgressServiceTest.java +++ b/fruitshorts-app-api/src/test/java/com/fruitshorts/playback/service/WatchProgressServiceTest.java @@ -19,12 +19,14 @@ import com.fruitshorts.playback.dal.mapper.WatchProgressMapper; import com.fruitshorts.playback.vo.ProgressRespVO; import com.fruitshorts.playback.vo.ProgressSaveReqVO; import org.apache.ibatis.builder.MapperBuilderAssistant; +import org.apache.ibatis.annotations.Select; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import java.time.LocalDateTime; +import java.lang.reflect.Method; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -179,6 +181,74 @@ class WatchProgressServiceTest { verify(historyMapper).insert(historyCaptor.capture()); assertThat(historyCaptor.getValue().getUserId()).isNull(); assertThat(historyCaptor.getValue().getDeviceId()).isEqualTo("device-a"); + + WatchProgress saved = progressCaptor.getValue(); + saved.setUpdatedAt(LocalDateTime.of(2026, 10, 27, 9, 0)); + Page databasePage = new Page<>(1, 20, 1); + databasePage.setRecords(List.of(saved)); + given(progressMapper.selectPage(any(Page.class), any())).willReturn(databasePage); + given(dramaService.listByIds(List.of(5L))) + .willReturn(List.of(drama(5L, "匿名观看", 10))); + given(episodeService.listByIds(List.of(88L))) + .willReturn(List.of(episode)); + + PageResult recent = progressService.recentPage( + new InteractionIdentity(null, "device-a"), 1, 20); + + assertThat(recent.getList()).hasSize(1); + assertThat(recent.getList().get(0).getEpisodeId()).isEqualTo(88L); + } + + @Test + void should_read_anonymous_progress_by_device() { + WatchProgress progress = progress(5L, 88L); + progress.setUserId(null); + progress.setDeviceId("device-a"); + given(progressMapper.selectOne(any())).willReturn(progress); + + ProgressRespVO result = progressService.ofDrama( + new InteractionIdentity(null, "device-a"), 5L); + + assertThat(result.getEpisodeId()).isEqualTo(88L); + @SuppressWarnings("unchecked") + ArgumentCaptor> wrapperCaptor = + ArgumentCaptor.forClass(Wrapper.class); + verify(progressMapper).selectOne(wrapperCaptor.capture()); + assertThat(wrapperCaptor.getValue().getSqlSegment()) + .contains("user_id IS NULL") + .contains("device_id"); + } + + @Test + void should_read_logged_user_progress() { + WatchProgress progress = progress(5L, 88L); + progress.setUserId(9L); + given(progressMapper.selectOne(any())).willReturn(progress); + + ProgressRespVO result = progressService.ofDrama( + new InteractionIdentity(9L, ""), 5L); + + assertThat(result.getEpisodeId()).isEqualTo(88L); + @SuppressWarnings("unchecked") + ArgumentCaptor> wrapperCaptor = + ArgumentCaptor.forClass(Wrapper.class); + verify(progressMapper).selectOne(wrapperCaptor.capture()); + assertThat(wrapperCaptor.getValue().getSqlSegment()) + .contains("user_id") + .doesNotContain("user_id IS NULL"); + } + + @Test + void should_declare_jdbc_type_for_nullable_identity_sql() throws Exception { + Method method = WatchProgressMapper.class.getMethod( + "selectAnyForIdentity", Long.class, String.class, Long.class); + Select select = method.getAnnotation(Select.class); + String sql = String.join("\n", select.value()); + + assertThat(sql) + .contains("#{userId,jdbcType=BIGINT} IS NOT NULL") + .contains("#{userId,jdbcType=BIGINT} IS NULL") + .doesNotContain("#{userId} "); } @Test diff --git a/fruitshorts-module-playback/src/main/java/com/fruitshorts/playback/dal/mapper/WatchProgressMapper.java b/fruitshorts-module-playback/src/main/java/com/fruitshorts/playback/dal/mapper/WatchProgressMapper.java index 88460fc..bd5ac4c 100644 --- a/fruitshorts-module-playback/src/main/java/com/fruitshorts/playback/dal/mapper/WatchProgressMapper.java +++ b/fruitshorts-module-playback/src/main/java/com/fruitshorts/playback/dal/mapper/WatchProgressMapper.java @@ -14,9 +14,9 @@ public interface WatchProgressMapper extends BaseMapper { @Select(""" SELECT * FROM watch_progress WHERE ( - (#{userId} IS NOT NULL AND user_id = #{userId}) + (#{userId,jdbcType=BIGINT} IS NOT NULL AND user_id = #{userId,jdbcType=BIGINT}) OR - (#{userId} IS NULL AND user_id IS NULL AND device_id = #{deviceId}) + (#{userId,jdbcType=BIGINT} IS NULL AND user_id IS NULL AND device_id = #{deviceId}) ) AND drama_id = #{dramaId} LIMIT 1