Skip to content

Commit

Permalink
add jooq integration (via #931)
Browse files Browse the repository at this point in the history
  • Loading branch information
baev committed Jun 28, 2023
1 parent a291559 commit b424823
Show file tree
Hide file tree
Showing 5 changed files with 318 additions and 0 deletions.
37 changes: 37 additions & 0 deletions allure-jooq/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
description = "Allure JOOQ Integration"

val jooqVersion = "3.18.4"

dependencies {
api(project(":allure-java-commons"))
implementation("org.jooq:jooq:${jooqVersion}")
testImplementation("io.zonky.test:embedded-postgres:2.0.4")
testImplementation("org.assertj:assertj-core")
testImplementation("org.junit.jupiter:junit-jupiter-api")
testImplementation("org.mockito:mockito-core")
testImplementation("org.slf4j:slf4j-simple")
testImplementation(platform("io.zonky.test.postgres:embedded-postgres-binaries-bom:15.3.0"))
testImplementation(project(":allure-assertj"))
testImplementation(project(":allure-java-commons-test"))
testImplementation(project(":allure-junit-platform"))
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
testRuntimeOnly("org.postgresql:postgresql:42.6.0")
}

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}

tasks.jar {
manifest {
attributes(mapOf(
"Automatic-Module-Name" to "io.qameta.allure.jooq"
))
}
}

tasks.test {
useJUnitPlatform()
}
142 changes: 142 additions & 0 deletions allure-jooq/src/main/java/io/qameta/allure/jooq/AllureJooq.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright 2016-2022 Qameta Software OÜ
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.qameta.allure.jooq;

import io.qameta.allure.Allure;
import io.qameta.allure.AllureLifecycle;
import io.qameta.allure.model.Status;
import io.qameta.allure.model.StepResult;
import org.jooq.ExecuteContext;
import org.jooq.ExecuteListener;
import org.jooq.Formattable;
import org.jooq.Query;
import org.jooq.Record;
import org.jooq.Routine;

import java.util.Objects;
import java.util.UUID;

import static java.lang.Boolean.FALSE;

/**
* @author charlie (Dmitry Baev).
*/
public class AllureJooq implements ExecuteListener {

private static final String STEP_UUID
= "io.qameta.allure.jooq.AllureJooq.STEP_UUID";
private static final String DO_BUFFER
= "io.qameta.allure.jooq.AllureJooq.DO_BUFFER";

private final AllureLifecycle lifecycle;

public AllureJooq() {
this(Allure.getLifecycle());
}

public AllureJooq(final AllureLifecycle lifecycle) {
this.lifecycle = lifecycle;
}

@Override
public void renderEnd(final ExecuteContext ctx) {
if (!lifecycle.getCurrentTestCaseOrStep().isPresent()) {
return;
}

final String stepName = stepName(ctx);
final String uuid = UUID.randomUUID().toString();
ctx.data(STEP_UUID, uuid);
lifecycle.startStep(uuid, new StepResult()
.setName(stepName)
);
}

private String stepName(final ExecuteContext ctx) {
final Query query = ctx.query();
if (query != null) {
return ctx.dsl().renderInlined(query);
}

final Routine<?> routine = ctx.routine();
if (ctx.routine() != null) {
return ctx.dsl().renderInlined(routine);
}

final String sql = ctx.sql();
if (Objects.nonNull(sql) && !sql.isEmpty()) {
return sql;
}

final String[] batchSQL = ctx.batchSQL();
if (batchSQL.length > 0 && batchSQL[batchSQL.length - 1] != null) {
return String.join("\n", batchSQL);
}
return "UNKNOWN";
}

@Override
public void recordEnd(final ExecuteContext ctx) {
if (ctx.recordLevel() > 0) {
return;
}

if (!lifecycle.getCurrentTestCaseOrStep().isPresent()) {
return;
}

final Record record = ctx.record();
if (record != null && !FALSE.equals(ctx.data(DO_BUFFER))) {
attachResultSet(record);
}
}

@Override
public void resultStart(final ExecuteContext ctx) {
ctx.data(DO_BUFFER, false);
}

@Override
public void resultEnd(final ExecuteContext ctx) {
if (!lifecycle.getCurrentTestCaseOrStep().isPresent()) {
return;
}

attachResultSet(ctx.result());
}

@Override
public void end(final ExecuteContext ctx) {
if (!lifecycle.getCurrentTestCaseOrStep().isPresent()) {
return;
}

final String stepUuid = (String) ctx.data(STEP_UUID);
if (Objects.isNull(stepUuid)) {
return;
}

lifecycle.updateStep(stepUuid, sr -> sr.setStatus(Status.PASSED));
lifecycle.stopStep(stepUuid);
}

private void attachResultSet(final Formattable formattable) {
if (Objects.nonNull(formattable)) {
Allure.addAttachment("ResultSet", "text/csv", formattable.formatCSV());
}
}

}
136 changes: 136 additions & 0 deletions allure-jooq/src/test/java/io/qameta/allure/jooq/AllureJooqTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* Copyright 2023 Qameta Software OÜ
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.qameta.allure.jooq;

