Skip to content

Commit

Permalink
Merge branch 'Draegerwerk:main' into sdccc-gradle
Browse files Browse the repository at this point in the history
  • Loading branch information
midttuna authored Dec 2, 2024
2 parents fd1b39b + 729356b commit 1c2cda0
Show file tree
Hide file tree
Showing 15 changed files with 328 additions and 129 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- support for Kotlin
- preconditions which observe mdib changes during the test run
- storing of IP addresses of inbound messages in the database
- a command line parameter to not create subdirectories in the test run directory

### Changed

- the collected data is now flushed after each precondition
- moved test case specific parameter into separate file test_parameter.toml
- sdc-ri version to 6.0.0-SNAPSHOT
- sdc-ri version to 6.2.0-SNAPSHOT

### Fixed

- support multiple mds for test case for BICEPS.R5042
- inconsistent messaging in SDCcc logs ("No problems were found" and "Test run was invalid" one after another.)
- incorrect behavior of the configuration option SDCcc.SummarizeMessageEncodingErrors
- SequenceIds are now ordered by the timestamp of the first message that used them

### Removed

Expand Down
129 changes: 84 additions & 45 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion sdccc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junitVersion>5.10.2</junitVersion>
<junitPlatformVersion>1.10.2</junitPlatformVersion>
<sdcriVersion>6.0.0-SNAPSHOT</sdcriVersion>
<sdcriVersion>6.2.0-SNAPSHOT</sdcriVersion>
<log4jVersion>2.17.1</log4jVersion>
<spotbugsVersion>4.7.3</spotbugsVersion>
<checkstyleConfigDir>../checkstyle</checkstyleConfigDir>
Expand Down
12 changes: 11 additions & 1 deletion sdccc/src/main/java/com/draeger/medical/sdccc/TestSuite.java
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,17 @@ public static void runWithArgs(
throws IOException {
// setup logging
final var testRunDir = TestRunConfig.createTestRunDirectory(
cmdLine.getTestRunDirectory().orElse(null));
cmdLine.getTestRunDirectory().orElse(null), cmdLine.getNoSubdirectories());
if (cmdLine.getNoSubdirectories() && testRunDir.isDirectory()) {
final var files = testRunDir.list();
if (files != null && files.length > 0) {
throw new RuntimeException(String.format(
"The specified test run directory %s was not empty, "
+ "although the command line option --no_subdirectories was set to true. Please make sure that "
+ "you use --test_run_directory to configure an empty test run directory.",
testRunDir));
}
}
final var logConfig = LoggingConfigurator.loggerConfig(testRunDir, cmdLine.getFileLogLevel());
checkLogConfig(logConfig);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class CommandLineOptions {
private static final String DEVICE_LOCATION_BED = "device_bed";
private static final String IP_ADDRESS = "ipaddress";
private static final String TEST_RUN_DIRECTORY = "test_run_directory";
private static final String NO_SUBDIRECTORIES = "no_subdirectories";
private static final String FILE_LOG_LEVEL = "file_log_level";
private final Path configPath;
private final Path testConfigPath;
Expand All @@ -56,6 +57,7 @@ public class CommandLineOptions {
private final String deviceBed;
private final String ipAddress;
private final String testRunDirectory;
private final Boolean noSubdirectories;
private final Level fileLogLevel;

/**
Expand Down Expand Up @@ -103,6 +105,7 @@ public CommandLineOptions(final String[] commandLineArguments) {
this.deviceBed = cmd.getOptionValue(DEVICE_LOCATION_BED);
this.ipAddress = cmd.getOptionValue(IP_ADDRESS);
this.testRunDirectory = cmd.getOptionValue(TEST_RUN_DIRECTORY);
this.noSubdirectories = Boolean.parseBoolean(cmd.getOptionValue(NO_SUBDIRECTORIES));
this.fileLogLevel = Level.toLevel(cmd.getOptionValue(FILE_LOG_LEVEL), Level.INFO);
}

Expand Down Expand Up @@ -186,6 +189,14 @@ private Options setupOptions() {
testRunDirectoryOpt.setRequired(false);
options.addOption(testRunDirectoryOpt);
}
{
final String description =
"If set to true, no directories are created in the directory configured with test_run_directory";
final var noSubdirectoriesOpt = new Option("ns", NO_SUBDIRECTORIES, true, description);
noSubdirectoriesOpt.setRequired(false);
noSubdirectoriesOpt.setType(Boolean.class);
options.addOption(noSubdirectoriesOpt);
}
{
final String description = "The log level to be used for the log file. e.g. DEBUG . The default is INFO.";
final var fileLogLevelOpt = new Option("fll", FILE_LOG_LEVEL, true, description);
Expand Down Expand Up @@ -258,6 +269,10 @@ public Optional<String> getTestRunDirectory() {
return Optional.ofNullable(testRunDirectory);
}

public Boolean getNoSubdirectories() {
return noSubdirectories;
}

public Level getFileLogLevel() {
return this.fileLogLevel;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package com.draeger.medical.sdccc.configuration;

import com.draeger.medical.sdccc.util.Constants;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.somda.sdc.common.guice.AbstractConfigurationModule;

Expand Down Expand Up @@ -49,6 +50,10 @@ void configureTestSuite() {

bind(TestSuiteConfig.ENABLE_MESSAGE_ENCODING_CHECK, Boolean.class, true);
bind(TestSuiteConfig.SUMMARIZE_MESSAGE_ENCODING_ERRORS, Boolean.class, true);
bind(Constants.CONFIGURATION_MODULE, AbstractConfigurationModule.class, new AbstractConfigurationModule() {
@Override
protected void defaultConfigure() {}
});
}

void configureTLS() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* This Source Code Form is subject to the terms of the MIT License.
* Copyright (c) 2023 Draegerwerk AG & Co. KGaA.
* Copyright (c) 2023-2024 Draegerwerk AG & Co. KGaA.
*
* SPDX-License-Identifier: MIT
*/
Expand Down Expand Up @@ -46,17 +46,22 @@ protected void defaultConfigure() {
* Also creates the 'testruns' parent directory if it doesn't exist when using default directory.
*
* @param baseDirectory directory to create test run dirs in, working directory if null
* @param noSubdirectories if true, no test run dirs are created
* @return File pointing to the new directory.
* @throws RuntimeException in case directory could not be created or already exists
*/
public static File createTestRunDirectory(final @Nullable String baseDirectory) {
// create test run dir and bind it as config parameter
final String testRunTimestamp = ZonedDateTime.now(ZoneOffset.UTC)
.format(DateTimeFormatter.ISO_DATE_TIME)
.replace(":", "-");
public static File createTestRunDirectory(final @Nullable String baseDirectory, final Boolean noSubdirectories) {
if (noSubdirectories) {
return createTestRunDirectory(baseDirectory, "");
} else {
// create test run dir and bind it as config parameter
final String testRunTimestamp = ZonedDateTime.now(ZoneOffset.UTC)
.format(DateTimeFormatter.ISO_DATE_TIME)
.replace(":", "-");

final String testRunName = "SDCcc_Testrun_" + testRunTimestamp;
return createTestRunDirectory(baseDirectory, testRunName);
final String testRunName = "SDCcc_Testrun_" + testRunTimestamp;
return createTestRunDirectory(baseDirectory, testRunName);
}
}

private static File createTestRunDirectory(final @Nullable String baseDirectory, final String testRunName) {
Expand All @@ -69,11 +74,6 @@ private static File createTestRunDirectory(final @Nullable String baseDirectory,
dirPath = Path.of(System.getProperty("user.dir"), "testruns", testRunName);
}
final File runDir = dirPath.toFile();
if (runDir.exists()) {
if (!runDir.mkdir()) {
throw new RuntimeException("Directory for test result data compromised.");
}
}
if (!runDir.exists()) {
if (!runDir.mkdirs()) {
throw new RuntimeException("Could not create directory for test result data");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
package com.draeger.medical.sdccc.manipulation.precondition

import com.draeger.medical.sdccc.messages.MessageStorage
import com.google.inject.Inject
import com.google.inject.Injector
import com.google.inject.Singleton
Expand Down Expand Up @@ -101,6 +102,8 @@ class PreconditionRegistry @Inject internal constructor(private val injector: In
for (precondition in preconditions) {
logger.info { "Running precondition ${precondition.javaClass.simpleName}" }
precondition.verifyPrecondition(injector)
// flush data after each precondition to ensure that each precondition has most current data
injector.getInstance(MessageStorage::class.java).flush()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,12 @@
import org.apache.commons.io.input.BOMInputStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.ScrollMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.query.spi.StreamDecorator;
import org.somda.sdc.dpws.CommunicationLog;
import org.somda.sdc.dpws.soap.ApplicationInfo;
import org.somda.sdc.dpws.soap.CommunicationContext;
Expand Down Expand Up @@ -1079,6 +1082,7 @@ private void awaitFlushBarrier() {

/**
* Retrieves all SequenceId attribute values that have been seen.
* Orders them by the timestamp of the first message that used the respective SequenceId.
*
* @return stream of all SequenceId attribute values that have been seen
* @throws IOException if storage is closed
Expand All @@ -1090,17 +1094,20 @@ public Stream<String> getUniqueSequenceIds() throws IOException {
throw new IOException(GET_UNIQUE_SEQUENCE_IDS_CALLED_ON_CLOSED_STORAGE);
}

final CriteriaQuery<String> criteria;

final CriteriaQuery<String> messageContentQuery;
try (final Session session = sessionFactory.openSession()) {
session.beginTransaction();

final CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
criteria = criteriaBuilder.createQuery(String.class);
final Root<MdibVersionGroupEntity> mdibVersionGroupEntityRoot = criteria.from(MdibVersionGroupEntity.class);
criteria.select(mdibVersionGroupEntityRoot.get(MdibVersionGroupEntity_.sequenceId));
criteria.distinct(true);
messageContentQuery = criteriaBuilder.createQuery(String.class);
final Root<MessageContent> messageContentRoot = messageContentQuery.from(MessageContent.class);
messageContentQuery.select(
messageContentRoot.join(MessageContent_.mdibVersionGroups).get(MdibVersionGroupEntity_.sequenceId));

messageContentQuery.orderBy(criteriaBuilder.asc(messageContentRoot.get(MessageContent_.nanoTimestamp)));
}

return this.getQueryResult(criteria);
return this.getOrderedQueryResult(messageContentQuery).distinct();
}

/**
Expand Down Expand Up @@ -1693,11 +1700,11 @@ public GetterResult<MessageContent> getInboundMessagesByTimeIntervalAndBodyType(
}

final boolean present;
try (final Stream<MessageContent> countingStream = this.getQueryResult(messageContentQuery)) {
try (final Stream<MessageContent> countingStream = this.getOrderedQueryResult(messageContentQuery)) {
present = countingStream.findAny().isPresent();
}

return new GetterResult<>(this.getQueryResult(messageContentQuery), present);
return new GetterResult<>(this.getOrderedQueryResult(messageContentQuery), present);
}

/**
Expand Down Expand Up @@ -1773,11 +1780,11 @@ public GetterResult<MessageContent> getInboundMessagesByTimestampAndBodyType(
}

final boolean present;
try (final Stream<MessageContent> countingStream = this.getQueryResult(messageContentQuery)) {
try (final Stream<MessageContent> countingStream = this.getOrderedQueryResult(messageContentQuery)) {
present = countingStream.findAny().isPresent();
}

return new GetterResult<>(this.getQueryResult(messageContentQuery), present);
return new GetterResult<>(this.getOrderedQueryResult(messageContentQuery), present);
}

/**
Expand Down Expand Up @@ -1817,11 +1824,11 @@ public GetterResult<ManipulationData> getManipulationDataByManipulation(final St
}

final boolean present;
try (final Stream<ManipulationData> countingStream = this.getQueryResult(criteria)) {
try (final Stream<ManipulationData> countingStream = this.getOrderedQueryResult(criteria)) {
present = countingStream.findAny().isPresent();
}

return new GetterResult<>(this.getQueryResult(criteria), present);
return new GetterResult<>(this.getOrderedQueryResult(criteria), present);
}

/**
Expand Down Expand Up @@ -1886,10 +1893,10 @@ public GetterResult<ManipulationData> getManipulationDataByParametersAndManipula
criteriaBuilder.and(parameterExistPredicates.toArray(new Predicate[0]))));
}
final boolean present;
try (final Stream<ManipulationData> countingStream = this.getQueryResult(criteria)) {
try (final Stream<ManipulationData> countingStream = this.getOrderedQueryResult(criteria)) {
present = countingStream.findAny().isPresent();
}
return new GetterResult<>(this.getQueryResult(criteria), present);
return new GetterResult<>(this.getOrderedQueryResult(criteria), present);
}

private <T> Stream<T> getQueryResult(final CriteriaQuery<T> criteriaQuery) {
Expand All @@ -1902,6 +1909,16 @@ private <T> Stream<T> getQueryResult(final CriteriaQuery<T> criteriaQuery) {
.onClose(resultIterator::close);
}

private <T> Stream<T> getOrderedQueryResult(final CriteriaQuery<T> criteriaQuery) {
final Session session = sessionFactory.openSession();
final Stream<T> results = getOrderedStreamForQuery(session, criteriaQuery);

final ResultIterator<T> resultIterator = new ResultIterator<>(session, results);

return StreamSupport.stream(Spliterators.spliteratorUnknownSize(resultIterator, Spliterator.ORDERED), false)
.onClose(resultIterator::close);
}

// be aware, that this does not use evict on cached objects
private <T> Stream<T> getStreamForQuery(final CriteriaQuery<T> criteriaQuery) {
final Session session = sessionFactory.openSession();
Expand All @@ -1926,6 +1943,23 @@ private <T> Stream<T> getStreamForQuery(final Session session, final CriteriaQue
.stream();
}

// be aware, that this does not use evict on cached objects
private <T> Stream<T> getOrderedStreamForQuery(final Session session, final CriteriaQuery<T> criteriaQuery) {
// The stream provided by Hibernate does not have the ORDERED characteristic.
// We hence build our own.
final ScrollableResultsImplementor scrollableResults =
(ScrollableResultsImplementor) session.createQuery(criteriaQuery)
.setReadOnly(true)
.setCacheable(false)
.setFetchSize(FETCH_SIZE)
.scroll(ScrollMode.FORWARD_ONLY);
final OrderedStreamIterator<T> iterator = new OrderedStreamIterator<>(scrollableResults);
final Spliterator<T> spliterator =
Spliterators.spliteratorUnknownSize(iterator, Spliterator.NONNULL | Spliterator.ORDERED);

return (Stream<T>) new StreamDecorator(StreamSupport.stream(spliterator, false), scrollableResults::close);
}

private void transmit(final List<DatabaseEntry> results) {
try (final Session session = sessionFactory.openSession()) {
final Transaction transaction = session.beginTransaction();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* This Source Code Form is subject to the terms of the MIT License.
* Copyright (c) 2023-2024 Draegerwerk AG & Co. KGaA.
*
* SPDX-License-Identifier: MIT
*/

package com.draeger.medical.sdccc.messages

import org.hibernate.query.spi.CloseableIterator
import org.hibernate.query.spi.ScrollableResultsImplementor

/**
* Iterator to be used to create Streams with the ORDERED characteristic from ScrollableResults.
*/
class OrderedStreamIterator<T>(private val results: ScrollableResultsImplementor) : CloseableIterator<T> {

override fun close() {
results.close()
}

override fun remove() {
throw UnsupportedOperationException(
"this stream does not support the" +
" remove operation"
)
}

override fun hasNext(): Boolean {
if (results.isClosed) {
return false
}
return results.next()
}

override fun next(): T {
val element = results.get()
@Suppress("UNCHECKED_CAST")
return if (element.size == 1) {
element[0]
} else {
element
} as T
}
}
Loading

0 comments on commit 1c2cda0

Please sign in to comment.