blob: 4f4d4bd05ee0f9bac27f4974237c977606bf2b09 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
package org.eclipse.mdm.api.odsadapter;
import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.eclipse.mdm.api.base.ConnectionException;
import org.eclipse.mdm.api.base.ServiceNotProvidedException;
import org.eclipse.mdm.api.base.Transaction;
import org.eclipse.mdm.api.base.adapter.EntityType;
import org.eclipse.mdm.api.base.adapter.ModelManager;
import org.eclipse.mdm.api.base.massdata.ExternalComponent;
import org.eclipse.mdm.api.base.massdata.WriteRequest;
import org.eclipse.mdm.api.base.massdata.WriteRequestBuilder;
import org.eclipse.mdm.api.base.model.AxisType;
import org.eclipse.mdm.api.base.model.BaseEntity;
import org.eclipse.mdm.api.base.model.Channel;
import org.eclipse.mdm.api.base.model.ChannelGroup;
import org.eclipse.mdm.api.base.model.ContextComponent;
import org.eclipse.mdm.api.base.model.ContextRoot;
import org.eclipse.mdm.api.base.model.ContextType;
import org.eclipse.mdm.api.base.model.Deletable;
import org.eclipse.mdm.api.base.model.Entity;
import org.eclipse.mdm.api.base.model.EnumRegistry;
import org.eclipse.mdm.api.base.model.FileLink;
import org.eclipse.mdm.api.base.model.Measurement;
import org.eclipse.mdm.api.base.model.MimeType;
import org.eclipse.mdm.api.base.model.PhysicalDimension;
import org.eclipse.mdm.api.base.model.Quantity;
import org.eclipse.mdm.api.base.model.ScalarType;
import org.eclipse.mdm.api.base.model.Test;
import org.eclipse.mdm.api.base.model.TestStep;
import org.eclipse.mdm.api.base.model.TypeSpecification;
import org.eclipse.mdm.api.base.model.Unit;
import org.eclipse.mdm.api.base.model.Value;
import org.eclipse.mdm.api.base.model.ValueType;
import org.eclipse.mdm.api.base.query.DataAccessException;
import org.eclipse.mdm.api.base.query.Filter;
import org.eclipse.mdm.api.base.search.SearchService;
import org.eclipse.mdm.api.dflt.ApplicationContext;
import org.eclipse.mdm.api.dflt.EntityManager;
import org.eclipse.mdm.api.dflt.model.CatalogComponent;
import org.eclipse.mdm.api.dflt.model.EntityFactory;
import org.eclipse.mdm.api.dflt.model.Pool;
import org.eclipse.mdm.api.dflt.model.Project;
import org.eclipse.mdm.api.dflt.model.TemplateComponent;
import org.eclipse.mdm.api.dflt.model.TemplateRoot;
import org.eclipse.mdm.api.dflt.model.TemplateTest;
import org.eclipse.mdm.api.dflt.model.TemplateTestStep;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
@Ignore
// FIXME 10.7.2017: this test needs a running ODS Server, that is not suitable for continuous build in Jenkins.
// Comment this in for local tests only.
public class ODSAdapterExtCompTest {
/*
* ATTENTION: ==========
*
* To run this test make sure the target service is running a MDM default model
* and any database constraint which enforces a relation of Test to a parent
* entity is deactivated!
*/
private static final Logger LOGGER = LoggerFactory.getLogger(ODSAdapterExtCompTest.class);
private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";
private static final String USER = "sa";
private static final String PASSWORD = "sa";
private static ApplicationContext context;
private static EntityManager entityManager;
private static EntityFactory entityFactory;
@BeforeClass
public static void setUpBeforeClass() throws ConnectionException {
String nameServiceHost = "localhost"; // System.getProperty("host");
String nameServicePort = "2809"; // System.getProperty("port");
String serviceName = "PODSTEST"; // System.getProperty("service");
if (nameServiceHost == null || nameServiceHost.isEmpty()) {
throw new IllegalArgumentException("name service host is unknown: define system property 'host'");
}
nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;
if (nameServicePort == null || nameServicePort.isEmpty()) {
throw new IllegalArgumentException("name service port is unknown: define system property 'port'");
}
if (serviceName == null || serviceName.isEmpty()) {
throw new IllegalArgumentException("service name is unknown: define system property 'service'");
}
Map<String, String> connectionParameters = new HashMap<>();
connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));
connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");
connectionParameters.put(PARAM_USER, USER);
connectionParameters.put(PARAM_PASSWORD, PASSWORD);
context = new ODSContextFactory().connect(connectionParameters);
entityManager = context.getEntityManager()
.orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class));
entityFactory = context.getEntityFactory()
.orElseThrow(() -> new IllegalStateException("Entity manager factory not available."));
}
@AfterClass
public static void tearDownAfterClass() throws ConnectionException {
if (context != null) {
context.close();
}
}
/*
* FIXME this test requires that there is a teststep with id 2, that has a
* unitundertest component called "filetest", that has an empty filelink
* attribute "myextref" and a string attrinute "attr1". remove the comment at
* org.junit.Test if you fulfill these requirements
*/
// @org.junit.Test
public void changeFile() throws Exception {
String idteststep = "2";
ModelManager modelManager = context.getModelManager().get();
SearchService searchService = context.getSearchService().get();
EntityType etteststep = modelManager.getEntityType(TestStep.class);
Transaction transaction;
transaction = entityManager.startTransaction();
try {
List<TestStep> mealist;
mealist = searchService.fetch(TestStep.class, Filter.idOnly(etteststep, idteststep));
assertEquals(1, mealist.size());
TestStep ts = mealist.get(0);
Map<ContextType, ContextRoot> loadContexts = ts.loadContexts(entityManager, ContextType.UNITUNDERTEST);
ContextRoot contextRoot = loadContexts.get(ContextType.UNITUNDERTEST);
Optional<ContextComponent> contextComponent = contextRoot.getContextComponent("filetest");
Value value = contextComponent.get().getValue("myextref");
contextComponent.get().getValue("attr1").set("val4711");
FileLink fl = FileLink.newRemote("", new MimeType(""), "");
FileLink fl2 = (FileLink) value.extract();
assertEquals(fl2, fl);
List<BaseEntity> toUpdate = new ArrayList<>();
toUpdate.add(contextComponent.get());
transaction.update(toUpdate);
transaction.commit();
} catch (RuntimeException e) {
transaction.abort();
throw e;
}
}
@org.junit.Test
public void runtTestScript() throws DataAccessException {
List<CatalogComponent> catalogComponents = createCatalogComponents();
List<TemplateRoot> templateRoots = createTemplateRoots(catalogComponents);
List<TemplateTestStep> templateTestSteps = createTemplateTestSteps(templateRoots);
TemplateTest templateTest = createTemplateTest(templateTestSteps);
PhysicalDimension physicalDimension = entityFactory.createPhysicalDimension("any_physical_dimension");
Unit unit = entityFactory.createUnit("any_unit", physicalDimension);
Quantity quantity = entityFactory.createQuantity("any_quantity", unit);
Transaction transaction = entityManager.startTransaction();
try {
create(transaction, "catalog components", catalogComponents);
create(transaction, "template roots", templateRoots);
create(transaction, "template test steps", templateTestSteps);
create(transaction, "template test", Collections.singletonList(templateTest));
create(transaction, "physical dimension", Collections.singletonList(physicalDimension));
create(transaction, "unit", Collections.singletonList(unit));
create(transaction, "quantity", Collections.singletonList(quantity));
transaction.commit();
} catch (RuntimeException e) {
transaction.abort();
e.printStackTrace();
fail("Unable to create test data due to: " + e.getMessage());
}
List<Project> projects = Collections.emptyList();
try {
projects = createTestData(templateTest, quantity);
} catch (RuntimeException e) {
e.printStackTrace();
}
transaction = entityManager.startTransaction();
// try {
// // delete in reverse order!
// if (!projects.isEmpty()) {
// delete(transaction, "projects and their children", projects);
// }
//
// delete(transaction, "quantity", Collections.singletonList(quantity));
// delete(transaction, "unit", Collections.singletonList(unit));
// delete(transaction, "physical dimension", Collections.singletonList(physicalDimension));
// delete(transaction, "template test", Collections.singletonList(templateTest));
// delete(transaction, "template test steps", templateTestSteps);
// delete(transaction, "template roots", templateRoots);
// delete(transaction, "catalog components", catalogComponents);
//
// transaction.commit();
// } catch (RuntimeException e) {
// transaction.abort();
// fail("Unable to delete test data due to: " + e.getMessage());
// }
if (projects.isEmpty()) {
fail("Was unable to create test data.");
}
}
private List<Project> createTestData(TemplateTest templateTest, Quantity quantity) throws DataAccessException {
Project project = entityFactory.createProject("simple_project");
Pool pool = entityFactory.createPool("simple_pool", project);
List<Test> tests = createTests(2, pool, templateTest);
// create measurement test data
List<WriteRequest> writeRequests = new ArrayList<>();
for (Test test : tests) {
for (TestStep testStep : test.getCommissionedTestSteps()) {
Optional<TemplateTestStep> templateTestStep = TemplateTestStep.of(testStep);
ContextRoot[] contextRoots = new ContextRoot[0];
if (templateTestStep.isPresent()) {
contextRoots = templateTestStep.get().getTemplateRoots().stream()
.map(templateRoot -> entityFactory.createContextRoot(templateRoot))
.toArray(ContextRoot[]::new);
}
for (int i = 1; i < 3; i++) {
Measurement measurement = entityFactory.createMeasurement("measurement_" + i, testStep,
contextRoots);
// create channels
List<Channel> channels = new ArrayList<>();
for (int j = 0; j < 5; j++) {
channels.add(entityFactory.createChannel("channel_ " + j, measurement, quantity));
}
// create channel group
ChannelGroup channelGroup = entityFactory.createChannelGroup("group", 10, measurement);
writeRequests.addAll(createMeasurementData(measurement, channelGroup, channels));
}
}
}
Transaction transaction = entityManager.startTransaction();
try {
create(transaction, "project and pool with tests based on templates with measurements and mass data",
Collections.singleton(project));
transaction.writeMeasuredValues(writeRequests);
transaction.commit();
return Collections.singletonList(project);
} catch (DataAccessException e) {
e.printStackTrace();
transaction.abort();
}
return Collections.emptyList();
}
private List<WriteRequest> createMeasurementData(Measurement measurement, ChannelGroup channelGroup,
List<Channel> channels) {
// set length of the channel value sequence
List<WriteRequest> writeRequests = new ArrayList<>();
// populate channel value write requests - one per channel
Collections.sort(channels, (c1, c2) -> c1.getName().compareTo(c2.getName()));
WriteRequestBuilder wrb = WriteRequest.create(channelGroup, channels.get(0), AxisType.X_AXIS);
writeRequests.add(wrb.implicitLinear(ScalarType.FLOAT, 0, 1).independent().build());
wrb = WriteRequest.create(channelGroup, channels.get(1), AxisType.Y_AXIS);
writeRequests.add(wrb.implicitConstant(ScalarType.SHORT, Short.MAX_VALUE).build());
wrb = WriteRequest.create(channelGroup, channels.get(2), AxisType.Y_AXIS);
writeRequests.add(wrb.implicitSaw(ScalarType.FLOAT, 0, 1, 4).build());
try {
File fileValues1 = File.createTempFile("fileValues1", ".btf");
fileValues1.deleteOnExit();
File fileValues2 = File.createTempFile("fileValues2", ".btf");
fileValues2.deleteOnExit();
File fileFlags1 = File.createTempFile("fileFlags1", ".btf");
fileFlags1.deleteOnExit();
File fileFlags2 = File.createTempFile("fileFlags2", ".btf");
fileFlags2.deleteOnExit();
try (OutputStream os = Files.newOutputStream(fileValues1.toPath(), StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING)) {
byte[] arrByte = new byte[] { 5, 32, 42, 9, 17 };
os.write(arrByte, 0, 5);
int[] arrInt = new int[] { 423, 645, 221, 111, 675 };
ByteBuffer buf = ByteBuffer.allocate(20);
buf.order(ByteOrder.LITTLE_ENDIAN);
IntBuffer intBuf = buf.asIntBuffer();
intBuf.put(arrInt);
intBuf.position(0);
os.write(buf.array());
}
FileLink fileLinkValues1 = FileLink.newLocal(fileValues1.toPath());
try (OutputStream os = Files.newOutputStream(fileValues2.toPath(), StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING)) {
byte[] arrByte = new byte[] { 65, 13, 8, 15, 21 };
os.write(arrByte, 0, 5);
int[] arrInt = new int[] { 353, 781, 582, 755, 231 };
ByteBuffer buf = ByteBuffer.allocate(20);
buf.order(ByteOrder.LITTLE_ENDIAN);
IntBuffer intBuf = buf.asIntBuffer();
intBuf.put(arrInt);
intBuf.position(0);
os.write(buf.array());
}
FileLink fileLinkValues2 = FileLink.newLocal(fileValues2.toPath());
try (OutputStream os = Files.newOutputStream(fileFlags1.toPath(), StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING)) {
short[] arrFlags = new short[] { 15, 15, 15, 15, 15 };
ByteBuffer buf = ByteBuffer.allocate(10);
buf.order(ByteOrder.LITTLE_ENDIAN);
ShortBuffer shortBuf = buf.asShortBuffer();
shortBuf.put(arrFlags);
shortBuf.position(0);
os.write(buf.array());
}
FileLink fileLinkFlags1 = FileLink.newLocal(fileFlags1.toPath());
try (OutputStream os = Files.newOutputStream(fileFlags2.toPath(), StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING)) {
short[] arrFlags = new short[] { 15, 15, 15, 15, 15 };
ByteBuffer buf = ByteBuffer.allocate(10);
buf.order(ByteOrder.LITTLE_ENDIAN);
ShortBuffer shortBuf = buf.asShortBuffer();
shortBuf.put(arrFlags);
shortBuf.position(0);
os.write(buf.array());
}
FileLink fileLinkFlags2 = FileLink.newLocal(fileFlags2.toPath());
wrb = WriteRequest.create(channelGroup, channels.get(3), AxisType.Y_AXIS);
writeRequests.add(wrb.explicitExternal().externalComponents(ScalarType.BYTE, Lists.newArrayList(
(new ExternalComponent()).setTypeSpecification(TypeSpecification.BYTE).setLength(5)
.setStartOffset(0).setBlocksize(5).setValuesPerBlock(5).setValueOffset(0)
.setFileLink(fileLinkValues1).setFlagsStartOffset(0L).setFlagsFileLink(fileLinkFlags1),
(new ExternalComponent()).setTypeSpecification(TypeSpecification.BYTE).setLength(5)
.setStartOffset(0).setBlocksize(5).setValuesPerBlock(5).setValueOffset(0)
.setFileLink(fileLinkValues2).setFlagsStartOffset(0L).setFlagsFileLink(fileLinkFlags2)))
.build());
wrb = WriteRequest.create(channelGroup, channels.get(4), AxisType.Y_AXIS);
writeRequests
.add(wrb.explicitExternal()
.externalComponents(ScalarType.INTEGER, Lists.newArrayList(
(new ExternalComponent()).setTypeSpecification(TypeSpecification.INTEGER)
.setLength(5).setStartOffset(5L).setBlocksize(20).setValuesPerBlock(5)
.setValueOffset(0).setFileLink(fileLinkValues1),
(new ExternalComponent()).setTypeSpecification(TypeSpecification.INTEGER)
.setLength(5).setStartOffset(5L).setBlocksize(20).setValuesPerBlock(5)
.setValueOffset(0).setFileLink(fileLinkValues2)))
.build());
} catch (IOException exc) {
}
return writeRequests;
}
private static void delete(Transaction transaction, String key, Collection<? extends Deletable> entities)
throws DataAccessException {
LOGGER.info(">>>>>>>>>>>>>>>>> deleting " + key + "...");
long start = System.currentTimeMillis();
transaction.delete(entities);
LOGGER.info(">>>>>>>>>>>>>>>>> " + key + " deleted in " + (System.currentTimeMillis() - start) + " ms");
}
private static void create(Transaction transaction, String key, Collection<? extends Entity> entities)
throws DataAccessException {
LOGGER.info(">>>>>>>>>>>>>>>>> creating " + key + "...");
long start = System.currentTimeMillis();
transaction.create(entities);
LOGGER.info(">>>>>>>>>>>>>>>>> " + key + " written in " + (System.currentTimeMillis() - start) + " ms");
}
private List<Test> createTests(int count, Pool pool, TemplateTest templateTest) {
return IntStream.range(1, ++count)
.mapToObj(i -> entityFactory.createTest("simple_test_" + i, pool, templateTest))
.collect(Collectors.toList());
}
private TemplateTest createTemplateTest(List<TemplateTestStep> templateTestSteps) {
TemplateTest templateTest = entityFactory.createTemplateTest("tpl_test");
templateTestSteps.forEach(tts -> {
entityFactory.createTemplateTestStepUsage(UUID.randomUUID().toString(), templateTest, tts);
});
return templateTest;
}
private List<TemplateTestStep> createTemplateTestSteps(List<TemplateRoot> templateRoots) {
// make sure each context type is given only once
templateRoots.stream().collect(Collectors.toMap(TemplateRoot::getContextType, Function.identity()));
List<TemplateTestStep> templateTestSteps = new ArrayList<>();
TemplateTestStep templateTestStep1 = entityFactory.createTemplateTestStep("tpl_test_step_1");
templateRoots.forEach(tr -> templateTestStep1.setTemplateRoot(tr));
templateTestSteps.add(templateTestStep1);
TemplateTestStep templateTestStep2 = entityFactory.createTemplateTestStep("tpl_test_step_2");
templateRoots.forEach(tr -> templateTestStep2.setTemplateRoot(tr));
templateTestSteps.add(templateTestStep2);
return templateTestSteps;
}
private List<TemplateRoot> createTemplateRoots(List<CatalogComponent> catalogComponents) {
Map<ContextType, List<CatalogComponent>> groups = catalogComponents.stream()
.collect(Collectors.groupingBy(CatalogComponent::getContextType));
List<TemplateRoot> templateRoots = new ArrayList<>();
groups.forEach((contextType, catalogComps) -> {
TemplateRoot templateRoot = entityFactory.createTemplateRoot(contextType,
"tpl_" + toLower(contextType.name()) + "_root");
// create child template components for template root
catalogComps.forEach(catalogComp -> {
TemplateComponent templateComponent = entityFactory
.createTemplateComponent("tpl_" + catalogComp.getName() + "_parent", templateRoot, catalogComp);
entityFactory.createTemplateComponent("tpl_" + catalogComp.getName() + "_child", templateComponent,
catalogComp);
});
templateRoots.add(templateRoot);
});
return templateRoots;
}
private List<CatalogComponent> createCatalogComponents() {
List<CatalogComponent> catalogComponents = new ArrayList<>();
catalogComponents.add(createCatalogComponent(ContextType.UNITUNDERTEST));
catalogComponents.add(createCatalogComponent(ContextType.TESTSEQUENCE));
catalogComponents.add(createCatalogComponent(ContextType.TESTEQUIPMENT));
return catalogComponents;
}
private CatalogComponent createCatalogComponent(ContextType contextType) {
CatalogComponent catalogComponent = entityFactory.createCatalogComponent(contextType,
toLower(contextType.name()));
entityFactory.createCatalogAttribute("string", ValueType.STRING, catalogComponent);
entityFactory.createCatalogAttribute("date", ValueType.DATE, catalogComponent);
entityFactory.createCatalogAttribute("long", ValueType.LONG, catalogComponent);
entityFactory.createCatalogAttribute("file_link", ValueType.FILE_LINK, catalogComponent);
entityFactory.createCatalogAttribute("file_link_array", ValueType.FILE_LINK_SEQUENCE, catalogComponent);
EnumRegistry er = EnumRegistry.getInstance();
entityFactory.createCatalogAttribute("scalar_type", er.get(EnumRegistry.SCALAR_TYPE), catalogComponent);
return catalogComponent;
}
private static String toLower(String name) {
return name.toLowerCase(Locale.ROOT);
}
}