Skip to content

Commit b424823

Browse files
authored
add jooq integration (via allure-framework#931)
1 parent a291559 commit b424823

5 files changed

Lines changed: 318 additions & 0 deletions

File tree

allure-jooq/build.gradle.kts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
description = "Allure JOOQ Integration"
2+
3+
val jooqVersion = "3.18.4"
4+
5+
dependencies {
6+
api(project(":allure-java-commons"))
7+
implementation("org.jooq:jooq:${jooqVersion}")
8+
testImplementation("io.zonky.test:embedded-postgres:2.0.4")
9+
testImplementation("org.assertj:assertj-core")
10+
testImplementation("org.junit.jupiter:junit-jupiter-api")
11+
testImplementation("org.mockito:mockito-core")
12+
testImplementation("org.slf4j:slf4j-simple")
13+
testImplementation(platform("io.zonky.test.postgres:embedded-postgres-binaries-bom:15.3.0"))
14+
testImplementation(project(":allure-assertj"))
15+
testImplementation(project(":allure-java-commons-test"))
16+
testImplementation(project(":allure-junit-platform"))
17+
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
18+
testRuntimeOnly("org.postgresql:postgresql:42.6.0")
19+
}
20+
21+
java {
22+
toolchain {
23+
languageVersion.set(JavaLanguageVersion.of(17))
24+
}
25+
}
26+
27+
tasks.jar {
28+
manifest {
29+
attributes(mapOf(
30+
"Automatic-Module-Name" to "io.qameta.allure.jooq"
31+
))
32+
}
33+
}
34+
35+
tasks.test {
36+
useJUnitPlatform()
37+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Copyright 2016-2022 Qameta Software OÜ
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.qameta.allure.jooq;
17+
18+
import io.qameta.allure.Allure;
19+
import io.qameta.allure.AllureLifecycle;
20+
import io.qameta.allure.model.Status;
21+
import io.qameta.allure.model.StepResult;
22+
import org.jooq.ExecuteContext;
23+
import org.jooq.ExecuteListener;
24+
import org.jooq.Formattable;
25+
import org.jooq.Query;
26+
import org.jooq.Record;
27+
import org.jooq.Routine;
28+
29+
import java.util.Objects;
30+
import java.util.UUID;
31+
32+
import static java.lang.Boolean.FALSE;
33+
34+
/**
35+
* @author charlie (Dmitry Baev).
36+
*/
37+
public class AllureJooq implements ExecuteListener {
38+
39+
private static final String STEP_UUID
40+
= "io.qameta.allure.jooq.AllureJooq.STEP_UUID";
41+
private static final String DO_BUFFER
42+
= "io.qameta.allure.jooq.AllureJooq.DO_BUFFER";
43+
44+
private final AllureLifecycle lifecycle;
45+
46+
public AllureJooq() {
47+
this(Allure.getLifecycle());
48+
}
49+
50+
public AllureJooq(final AllureLifecycle lifecycle) {
51+
this.lifecycle = lifecycle;
52+
}
53+
54+
@Override
55+
public void renderEnd(final ExecuteContext ctx) {
56+
if (!lifecycle.getCurrentTestCaseOrStep().isPresent()) {
57+
return;
58+
}
59+
60+
final String stepName = stepName(ctx);
61+
final String uuid = UUID.randomUUID().toString();
62+
ctx.data(STEP_UUID, uuid);
63+
lifecycle.startStep(uuid, new StepResult()
64+
.setName(stepName)
65+
);
66+
}
67+
68+
private String stepName(final ExecuteContext ctx) {
69+
final Query query = ctx.query();
70+
if (query != null) {
71+
return ctx.dsl().renderInlined(query);
72+
}
73+
74+
final Routine<?> routine = ctx.routine();
75+
if (ctx.routine() != null) {
76+
return ctx.dsl().renderInlined(routine);
77+
}
78+
79+
final String sql = ctx.sql();
80+
if (Objects.nonNull(sql) && !sql.isEmpty()) {
81+
return sql;
82+
}
83+
84+
final String[] batchSQL = ctx.batchSQL();
85+
if (batchSQL.length > 0 && batchSQL[batchSQL.length - 1] != null) {
86+
return String.join("\n", batchSQL);
87+
}
88+
return "UNKNOWN";
89+
}
90+
91+
@Override
92+
public void recordEnd(final ExecuteContext ctx) {
93+
if (ctx.recordLevel() > 0) {
94+
return;
95+
}
96+
97+
if (!lifecycle.getCurrentTestCaseOrStep().isPresent()) {
98+
return;
99+
}
100+
101+
final Record record = ctx.record();
102+
if (record != null && !FALSE.equals(ctx.data(DO_BUFFER))) {
103+
attachResultSet(record);
104+
}
105+
}
106+
107+
@Override
108+
public void resultStart(final ExecuteContext ctx) {
109+
ctx.data(DO_BUFFER, false);
110+
}
111+
112+
@Override
113+
public void resultEnd(final ExecuteContext ctx) {
114+
if (!lifecycle.getCurrentTestCaseOrStep().isPresent()) {
115+
return;
116+
}
117+
118+
attachResultSet(ctx.result());
119+
}
120+
121+
@Override
122+
public void end(final ExecuteContext ctx) {
123+
if (!lifecycle.getCurrentTestCaseOrStep().isPresent()) {
124+
return;
125+
}
126+
127+
final String stepUuid = (String) ctx.data(STEP_UUID);
128+
if (Objects.isNull(stepUuid)) {
129+
return;
130+
}
131+
132+
lifecycle.updateStep(stepUuid, sr -> sr.setStatus(Status.PASSED));
133+
lifecycle.stopStep(stepUuid);
134+
}
135+
136+
private void attachResultSet(final Formattable formattable) {
137+
if (Objects.nonNull(formattable)) {
138+
Allure.addAttachment("ResultSet", "text/csv", formattable.formatCSV());
139+
}
140+
}
141+
142+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright 2023 Qameta Software OÜ
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.qameta.allure.jooq;
17+
18+
import io.qameta.allure.Allure;
19+
import io.qameta.allure.model.Attachment;
20+
import io.qameta.allure.model.Status;
21+
import io.qameta.allure.model.StepResult;
22+
import io.qameta.allure.model.TestResult;
23+
import io.qameta.allure.test.AllureResults;
24+
import io.zonky.test.db.postgres.embedded.EmbeddedPostgres;
25+
import org.jooq.DSLContext;
26+
import org.jooq.Field;
27+
import org.jooq.Name;
28+
import org.jooq.Record;
29+
import org.jooq.SQLDialect;
30+
import org.jooq.Table;
31+
import org.jooq.impl.DSL;
32+
import org.jooq.impl.DataSourceConnectionProvider;
33+
import org.jooq.impl.DefaultConfiguration;
34+
import org.jooq.impl.DefaultDSLContext;
35+
import org.jooq.impl.SQLDataType;
36+
import org.junit.jupiter.api.Test;
37+
38+
import javax.sql.DataSource;
39+
import java.io.IOException;
40+
import java.io.UncheckedIOException;
41+
import java.nio.charset.StandardCharsets;
42+
import java.util.function.Consumer;
43+
44+
import static io.qameta.allure.test.RunUtils.runWithinTestContext;
45+
import static org.assertj.core.api.Assertions.assertThat;
46+
import static org.assertj.core.api.Assertions.tuple;
47+
48+
/**
49+
* @author charlie (Dmitry Baev).
50+
*/
51+
class AllureJooqTest {
52+
53+
@Test
54+
void shouldSupportFetchSqlStatements() {
55+
final AllureResults results = execute(dsl -> dsl.fetchSingle("select 1"));
56+
57+
final TestResult result = results.getTestResults().get(0);
58+
assertThat(result.getSteps())
59+
.extracting(StepResult::getName, StepResult::getStatus)
60+
.containsExactly(
61+
tuple("select 1", Status.PASSED)
62+
);
63+
}
64+
65+
@Test
66+
void shouldAddResultSetsAsAttachments() {
67+
final AllureResults results = execute(dsl -> dsl.fetchSingle("select 1 as one, 2 as two"));
68+
final TestResult result = results.getTestResults().get(0);
69+
final StepResult step = result.getSteps().get(0);
70+
assertThat(step.getAttachments())
71+
.extracting(Attachment::getName, Attachment::getType)
72+
.containsExactly(
73+
tuple("ResultSet", "text/csv")
74+
);
75+
76+
final Attachment attachment = step.getAttachments().get(0);
77+
78+
final byte[] content = results.getAttachments().get(attachment.getSource());
79+
80+
assertThat(new String(content, StandardCharsets.UTF_8))
81+
.contains("one,two\n1,2\n");
82+
83+
}
84+
85+
@Test
86+
void shouldSupportCreateTableStatements() {
87+
final AllureResults results = execute(dsl -> {
88+
final Name tableName = DSL.name("first_table");
89+
final Field<Long> id = DSL.field("id", SQLDataType.BIGINT);
90+
final Field<String> name = DSL.field("name", SQLDataType.VARCHAR);
91+
dsl.createTable(tableName)
92+
.column(id)
93+
.column(name)
94+
.primaryKey(id)
95+
.execute();
96+
97+
final Table<Record> table = DSL.table(tableName);
98+
99+
dsl.insertInto(table, id, name)
100+
.values(1L, "first")
101+
.values(2L, "second")
102+
.execute();
103+
});
104+
105+
final TestResult result = results.getTestResults().get(0);
106+
assertThat(result.getSteps())
107+
.extracting(StepResult::getName, StepResult::getStatus)
108+
.containsExactly(
109+
tuple("create table \"first_table\" (id bigint, name varchar, primary key (id))", Status.PASSED),
110+
tuple("insert into \"first_table\" (id, name) values (1, 'first'), (2, 'second')", Status.PASSED)
111+
);
112+
}
113+
114+
private static AllureResults execute(final Consumer<DSLContext> dslContextConsumer) {
115+
final EmbeddedPostgres.Builder builder = EmbeddedPostgres.builder();
116+
try (EmbeddedPostgres postgres = builder.start()) {
117+
final DataSource dataSource = postgres.getPostgresDatabase();
118+
119+
final DataSourceConnectionProvider connectionProvider = new DataSourceConnectionProvider(dataSource);
120+
final DefaultConfiguration configuration = new DefaultConfiguration();
121+
configuration.set(SQLDialect.POSTGRES);
122+
configuration.set(connectionProvider);
123+
124+
return runWithinTestContext(
125+
() -> {
126+
final DefaultDSLContext dsl = new DefaultDSLContext(configuration);
127+
dslContextConsumer.accept(dsl);
128+
},
129+
Allure::setLifecycle,
130+
allureLifecycle -> configuration.setExecuteListener(new AllureJooq(allureLifecycle))
131+
);
132+
} catch (IOException e) {
133+
throw new UncheckedIOException(e);
134+
}
135+
}
136+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
org.slf4j.simpleLogger.log.org.jooq.Constants=warn
2+
org.slf4j.simpleLogger.log.org.jooq.tools.LoggerListener=info

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ include("allure-java-commons-test")
2020
include("allure-java-migration")
2121
include("allure-jax-rs")
2222
include("allure-jbehave")
23+
include("allure-jooq")
2324
include("allure-jsonunit")
2425
include("allure-junit-platform")
2526
include("allure-junit4")

0 commit comments

Comments
 (0)