diff --git a/README.md b/README.md index ab5b41aa..b8131cd0 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ For **Java 8** compatible version take a look at release [0.7.0](https://github. All checks can be divided into 2 groups: 1. Runtime checks (those that make sense to perform only on a production database with real data and statistics). - Runtime checks usually [require aggregating data from all nodes in the cluster](https://github.com/mfvanek/pg-index-health/blob/d1473dc68975ebe932d92c9e43ceebde657d0cc7/pg-index-health-core/src/main/java/io/github/mfvanek/pg/common/maintenance/Diagnostic.java#L162). - This necessitated creating [our own abstraction over the database connection](https://github.com/mfvanek/pg-index-health/tree/master/pg-index-health-jdbc-connection). + Runtime checks usually [require aggregating data from all nodes in the cluster](https://github.com/mfvanek/pg-index-health/blob/3e9a63cc2a04799f3e97c9bec9b684ababca8db7/pg-index-health-core/src/main/java/io/github/mfvanek/pg/core/checks/common/Diagnostic.java#L162). + This necessitated creating [our own abstraction over the database connection](https://github.com/mfvanek/pg-index-health/blob/3e9a63cc2a04799f3e97c9bec9b684ababca8db7/pg-index-health-jdbc-connection/src/main/java/io/github/mfvanek/pg/connection/HighAvailabilityPgConnection.java#L22). 2. Static checks (those can be run in tests on an empty database). All static checks can be performed at runtime as well. @@ -81,6 +81,7 @@ For raw sql queries see [pg-index-health-sql](https://github.com/mfvanek/pg-inde ### Static checks Static checks are based on [information schema](https://www.postgresql.org/docs/current/information-schema.html)/[system catalogs](https://www.postgresql.org/docs/current/catalogs.html). +They work with finite database state (after all migrations are applied). ### Runtime checks @@ -88,7 +89,7 @@ Static checks are based on [information schema](https://www.postgresql.org/docs/ (formerly known as [PostgreSQL's statistics collector](https://www.postgresql.org/docs/14/monitoring-stats.html)). You can call `pg_stat_reset()` on each host to reset all statistics counters for the current database to zero -but the best way to do it is to use [DatabaseManagement::resetStatistics()](https://github.com/mfvanek/pg-index-health/blob/d1473dc68975ebe932d92c9e43ceebde657d0cc7/pg-index-health/src/main/java/io/github/mfvanek/pg/common/management/DatabaseManagement.java#L33) method. +but the best way to do it is to use [DatabaseManagement::resetStatistics()](https://github.com/mfvanek/pg-index-health/blob/3e9a63cc2a04799f3e97c9bec9b684ababca8db7/pg-index-health/src/main/java/io/github/mfvanek/pg/health/checks/management/DatabaseManagement.java#L33) method. ## Installation @@ -116,12 +117,15 @@ Using Maven: ## Articles and publications +### In Russian * [Index health in PostgreSQL through the eyes of a Java developer](https://habr.com/ru/post/490824/) +* [DBA: finding useless indexes](https://habr.com/ru/companies/tensor/articles/488104/) +* [The series of articles "Static analysis of the database structure"](https://habr.com/ru/articles/800121/) ## How to use There are three main scenarios of using **pg-index-health** in your projects: -* unit\functional testing; +* unit\functional testing (see **standard test** in section below); * collecting indexes health data and monitoring bloat; * analysis of database configuration. @@ -161,6 +165,45 @@ Using Maven: ``` +### Standard test + +Add a standard test to your project as shown below. Ideally, all checks should work and return an empty result. + +```java +import io.github.mfvanek.pg.core.checks.common.DatabaseCheckOnHost; +import io.github.mfvanek.pg.core.checks.common.Diagnostic; +import io.github.mfvanek.pg.model.dbobject.DbObject; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@ActiveProfiles("test") +class DatabaseStructureStaticAnalysisTest { + + @Autowired + private List> checks; + + @Test + void checksShouldWork() { + assertThat(checks) + .hasSameSizeAs(Diagnostic.values()); + + checks.stream() + .filter(DatabaseCheckOnHost::isStatic) + .forEach(c -> + assertThat(c.check()) + .as(c.getDiagnostic().name()) + .isEmpty()); + } +} +``` + ### Spring Boot compatibility | Spring Boot | Min JDK | pg-index-health-test-starter | diff --git a/spring-boot-integration/h2-demo-app/src/test/java/io/github/mfvanek/pg/spring/h2/H2DemoApplicationTest.java b/spring-boot-integration/h2-demo-app/src/test/java/io/github/mfvanek/pg/spring/h2/H2DemoApplicationTest.java index 425bd9d5..bcee53ca 100644 --- a/spring-boot-integration/h2-demo-app/src/test/java/io/github/mfvanek/pg/spring/h2/H2DemoApplicationTest.java +++ b/spring-boot-integration/h2-demo-app/src/test/java/io/github/mfvanek/pg/spring/h2/H2DemoApplicationTest.java @@ -20,8 +20,8 @@ import static org.assertj.core.api.Assertions.assertThat; -@ActiveProfiles("test") @SpringBootTest +@ActiveProfiles("test") class H2DemoApplicationTest { @Autowired diff --git a/spring-boot-integration/kotlin-custom-ds-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/custom/ds/DatabaseStructureStaticAnalysisTest.kt b/spring-boot-integration/kotlin-custom-ds-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/custom/ds/DatabaseStructureStaticAnalysisTest.kt new file mode 100644 index 00000000..fd08e2ae --- /dev/null +++ b/spring-boot-integration/kotlin-custom-ds-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/custom/ds/DatabaseStructureStaticAnalysisTest.kt @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019-2024. Ivan Vakhrushev and others. + * https://github.com/mfvanek/pg-index-health + * + * This file is a part of "pg-index-health" - a Java library for + * analyzing and maintaining indexes health in PostgreSQL databases. + * + * Licensed under the Apache License 2.0 + */ + +package io.github.mfvanek.pg.spring.postgres.kt.custom.ds + +import io.github.mfvanek.pg.core.checks.common.DatabaseCheckOnHost +import io.github.mfvanek.pg.core.checks.common.Diagnostic +import io.github.mfvanek.pg.model.context.PgContext +import io.github.mfvanek.pg.model.dbobject.DbObject +import io.github.mfvanek.pg.model.predicates.SkipLiquibaseTablesPredicate +import io.github.mfvanek.pg.model.table.Table +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.ActiveProfiles + +@SpringBootTest +@ActiveProfiles("test") +internal class DatabaseStructureStaticAnalysisTest { + + @Autowired + private lateinit var checks: List> + + @Test + fun checksShouldWork() { + assertThat(checks) + .hasSameSizeAs(Diagnostic.entries.toTypedArray()) + + checks + .filter { it.isStatic } + .forEach { check -> + val ctx = PgContext.of("custom_ds_schema") + // Due to the use of spring.liquibase.default-schema, all names are resolved without a schema + val listAssert = assertThat(check.check(ctx, SkipLiquibaseTablesPredicate.ofPublic())) + .`as`(check.diagnostic.name) + + when (check.diagnostic) { + Diagnostic.TABLES_NOT_LINKED_TO_OTHERS -> + listAssert + .hasSize(1) + .containsExactly(Table.of("warehouse")) + + else -> listAssert.isEmpty() + } + } + } +} diff --git a/spring-boot-integration/kotlin-custom-ds-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/custom/ds/PostgresCustomDataSourceDemoApplicationKtRunTest.kt b/spring-boot-integration/kotlin-custom-ds-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/custom/ds/PostgresCustomDataSourceDemoApplicationKtRunTest.kt index 05054359..3c45e64d 100644 --- a/spring-boot-integration/kotlin-custom-ds-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/custom/ds/PostgresCustomDataSourceDemoApplicationKtRunTest.kt +++ b/spring-boot-integration/kotlin-custom-ds-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/custom/ds/PostgresCustomDataSourceDemoApplicationKtRunTest.kt @@ -17,7 +17,6 @@ internal class PostgresCustomDataSourceDemoApplicationKtRunTest { assertThat(output.all) .contains("Reading from custom_ds_schema.databasechangelog") .contains("Starting PostgresCustomDataSourceDemoApplicationKt using Java") - .contains("Container is started (JDBC URL: jdbc:postgresql://localhost:") .contains("Started PostgresCustomDataSourceDemoApplicationKt in") } } diff --git a/spring-boot-integration/kotlin-custom-ds-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/custom/ds/PostgresCustomDataSourceDemoApplicationKtTest.kt b/spring-boot-integration/kotlin-custom-ds-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/custom/ds/PostgresCustomDataSourceDemoApplicationKtTest.kt index f2a554ea..4277e98f 100644 --- a/spring-boot-integration/kotlin-custom-ds-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/custom/ds/PostgresCustomDataSourceDemoApplicationKtTest.kt +++ b/spring-boot-integration/kotlin-custom-ds-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/custom/ds/PostgresCustomDataSourceDemoApplicationKtTest.kt @@ -2,12 +2,6 @@ package io.github.mfvanek.pg.spring.postgres.kt.custom.ds import com.zaxxer.hikari.HikariDataSource import io.github.mfvanek.pg.connection.PgConnection -import io.github.mfvanek.pg.core.checks.common.DatabaseCheckOnHost -import io.github.mfvanek.pg.core.checks.common.Diagnostic -import io.github.mfvanek.pg.model.context.PgContext -import io.github.mfvanek.pg.model.dbobject.DbObject -import io.github.mfvanek.pg.model.predicates.SkipLiquibaseTablesPredicate -import io.github.mfvanek.pg.model.table.Table import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired @@ -15,16 +9,13 @@ import org.springframework.boot.test.context.SpringBootTest import org.springframework.context.ApplicationContext import org.springframework.test.context.ActiveProfiles -@ActiveProfiles("test") @SpringBootTest +@ActiveProfiles("test") internal class PostgresCustomDataSourceDemoApplicationKtTest { @Autowired private lateinit var applicationContext: ApplicationContext - @Autowired - private lateinit var checks: List> - @Test fun contextLoadsAndContainsPgIndexHealthBeans() { assertThat(applicationContext.getBean("pgihCustomDataSource")) @@ -33,28 +24,4 @@ internal class PostgresCustomDataSourceDemoApplicationKtTest { assertThat(applicationContext.getBean("pgConnection")) .isInstanceOf(PgConnection::class.java) } - - @Test - fun checksShouldWork() { - assertThat(checks) - .hasSameSizeAs(Diagnostic.entries.toTypedArray()) - - checks - .filter { it.isStatic } - .forEach { check -> - val ctx = PgContext.of("custom_ds_schema") - // Due to the use of spring.liquibase.default-schema, all names are resolved without a schema - val listAssert = assertThat(check.check(ctx, SkipLiquibaseTablesPredicate.ofPublic())) - .`as`(check.diagnostic.name) - - when (check.diagnostic) { - Diagnostic.TABLES_NOT_LINKED_TO_OTHERS -> - listAssert - .hasSize(1) - .containsExactly(Table.of("warehouse")) - - else -> listAssert.isEmpty() - } - } - } } diff --git a/spring-boot-integration/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/DatabaseStructureStaticAnalysisTest.kt b/spring-boot-integration/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/DatabaseStructureStaticAnalysisTest.kt new file mode 100644 index 00000000..11c1af50 --- /dev/null +++ b/spring-boot-integration/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/DatabaseStructureStaticAnalysisTest.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019-2024. Ivan Vakhrushev and others. + * https://github.com/mfvanek/pg-index-health + * + * This file is a part of "pg-index-health" - a Java library for + * analyzing and maintaining indexes health in PostgreSQL databases. + * + * Licensed under the Apache License 2.0 + */ + +package io.github.mfvanek.pg.spring.postgres.kt + +import io.github.mfvanek.pg.core.checks.common.DatabaseCheckOnHost +import io.github.mfvanek.pg.core.checks.common.Diagnostic +import io.github.mfvanek.pg.model.dbobject.DbObject +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.ActiveProfiles + +@SpringBootTest +@ActiveProfiles("test") +internal class DatabaseStructureStaticAnalysisTest { + + @Autowired + private lateinit var checks: List> + + @Test + fun checksShouldWork() { + assertThat(checks) + .hasSameSizeAs(Diagnostic.entries.toTypedArray()) + + checks + .filter { it.isStatic } + .forEach { + assertThat(it.check()) + .`as`(it.diagnostic.name) + .isEmpty() + } + } +} diff --git a/spring-boot-integration/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/PostgresDemoApplicationKtTest.kt b/spring-boot-integration/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/PostgresDemoApplicationKtTest.kt index 8eeedc73..c8931176 100644 --- a/spring-boot-integration/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/PostgresDemoApplicationKtTest.kt +++ b/spring-boot-integration/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/PostgresDemoApplicationKtTest.kt @@ -12,9 +12,6 @@ package io.github.mfvanek.pg.spring.postgres.kt import com.zaxxer.hikari.HikariDataSource import io.github.mfvanek.pg.connection.PgConnection -import io.github.mfvanek.pg.core.checks.common.DatabaseCheckOnHost -import io.github.mfvanek.pg.core.checks.common.Diagnostic -import io.github.mfvanek.pg.model.dbobject.DbObject import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired @@ -23,8 +20,8 @@ import org.springframework.context.ApplicationContext import org.springframework.core.env.Environment import org.springframework.test.context.ActiveProfiles -@ActiveProfiles("test") @SpringBootTest +@ActiveProfiles("test") internal class PostgresDemoApplicationKtTest { @Autowired @@ -33,9 +30,6 @@ internal class PostgresDemoApplicationKtTest { @Autowired private lateinit var environment: Environment - @Autowired - private lateinit var checks: List> - @Test fun contextLoadsAndContainsPgIndexHealthBeans() { assertThat(applicationContext.getBean("dataSource")) @@ -49,18 +43,4 @@ internal class PostgresDemoApplicationKtTest { .startsWith("jdbc:postgresql://localhost:") .endsWith("/demo_for_pg_index_health_starter?loggerLevel=OFF") } - - @Test - fun checksShouldWork() { - assertThat(checks) - .hasSameSizeAs(Diagnostic.entries.toTypedArray()) - - checks - .filter { it.isStatic } - .forEach { - assertThat(it.check()) - .`as`(it.diagnostic.name) - .isEmpty() - } - } } diff --git a/spring-boot-integration/postgres-demo-app-with-custom-user/src/test/java/io/github/mfvanek/pg/spring/postgres/with/custom/user/DatabaseStructureStaticAnalysisTest.java b/spring-boot-integration/postgres-demo-app-with-custom-user/src/test/java/io/github/mfvanek/pg/spring/postgres/with/custom/user/DatabaseStructureStaticAnalysisTest.java new file mode 100644 index 00000000..10d3c995 --- /dev/null +++ b/spring-boot-integration/postgres-demo-app-with-custom-user/src/test/java/io/github/mfvanek/pg/spring/postgres/with/custom/user/DatabaseStructureStaticAnalysisTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2019-2024. Ivan Vakhrushev and others. + * https://github.com/mfvanek/pg-index-health + * + * This file is a part of "pg-index-health" - a Java library for + * analyzing and maintaining indexes health in PostgreSQL databases. + * + * Licensed under the Apache License 2.0 + */ + +package io.github.mfvanek.pg.spring.postgres.with.custom.user; + +import io.github.mfvanek.pg.core.checks.common.DatabaseCheckOnHost; +import io.github.mfvanek.pg.core.checks.common.Diagnostic; +import io.github.mfvanek.pg.model.column.Column; +import io.github.mfvanek.pg.model.column.ColumnWithSerialType; +import io.github.mfvanek.pg.model.column.SerialType; +import io.github.mfvanek.pg.model.context.PgContext; +import io.github.mfvanek.pg.model.dbobject.DbObject; +import io.github.mfvanek.pg.model.predicates.SkipLiquibaseTablesPredicate; +import io.github.mfvanek.pg.model.table.Table; +import org.assertj.core.api.ListAssert; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.InstanceOfAssertFactories.list; + +@SpringBootTest +@ActiveProfiles("test") +class DatabaseStructureStaticAnalysisTest { + + @Autowired + private List> checks; + + @Test + void checksShouldWorkForPublicSchema() { + assertThat(checks) + .hasSameSizeAs(Diagnostic.values()); + + checks.stream() + .filter(DatabaseCheckOnHost::isStatic) + .forEach(c -> { + assertThat(c.check()) + .as(c.getDiagnostic().name()) + .isEmpty(); + + assertThat(c.getHost().getPgUrl()) + .startsWith("jdbc:postgresql://localhost:") + .endsWith("/demo_for_pgih_with_custom_user?loggerLevel=OFF"); + }); + } + + @Test + void checksShouldWorkForMainSchema() { + assertThat(checks) + .hasSameSizeAs(Diagnostic.values()); + + final PgContext ctx = PgContext.of("main_schema"); + checks.stream() + .filter(DatabaseCheckOnHost::isStatic) + .forEach(c -> { + final ListAssert listAssert = assertThat(c.check(ctx, SkipLiquibaseTablesPredicate.of(ctx))) + .as(c.getDiagnostic().name()); + + switch (c.getDiagnostic()) { + case TABLES_NOT_LINKED_TO_OTHERS: + listAssert + .hasSize(1) + .asInstanceOf(list(Table.class)) + .containsExactly(Table.of(ctx, "warehouse")); + break; + + case PRIMARY_KEYS_WITH_SERIAL_TYPES: + listAssert + .hasSize(1) + .asInstanceOf(list(ColumnWithSerialType.class)) + .containsExactly(ColumnWithSerialType.of( + Column.ofNotNull(ctx, "warehouse", "id"), + SerialType.BIG_SERIAL, ctx.enrichWithSchema("warehouse_id_seq"))); + break; + + default: + listAssert.isEmpty(); + break; + } + }); + } + + @Test + void checksShouldWorkForAdditionalSchema() { + assertThat(checks) + .hasSameSizeAs(Diagnostic.values()); + + final PgContext ctx = PgContext.of("additional_schema"); + checks.stream() + .filter(DatabaseCheckOnHost::isStatic) + .forEach(c -> { + final ListAssert listAssert = assertThat(c.check(ctx)) + .as(c.getDiagnostic().name()); + + switch (c.getDiagnostic()) { + case TABLES_WITHOUT_DESCRIPTION: + case TABLES_NOT_LINKED_TO_OTHERS: + listAssert.hasSize(1) + .asInstanceOf(list(Table.class)) + .containsExactly(Table.of(ctx, "additional_table")); + break; + + case COLUMNS_WITHOUT_DESCRIPTION: + listAssert.hasSize(2); + break; + + case PRIMARY_KEYS_WITH_SERIAL_TYPES: + listAssert.hasSize(1) + .asInstanceOf(list(ColumnWithSerialType.class)) + .containsExactly(ColumnWithSerialType.of( + Column.ofNotNull(ctx, "additional_table", "id"), SerialType.BIG_SERIAL, ctx.enrichWithSchema("additional_table_id_seq")) + ); + break; + + default: + listAssert.isEmpty(); + break; + } + }); + } +} diff --git a/spring-boot-integration/postgres-demo-app-with-custom-user/src/test/java/io/github/mfvanek/pg/spring/postgres/with/custom/user/PostgresWithCustomUserDemoApplicationTest.java b/spring-boot-integration/postgres-demo-app-with-custom-user/src/test/java/io/github/mfvanek/pg/spring/postgres/with/custom/user/PostgresWithCustomUserDemoApplicationTest.java index 6517f1ae..bee8ac46 100644 --- a/spring-boot-integration/postgres-demo-app-with-custom-user/src/test/java/io/github/mfvanek/pg/spring/postgres/with/custom/user/PostgresWithCustomUserDemoApplicationTest.java +++ b/spring-boot-integration/postgres-demo-app-with-custom-user/src/test/java/io/github/mfvanek/pg/spring/postgres/with/custom/user/PostgresWithCustomUserDemoApplicationTest.java @@ -12,16 +12,6 @@ import com.zaxxer.hikari.HikariDataSource; import io.github.mfvanek.pg.connection.PgConnection; -import io.github.mfvanek.pg.core.checks.common.DatabaseCheckOnHost; -import io.github.mfvanek.pg.core.checks.common.Diagnostic; -import io.github.mfvanek.pg.model.column.Column; -import io.github.mfvanek.pg.model.column.ColumnWithSerialType; -import io.github.mfvanek.pg.model.column.SerialType; -import io.github.mfvanek.pg.model.context.PgContext; -import io.github.mfvanek.pg.model.dbobject.DbObject; -import io.github.mfvanek.pg.model.predicates.SkipLiquibaseTablesPredicate; -import io.github.mfvanek.pg.model.table.Table; -import org.assertj.core.api.ListAssert; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -29,13 +19,10 @@ import org.springframework.core.env.Environment; import org.springframework.test.context.ActiveProfiles; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.InstanceOfAssertFactories.list; -@ActiveProfiles("test") @SpringBootTest +@ActiveProfiles("test") class PostgresWithCustomUserDemoApplicationTest { @Autowired @@ -44,9 +31,6 @@ class PostgresWithCustomUserDemoApplicationTest { @Autowired private Environment environment; - @Autowired - private List> checks; - @Test void contextLoadsAndDoesNotContainPgIndexHealthBeans() { assertThat(applicationContext.getBean("dataSource")) @@ -64,97 +48,4 @@ void contextLoadsAndDoesNotContainPgIndexHealthBeans() { assertThat(environment.getProperty("spring.liquibase.url")) .isNotBlank(); } - - @Test - void checksShouldWorkForPublicSchema() { - assertThat(checks) - .hasSameSizeAs(Diagnostic.values()); - - checks.stream() - .filter(DatabaseCheckOnHost::isStatic) - .forEach(c -> { - assertThat(c.check()) - .as(c.getDiagnostic().name()) - .isEmpty(); - - assertThat(c.getHost().getPgUrl()) - .startsWith("jdbc:postgresql://localhost:") - .endsWith("/demo_for_pgih_with_custom_user?loggerLevel=OFF"); - }); - } - - @Test - void checksShouldWorkForMainSchema() { - assertThat(checks) - .hasSameSizeAs(Diagnostic.values()); - - final PgContext ctx = PgContext.of("main_schema"); - checks.stream() - .filter(DatabaseCheckOnHost::isStatic) - .forEach(c -> { - final ListAssert listAssert = assertThat(c.check(ctx, SkipLiquibaseTablesPredicate.of(ctx))) - .as(c.getDiagnostic().name()); - - switch (c.getDiagnostic()) { - case TABLES_NOT_LINKED_TO_OTHERS: - listAssert - .hasSize(1) - .asInstanceOf(list(Table.class)) - .containsExactly(Table.of(ctx, "warehouse")); - break; - - case PRIMARY_KEYS_WITH_SERIAL_TYPES: - listAssert - .hasSize(1) - .asInstanceOf(list(ColumnWithSerialType.class)) - .containsExactly(ColumnWithSerialType.of( - Column.ofNotNull(ctx, "warehouse", "id"), - SerialType.BIG_SERIAL, ctx.enrichWithSchema("warehouse_id_seq"))); - break; - - default: - listAssert.isEmpty(); - break; - } - }); - } - - @Test - void checksShouldWorkForAdditionalSchema() { - assertThat(checks) - .hasSameSizeAs(Diagnostic.values()); - - final PgContext ctx = PgContext.of("additional_schema"); - checks.stream() - .filter(DatabaseCheckOnHost::isStatic) - .forEach(c -> { - final ListAssert listAssert = assertThat(c.check(ctx)) - .as(c.getDiagnostic().name()); - - switch (c.getDiagnostic()) { - case TABLES_WITHOUT_DESCRIPTION: - case TABLES_NOT_LINKED_TO_OTHERS: - listAssert.hasSize(1) - .asInstanceOf(list(Table.class)) - .containsExactly(Table.of(ctx, "additional_table")); - break; - - case COLUMNS_WITHOUT_DESCRIPTION: - listAssert.hasSize(2); - break; - - case PRIMARY_KEYS_WITH_SERIAL_TYPES: - listAssert.hasSize(1) - .asInstanceOf(list(ColumnWithSerialType.class)) - .containsExactly(ColumnWithSerialType.of( - Column.ofNotNull(ctx, "additional_table", "id"), SerialType.BIG_SERIAL, ctx.enrichWithSchema("additional_table_id_seq")) - ); - break; - - default: - listAssert.isEmpty(); - break; - } - }); - } } diff --git a/spring-boot-integration/postgres-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/DatabaseStructureStaticAnalysisTest.java b/spring-boot-integration/postgres-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/DatabaseStructureStaticAnalysisTest.java new file mode 100644 index 00000000..14b341fd --- /dev/null +++ b/spring-boot-integration/postgres-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/DatabaseStructureStaticAnalysisTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019-2024. Ivan Vakhrushev and others. + * https://github.com/mfvanek/pg-index-health + * + * This file is a part of "pg-index-health" - a Java library for + * analyzing and maintaining indexes health in PostgreSQL databases. + * + * Licensed under the Apache License 2.0 + */ + +package io.github.mfvanek.pg.spring.postgres; + +import io.github.mfvanek.pg.core.checks.common.DatabaseCheckOnHost; +import io.github.mfvanek.pg.core.checks.common.Diagnostic; +import io.github.mfvanek.pg.model.dbobject.DbObject; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@ActiveProfiles("test") +class DatabaseStructureStaticAnalysisTest { + + @Autowired + private List> checks; + + @Test + void checksShouldWork() { + assertThat(checks) + .hasSameSizeAs(Diagnostic.values()); + + checks.stream() + .filter(DatabaseCheckOnHost::isStatic) + .forEach(c -> + assertThat(c.check()) + .as(c.getDiagnostic().name()) + .isEmpty()); + } +} diff --git a/spring-boot-integration/postgres-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/PostgresDemoApplicationTest.java b/spring-boot-integration/postgres-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/PostgresDemoApplicationTest.java index 19fa1efc..5692a15b 100644 --- a/spring-boot-integration/postgres-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/PostgresDemoApplicationTest.java +++ b/spring-boot-integration/postgres-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/PostgresDemoApplicationTest.java @@ -12,9 +12,6 @@ import com.zaxxer.hikari.HikariDataSource; import io.github.mfvanek.pg.connection.PgConnection; -import io.github.mfvanek.pg.core.checks.common.DatabaseCheckOnHost; -import io.github.mfvanek.pg.core.checks.common.Diagnostic; -import io.github.mfvanek.pg.model.dbobject.DbObject; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -22,12 +19,10 @@ import org.springframework.core.env.Environment; import org.springframework.test.context.ActiveProfiles; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; -@ActiveProfiles("test") @SpringBootTest +@ActiveProfiles("test") class PostgresDemoApplicationTest { @Autowired @@ -36,9 +31,6 @@ class PostgresDemoApplicationTest { @Autowired private Environment environment; - @Autowired - private List> checks; - @Test void contextLoadsAndDoesNotContainPgIndexHealthBeans() { assertThat(applicationContext.getBean("dataSource")) @@ -52,16 +44,4 @@ void contextLoadsAndDoesNotContainPgIndexHealthBeans() { .startsWith("jdbc:postgresql://localhost:") .endsWith("/demo_for_pg_index_health_starter?loggerLevel=OFF"); } - - @Test - void checksShouldWork() { - assertThat(checks) - .hasSameSizeAs(Diagnostic.values()); - - checks.stream() - .filter(DatabaseCheckOnHost::isStatic) - .forEach(c -> assertThat(c.check()) - .as(c.getDiagnostic().name()) - .isEmpty()); - } } diff --git a/spring-boot-integration/postgres-tc-url-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/tc/url/DatabaseStructureStaticAnalysisTest.java b/spring-boot-integration/postgres-tc-url-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/tc/url/DatabaseStructureStaticAnalysisTest.java new file mode 100644 index 00000000..ebfe24dd --- /dev/null +++ b/spring-boot-integration/postgres-tc-url-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/tc/url/DatabaseStructureStaticAnalysisTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019-2024. Ivan Vakhrushev and others. + * https://github.com/mfvanek/pg-index-health + * + * This file is a part of "pg-index-health" - a Java library for + * analyzing and maintaining indexes health in PostgreSQL databases. + * + * Licensed under the Apache License 2.0 + */ + +package io.github.mfvanek.pg.spring.postgres.tc.url; + +import io.github.mfvanek.pg.core.checks.common.DatabaseCheckOnHost; +import io.github.mfvanek.pg.core.checks.common.Diagnostic; +import io.github.mfvanek.pg.model.dbobject.DbObject; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@ActiveProfiles("test") +class DatabaseStructureStaticAnalysisTest { + + @Autowired + private List> checks; + + @Test + void checksShouldWork() { + assertThat(checks) + .hasSameSizeAs(Diagnostic.values()); + + checks.stream() + .filter(DatabaseCheckOnHost::isStatic) + .forEach(c -> { + assertThat(c.check()) + .as(c.getDiagnostic().name()) + .isEmpty(); + + assertThat(c.getHost().getPgUrl()) + .startsWith("jdbc:postgresql://localhost:") + .endsWith("/test?loggerLevel=OFF"); + }); + } +} diff --git a/spring-boot-integration/postgres-tc-url-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/tc/url/PostgresTestcontainersUrlDemoApplicationTest.java b/spring-boot-integration/postgres-tc-url-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/tc/url/PostgresTestcontainersUrlDemoApplicationTest.java index f3d18345..3702b38b 100644 --- a/spring-boot-integration/postgres-tc-url-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/tc/url/PostgresTestcontainersUrlDemoApplicationTest.java +++ b/spring-boot-integration/postgres-tc-url-demo-app/src/test/java/io/github/mfvanek/pg/spring/postgres/tc/url/PostgresTestcontainersUrlDemoApplicationTest.java @@ -12,9 +12,6 @@ import com.zaxxer.hikari.HikariDataSource; import io.github.mfvanek.pg.connection.PgConnection; -import io.github.mfvanek.pg.core.checks.common.DatabaseCheckOnHost; -import io.github.mfvanek.pg.core.checks.common.Diagnostic; -import io.github.mfvanek.pg.model.dbobject.DbObject; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -22,12 +19,10 @@ import org.springframework.core.env.Environment; import org.springframework.test.context.ActiveProfiles; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; -@ActiveProfiles("test") @SpringBootTest +@ActiveProfiles("test") class PostgresTestcontainersUrlDemoApplicationTest { @Autowired @@ -36,9 +31,6 @@ class PostgresTestcontainersUrlDemoApplicationTest { @Autowired private Environment environment; - @Autowired - private List> checks; - @Test void contextLoadsAndDoesNotContainPgIndexHealthBeans() { assertThat(applicationContext.getBean("dataSource")) @@ -51,22 +43,4 @@ void contextLoadsAndDoesNotContainPgIndexHealthBeans() { .isNotBlank() .isEqualTo("jdbc:tc:postgresql:17.2:///demo_for_pg_index_health_starter"); } - - @Test - void checksShouldWork() { - assertThat(checks) - .hasSameSizeAs(Diagnostic.values()); - - checks.stream() - .filter(DatabaseCheckOnHost::isStatic) - .forEach(c -> { - assertThat(c.check()) - .as(c.getDiagnostic().name()) - .isEmpty(); - - assertThat(c.getHost().getPgUrl()) - .startsWith("jdbc:postgresql://localhost:") - .endsWith("/test?loggerLevel=OFF"); - }); - } }