SimpleNotes/persistence/test/notes/BaseNoteRepositoryImplTest.kt
2021-02-27 18:07:22 +01:00

340 lines
11 KiB
Kotlin

package be.simplenotes.persistence.notes
import be.simplenotes.persistence.DbTest
import be.simplenotes.persistence.converters.NoteConverter
import be.simplenotes.persistence.repositories.NoteRepository
import be.simplenotes.persistence.repositories.UserRepository
import be.simplenotes.persistence.users.createFakeUser
import be.simplenotes.types.ExportedNote
import be.simplenotes.types.PersistedUser
import me.liuwj.ktorm.database.Database
import me.liuwj.ktorm.dsl.eq
import me.liuwj.ktorm.entity.filter
import me.liuwj.ktorm.entity.find
import me.liuwj.ktorm.entity.mapColumns
import me.liuwj.ktorm.entity.toList
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.jupiter.api.*
import java.sql.SQLIntegrityConstraintViolationException
internal abstract class BaseNoteRepositoryImplTest : DbTest() {
private lateinit var noteRepo: NoteRepository
private lateinit var userRepo: UserRepository
private lateinit var db: Database
private lateinit var user1: PersistedUser
private lateinit var user2: PersistedUser
@BeforeEach
fun insertUsers() {
noteRepo = beanContext.getBean()
userRepo = beanContext.getBean()
db = beanContext.getBean()
user1 = userRepo.createFakeUser()!!
user2 = userRepo.createFakeUser()!!
}
@Nested
@DisplayName("create()")
inner class Create {
@Test
fun `create note for non existing user`() {
val note = fakeNote()
assertThatThrownBy {
noteRepo.create(1000, note)
}.isInstanceOf(SQLIntegrityConstraintViolationException::class.java)
}
@Test
fun `create note for existing user`() {
val note = fakeNote()
assertThat(noteRepo.create(user1.id, note))
.hasNoNullFieldsOrProperties()
.usingRecursiveComparison()
.ignoringFields("uuid", "updatedAt", "public")
.isEqualTo(note)
assertThat(db.notes.toList())
.hasSize(1)
.first()
.usingRecursiveComparison()
.ignoringFields("uuid", "updatedAt", "public")
.isEqualTo(note)
}
}
@Nested
@DisplayName("findAll()")
inner class FindAll {
@Test
fun `find all notes`() {
val notes1 = noteRepo.insertFakeNotes(user1, count = 3)
val notes2 = listOf(noteRepo.insertFakeNote(user2))
assertThat(noteRepo.findAll(user1.id))
.hasSize(3)
.usingElementComparatorIgnoringFields("updatedAt")
.containsExactlyInAnyOrderElementsOf(
notes1.map { it.toPersistedMeta() }
)
assertThat(noteRepo.findAll(user2.id))
.hasSize(1)
.usingElementComparatorIgnoringFields("updatedAt")
.containsExactlyInAnyOrderElementsOf(
notes2.map { it.toPersistedMeta() }
)
assertThat(noteRepo.findAll(1000)).isEmpty()
}
// TODO: datetime -> timestamp migration
@Disabled("Not working with mariadb, inserts are too fast so the updated_at is the same")
@Test
fun pagination() {
(50 downTo 1).forEach { i ->
noteRepo.insertFakeNote(user1, "$i")
}
assertThat(noteRepo.findAll(user1.id, limit = 20, offset = 0).onEach { println(it) })
.hasSize(20)
.allMatch { it.title.toInt() in 1..20 }
assertThat(noteRepo.findAll(user1.id, limit = 20, offset = 20))
.hasSize(20)
.allMatch { it.title.toInt() in 21..40 }
assertThat(noteRepo.findAll(user1.id, limit = 20, offset = 40))
.hasSize(10)
.allMatch { it.title.toInt() in 41..50 }
}
@Test
fun `find all notes with tag`() {
with(noteRepo) {
insertFakeNote(user1, "1", listOf("a", "b"))
insertFakeNote(user1, "2", tags = emptyList())
insertFakeNote(user1, "3", listOf("c"))
insertFakeNote(user1, "4", listOf("c"))
insertFakeNote(user2, "5", listOf("c"))
}
assertThat(noteRepo.findAll(user1.id, tag = "a"))
.hasSize(1)
.first()
.hasFieldOrPropertyWithValue("title", "1")
assertThat(noteRepo.findAll(user1.id, tag = "c"))
.hasSize(2)
assertThat(noteRepo.findAll(user2.id, tag = "c"))
.hasSize(1)
}
}
@Nested
@DisplayName("find() | exists()")
inner class FindExists {
@Test
@Suppress("UNCHECKED_CAST")
fun `find an existing note`() {
val fakeNote = noteRepo.insertFakeNote(user1)
val converter = beanContext.getBean(NoteConverter::class.java)
val note = db.notes.find { it.title eq fakeNote.meta.title }!!
.let { entity ->
val tags = db.tags.filter { it.noteUuid eq entity.uuid }.mapColumns { it.name } as List<String>
converter.toPersistedNote(entity, tags)
}
assertThat(noteRepo.find(user1.id, note.uuid)).isEqualTo(note)
assertThat(noteRepo.exists(user1.id, note.uuid)).isTrue
}
@Test
fun `find an existing note from the wrong user`() {
val note = noteRepo.insertFakeNote(user1)
assertThat(noteRepo.find(user2.id, note.uuid)).isNull()
assertThat(noteRepo.exists(user2.id, note.uuid)).isFalse
}
@Test
fun `find a non existing note`() {
noteRepo.insertFakeNote(user1)
val uuid = fakeUuid()
assertThat(noteRepo.find(user1.id, uuid)).isNull()
assertThat(noteRepo.exists(user2.id, uuid)).isFalse
}
}
@Nested
@DisplayName("delete()")
inner class Delete {
@Test
fun `delete an existing note for a user should succeed and then fail`() {
val note = noteRepo.insertFakeNote(user1)
assertThat(noteRepo.delete(user1.id, note.uuid)).isTrue
}
@Test
fun `delete an existing note for the wrong user`() {
val note = noteRepo.insertFakeNote(user1)
assertThat(noteRepo.delete(1000, note.uuid)).isFalse
}
}
@Nested
@DisplayName("getTags()")
inner class Tags {
@Test
fun getTags() {
val notes1 = noteRepo.insertFakeNotes(user1, count = 3)
val notes2 = noteRepo.insertFakeNotes(user2, count = 1)
val user1Tags = notes1.flatMap { it.meta.tags }.toSet()
assertThat(noteRepo.getTags(user1.id))
.containsExactlyInAnyOrderElementsOf(user1Tags)
val user2Tags = notes2.flatMap { it.meta.tags }.toSet()
assertThat(noteRepo.getTags(user2.id))
.containsExactlyInAnyOrderElementsOf(user2Tags)
assertThat(noteRepo.getTags(1000))
.isEmpty()
}
}
@Nested
@DisplayName("update()")
inner class Update {
@Test
fun getTags() {
val note1 = noteRepo.insertFakeNote(user1)
val newNote1 = fakeNote()
assertThat(noteRepo.update(user1.id, note1.uuid, newNote1)).isNotNull
assertThat(noteRepo.find(user1.id, note1.uuid))
.usingRecursiveComparison()
.ignoringFields("updatedAt", "uuid", "public")
.isEqualTo(newNote1)
val note2 = noteRepo.insertFakeNote(user1)
val newNote2 = fakeNote().let {
it.copy(meta = it.meta.copy(tags = tagGenerator().take(3).toList()))
}
assertThat(noteRepo.update(user1.id, note2.uuid, newNote2))
.isNotNull
assertThat(noteRepo.find(user1.id, note2.uuid))
.usingRecursiveComparison()
.ignoringFields("updatedAt", "uuid", "public")
.isEqualTo(newNote2)
}
}
@Nested
inner class Trash {
@Test
fun `trashed noted should be restored`() {
val note1 = noteRepo.insertFakeNote(user1, "1", listOf("a", "b"))
assertThat(noteRepo.delete(user1.id, note1.uuid, permanent = false))
.isTrue
val isDeleted = db.notes
.find { it.uuid eq note1.uuid }
?.deleted
assertThat(isDeleted).`as`("Check that Notes.deleted is true").isTrue
assertThat(noteRepo.restore(user1.id, note1.uuid)).isTrue
val isDeleted2 = db.notes
.find { it.uuid eq note1.uuid }
?.deleted
assertThat(isDeleted2).`as`("Check that Notes.deleted is false after restore()").isFalse
}
@Test
fun `permanent delete`() {
val note = noteRepo.insertFakeNote(user1)
assertThat(noteRepo.delete(user1.id, note.uuid, permanent = true)).isTrue
assertThat(noteRepo.restore(user1.id, note.uuid)).isFalse
}
}
@Test
fun count() {
assertThat(noteRepo.count(user1.id)).isEqualTo(0)
noteRepo.insertFakeNotes(user1, count = 10)
assertThat(noteRepo.count(user1.id)).isEqualTo(10)
}
@Test
fun countWithTag() {
noteRepo.insertFakeNote(user1, tags = listOf("a", "b"))
noteRepo.insertFakeNote(user1, tags = emptyList())
noteRepo.insertFakeNote(user1, tags = listOf("a"))
noteRepo.insertFakeNote(user1, tags = emptyList())
assertThat(noteRepo.count(user1.id, tag = "a")).isEqualTo(2)
}
@Test
fun export() {
val notes = noteRepo.insertFakeNotes(user1, count = 4)
noteRepo.delete(user1.id, notes.first().uuid, permanent = false)
val export = noteRepo.export(user1.id)
val expected = notes.mapIndexed { i, n ->
ExportedNote(
title = n.meta.title,
tags = n.meta.tags,
markdown = n.markdown,
html = n.html,
updatedAt = n.updatedAt,
trash = i == 0,
)
}
assertThat(export)
.usingElementComparatorIgnoringFields("updatedAt")
.containsExactlyInAnyOrderElementsOf(expected)
}
@Test
fun findAllDetails() {
val notes = noteRepo.insertFakeNotes(user1, count = 10)
val res = noteRepo.findAllDetails(user1.id)
assertThat(res)
.usingElementComparatorIgnoringFields("updatedAt")
.containsExactlyInAnyOrderElementsOf(notes)
}
@Test
fun access() {
val n = noteRepo.insertFakeNote(user1)
noteRepo.makePublic(user1.id, n.uuid)
assertThat(noteRepo.findPublic(n.uuid))
.usingRecursiveComparison()
.ignoringFields("updatedAt")
.isEqualTo(n.copy(public = true))
noteRepo.makePrivate(user1.id, n.uuid)
assertThat(noteRepo.findPublic(n.uuid)).isNull()
}
}