Skip to content

Commit

Permalink
Adds basic CI facilities to build Unit Tests:
Browse files Browse the repository at this point in the history
- GitHub Action for pushes / PRs to dev and main
- Service containers for PostgreSQL and Cottontail DB
- Scaffold for test case on database layer (to be extended).

Signed-off-by: Ralph Gasser <[email protected]>
  • Loading branch information
ppanopticon committed Jul 11, 2024
1 parent a74dc3a commit 7ff7d5f
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 2 deletions.
50 changes: 50 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Java CI with Gradle

on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main, dev ]

jobs:
build:
runs-on: ubuntu-latest

# Setup Cottontail DB and PostgreSQL service container
services:
cottontail:
image: vitrivr/cottontaildb:0.16.6
ports:
- 1865:1865
options: -it
pgvector:
image: pgvector/pgvector:pg16
ports:
- 5432:5432
env:
POSTGRES_PASSWORD: vitrivr

# Start actual job.
steps:
- uses: actions/checkout@v2
- name: Cottontail DB connection test
run: nc -zv 127.0.0.1 1865
- name: PostgreSQL connection test
run: nc -zv 127.0.0.1 5432
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle
- name: Test with gradle ubuntu
if: matrix.os == 'ubuntu-latest'
run: ./gradlew test --info
- name: Test with gradle windows
if: matrix.os == 'windows-latest'
run: ./gradlew test --info
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ subprojects {
}

/* Common plugins. */
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'kotlin'
apply plugin: 'java'
apply plugin: 'java-test-fixtures'

