Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Changelog

## [Unreleased]
### Changed
- Client version updated on [5.4.3](https://github.com/reportportal/client-java/releases/tag/5.4.3), by @HardNorth
- Replace "jsr305" annotations with "jakarta.annotation-api", by @HardNorth
- Switch on use of `Instant` class instead of `Date` to get more timestamp precision, by @HardNorth
### Fixed
- Issue [#43](https://github.com/reportportal/agent-java-karate/issues/43) NullpointerException in case of `null` parameter in Examples, by @HardNorth

## [5.2.2]
### Changed
Expand Down
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ dependencies {
api "com.epam.reportportal:client-java:${client_version}"
compileOnly "com.intuit.karate:karate-core:${karate_version}"
implementation "org.slf4j:slf4j-api:${slf4j_api_version}"
implementation "org.apache.commons:commons-lang3:3.18.0"

testImplementation "com.intuit.karate:karate-core:${karate_version}"
testImplementation "com.epam.reportportal:logger-java-logback:${logger_version}"
Expand All @@ -55,6 +56,7 @@ dependencies {
testImplementation "org.mockito:mockito-junit-jupiter:${mockito_version}"
testImplementation "org.hamcrest:hamcrest-core:${hamcrest_version}"
testImplementation "com.squareup.okhttp3:okhttp:${okhttp_version}"
testImplementation "org.apache.commons:commons-lang3:3.18.0"
}

test {
Expand Down
10 changes: 5 additions & 5 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
name=agent-java-karate
version=5.2.3-SNAPSHOT
version=5.3.0-SNAPSHOT
description=EPAM ReportPortal. Karate test framework [1.3.1, ) adapter
gradle_version=8.2
karate_version=1.4.1
junit_version=5.10.1
mockito_version=5.4.0
test_utils_version=0.0.13
client_version=5.3.17
test_utils_version=0.1.0
client_version=5.4.3
slf4j_api_version=2.0.7
logger_version=5.2.3
logger_version=5.4.0
hamcrest_version=2.2
okhttp_version=4.12.0
scripts_url=https://raw.githubusercontent.com/reportportal/gradle-scripts
scripts_branch=develop
scripts_branch=master
excludeTests=
35 changes: 20 additions & 15 deletions src/main/java/com/epam/reportportal/karate/ReportPortalHook.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,18 @@
import com.intuit.karate.http.HttpRequest;
import com.intuit.karate.http.Response;
import io.reactivex.Maybe;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

Expand All @@ -63,7 +68,7 @@ public class ReportPortalHook implements RuntimeHook {
private final Map<String, Maybe<String>> backgroundIdMap = new ConcurrentHashMap<>();
private final Map<String, ItemStatus> backgroundStatusMap = new ConcurrentHashMap<>();
private final Map<String, Maybe<String>> stepIdMap = new ConcurrentHashMap<>();
private final Map<Maybe<String>, Date> stepStartTimeMap = new ConcurrentHashMap<>();
private final Map<Maybe<String>, Instant> stepStartTimeMap = new ConcurrentHashMap<>();
private final Set<Maybe<String>> innerFeatures = Collections.newSetFromMap(new ConcurrentHashMap<>());
private volatile Thread shutDownHook;

Expand Down Expand Up @@ -175,7 +180,7 @@ public boolean beforeFeature(FeatureRuntime fr) {
Maybe<String> itemId = launch.get().startTestItem(scenarioId, rq);
innerFeatures.add(itemId);
if (StringUtils.isNotBlank(rq.getDescription())) {
ReportPortalUtils.sendLog(itemId, rq.getDescription(), LogLevel.INFO, rq.getStartTime());
ReportPortalUtils.sendLog(itemId, rq.getDescription(), LogLevel.INFO, (Instant) rq.getStartTime());
}
return itemId;
}
Expand All @@ -192,7 +197,7 @@ public boolean beforeFeature(FeatureRuntime fr) {
*/
@Nonnull
protected FinishTestItemRQ buildFinishFeatureRq(@Nonnull FeatureRuntime fr) {
return buildFinishTestItemRq(Calendar.getInstance().getTime(), fr.result.isFailed() ? ItemStatus.FAILED : ItemStatus.PASSED);
return buildFinishTestItemRq(Instant.now(), fr.result.isFailed() ? ItemStatus.FAILED : ItemStatus.PASSED);
}

@Override
Expand Down Expand Up @@ -298,7 +303,7 @@ public Maybe<String> startBackground(@Nonnull Step step, @Nonnull ScenarioRuntim
@Nonnull
@SuppressWarnings("unused")
protected FinishTestItemRQ buildFinishBackgroundRq(@Nullable StepResult stepResult, @Nonnull ScenarioRuntime sr) {
return buildFinishTestItemRq(Calendar.getInstance().getTime(), backgroundStatusMap.remove(sr.scenario.getUniqueId()));
return buildFinishTestItemRq(Instant.now(), backgroundStatusMap.remove(sr.scenario.getUniqueId()));
}

/**
Expand Down Expand Up @@ -335,17 +340,17 @@ public void afterScenario(ScenarioRuntime sr) {
* previous step startTime > current step startTime.
*
* @param stepId step ID.
* @return step new startTime in Date format.
* @return step new startTime in Instant format.
*/
@Nonnull
private Date getStepStartTime(@Nullable Maybe<String> stepId) {
Date currentStepStartTime = Calendar.getInstance().getTime();
private Instant getStepStartTime(@Nullable Maybe<String> stepId) {
Instant currentStepStartTime = Instant.now();
if (stepId == null || stepStartTimeMap.isEmpty()) {
return currentStepStartTime;
}
Date lastStepStartTime = stepStartTimeMap.get(stepId);
Instant lastStepStartTime = stepStartTimeMap.get(stepId);
if (lastStepStartTime.compareTo(currentStepStartTime) >= 0) {
currentStepStartTime.setTime(lastStepStartTime.getTime() + 1);
currentStepStartTime = lastStepStartTime.plus(1, ChronoUnit.MICROS);
}
return currentStepStartTime;
}
Expand All @@ -361,7 +366,7 @@ private Date getStepStartTime(@Nullable Maybe<String> stepId) {
protected StartTestItemRQ buildStartStepRq(@Nonnull Step step, @Nonnull ScenarioRuntime sr) {
StartTestItemRQ rq = ReportPortalUtils.buildStartStepRq(step, sr.scenario);
Maybe<String> stepId = stepIdMap.get(sr.scenario.getUniqueId());
Date startTime = getStepStartTime(stepId);
Instant startTime = getStepStartTime(stepId);
rq.setStartTime(startTime);
return rq;
}
Expand All @@ -388,7 +393,7 @@ public boolean beforeStep(Step step, ScenarioRuntime sr) {

String scenarioId = sr.scenario.getUniqueId();
Maybe<String> stepId = launch.get().startTestItem(background ? backgroundId : scenarioIdMap.get(scenarioId), stepRq);
stepStartTimeMap.put(stepId, stepRq.getStartTime());
stepStartTimeMap.put(stepId, (Instant) stepRq.getStartTime());
stepIdMap.put(scenarioId, stepId);
ofNullable(stepRq.getParameters()).filter(params -> !params.isEmpty())
.ifPresent(params -> sendLog(stepId, String.format(PARAMETERS_PATTERN, formatParametersAsTable(params)), LogLevel.INFO));
Expand Down Expand Up @@ -430,7 +435,7 @@ public void sendStepResults(StepResult stepResult, ScenarioRuntime sr) {
@Nonnull
@SuppressWarnings("unused")
protected FinishTestItemRQ buildFinishStepRq(@Nonnull StepResult stepResult, @Nonnull ScenarioRuntime sr) {
return buildFinishTestItemRq(Calendar.getInstance().getTime(), getStepStatus(stepResult.getResult().getStatus()));
return buildFinishTestItemRq(Instant.now(), getStepStatus(stepResult.getResult().getStatus()));
}

private void saveBackgroundStatus(@Nonnull StepResult stepResult, @Nonnull ScenarioRuntime sr) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@
import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ;
import com.intuit.karate.core.*;
import io.reactivex.Maybe;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

import static com.epam.reportportal.karate.ReportPortalUtils.*;
Expand All @@ -51,7 +55,7 @@ public class ReportPortalPublisher {
protected final MemoizingSupplier<Launch> launch;
private final Map<String, Maybe<String>> featureIdMap = new HashMap<>();
private final Map<String, Maybe<String>> scenarioIdMap = new HashMap<>();
private final Map<Maybe<String>, Long> stepStartTimeMap = new HashMap<>();
private final Map<Maybe<String>, Instant> stepStartTimeMap = new HashMap<>();
private Maybe<String> backgroundId;
private ItemStatus backgroundStatus;
private Maybe<String> stepId;
Expand Down Expand Up @@ -137,7 +141,7 @@ public void startFeature(@Nonnull FeatureResult featureResult) {
*/
@Nonnull
protected FinishTestItemRQ buildFinishFeatureRq(@Nonnull FeatureResult featureResult) {
return buildFinishTestItemRq(Calendar.getInstance().getTime(), featureResult.isFailed() ? ItemStatus.FAILED : ItemStatus.PASSED);
return buildFinishTestItemRq(Instant.now(), featureResult.isFailed() ? ItemStatus.FAILED : ItemStatus.PASSED);
}

/**
Expand Down Expand Up @@ -257,7 +261,7 @@ public void startBackground(@Nonnull StepResult stepResult, @Nonnull ScenarioRes
@Nonnull
@SuppressWarnings("unused")
protected FinishTestItemRQ buildFinishBackgroundRq(@Nullable StepResult stepResult, @Nonnull ScenarioResult scenarioResult) {
return buildFinishTestItemRq(Calendar.getInstance().getTime(), backgroundStatus);
return buildFinishTestItemRq(Instant.now(), backgroundStatus);

}

Expand All @@ -282,19 +286,19 @@ public void finishBackground(@Nullable StepResult stepResult, @Nonnull ScenarioR
* previous step startTime > current step startTime.
*
* @param stepId step ID.
* @return step new startTime in Date format.
* @return step new startTime in Instant format.
*/
private Date getStepStartTime(@Nonnull Maybe<String> stepId) {
long currentStepStartTime = Calendar.getInstance().getTime().getTime();
private Instant getStepStartTime(@Nonnull Maybe<String> stepId) {
Instant currentStepStartTime = Instant.now();

if (!stepStartTimeMap.isEmpty()) {
long lastStepStartTime = stepStartTimeMap.get(stepId);
Instant lastStepStartTime = stepStartTimeMap.get(stepId);

if (lastStepStartTime >= currentStepStartTime) {
currentStepStartTime += (lastStepStartTime - currentStepStartTime) + 1;
if (lastStepStartTime.compareTo(currentStepStartTime) >= 0) {
currentStepStartTime = lastStepStartTime.plus(1, ChronoUnit.MICROS);
}
}
return new Date(currentStepStartTime);
return currentStepStartTime;
}

/**
Expand All @@ -307,7 +311,7 @@ private Date getStepStartTime(@Nonnull Maybe<String> stepId) {
@Nonnull
protected StartTestItemRQ buildStartStepRq(@Nonnull StepResult stepResult, @Nonnull ScenarioResult scenarioResult) {
StartTestItemRQ rq = ReportPortalUtils.buildStartStepRq(stepResult.getStep(), scenarioResult.getScenario());
Date startTime = getStepStartTime(stepId);
Instant startTime = getStepStartTime(stepId);
rq.setStartTime(startTime);
return rq;
}
Expand All @@ -331,7 +335,7 @@ public void startStep(StepResult stepResult, ScenarioResult scenarioResult) {
background && backgroundId != null ? backgroundId : scenarioIdMap.get(scenarioResult.getScenario().getName()),
stepRq
);
stepStartTimeMap.put(stepId, stepRq.getStartTime().getTime());
stepStartTimeMap.put(stepId, (Instant) stepRq.getStartTime());
ofNullable(stepRq.getParameters()).filter(params -> !params.isEmpty())
.ifPresent(params -> sendLog(stepId, String.format(PARAMETERS_PATTERN, formatParametersAsTable(params)), LogLevel.INFO));
ofNullable(step.getTable()).ifPresent(table -> sendLog(stepId, "Table:\n\n" + formatDataTable(table.getRows()), LogLevel.INFO));
Expand All @@ -351,7 +355,7 @@ public void startStep(StepResult stepResult, ScenarioResult scenarioResult) {
@Nonnull
@SuppressWarnings("unused")
protected FinishTestItemRQ buildFinishStepRq(@Nonnull StepResult stepResult, @Nonnull ScenarioResult scenarioResult) {
return buildFinishTestItemRq(Calendar.getInstance().getTime(), getStepStatus(stepResult.getResult().getStatus()));
return buildFinishTestItemRq(Instant.now(), getStepStatus(stepResult.getResult().getStatus()));
}

@SuppressWarnings("unused")
Expand Down
31 changes: 16 additions & 15 deletions src/main/java/com/epam/reportportal/karate/ReportPortalUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@
import com.epam.ta.reportportal.ws.model.log.SaveLogRQ;
import com.intuit.karate.core.*;
import io.reactivex.Maybe;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.time.Instant;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -86,7 +87,7 @@ public static String formatExampleKey(@Nonnull final Map<String, Object> example
return example.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.map(e -> e.getKey() + KEY_VALUE_SEPARATOR + e.getValue().toString())
.map(e -> e.getKey() + KEY_VALUE_SEPARATOR + ofNullable(e.getValue()).map(Object::toString).orElse(NULL_VALUE))
.collect(Collectors.joining(PARAMETER_ITEMS_DELIMITER, PARAMETER_ITEMS_START, PARAMETER_ITEMS_END));
}

Expand Down Expand Up @@ -135,7 +136,7 @@ public static void unregisterShutdownHook(@Nonnull Thread hook) {
public static StartLaunchRQ buildStartLaunchRq(@Nonnull ListenerParameters parameters) {
StartLaunchRQ rq = new StartLaunchRQ();
rq.setName(parameters.getLaunchName());
rq.setStartTime(Calendar.getInstance().getTime());
rq.setStartTime(Instant.now());
rq.setMode(parameters.getLaunchRunningMode());
rq.setAttributes(new HashSet<>(parameters.getAttributes()));
if (isNotBlank(parameters.getDescription())) {
Expand Down Expand Up @@ -166,7 +167,7 @@ public static StartLaunchRQ buildStartLaunchRq(@Nonnull ListenerParameters param
@SuppressWarnings("unused")
public static FinishExecutionRQ buildFinishLaunchRq(@Nonnull ListenerParameters parameters) {
FinishExecutionRQ rq = new FinishExecutionRQ();
rq.setEndTime(Calendar.getInstance().getTime());
rq.setEndTime(Instant.now());
return rq;
}

Expand Down Expand Up @@ -200,12 +201,12 @@ public static String getCodeRef(@Nonnull Scenario scenario) {
* Build default start test item event/request
*
* @param name item's name
* @param startTime item's start time in Date format
* @param startTime item's start time in Instant format
* @param type item's type (e.g. feature, scenario, step, etc.)
* @return request to ReportPortal
*/
@Nonnull
public static StartTestItemRQ buildStartTestItemRq(@Nonnull String name, @Nonnull Date startTime, @Nonnull ItemType type) {
public static StartTestItemRQ buildStartTestItemRq(@Nonnull String name, @Nonnull Instant startTime, @Nonnull ItemType type) {
StartTestItemRQ rq = new StartTestItemRQ();
rq.setName(name);
rq.setStartTime(startTime);
Expand All @@ -221,7 +222,7 @@ public static StartTestItemRQ buildStartTestItemRq(@Nonnull String name, @Nonnul
* @return request to ReportPortal
*/
@Nonnull
public static FinishTestItemRQ buildFinishTestItemRq(@Nonnull Date endTime, @Nullable ItemStatus status) {
public static FinishTestItemRQ buildFinishTestItemRq(@Nonnull Instant endTime, @Nullable ItemStatus status) {
FinishTestItemRQ rq = new FinishTestItemRQ();
rq.setEndTime(endTime);
rq.setStatus(ofNullable(status).map(Enum::name).orElse(null));
Expand All @@ -248,7 +249,7 @@ public static Set<ItemAttributesRQ> toAttributes(@Nullable List<Tag> tags) {
@Nonnull
public static StartTestItemRQ buildStartFeatureRq(@Nonnull Feature feature) {
String featureName = ofNullable(feature.getName()).filter(n -> !n.isBlank()).orElseGet(() -> getCodeRef(feature));
StartTestItemRQ rq = buildStartTestItemRq(featureName, Calendar.getInstance().getTime(), ItemType.STORY);
StartTestItemRQ rq = buildStartTestItemRq(featureName, Instant.now(), ItemType.STORY);
rq.setAttributes(toAttributes(feature.getTags()));
String featurePath = feature.getResource().getUri().toString();
String description = feature.getDescription();
Expand Down Expand Up @@ -310,7 +311,7 @@ public static TestCaseIdEntry getTestCaseId(@Nonnull Scenario scenario) {
@Nonnull
public static StartTestItemRQ buildStartScenarioRq(@Nonnull ScenarioResult result) {
Scenario scenario = result.getScenario();
StartTestItemRQ rq = buildStartTestItemRq(scenario.getName(), Calendar.getInstance().getTime(), ItemType.STEP);
StartTestItemRQ rq = buildStartTestItemRq(scenario.getName(), Instant.now(), ItemType.STEP);
rq.setCodeRef(getCodeRef(scenario));
rq.setTestCaseId(ofNullable(getTestCaseId(scenario)).map(TestCaseIdEntry::getId).orElse(null));
rq.setAttributes(toAttributes(scenario.getTags()));
Expand All @@ -329,7 +330,7 @@ public static StartTestItemRQ buildStartScenarioRq(@Nonnull ScenarioResult resul
public static FinishTestItemRQ buildFinishScenarioRq(@Nonnull ScenarioResult result) {
Scenario scenario = result.getScenario();
FinishTestItemRQ rq = buildFinishTestItemRq(
Calendar.getInstance().getTime(),
Instant.now(),
result.getFailureMessageForDisplay() == null ? ItemStatus.PASSED : ItemStatus.FAILED
);
rq.setDescription(buildDescription(scenario, result.getErrorMessage(), getParameters(scenario)));
Expand Down Expand Up @@ -371,7 +372,7 @@ private static void appendWithDelimiter(StringBuilder builder, String text) {
@Nonnull
@SuppressWarnings("unused")
public static StartTestItemRQ buildStartBackgroundRq(@Nonnull Step step, @Nonnull Scenario scenario) {
StartTestItemRQ rq = buildStartTestItemRq(Background.KEYWORD, Calendar.getInstance().getTime(), ItemType.STEP);
StartTestItemRQ rq = buildStartTestItemRq(Background.KEYWORD, Instant.now(), ItemType.STEP);
rq.setHasStats(false);
return rq;
}
Expand All @@ -386,7 +387,7 @@ public static StartTestItemRQ buildStartBackgroundRq(@Nonnull Step step, @Nonnul
@Nonnull
public static StartTestItemRQ buildStartStepRq(@Nonnull Step step, @Nonnull Scenario scenario) {
String stepName = step.getPrefix() + " " + step.getText();
StartTestItemRQ rq = buildStartTestItemRq(stepName, Calendar.getInstance().getTime(), ItemType.STEP);
StartTestItemRQ rq = buildStartTestItemRq(stepName, Instant.now(), ItemType.STEP);
rq.setHasStats(false);
if (step.isOutline()) {
List<ParameterResource> parameters = scenario.getExampleData()
Expand Down Expand Up @@ -440,7 +441,7 @@ public static ItemStatus getStepStatus(String status) {
* @param level log level
* @param logTime log time
*/
public static void sendLog(Maybe<String> itemId, String message, LogLevel level, Date logTime) {
public static void sendLog(Maybe<String> itemId, String message, LogLevel level, Instant logTime) {
ReportPortal.emitLog(
itemId, id -> {
SaveLogRQ rq = new SaveLogRQ();
Expand All @@ -461,7 +462,7 @@ public static void sendLog(Maybe<String> itemId, String message, LogLevel level,
* @param level log level
*/
public static void sendLog(Maybe<String> itemId, String message, LogLevel level) {
sendLog(itemId, message, level, Calendar.getInstance().getTime());
sendLog(itemId, message, level, Instant.now());
}

/**
Expand Down
Loading