import io.qameta.allure.Allure;
import io.qameta.allure.model.Attachment;
import io.qameta.allure.model.Status;
import io.qameta.allure.model.StepResult;
import io.qameta.allure.model.TestResult;
import io.qameta.allure.test.AllureResults;
import io.zonky.test.db.postgres.embedded.EmbeddedPostgres;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.Name;
import org.jooq.Record;
import org.jooq.SQLDialect;
import org.jooq.Table;
import org.jooq.impl.DSL;
import org.jooq.impl.DataSourceConnectionProvider;
import org.jooq.impl.DefaultConfiguration;
import org.jooq.impl.DefaultDSLContext;
import org.jooq.impl.SQLDataType;
import org.junit.jupiter.api.Test;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.function.Consumer;

import static io.qameta.allure.test.RunUtils.runWithinTestContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;

/**
* @author charlie (Dmitry Baev).
*/
class AllureJooqTest {

@Test
void shouldSupportFetchSqlStatements() {
final AllureResults results = execute(dsl -> dsl.fetchSingle("select 1"));

final TestResult result = results.getTestResults().get(0);
assertThat(result.getSteps())
.extracting(StepResult::getName, StepResult::getStatus)
.containsExactly(
tuple("select 1", Status.PASSED)
);
}

@Test
void shouldAddResultSetsAsAttachments() {
final AllureResults results = execute(dsl -> dsl.fetchSingle("select 1 as one, 2 as two"));
final TestResult result = results.getTestResults().get(0);
final StepResult step = result.getSteps().get(0);
assertThat(step.getAttachments())
.extracting(Attachment::getName, Attachment::getType)
.containsExactly(
tuple("ResultSet", "text/csv")
);

final Attachment attachment = step.getAttachments().get(0);

final byte[] content = results.getAttachments().get(attachment.getSource());

assertThat(new String(content, StandardCharsets.UTF_8))
.contains("one,two\n1,2\n");

}

@Test
void shouldSupportCreateTableStatements() {
final AllureResults results = execute(dsl -> {
final Name tableName = DSL.name("first_table");
final Field<Long> id = DSL.field("id", SQLDataType.BIGINT);
final Field<String> name = DSL.field("name", SQLDataType.VARCHAR);
dsl.createTable(tableName)
.column(id)
.column(name)
.primaryKey(id)
.execute();

final Table<Record> table = DSL.table(tableName);

dsl.insertInto(table, id, name)
.values(1L, "first")
.values(2L, "second")
.execute();
});

final TestResult result = results.getTestResults().get(0);
assertThat(result.getSteps())
.extracting(StepResult::getName, StepResult::getStatus)
.containsExactly(
tuple("create table \"first_table\" (id bigint, name varchar, primary key (id))", Status.PASSED),
tuple("insert into \"first_table\" (id, name) values (1, 'first'), (2, 'second')", Status.PASSED)
);
}

private static AllureResults execute(final Consumer<DSLContext> dslContextConsumer) {
final EmbeddedPostgres.Builder builder = EmbeddedPostgres.builder();
try (EmbeddedPostgres postgres = builder.start()) {
final DataSource dataSource = postgres.getPostgresDatabase();

final DataSourceConnectionProvider connectionProvider = new DataSourceConnectionProvider(dataSource);
final DefaultConfiguration configuration = new DefaultConfiguration();
configuration.set(SQLDialect.POSTGRES);
configuration.set(connectionProvider);

return runWithinTestContext(
() -> {
final DefaultDSLContext dsl = new DefaultDSLContext(configuration);
dslContextConsumer.accept(dsl);
},
Allure::setLifecycle,
allureLifecycle -> configuration.setExecuteListener(new AllureJooq(allureLifecycle))
);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
2 changes: 2 additions & 0 deletions allure-jooq/src/test/resources/simplelogger.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
org.slf4j.simpleLogger.log.org.jooq.Constants=warn
org.slf4j.simpleLogger.log.org.jooq.tools.LoggerListener=info
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ include("allure-java-commons-test")
include("allure-java-migration")
include("allure-jax-rs")
include("allure-jbehave")
include("allure-jooq")
include("allure-jsonunit")
include("allure-junit-platform")
include("allure-junit4")
Expand Down

0 comments on commit b424823

Please sign in to comment.