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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Changelog

## [Unreleased]
### Changed
- Client version updated on [5.4.4](https://github.com/reportportal/client-java/releases/tag/5.4.4), by @HardNorth
### Fixed
- Some data cleanup in `ReportPortalHook` class, by @HardNorth
- Some step order issues in rare cases, by @HardNorth

## [5.3.1]
### Added
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ karate_version=1.4.1
junit_version=5.10.1
mockito_version=5.4.0
test_utils_version=0.1.0
client_version=5.4.3
client_version=5.4.4
slf4j_api_version=2.0.7
logger_version=5.4.0
hamcrest_version=2.2
Expand Down
24 changes: 7 additions & 17 deletions src/main/java/com/epam/reportportal/karate/ReportPortalHook.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import org.slf4j.LoggerFactory;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
Expand All @@ -66,7 +65,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>, Instant> stepStartTimeMap = new ConcurrentHashMap<>();
private final Map<String, Instant> stepStartTimeMap = new ConcurrentHashMap<>();
private final Set<Maybe<String>> innerFeatures = Collections.newSetFromMap(new ConcurrentHashMap<>());
private volatile Thread shutDownHook;

Expand Down Expand Up @@ -343,6 +342,7 @@ protected void embedAttachments(@Nonnull Maybe<String> itemId, @Nullable List<Em
@Override
public void afterScenario(ScenarioRuntime sr) {
Maybe<String> scenarioId = scenarioIdMap.get(sr.scenario.getUniqueId());
stepStartTimeMap.remove(sr.scenario.getUniqueId());
finishBackground(null, sr);

if (scenarioId == null) {
Expand Down Expand Up @@ -370,20 +370,12 @@ public void afterScenario(ScenarioRuntime sr) {
* Get step start time. To keep the steps order in case previous step startTime == current step startTime or
* previous step startTime > current step startTime.
*
* @param stepId step ID.
* @param scenarioUniqueId Karate's Scenario Unique ID
* @return step new startTime in Instant format.
*/
@Nonnull
private Instant getStepStartTime(@Nullable Maybe<String> stepId) {
Instant currentStepStartTime = Instant.now();
if (stepId == null || stepStartTimeMap.isEmpty()) {
return currentStepStartTime;
}
Instant lastStepStartTime = stepStartTimeMap.get(stepId);
if (lastStepStartTime.compareTo(currentStepStartTime) >= 0) {
currentStepStartTime = lastStepStartTime.plus(1, ChronoUnit.MICROS);
}
return currentStepStartTime;
private Instant getStepStartTime(@Nullable String scenarioUniqueId) {
return ReportPortalUtils.getStepStartTime(scenarioUniqueId, stepStartTimeMap, launch.get().useMicroseconds());
}

/**
Expand All @@ -396,8 +388,7 @@ private Instant getStepStartTime(@Nullable Maybe<String> stepId) {
@Nonnull
protected StartTestItemRQ buildStartStepRq(@Nonnull Step step, @Nonnull ScenarioRuntime sr) {
StartTestItemRQ rq = ReportPortalUtils.buildStartStepRq(step, sr.scenario);
Maybe<String> stepId = stepIdMap.get(sr.scenario.getUniqueId());
Instant startTime = getStepStartTime(stepId);
Instant startTime = getStepStartTime(sr.scenario.getUniqueId());
rq.setStartTime(startTime);
return rq;
}
Expand All @@ -424,7 +415,6 @@ 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, (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 @@ -490,7 +480,7 @@ public void afterStep(StepResult stepResult, ScenarioRuntime sr) {
}

sendStepResults(stepResult, sr);
Maybe<String> stepId = stepIdMap.get(sr.scenario.getUniqueId());
Maybe<String> stepId = stepIdMap.remove(sr.scenario.getUniqueId());
if (stepId == null) {
LOGGER.error("ERROR: Trying to finish unspecified step.");
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
import org.slf4j.LoggerFactory;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -55,7 +54,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>, Instant> stepStartTimeMap = new HashMap<>();
private final Map<String, Instant> stepStartTimeMap = new HashMap<>();
private Maybe<String> backgroundId;
private ItemStatus backgroundStatus;
private Maybe<String> stepId;
Expand Down Expand Up @@ -164,7 +163,6 @@ public void finishFeature(FeatureResult featureResult) {
finishStep(stepResult, scenarioResult);
}

stepStartTimeMap.clear();
finishScenario(scenarioResult);
}

Expand Down Expand Up @@ -220,6 +218,7 @@ public void finishScenario(ScenarioResult scenarioResult) {

FinishTestItemRQ rq = buildFinishScenarioRq(scenarioResult);
Maybe<String> removedScenarioId = scenarioIdMap.remove(scenarioResult.getScenario().getName());
stepStartTimeMap.remove(scenarioResult.getScenario().getUniqueId());
//noinspection ReactiveStreamsUnusedPublisher
launch.get().finishTestItem(removedScenarioId, rq);
finishBackground(null, scenarioResult);
Expand Down Expand Up @@ -285,20 +284,12 @@ public void finishBackground(@Nullable StepResult stepResult, @Nonnull ScenarioR
* Get step start time. To keep the steps order in case previous step startTime == current step startTime or
* previous step startTime > current step startTime.
*
* @param stepId step ID.
* @param scenarioUniqueId Karate's Scenario Unique ID
* @return step new startTime in Instant format.
*/
private Instant getStepStartTime(@Nonnull Maybe<String> stepId) {
Instant currentStepStartTime = Instant.now();

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

if (lastStepStartTime.compareTo(currentStepStartTime) >= 0) {
currentStepStartTime = lastStepStartTime.plus(1, ChronoUnit.MICROS);
}
}
return currentStepStartTime;
@Nonnull
private Instant getStepStartTime(@Nullable String scenarioUniqueId) {
return ReportPortalUtils.getStepStartTime(scenarioUniqueId, stepStartTimeMap, launch.get().useMicroseconds());
}

/**
Expand All @@ -311,7 +302,7 @@ private Instant getStepStartTime(@Nonnull Maybe<String> stepId) {
@Nonnull
protected StartTestItemRQ buildStartStepRq(@Nonnull StepResult stepResult, @Nonnull ScenarioResult scenarioResult) {
StartTestItemRQ rq = ReportPortalUtils.buildStartStepRq(stepResult.getStep(), scenarioResult.getScenario());
Instant startTime = getStepStartTime(stepId);
Instant startTime = getStepStartTime(scenarioResult.getScenario().getUniqueId());
rq.setStartTime(startTime);
return rq;
}
Expand All @@ -335,7 +326,6 @@ public void startStep(StepResult stepResult, ScenarioResult scenarioResult) {
background && backgroundId != null ? backgroundId : scenarioIdMap.get(scenarioResult.getScenario().getName()),
stepRq
);
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 Down
67 changes: 52 additions & 15 deletions src/main/java/com/epam/reportportal/karate/ReportPortalUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.slf4j.LoggerFactory;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -472,21 +473,23 @@ public static void sendLog(Maybe<String> itemId, String message, LogLevel level)
* @param embed Karate's Embed object
*/
public static void embedAttachment(@Nonnull Maybe<String> itemId, @Nonnull Embed embed) {
ReportPortal.emitLog(itemId, id -> {
SaveLogRQ rq = new SaveLogRQ();
rq.setItemUuid(id);
rq.setLevel(LogLevel.INFO.name());
rq.setLogTime(Instant.now());
rq.setMessage("Attachment: " + embed.getResourceType().contentType);

SaveLogRQ.File file = new SaveLogRQ.File();
file.setName(embed.getFile().getName());
file.setContent(embed.getBytes());
file.setContentType(embed.getResourceType().contentType);
rq.setFile(file);

return rq;
});
ReportPortal.emitLog(
itemId, id -> {
SaveLogRQ rq = new SaveLogRQ();
rq.setItemUuid(id);
rq.setLevel(LogLevel.INFO.name());
rq.setLogTime(Instant.now());
rq.setMessage("Attachment: " + embed.getResourceType().contentType);

SaveLogRQ.File file = new SaveLogRQ.File();
file.setName(embed.getFile().getName());
file.setContent(embed.getBytes());
file.setContentType(embed.getResourceType().contentType);
rq.setFile(file);

return rq;
}
);
}

/**
Expand Down Expand Up @@ -539,4 +542,38 @@ public static String getInnerScenarioName(String name) {
public static String getInnerFeatureName(String name) {
return FEATURE_TAG + name;
}

/**
* Get step start time. To keep the steps order in case previous step startTime == current step startTime or
* previous step startTime &gt; current step startTime.
*
* @param scenarioUniqueId Karate's Scenario Unique ID, a key for stepStartTimeMap
* @param stepStartTimeMap a holder for start times for every particular scenario
* @param useMicroseconds if server supports microseconds
* @return step new startTime in Instant format.
*/
public static Instant getStepStartTime(@Nullable String scenarioUniqueId, Map<String, Instant> stepStartTimeMap,
boolean useMicroseconds) {
Instant currentStepStartTime = Instant.now().truncatedTo(ChronoUnit.MICROS);
if (scenarioUniqueId == null || stepStartTimeMap.isEmpty()) {
stepStartTimeMap.put(scenarioUniqueId, currentStepStartTime);
return currentStepStartTime;
}
Instant lastStepStartTime = stepStartTimeMap.get(scenarioUniqueId);
if (lastStepStartTime == null) {
stepStartTimeMap.put(scenarioUniqueId, currentStepStartTime);
return currentStepStartTime;
}
if (useMicroseconds) {
if (lastStepStartTime.compareTo(currentStepStartTime) >= 0) {
currentStepStartTime = lastStepStartTime.plus(1, ChronoUnit.MICROS);
}
} else {
if (lastStepStartTime.truncatedTo(ChronoUnit.MILLIS).compareTo(currentStepStartTime.truncatedTo(ChronoUnit.MILLIS)) >= 0) {
currentStepStartTime = lastStepStartTime.plus(1, ChronoUnit.MILLIS);
}
}
stepStartTimeMap.put(scenarioUniqueId, currentStepStartTime);
return currentStepStartTime;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@
import com.epam.ta.reportportal.ws.model.StartTestItemRQ;
import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ;
import com.intuit.karate.Results;
import io.reactivex.Maybe;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.ArgumentCaptor;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -54,13 +55,29 @@ public void setupMock() {
mockBatchLogging(client);
}

public static Stream<Arguments> testCases() {
return Stream.of( //
Arguments.of(false, false), //
Arguments.of(false, true), //
Arguments.of(true, false), //
Arguments.of(true, true) //
);
}

@SuppressWarnings({ "rawtypes", "unchecked" })
@ParameterizedTest
@ValueSource(booleans = { true, false })
public void test_each_item_has_correct_start_date(boolean report) {
@MethodSource("testCases")
public void test_each_item_has_correct_start_date(boolean report, boolean useMicroseconds) {
Results results;
if (report) {
if (useMicroseconds) {
when(client.getApiInfo()).thenReturn(Maybe.just(TestUtils.testApiInfo()));
}
results = TestUtils.runAsReport(rp, TEST_FEATURE);
} else {
if (useMicroseconds) {
when(client.getApiInfo()).thenReturn(Maybe.just(TestUtils.testApiInfo()));
}
results = TestUtils.runAsHook(rp, TEST_FEATURE);
}
assertThat(results.getFailCount(), equalTo(0));
Expand All @@ -80,13 +97,13 @@ public void test_each_item_has_correct_start_date(boolean report) {

assertThat(
"Launch start time is greater than Feature start time.",
(Date) featureRq.getStartTime(),
greaterThanOrEqualTo((Date) launchRq.getStartTime())
(Comparable) featureRq.getStartTime(),
greaterThanOrEqualTo((Comparable) launchRq.getStartTime())
);
assertThat(
"Feature start time is greater than Scenario start time.",
(Date) scenarioRq.getStartTime(),
greaterThanOrEqualTo((Date) featureRq.getStartTime())
(Comparable) scenarioRq.getStartTime(),
greaterThanOrEqualTo((Comparable) featureRq.getStartTime())
);

List<StartTestItemRQ> steps = stepCaptor.getAllValues();
Expand All @@ -98,19 +115,19 @@ public void test_each_item_has_correct_start_date(boolean report) {
.orElseThrow();

assertThat(
"Scenario start time is greater than Step start time.",
(Date) firstStep.getStartTime(),
greaterThanOrEqualTo((Date) scenarioRq.getStartTime())
"First Step start time is greater or equal than Scenario start time.",
(Comparable) firstStep.getStartTime(),
greaterThanOrEqualTo((Comparable) scenarioRq.getStartTime())
);
assertThat(
"First Step start time is greater or equal than Second Step start time.",
(Date) secondStep.getStartTime(),
greaterThan((Date) firstStep.getStartTime())
"Second Step start time is greater than First Step start time.",
(Comparable) secondStep.getStartTime(),
greaterThan((Comparable) firstStep.getStartTime())
);
assertThat(
"Second Step start time is greater or equal than Third Step start time.",
(Date) thirdStep.getStartTime(),
greaterThan((Date) secondStep.getStartTime())
"Third Step start time is greater than Second Step start time.",
(Comparable) thirdStep.getStartTime(),
greaterThan((Comparable) secondStep.getStartTime())
);
}
}
10 changes: 10 additions & 0 deletions src/test/java/com/epam/reportportal/karate/utils/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
import com.epam.reportportal.karate.KarateReportPortalRunner;
import com.epam.reportportal.karate.ReportPortalHook;
import com.epam.reportportal.listeners.ListenerParameters;
import com.epam.reportportal.service.LaunchImpl;
import com.epam.reportportal.service.ReportPortal;
import com.epam.reportportal.service.ReportPortalClient;
import com.epam.reportportal.util.test.CommonUtils;
import com.epam.reportportal.utils.http.HttpRequestUtils;
import com.epam.ta.reportportal.ws.model.ApiInfo;
import com.epam.ta.reportportal.ws.model.BatchSaveOperatingRS;
import com.epam.ta.reportportal.ws.model.Constants;
import com.epam.ta.reportportal.ws.model.OperationCompletionRS;
Expand Down Expand Up @@ -250,4 +252,12 @@ public static List<Pair<String, byte[]>> extractBinaryParts(List<MultipartBody.P
})
.collect(Collectors.toList());
}

public static ApiInfo testApiInfo() {
ApiInfo apiInfo = new ApiInfo();
ApiInfo.Build build = new ApiInfo.Build();
apiInfo.setBuild(build);
build.setVersion(LaunchImpl.MICROSECONDS_MIN_VERSION);
return apiInfo;
}
}