/* Java Version */
sourceCompatibility = JavaVersion.VERSION_21
Expand Down
4 changes: 4 additions & 0 deletions vitrivr-engine-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ plugins {
dependencies {
/** JOML dependencies for 3D mesh support. */
implementation group: 'org.joml', name: 'joml', version: version_joml

/** dependencies for exif metadata extraction. */
implementation 'com.drewnoakes:metadata-extractor:2.19.0'
implementation 'com.google.code.gson:gson:2.8.9'
implementation group: 'io.javalin.community.openapi', name: 'javalin-openapi-plugin', version: version_javalinopenapi

/* Test Fixtures from Cottontail DB core. .*/
testFixturesImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: version_junit
}

/* Publication of vitrivr engine core to Maven Central. */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package org.vitrivr.engine.core.config.schema

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import org.vitrivr.engine.core.model.metamodel.Schema
import org.vitrivr.engine.core.operators.general.Exporter
import org.vitrivr.engine.core.resolver.Resolver
import java.nio.file.Files
import java.nio.file.Paths


/**
Expand Down Expand Up @@ -43,4 +46,22 @@ data class SchemaConfig(
* List of [PipelineConfig]s that are part of this [SchemaConfig].
*/
val extractionPipelines: List<PipelineConfig> = emptyList()
)
) {

companion object {

/**
* Tries to load a [SchemaConfig] from the resources.
*
* @param resourcePath Path to the resource.
* @return [SchemaConfig]
*/
fun loadFromResource(resourcePath: String): SchemaConfig {
val json = Json { ignoreUnknownKeys = true } // Configure Json to ignore unknown keys
val uri = this::class.java.classLoader.resources("test-schema-postgres.json").findFirst().orElseThrow { IllegalArgumentException("Resource '$resourcePath' not found!") }.toURI()
val path = Paths.get(uri)
val jsonString = Files.readString(path)
return json.decodeFromString<SchemaConfig>(jsonString)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.vitrivr.engine.core.database

import org.vitrivr.engine.core.config.schema.SchemaConfig
import org.vitrivr.engine.core.model.metamodel.SchemaManager

/**
* Abstract base class for database tests.
*
* @author Ralph Gasser
* @version 1.0.0
*/
abstract class AbstractDatabaseTest(schemaPath: String) {

companion object {
val SCHEMA_NAME = "vitrivr-test"
}


/** [SchemaManager] for this [AbstractDatabaseTest]. */
protected val manager = SchemaManager()

init {
/* Loads schema. */
val schema = SchemaConfig.loadFromResource(schemaPath)
this.manager.load(schema)
}


/** */
protected val schema = this.manager.getSchema("vitrivr-test") ?: throw IllegalArgumentException("Schema 'vitrivr-test' not found!")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.vitrivr.engine.core.database.retrievable

import org.junit.jupiter.api.AfterEach
import org.vitrivr.engine.core.database.AbstractDatabaseTest

/**
* An abstract set of test cases to test the proper functioning of [RetrievableInitializer] implementations.
*
* @author Ralph Gasser
* @version 1.0.0
*/
abstract class AbstractRetrievableInitializerTest(schemaPath: String) : AbstractDatabaseTest(schemaPath) {
/**
* Tests if the [RetrievableInitializer] can be initialized without throwing an exception. Furthermore,
* the test should check if the necessary tables have been created.
*/
abstract fun testIsInitializedWithoutInitialization()

/**
* Tests if the [RetrievableInitializer] can be initialized without throwing an exception. Furthermore,
* the test should check if the necessary tables have been created.
*/
abstract fun testInitializeEntities()

/**
* Cleans up the database after each test.
*
*/
@AfterEach
open fun cleanup() {
this.schema.connection.getRetrievableInitializer().deinitialize()
for (field in this.schema.fields()) {
field.getInitializer().deinitialize()
}
}
}
3 changes: 3 additions & 0 deletions vitrivr-engine-module-pgvector/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ dependencies {

/** PostgreSQL driver. */
implementation group: 'org.postgresql', name: 'postgresql', version: version_jdbc_postgres

/** Vitrivr engine Core is required for running tests. */
testImplementation(testFixtures(project(':vitrivr-engine-core')))
}

/* Publication of vitrivr engine query to Maven Central. */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.vitrivr.engine.database.pgvector

import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.vitrivr.engine.core.database.retrievable.AbstractRetrievableInitializerTest

/**
* An [AbstractRetrievableInitializerTest] for the [PgVectorConnection].
*
* @author Ralph Gasser
* @version 1.0.0
*/
class RetrievableInitializerTest : AbstractRetrievableInitializerTest("test-schema-postgres.json") {

/** Internal [PgVectorConnection] object. */
private val connection = this.schema.connection as? PgVectorConnection ?: throw IllegalArgumentException("Schema 'vitrivr-test' not found!")

@Test
override fun testIsInitializedWithoutInitialization() {
Assertions.assertFalse(this.connection.getRetrievableInitializer().isInitialized())
}

@Test
override fun testInitializeEntities() {
/* Check initialization status (should be false). */
Assertions.assertFalse(this.connection.getRetrievableInitializer().isInitialized())

/* Initialize basic tables. */
this.connection.getRetrievableInitializer().initialize()

/* Check initialization status (should be true). */
Assertions.assertTrue(this.connection.getRetrievableInitializer().isInitialized())

/* Check for existence of tables. */
this.connection.jdbc.prepareStatement("SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_schema = ? AND table_name = ?)").use { statement ->
/* Check existence of retrievable table. */
statement.setString(1, SCHEMA_NAME)
statement.setString(2, RETRIEVABLE_ENTITY_NAME)
statement.executeQuery().use { result ->
Assertions.assertTrue(result.next() && result.getBoolean(1))
}

/* Check existence of relationship table. */
statement.setString(1, SCHEMA_NAME)
statement.setString(2, RELATIONSHIP_ENTITY_NAME)
statement.executeQuery().use { result ->
Assertions.assertTrue(result.next() && result.getBoolean(1))
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "vitrivr-test",
"connection": {
"database": "PgVectorConnectionProvider",
"parameters": {
"host": "127.0.0.1",
"port": "5432",
"username": "postgres",
"password": "vitrivr"
}
},
"fields": [
{
"name": "averagecolor",
"factory": "AverageColor"
},
{
"name": "file",
"factory": "FileSourceMetadata"
},
{
"name": "time",
"factory": "TemporalMetadata"
},
{
"name": "video",
"factory": "VideoSourceMetadata"
}
],
"exporters": []
}

0 comments on commit 7ff7d5f

Please sign in to comment.