Compare commits

...

4 Commits

5 changed files with 41 additions and 21 deletions

View File

@@ -20,12 +20,12 @@
- 기본 노출 수: - 기본 노출 수:
- `banners`: 메인 홈 추천 배너와 동일 - `banners`: 메인 홈 추천 배너와 동일
- `originalSeries`: 최신순 12개 - `originalSeries`: 최신순 12개
- `latestAudios`: 최신순 12 - `latestAudios`: 최신순 15
- `newAndHotAudios`: 최대 12개 - `newAndHotAudios`: 최대 12개
- `freeAudios`: 최대 10개 랜덤 - `freeAudios`: 최대 15개 랜덤
- `pointAudios`: 최대 10개 랜덤 - `pointAudios`: 최대 15개 랜덤
- `mostCommentedAudios`: 최대 5개 - `mostCommentedAudios`: 최대 5개
- `recommendedAudios`: 최대 10개 - `recommendedAudios`: 최대 20개
- 공개 오디오 공통 조건: `AudioContent.isActive == true`, `AudioContent.duration != null`, `AudioContent.releaseDate != null`, `AudioContent.releaseDate <= now`, 크리에이터 회원 활성. - 공개 오디오 공통 조건: `AudioContent.isActive == true`, `AudioContent.duration != null`, `AudioContent.releaseDate != null`, `AudioContent.releaseDate <= now`, 크리에이터 회원 활성.
- 비회원과 19금 노출 불가 회원은 성인 콘텐츠를 제외하고 `SAFE` 스냅샷을 조회한다. - 비회원과 19금 노출 불가 회원은 성인 콘텐츠를 제외하고 `SAFE` 스냅샷을 조회한다.
- 19금 노출 가능 회원은 성인/비성인 콘텐츠를 모두 포함하는 `ALL` 스냅샷을 조회한다. - 19금 노출 가능 회원은 성인/비성인 콘텐츠를 모두 포함하는 `ALL` 스냅샷을 조회한다.
@@ -346,7 +346,7 @@ interface AudioRecommendationQueryPort {
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/AudioRecommendationQueryRepository.kt` - Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/AudioRecommendationQueryRepository.kt`
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepository.kt` - Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepository.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepositoryTest.kt` - Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepositoryTest.kt`
- RED: 배너는 기존 홈 추천 배너와 동일 필드/활성/차단 정책을 적용하고, 오리지널 시리즈는 `isOriginal = true` 최신순 12개, 최신 오디오는 `releaseDate desc`, `audioContentId desc` 12개를 반환하는 repository 테스트를 작성한다. - RED: 배너는 기존 홈 추천 배너와 동일 필드/활성/차단 정책을 적용하고, 오리지널 시리즈는 `isOriginal = true` 최신순 12개, 최신 오디오는 `releaseDate desc`, `audioContentId desc` 15개를 반환하는 repository 테스트를 작성한다.
- 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.audio.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest` - 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.audio.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest`
- GREEN: QueryDSL로 `findBanners`, `findOriginalSeries`, `findLatestAudios`를 구현한다. 이미지 경로는 `toCdnUrl(cloudFrontHost)`를 사용한다. - GREEN: QueryDSL로 `findBanners`, `findOriginalSeries`, `findLatestAudios`를 구현한다. 이미지 경로는 `toCdnUrl(cloudFrontHost)`를 사용한다.
- REFACTOR: 공개 오디오 조건, 성인 콘텐츠 조건, 차단 관계 조건을 private 조건 함수로 분리한다. - REFACTOR: 공개 오디오 조건, 성인 콘텐츠 조건, 차단 관계 조건을 private 조건 함수로 분리한다.
@@ -356,7 +356,7 @@ interface AudioRecommendationQueryPort {
- Files: - Files:
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepository.kt` - Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepository.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepositoryTest.kt` - Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepositoryTest.kt`
- RED: 무료 오디오는 `price = 0` 공개 오디오 중 최대 10개, 포인트 오디오는 `isPointAvailable = true` 공개 오디오 중 최대 10개를 반환하고 두 섹션 간 중복을 제거하지 않는 테스트를 작성한다. - RED: 무료 오디오는 `price = 0` 공개 오디오 중 최대 15개, 포인트 오디오는 `isPointAvailable = true` 공개 오디오 중 최대 15개를 반환하고 두 섹션 간 중복을 제거하지 않는 테스트를 작성한다.
- 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.audio.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest` - 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.audio.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest`
- GREEN: `findFreeAudios`, `findPointAudios`를 구현하고 DB 랜덤 정렬은 기존 repository 관례에 맞춰 `Expressions.numberTemplate(Double::class.java, "function('rand')")` 또는 동일 프로젝트에서 쓰는 랜덤 정렬 방식을 사용한다. - GREEN: `findFreeAudios`, `findPointAudios`를 구현하고 DB 랜덤 정렬은 기존 repository 관례에 맞춰 `Expressions.numberTemplate(Double::class.java, "function('rand')")` 또는 동일 프로젝트에서 쓰는 랜덤 정렬 방식을 사용한다.
- REFACTOR: 무료/포인트 조회가 같은 공통 projection 함수를 사용하게 정리한다. - REFACTOR: 무료/포인트 조회가 같은 공통 projection 함수를 사용하게 정리한다.
@@ -399,11 +399,11 @@ interface AudioRecommendationQueryPort {
- Files: - Files:
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepository.kt` - Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepository.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepositoryTest.kt` - Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/audio/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepositoryTest.kt`
- RED: 상세 조회수 45%, 좋아요 25%, 댓글 수 20%, 최신성 10% 점수를 계산하고 `SAFE/ALL` visibility별 최대 10개 후보를 반환하는 테스트를 작성한다. - RED: 상세 조회수 45%, 좋아요 25%, 댓글 수 20%, 최신성 10% 점수를 계산하고 `SAFE/ALL` visibility별 최대 20개 후보를 반환하는 테스트를 작성한다.
- 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.audio.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest` - 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.audio.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest`
- GREEN: `findRecommendedAudioSnapshots(...)`를 구현한다. 상세 조회수는 `creator_content_view_history` count를 사용하고 `AudioContent.playCount`를 사용하지 않는다. - GREEN: `findRecommendedAudioSnapshots(...)`를 구현한다. 상세 조회수는 `creator_content_view_history` count를 사용하고 `AudioContent.playCount`를 사용하지 않는다.
- REFACTOR: New & Hot과 공유 가능한 조회수/좋아요/댓글 aggregate CTE를 private SQL fragment 또는 QueryDSL helper로 정리한다. - REFACTOR: New & Hot과 공유 가능한 조회수/좋아요/댓글 aggregate CTE를 private SQL fragment 또는 QueryDSL helper로 정리한다.
- 기대 결과: `RECOMMENDED_AUDIO_SAFE/ALL`에 저장할 top 10 후보가 정확한 점수순으로 산출된다. - 기대 결과: `RECOMMENDED_AUDIO_SAFE/ALL`에 저장할 top 20 후보가 정확한 점수순으로 산출된다.
- [x] **Task 4.4: 스냅샷 refresh service와 lazy 보강 구현** - [x] **Task 4.4: 스냅샷 refresh service와 lazy 보강 구현**
- Files: - Files:
@@ -680,3 +680,5 @@ interface AudioRecommendationQueryPort {
- 2026-06-23 리뷰 보정 검증: repository focused test는 병렬 Gradle 실행 중 `kaptGenerateStubsTestKotlin` 출력 디렉터리 충돌로 1회 실패해 단독 재실행했다. H2 `MODE=MySQL``TIMESTAMPDIFF` 경계 동작이 운영 MySQL 공식 기준과 달라 신규 repository 경계 테스트는 제거하고 Kotlin 정책 테스트로 24시간 경계를 고정했다. 최종 `./gradlew test --tests kr.co.vividnext.sodalive.v2.audio.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest`: `BUILD SUCCESSFUL`. - 2026-06-23 리뷰 보정 검증: repository focused test는 병렬 Gradle 실행 중 `kaptGenerateStubsTestKotlin` 출력 디렉터리 충돌로 1회 실패해 단독 재실행했다. H2 `MODE=MySQL``TIMESTAMPDIFF` 경계 동작이 운영 MySQL 공식 기준과 달라 신규 repository 경계 테스트는 제거하고 Kotlin 정책 테스트로 24시간 경계를 고정했다. 최종 `./gradlew test --tests kr.co.vividnext.sodalive.v2.audio.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest`: `BUILD SUCCESSFUL`.
- 2026-06-23 리뷰 보정 검증: `./gradlew ktlintCheck`: `BUILD SUCCESSFUL`, `git diff --check`: 출력 없음. - 2026-06-23 리뷰 보정 검증: `./gradlew ktlintCheck`: `BUILD SUCCESSFUL`, `git diff --check`: 출력 없음.
- 2026-06-25 후속 보정: `DefaultAudioRecommendationQueryRepositoryTest.shouldFindNewAndHotSnapshotsWithVisibility`의 score 비교 실패 원인은 repository native SQL의 `timestampdiff(day, c.release_date, :snapshotAt)` 최신성 계산이 DB 날짜 경계 기준에 의존해 `AudioRecommendationScorePolicy`의 24시간 경과 기준 `ChronoUnit.DAYS` 계산과 어긋날 수 있는 점으로 확인했다. `DefaultAudioRecommendationQueryRepository`의 New & Hot/추천 오디오 공개일 최신성 계산을 `floor(timestampdiff(hour, c.release_date, :snapshotAt) / 24)`로 변경해 Kotlin 정책과 일치시켰고, `SAFE` 성인 콘텐츠 제외 조건은 기존 `(:includeAdult = true or c.is_adult = false)` 구현이 올바른 것으로 확인했다. 검증은 `./gradlew test --rerun-tasks --tests 'kr.co.vividnext.sodalive.v2.content.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest.shouldFindNewAndHotSnapshotsWithVisibility'`, `./gradlew test --rerun-tasks --tests 'kr.co.vividnext.sodalive.v2.content.recommendation.domain.AudioRecommendationScorePolicyTest'`, `./gradlew ktlintCheck` 모두 `BUILD SUCCESSFUL`로 완료했다. - 2026-06-25 후속 보정: `DefaultAudioRecommendationQueryRepositoryTest.shouldFindNewAndHotSnapshotsWithVisibility`의 score 비교 실패 원인은 repository native SQL의 `timestampdiff(day, c.release_date, :snapshotAt)` 최신성 계산이 DB 날짜 경계 기준에 의존해 `AudioRecommendationScorePolicy`의 24시간 경과 기준 `ChronoUnit.DAYS` 계산과 어긋날 수 있는 점으로 확인했다. `DefaultAudioRecommendationQueryRepository`의 New & Hot/추천 오디오 공개일 최신성 계산을 `floor(timestampdiff(hour, c.release_date, :snapshotAt) / 24)`로 변경해 Kotlin 정책과 일치시켰고, `SAFE` 성인 콘텐츠 제외 조건은 기존 `(:includeAdult = true or c.is_adult = false)` 구현이 올바른 것으로 확인했다. 검증은 `./gradlew test --rerun-tasks --tests 'kr.co.vividnext.sodalive.v2.content.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest.shouldFindNewAndHotSnapshotsWithVisibility'`, `./gradlew test --rerun-tasks --tests 'kr.co.vividnext.sodalive.v2.content.recommendation.domain.AudioRecommendationScorePolicyTest'`, `./gradlew ktlintCheck` 모두 `BUILD SUCCESSFUL`로 완료했다.
- 2026-07-12 후속 정책 변경: 콘텐츠 추천 탭의 `latestAudios`, `freeAudios`, `pointAudios` 기본 노출 수를 각각 15개로 확정했다. PRD/plan-task의 섹션별 기본 노출 수와 관련 task 설명을 15개 정책으로 갱신했고, service 테스트는 `AudioRecommendationQueryService` 상수 기준으로 limit 전달을 검증하도록 정리했다. 검증은 `./gradlew --no-daemon test --tests kr.co.vividnext.sodalive.v2.content.recommendation.application.AudioRecommendationQueryServiceTest`, `./gradlew --no-daemon ktlintCheck`, `./gradlew --no-daemon tasks --all` 모두 `BUILD SUCCESSFUL`로 완료했다. 단, `tasks --all`은 일반 sandbox에서 `~/.gradle` wrapper lock 파일 접근 제한으로 실패해 승인 후 재실행했다.
- 2026-07-12 후속 정책 변경: 콘텐츠 추천 탭의 `recommendedAudios``RECOMMENDED_AUDIO_SAFE/ALL` 스냅샷 후보 저장 수를 최대 20개로 확정했다. PRD의 섹션별 기본 노출 수와 추천 오디오 요구사항, plan-task의 개요와 Task 4.3 후보 산정 설명을 20개 정책으로 갱신했다. 해당 개수는 정책값으로 이후 변경될 수 있으므로 테스트는 `assertEquals(20, RECOMMENDED_AUDIO_LIMIT)`처럼 숫자 자체를 고정하지 않고, 기존 service/refresh 테스트에서 `RECOMMENDED_AUDIO_LIMIT`가 snapshot 조회와 후보 산정 port 호출에 전달되는 흐름을 검증하는 방식으로 유지했다. 검증은 이전 개수 정책 문구 잔존 검색 결과 없음, `./gradlew --no-daemon test --tests kr.co.vividnext.sodalive.v2.content.recommendation.application.AudioRecommendationQueryServiceTest --tests kr.co.vividnext.sodalive.v2.content.recommendation.application.AudioRecommendationSnapshotRefreshServiceTest` `BUILD SUCCESSFUL`, `git diff --check` 출력 없음, `./gradlew --no-daemon tasks --all` `BUILD SUCCESSFUL`로 완료했다. 단, `tasks --all`은 일반 sandbox에서 `~/.gradle` wrapper lock 파일 접근 제한으로 실패해 승인 후 재실행했다.

View File

@@ -65,12 +65,12 @@
- 섹션별 기본 노출 수는 아래와 같다. - 섹션별 기본 노출 수는 아래와 같다.
- `banners`: 메인 홈 추천 배너와 동일 - `banners`: 메인 홈 추천 배너와 동일
- `originalSeries`: 최신순 12개 - `originalSeries`: 최신순 12개
- `latestAudios`: 최신순 12 - `latestAudios`: 최신순 15
- `newAndHotAudios`: 최대 12개 - `newAndHotAudios`: 최대 12개
- `freeAudios`: 최대 10개 랜덤 - `freeAudios`: 최대 15개 랜덤
- `pointAudios`: 최대 10개 랜덤 - `pointAudios`: 최대 15개 랜덤
- `mostCommentedAudios`: 최대 5개 - `mostCommentedAudios`: 최대 5개
- `recommendedAudios`: 최대 10개 - `recommendedAudios`: 최대 20개
- 특정 섹션 데이터가 부족하면 가능한 개수만 내려주고 전체 API는 성공 처리한다. - 특정 섹션 데이터가 부족하면 가능한 개수만 내려주고 전체 API는 성공 처리한다.
- 무료/포인트/추천 오디오 섹션 사이에는 같은 오디오가 중복 노출될 수 있다. - 무료/포인트/추천 오디오 섹션 사이에는 같은 오디오가 중복 노출될 수 있다.
@@ -98,7 +98,7 @@
### Feature D. 새로 올라온 오디오 ### Feature D. 새로 올라온 오디오
#### Requirements #### Requirements
- 공개된 오디오 콘텐츠를 최신순으로 12개 조회한다. - 공개된 오디오 콘텐츠를 최신순으로 15개 조회한다.
- 최신순 기준은 `releaseDate desc`, 동률이면 `audioContentId desc`로 한다. - 최신순 기준은 `releaseDate desc`, 동률이면 `audioContentId desc`로 한다.
- Response는 공통 오디오 카드 응답을 사용한다. - Response는 공통 오디오 카드 응답을 사용한다.
@@ -126,14 +126,14 @@
### Feature F. 무료 오디오 ### Feature F. 무료 오디오
#### Requirements #### Requirements
- 무료 오디오 중 랜덤으로 최대 10개 조회한다. - 무료 오디오 중 랜덤으로 최대 15개 조회한다.
- 무료 오디오는 `price = 0`인 공개 오디오로 정의한다. - 무료 오디오는 `price = 0`인 공개 오디오로 정의한다.
- Response는 공통 오디오 카드 응답을 사용한다. - Response는 공통 오디오 카드 응답을 사용한다.
### Feature G. 포인트 오디오 ### Feature G. 포인트 오디오
#### Requirements #### Requirements
- 포인트 사용 가능 오디오 중 랜덤으로 최대 10개 조회한다. - 포인트 사용 가능 오디오 중 랜덤으로 최대 15개 조회한다.
- 포인트 오디오는 `isPointAvailable = true`인 공개 오디오로 정의한다. - 포인트 오디오는 `isPointAvailable = true`인 공개 오디오로 정의한다.
- Response는 공통 오디오 카드 응답을 사용한다. - Response는 공통 오디오 카드 응답을 사용한다.
@@ -155,7 +155,7 @@
### Feature I. 추천 오디오 ### Feature I. 추천 오디오
#### Requirements #### Requirements
- 최대 10개를 표시한다. - 최대 20개를 표시한다.
- KST 매일 00:00에 전날 23:59:59 KST까지의 데이터를 반영해 스냅샷을 갱신한다. - KST 매일 00:00에 전날 23:59:59 KST까지의 데이터를 반영해 스냅샷을 갱신한다.
- 추천 점수는 `조회수 45% + 좋아요 25% + 댓글 수 20% + 최신성 10%`로 계산한다. - 추천 점수는 `조회수 45% + 좋아요 25% + 댓글 수 20% + 최신성 10%`로 계산한다.
- 조회수는 `creator_content_view_history`의 상세 페이지 조회 이력을 기준으로 스냅샷 집계 기간 내 `content_id`별 count를 사용한다. - 조회수는 `creator_content_view_history`의 상세 페이지 조회 이력을 기준으로 스냅샷 집계 기간 내 `content_id`별 count를 사용한다.

View File

@@ -146,12 +146,12 @@ class AudioRecommendationQueryService(
companion object { companion object {
const val BANNER_LIMIT = 20 const val BANNER_LIMIT = 20
const val ORIGINAL_SERIES_LIMIT = 12 const val ORIGINAL_SERIES_LIMIT = 12
const val LATEST_AUDIO_LIMIT = 12 const val LATEST_AUDIO_LIMIT = 15
const val FREE_AUDIO_LIMIT = 10 const val FREE_AUDIO_LIMIT = 15
const val POINT_AUDIO_LIMIT = 10 const val POINT_AUDIO_LIMIT = 15
const val NEW_AND_HOT_HOME_LIMIT = 12 const val NEW_AND_HOT_HOME_LIMIT = 12
const val MOST_COMMENTED_AUDIO_LIMIT = 5 const val MOST_COMMENTED_AUDIO_LIMIT = 5
const val RECOMMENDED_AUDIO_LIMIT = 10 const val RECOMMENDED_AUDIO_LIMIT = 20
private const val LAZY_REFRESH_MARKER_KEY_PREFIX = "audio-recommendation:new-and-hot:lazy-refresh-attempted" private const val LAZY_REFRESH_MARKER_KEY_PREFIX = "audio-recommendation:new-and-hot:lazy-refresh-attempted"
private const val LAZY_REFRESH_ATTEMPTED_VALUE = "1" private const val LAZY_REFRESH_ATTEMPTED_VALUE = "1"
private val LAZY_REFRESH_MARKER_TTL: Duration = Duration.ofDays(2) private val LAZY_REFRESH_MARKER_TTL: Duration = Duration.ofDays(2)

View File

@@ -130,7 +130,7 @@ class AudioRecommendationSnapshotRefreshService(
companion object { companion object {
const val NEW_AND_HOT_SNAPSHOT_LIMIT = 100 const val NEW_AND_HOT_SNAPSHOT_LIMIT = 100
const val MOST_COMMENTED_LIMIT = 5 const val MOST_COMMENTED_LIMIT = 5
const val RECOMMENDED_AUDIO_LIMIT = 10 const val RECOMMENDED_AUDIO_LIMIT = 20
private val KST_ZONE: ZoneId = ZoneId.of("Asia/Seoul") private val KST_ZONE: ZoneId = ZoneId.of("Asia/Seoul")
} }
} }

View File

@@ -87,6 +87,24 @@ class AudioRecommendationQueryServiceTest {
AudioRecommendationQueryService.RECOMMENDED_AUDIO_LIMIT AudioRecommendationQueryService.RECOMMENDED_AUDIO_LIMIT
) )
Mockito.verify(queryPort).findBanners(AudioRecommendationQueryService.BANNER_LIMIT, null, false) Mockito.verify(queryPort).findBanners(AudioRecommendationQueryService.BANNER_LIMIT, null, false)
Mockito.verify(queryPort).findLatestAudios(
eqValue(AudioRecommendationQueryService.LATEST_AUDIO_LIMIT),
Mockito.isNull(),
eqValue(false),
anyLocalDateTime()
)
Mockito.verify(queryPort).findFreeAudios(
eqValue(AudioRecommendationQueryService.FREE_AUDIO_LIMIT),
Mockito.isNull(),
eqValue(false),
anyLocalDateTime()
)
Mockito.verify(queryPort).findPointAudios(
eqValue(AudioRecommendationQueryService.POINT_AUDIO_LIMIT),
Mockito.isNull(),
eqValue(false),
anyLocalDateTime()
)
Mockito.verify(queryPort).findAudioCardsByIds( Mockito.verify(queryPort).findAudioCardsByIds(
eqValue(listOf(1L)), eqValue(listOf(1L)),
Mockito.isNull(), Mockito.isNull(),