Skip to content

Commit

Permalink
Merge branch 'dev' into 2830-data-adapter-losing-dimension-selection
Browse files Browse the repository at this point in the history
  • Loading branch information
dominikriemer committed May 21, 2024
2 parents 6b90352 + f8f9ee3 commit af8eb4d
Show file tree
Hide file tree
Showing 15 changed files with 236 additions and 135 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ protected List<String> getEventKeys() {

@Override
protected void applyTransformation(Map<String, Object> event, List<String> eventKeys) {
event.remove(eventKeys.get(0));
event.remove(eventKeys.get(0));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,41 +18,39 @@

package org.apache.streampipes.connect.shared.preprocessing.transform.schema;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class DeleteTransformationRuleTest {

@Test
public void transformSimple() {
Map<String, Object> event = new HashMap<>();
var event = new HashMap<String, Object>();
event.put("key", "value");

DeleteTransformationRule deleteRule = new DeleteTransformationRule(List.of("key"));
var deleteRule = new DeleteTransformationRule(List.of("key"));

Map<String, Object> result = deleteRule.apply(event);
var result = deleteRule.apply(event);

Assertions.assertEquals(0,
result.keySet().size());
assertEquals(0, result.keySet().size());
}

@Test
public void transformNested() {
Map<String, Object> child = new HashMap<>();
var child = new HashMap<String, Object>();
child.put("child", "value");
Map<String, Object> event = new HashMap<>();
var event = new HashMap<String, Object>();
event.put("parent", child);

DeleteTransformationRule deleteRule = new DeleteTransformationRule(Arrays.asList("parent", "child"));
var deleteRule = new DeleteTransformationRule(Arrays.asList("parent", "child"));

Map<String, Object> result = deleteRule.apply(event);
var result = deleteRule.apply(event);

Assertions.assertEquals(1,
result.keySet().size());
assertEquals(1, result.keySet().size());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,61 @@

## Description

Publishes various simulated machine sensor data in a configurable time interval (in milliseconds).
Sensors are:
* flowrate
* pressure
* waterlevel
This adapter publishes simulated machine sensor data at a configurable time interval. It is ideal for exploring the
capabilities of StreamPipes without needing your own data or for testing purposes. Three different sensor scenarios are
available:

* Flowrate
* Pressure
* Water Level

All scenarios include an error or anomaly condition, making them suitable for trend detection, anomaly detection, and
similar applications.

### Flowrate Sensor

This scenario simulates a flowrate sensor in a piping system, including a sensor defect situation. The generated data
stream includes:

- **Sensor ID**: The identifier or name of the sensor, such as `sensor01`.
- **Mass Flow**: Numeric value denoting the current mass flow in the sensor, ranging from 0 to 10.
- **Volume Flow**: Numeric value denoting the current volume flow, ranging from 0 to 10.
- **Temperature**: Numeric value denoting the current temperature in degrees Celsius, ranging from 40 to 100.
- **Density**: Numeric value denoting the current density of the fluid, ranging from 40 to 50.
- **Sensor Fault Flags**: Boolean indicator of sensor issues.

The sensor defect scenario is as follows: Normally, temperature values range between 40 and 50 degrees Celsius. After
thirty seconds, the simulation switches to defect mode for another thirty seconds, with temperatures ranging from 80 to
100 degrees Celsius and `Sensor Fault Flags` set to `true`.

### Pressure Sensor

This scenario simulates a pressure sensor in a gas tank, including an anomaly situation. The generated data stream
includes:

- **Sensor ID**: The identifier or name of the sensor, such as `sensor01`.
- **Pressure**: Numeric value denoting the current pressure in the tank, ranging from 10 to 70.

The anomaly scenario is as follows: Normally, pressure values range between 10 and 40. After thirty seconds, the
simulation switches to anomaly mode for another thirty seconds, with pressure values ranging from 40 to 70.

### Water Level Sensor

This scenario simulates a sensor in a water tank, including an overflow situation. The generated data stream includes:

- **Sensor ID**: The identifier or name of the sensor, such as `sensor01`.
- **Level**: Numeric value denoting the current water level in the tank, ranging from 20 to 80.
- **Overflow**: Boolean indicator of tank overflow.

The overflow scenario is as follows: Normally, level values range between 20 and 30. After thirty seconds, the
simulation switches to overflow mode for another thirty seconds, with level values ranging from 60 to 80 and `Overflow`
set to `true`.

## Configuration

When creating the adapter, the following parameters can be configured:

- **Wait Time**: The time in milliseconds between two sensor events. Defaults to 1000 (1 second).
- **Sensor**: Select one of the sensor scenarios described above: `flowrate`, `pressure`, `waterlevel`.

***
Original file line number Diff line number Diff line change
Expand Up @@ -248,22 +248,22 @@ public <V> List<V> selectedTreeNodesInternalNames(String internalName,
List<TreeInputNode> allNodes = new ArrayList<>();
RuntimeResolvableTreeInputStaticProperty sp =
getStaticPropertyByName(internalName, RuntimeResolvableTreeInputStaticProperty.class);
if (sp.getNodes().size() > 0) {
if (!sp.getNodes().isEmpty()) {
sp.getNodes().forEach(node -> buildFlatTree(node, allNodes));
}

if (allNodes.size() > 0) {
return allNodes
if (!allNodes.isEmpty()) {
return sp.getSelectedNodesInternalNames()
.stream()
.filter(node -> {
if (!onlyDataNodes) {
return true;
} else {
return node.isDataNode();
var existingNode = allNodes.stream().filter(n -> n.getInternalNodeName().equals(node)).findFirst();
return existingNode.map(TreeInputNode::isDataNode).orElse(false);
}
})
.filter(TreeInputNode::isSelected)
.map(node -> typeParser.parse(node.getInternalNodeName(), targetClass))
.map(node -> typeParser.parse(node, targetClass))
.collect(Collectors.toList());
} else {
return new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"timestamp": 1667904471000,
"parent": {
"child": "text"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
timestamp;reserved bit;reserved bit_1;reserved bit_2
1715356080000;true;true;true
2 changes: 1 addition & 1 deletion ui/cypress/support/utils/ConnectEventSchemaUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ export class ConnectEventSchemaUtils {
}

public static deleteProperty(propertyName: string) {
cy.dataCy('delete-property-' + propertyName, { timeout: 10000 })
cy.dataCy('"delete-property-' + propertyName + '"', { timeout: 10000 })
.children()
.click({ force: true });
cy.dataCy('connect-schema-delete-properties-btn', {
Expand Down
34 changes: 19 additions & 15 deletions ui/cypress/support/utils/connect/ConnectUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,29 +278,33 @@ export class ConnectUtils {

public static setUpPreprocessingRuleTest(
overwriteTimestamp: boolean,
adapterConfigurationBuilder?: AdapterBuilder,
): AdapterInput {
const adapterConfiguration = AdapterBuilder.create('File_Stream')
.setStoreInDataLake()
.setTimestampProperty('timestamp')
.addProtocolInput(
'radio',
'speed',
'fastest_\\(ignore_original_time\\)',
)
.addProtocolInput('radio', 'replayonce', 'yes')
.setName('Adapter to test rules')
.setFormat('csv')
.addFormatInput('input', ConnectBtns.csvDelimiter(), ';')
.addFormatInput('checkbox', ConnectBtns.csvHeader(), 'check');
if (!adapterConfigurationBuilder) {
adapterConfigurationBuilder = AdapterBuilder.create('File_Stream')
.setStoreInDataLake()
.setTimestampProperty('timestamp')
.addProtocolInput(
'radio',
'speed',
'fastest_\\(ignore_original_time\\)',
)
.addProtocolInput('radio', 'replayonce', 'yes')
.setName('Adapter to test rules')
.setFormat('csv')
.addFormatInput('input', ConnectBtns.csvDelimiter(), ';')
.addFormatInput('checkbox', ConnectBtns.csvHeader(), 'check');
}

if (overwriteTimestamp) {
adapterConfiguration.addProtocolInput(
adapterConfigurationBuilder.addProtocolInput(
'checkbox',
'replaceTimestamp',
'check',
);
}
adapterConfiguration = adapterConfiguration.build();

const adapterConfiguration = adapterConfigurationBuilder.build();

ConnectUtils.goToConnect();
ConnectUtils.goToNewAdapterPage();
Expand Down
76 changes: 76 additions & 0 deletions ui/cypress/tests/adapter/rules/deleteTransformationRule.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import { ConnectUtils } from '../../../support/utils/connect/ConnectUtils';
import { FileManagementUtils } from '../../../support/utils/FileManagementUtils';
import { ConnectEventSchemaUtils } from '../../../support/utils/ConnectEventSchemaUtils';
import { AdapterBuilder } from '../../../support/builder/AdapterBuilder';

describe('Connect delete rule transformation', () => {
beforeEach('Setup Test', () => {
cy.initStreamPipesTest();
});

it('Test delete with same prefix', () => {
FileManagementUtils.addFile(
'connect/deleteTransformationRule/prefixInput.csv',
);

ConnectUtils.setUpPreprocessingRuleTest(false);

ConnectEventSchemaUtils.deleteProperty('reserved bit');
ConnectEventSchemaUtils.deleteProperty('reserved bit_1');
ConnectEventSchemaUtils.deleteProperty('reserved bit_2');

cy.dataCy('schema-preview-result-event').should(
'have.text',
'{\u00A0\u00A0\u00A0\u00A0"timestamp":\u00A01715356080000}',
);
});

it('Test delete nested properties', () => {
FileManagementUtils.addFile(
'connect/deleteTransformationRule/nestedInput.json',
);

const adapterConfigurationBuilder = AdapterBuilder.create('File_Stream')
.setStoreInDataLake()
.setTimestampProperty('timestamp')
.addProtocolInput(
'radio',
'speed',
'fastest_\\(ignore_original_time\\)',
)
.addProtocolInput('radio', 'replayonce', 'yes')
.setName('Adapter to test rules')
.setFormat('json');

ConnectUtils.setUpPreprocessingRuleTest(
false,
adapterConfigurationBuilder,
);

// Test to delete the child property
ConnectEventSchemaUtils.deleteProperty('child');

// The resulting string contains non-breaking spaces character (\u00A0)
cy.dataCy('schema-preview-result-event').should(
'have.text',
'{\u00A0\u00A0\u00A0\u00A0"parent":\u00A0{},\u00A0\u00A0\u00A0\u00A0"timestamp":\u00A01667904471000}',
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
<pre
[innerHTML]="desiredField | jsonpretty"
class="preview-text"
data-cy="schema-preview-result-event"
></pre>
</sp-basic-inner-panel>
</div>
Expand Down
68 changes: 0 additions & 68 deletions ui/src/app/connect/services/transformation-rule.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import { TransformationRuleService } from './transformation-rule.service';
import {
CreateNestedRuleDescription,
DeleteRuleDescription,
EventPropertyNested,
EventPropertyPrimitive,
EventPropertyUnion,
Expand Down Expand Up @@ -196,73 +195,6 @@ describe('TransformationRuleService', () => {

expect(result.length).toBe(1);
expect(result[0].oldRuntimeKey).toBe('a');
// expect(result[0].newRuntimeKey).toBe('b.a');
});

it('Delete simple', () => {
const oldEventSchema: EventSchema = new EventSchema();
const eventProperty: EventPropertyPrimitive =
new EventPropertyPrimitive();
eventProperty.runtimeName = 'a';
oldEventSchema.eventProperties = [];
oldEventSchema.eventProperties.push(eventProperty);

const newEventSchema: EventSchema = new EventSchema();
newEventSchema.eventProperties = [];

const result: DeleteRuleDescription[] = service.getDeleteRules(
newEventSchema.eventProperties,
oldEventSchema,
newEventSchema,
);

expect(result.length).toBe(1);
expect(result[0].runtimeKey).toBe('a');
});

it('Delete nested', () => {
const oldEventSchema: EventSchema = new EventSchema();
const eventProperty: EventPropertyPrimitive =
new EventPropertyPrimitive();
eventProperty.elementId = 'id_2';
eventProperty.runtimeName = 'a';
const eventPropertyNested: EventPropertyNested =
new EventPropertyNested();
eventPropertyNested.elementId = 'id_1';
eventPropertyNested.eventProperties = [];
eventPropertyNested.eventProperties.push(eventProperty);
eventPropertyNested.runtimeName = 'b';
oldEventSchema.eventProperties = [];
oldEventSchema.eventProperties.push(eventPropertyNested);

let newEventSchema: EventSchema = new EventSchema();
const newEventPropertyNested: EventPropertyNested =
new EventPropertyNested();
newEventPropertyNested.elementId = 'id_1';
newEventPropertyNested.runtimeName = 'b';
newEventPropertyNested.eventProperties = [];
newEventSchema.eventProperties = [];
newEventSchema.eventProperties.push(newEventPropertyNested);

let result: DeleteRuleDescription[] = service.getDeleteRules(
newEventSchema.eventProperties,
oldEventSchema,
newEventSchema,
);

expect(result.length).toBe(1);
expect(result[0].runtimeKey).toBe('b.a');

newEventSchema = new EventSchema();
newEventSchema.eventProperties = [];
result = service.getDeleteRules(
newEventSchema.eventProperties,
oldEventSchema,
newEventSchema,
);

expect(result.length).toBe(1);
expect(result[0].runtimeKey).toBe('b');
});

it('Rename simple', () => {
Expand Down
Loading

0 comments on commit af8eb4d

Please sign in to comment.