Repository: apache/streampipes
Pull request #2022 (2023-10-12 18:31:05)

[#1891] Implement Unit Tests for BooleanFilterProcessor
<!--
  ~ 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.
  ~
  -->
  
  <!--
Thanks for contributing! Here are some tips you can follow to help us incorporate your contribution quickly and easily:
1. If this is your first time, please read our contributor guidelines:
    - https://streampipes.apache.org/getinvolved.html
    - https://cwiki.apache.org/confluence/display/STREAMPIPES/Getting+Started
2. Make sure the PR title is formatted like: `[#<GitHub issue id>] PR title ...`
3. If the PR is unfinished, add '[WIP]' in your PR title, e.g., `[WIP][#<GitHub issue id>] PR title ...`.
4. Please write your PR title to summarize what this PR proposes/fixes.
5. Link the PR to the corresponding GitHub issue (if present) in the `Development` section in the right menu bar. 
6. Be sure to keep the PR description updated to reflect all changes.
7. If possible, provide a concise example to reproduce the issue for a faster review.
8. Make sure tests pass via `mvn clean install`.
9. (Optional) If the contribution is large, please file an Apache ICLA
    - http://apache.org/licenses/icla.pdf
-->

### Purpose
<!--
Please clarify what changes you are proposing and describe how those changes will address the issue.
Furthermore, describe potential consequences the changes might have.
-->
See #1891

### Remarks
<!--
Is there anything left we need to pay attention on?
Are there some references that might be important? E.g. links to Confluence, or discussions
on the mailing list or GitHub.
-->
PR introduces (a) breaking change(s): no

PR introduces (a) deprecation(s): no



Patch:
diff --git a/streampipes-extensions/streampipes-processors-filters-jvm/pom.xml b/streampipes-extensions/streampipes-processors-filters-jvm/pom.xml
index 98bfabefdb..09dc0887bf 100644
--- a/streampipes-extensions/streampipes-processors-filters-jvm/pom.xml
+++ b/streampipes-extensions/streampipes-processors-filters-jvm/pom.xml
@@ -43,6 +43,12 @@
             <groupId>org.quartz-scheduler</groupId>
             <artifactId>quartz</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.streampipes</groupId>
+            <artifactId>streampipes-test-utils</artifactId>
+            <version>0.93.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/ui/src/app/configuration/general-configuration/general-configuration.component.html b/ui/src/app/configuration/general-configuration/general-configuration.component.html
index 812fa66112..f4872b6487 100644
--- a/ui/src/app/configuration/general-configuration/general-configuration.component.html
+++ b/ui/src/app/configuration/general-configuration/general-configuration.component.html
@@ -36,6 +36,7 @@
                             fxFlex
                             matInput
                             required
+                            data-cy="general-config-app-name"
                         />
                     </mat-form-field>
                     <div class="subsection-title">Host and Port</div>
@@ -62,6 +63,7 @@
                                     fxFlex
                                     matInput
                                     required
+                                    data-cy="general-config-hostname"
                                 />
                             </mat-form-field>
                             <mat-form-field color="accent" class="ml-10">
@@ -72,6 +74,7 @@
                                     matInput
                                     type="number"
                                     required
+                                    data-cy="general-config-port"
                                 />
                             </mat-form-field>
                         </div>
diff --git a/ui/src/app/configuration/label-configuration/edit-label/edit-label.component.html b/ui/src/app/configuration/label-configuration/edit-label/edit-label.component.html
index 2dd47fdec7..0135229cc3 100644
--- a/ui/src/app/configuration/label-configuration/edit-label/edit-label.component.html
+++ b/ui/src/app/configuration/label-configuration/edit-label/edit-label.component.html
@@ -34,11 +34,15 @@
         ></sp-label>
         <mat-form-field color="accent" appearance="outline">
             <mat-label>Label</mat-label>
-            <input matInput [(ngModel)]="label.label" />
+            <input matInput [(ngModel)]="label.label" data-cy="label-name" />
         </mat-form-field>
         <mat-form-field color="accent" appearance="outline">
             <mat-label>Desription</mat-label>
-            <input matInput [(ngModel)]="label.description" />
+            <input
+                matInput
+                [(ngModel)]="label.description"
+                data-cy="label-description"
+            />
         </mat-form-field>
         <input
             [(colorPicker)]="label.color"
@@ -58,6 +62,7 @@
                 mat-button
                 mat-raised-button
                 color="accent"
+                data-cy="save-label-button"
                 (click)="saveEmitter.emit(label)"
             >
                 Save
diff --git a/ui/src/app/configuration/label-configuration/label-configuration.component.html b/ui/src/app/configuration/label-configuration/label-configuration.component.html
index bb5dff9635..14665314dd 100644
--- a/ui/src/app/configuration/label-configuration/label-configuration.component.html
+++ b/ui/src/app/configuration/label-configuration/label-configuration.component.html
@@ -26,6 +26,7 @@
                 mat-button
                 mat-raised-button
                 color="accent"
+                data-cy="new-label-button"
                 (click)="createLabelMode = true"
             >
                 <i class="material-icons">add</i><span>&nbsp;New label</span>
@@ -43,6 +44,7 @@
                 fxLayout="column"
                 *ngFor="let label of allLabels"
                 class="label-item"
+                data-cy="available-labels-list"
             >
                 <div
                     fxLayout="row"
@@ -53,6 +55,7 @@
                         fxFlex="20"
                         [labelText]="label.label"
                         [labelBackground]="label.color"
+                        data-cy="label-text"
                     >
                     </sp-label>
                     <span fxFlex="50" *ngIf="!isEditMode(label._id)">{{
@@ -71,6 +74,7 @@
                             mat-icon-button
                             color="warn"
                             (click)="deleteLabel(label)"
+                            data-cy="delete-label-button"
                         >
                             <i class="material-icons">delete</i>
                         </button>


Test patch:
diff --git a/streampipes-extensions/streampipes-processors-filters-jvm/src/test/java/org/apache/streampipes/processors/filters/jvm/processor/booleanfilter/TestBooleanFilterProcessor.java b/streampipes-extensions/streampipes-processors-filters-jvm/src/test/java/org/apache/streampipes/processors/filters/jvm/processor/booleanfilter/TestBooleanFilterProcessor.java
new file mode 100644
index 0000000000..30a5358308
--- /dev/null
+++ b/streampipes-extensions/streampipes-processors-filters-jvm/src/test/java/org/apache/streampipes/processors/filters/jvm/processor/booleanfilter/TestBooleanFilterProcessor.java
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ *
+ */
+
+package org.apache.streampipes.processors.filters.jvm.processor.booleanfilter;
+
+import org.apache.streampipes.model.graph.DataProcessorDescription;
+import org.apache.streampipes.model.graph.DataProcessorInvocation;
+import org.apache.streampipes.model.runtime.Event;
+import org.apache.streampipes.model.runtime.EventFactory;
+import org.apache.streampipes.model.runtime.SchemaInfo;
+import org.apache.streampipes.model.runtime.SourceInfo;
+import org.apache.streampipes.model.staticproperty.MappingPropertyUnary;
+import org.apache.streampipes.model.staticproperty.OneOfStaticProperty;
+import org.apache.streampipes.test.extensions.api.StoreEventCollector;
+import org.apache.streampipes.test.generator.EventStreamGenerator;
+import org.apache.streampipes.test.generator.InvocationGraphGenerator;
+import org.apache.streampipes.test.generator.grounding.EventGroundingGenerator;
+import org.apache.streampipes.wrapper.params.compat.ProcessorParams;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Parameterized.class)
+public class TestBooleanFilterProcessor {
+
+  private static final Logger LOG = LoggerFactory.getLogger(TestBooleanFilterProcessor.class);
+
+  @org.junit.runners.Parameterized.Parameters
+  public static Iterable<Object[]> data() {
+    List<Boolean> allTrue = Arrays.asList(true, true, true);
+    List<Boolean> allFalse = Arrays.asList(false, false, false);
+    List<Boolean> someTrueSomeFalse = Arrays.asList(true, false, true, false, true, false, true, false, true);
+    List<Boolean> empty = Arrays.asList();
+    return Arrays.asList(new Object[][]{
+        {"True", "Test", someTrueSomeFalse, 5},
+        {"True", "Test", allTrue, 3},
+        {"True", "Test", allFalse, 0},
+        {"True", "Test", empty, 0},
+        {"False", "Test", someTrueSomeFalse, 4},
+        {"False", "Test", allTrue, 0},
+        {"False", "Test", allFalse, 3},
+        {"False", "Test", empty, 0},
+    });
+  }
+
+  @org.junit.runners.Parameterized.Parameter
+  public String boolToKeep;
+
+  @org.junit.runners.Parameterized.Parameter(1)
+  public String fieldName;
+
+  @org.junit.runners.Parameterized.Parameter(2)
+  public List<Boolean> eventBooleans;
+
+  @org.junit.runners.Parameterized.Parameter(3)
+  public int expectedFilteredBooleanCount;
+
+  @Test
+  public void testBoolenFilter() {
+    BooleanFilterProcessor bfp = new BooleanFilterProcessor();
+    DataProcessorDescription originalGraph = bfp.declareModel();
+    originalGraph.setSupportedGrounding(EventGroundingGenerator.makeDummyGrounding());
+
+    DataProcessorInvocation graph =
+        InvocationGraphGenerator.makeEmptyInvocation(originalGraph);
+
+    graph.setInputStreams(Collections
+        .singletonList(EventStreamGenerator
+            .makeStreamWithProperties(Collections.singletonList(fieldName))));
+
+    graph.setOutputStream(EventStreamGenerator.makeStreamWithProperties(Collections.singletonList(fieldName)));
+
+    graph.getOutputStream().getEventGrounding().getTransportProtocol().getTopicDefinition()
+        .setActualTopicName("output-topic");
+
+    graph.getStaticProperties().stream()
+        .filter(p -> p instanceof MappingPropertyUnary)
+        .map((p -> (MappingPropertyUnary) p))
+        // Must hardcode since BOOLEAN_MAPPING is private
+        .filter(p -> p.getInternalName().equals("boolean-mapping"))
+        .findFirst().get().setSelectedProperty("s0::" + fieldName);
+    ProcessorParams params = new ProcessorParams(graph);
+    params.extractor().getStaticPropertyByName(BooleanFilterProcessor.VALUE, OneOfStaticProperty.class).getOptions()
+        .stream().filter(ot -> ot.getName().equals(boolToKeep)).findFirst()
+        .get().setSelected(true);
+    StoreEventCollector collector = new StoreEventCollector();
+
+    bfp.onInvocation(params, collector, null);
+
+    int result = sendEvents(bfp, collector);
+
+    LOG.info("Expected filtered boolean count is {}", expectedFilteredBooleanCount);
+    LOG.info("Actual filtered boolean count is {}", result);
+    assertEquals(expectedFilteredBooleanCount, result);
+  }
+
+  private int sendEvents(BooleanFilterProcessor processor, StoreEventCollector collector) {
+    List<Event> events = makeEvents();
+    for (Event event : events) {
+      LOG.info("Sending event with value "
+          + event.getFieldBySelector("s0::" + fieldName).getAsPrimitive().getAsBoolean());
+      processor.onEvent(event, collector);
+      try {
+        Thread.sleep(100);
+      } catch (InterruptedException e) {
+        e.printStackTrace();
+      }
+    }
+    return collector.getEvents().size();
+  }
+
+  private List<Event> makeEvents() {
+    List<Event> events = new ArrayList<>();
+    for (Boolean eventSetting : eventBooleans) {
+      events.add(makeEvent(eventSetting));
+    }
+    return events;
+  }
+
+  private Event makeEvent(Boolean value) {
+    Map<String, Object> map = new HashMap<>();
+    map.put(fieldName, value);
+    return EventFactory.fromMap(map, new SourceInfo("test" + "-topic", "s0"),
+        new SchemaInfo(null, new ArrayList<>()));
+  }
+}
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/test/java/org/apache/streampipes/processors/transformation/jvm/processor/value/change/TestChangedValueDetectionProcessor.java b/streampipes-extensions/streampipes-processors-transformation-jvm/src/test/java/org/apache/streampipes/processors/transformation/jvm/processor/value/change/TestChangedValueDetectionProcessor.java
index 001991630f..f7c38a6c3a 100644
--- a/streampipes-extensions/streampipes-processors-transformation-jvm/src/test/java/org/apache/streampipes/processors/transformation/jvm/processor/value/change/TestChangedValueDetectionProcessor.java
+++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/test/java/org/apache/streampipes/processors/transformation/jvm/processor/value/change/TestChangedValueDetectionProcessor.java
@@ -18,9 +18,6 @@
 
 package org.apache.streampipes.processors.transformation.jvm.processor.value.change;
 
-import org.apache.streampipes.commons.exceptions.SpRuntimeException;
-import org.apache.streampipes.extensions.api.pe.routing.SpOutputCollector;
-import org.apache.streampipes.messaging.InternalEventProcessor;
 import org.apache.streampipes.model.graph.DataProcessorInvocation;
 import org.apache.streampipes.model.runtime.Event;
 import org.apache.streampipes.model.runtime.EventFactory;
@@ -31,6 +28,7 @@ import org.apache.streampipes.model.staticproperty.MappingPropertyUnary;
 import org.apache.streampipes.sdk.builder.PrimitivePropertyBuilder;
 import org.apache.streampipes.sdk.builder.adapter.GuessSchemaBuilder;
 import org.apache.streampipes.sdk.utils.Datatypes;
+import org.apache.streampipes.test.extensions.api.StoreEventCollector;
 import org.apache.streampipes.test.generator.InvocationGraphGenerator;
 import org.apache.streampipes.wrapper.params.compat.ProcessorParams;
 
@@ -38,7 +36,6 @@ import org.junit.Test;
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import static org.junit.Assert.assertEquals;
@@ -60,8 +57,8 @@ public class TestChangedValueDetectionProcessor {
 
     // Create event with no DIMENSION_PROPERTY
     event.getSchemaInfo()
-      .getEventSchema()
-      .getEventProperties().get(0)
+        .getEventSchema()
+        .getEventProperties().get(0)
         .setPropertyScope(PropertyScope.MEASUREMENT_PROPERTY.name());
 
     assertEquals("l1", processor.getDimensionKey(event));
@@ -87,9 +84,9 @@ public class TestChangedValueDetectionProcessor {
     DataProcessorInvocation graph = InvocationGraphGenerator.makeEmptyInvocation(processor.declareModel());
 
     graph.getStaticProperties().stream()
-    .filter(p -> p instanceof MappingPropertyUnary)
-    .map((p -> (MappingPropertyUnary) p))
-    .findFirst().get().setSelectedProperty("s0::value");
+        .filter(p -> p instanceof MappingPropertyUnary)
+        .map((p -> (MappingPropertyUnary) p))
+        .findFirst().get().setSelectedProperty("s0::value");
 
     ProcessorParams params = new ProcessorParams(graph);
     processor.onInvocation(params, null, null);
@@ -117,9 +114,9 @@ public class TestChangedValueDetectionProcessor {
     DataProcessorInvocation graph = InvocationGraphGenerator.makeEmptyInvocation(processor.declareModel());
 
     graph.getStaticProperties().stream()
-    .filter(p -> p instanceof MappingPropertyUnary)
-    .map((p -> (MappingPropertyUnary) p))
-    .findFirst().get().setSelectedProperty("s0::value");
+        .filter(p -> p instanceof MappingPropertyUnary)
+        .map((p -> (MappingPropertyUnary) p))
+        .findFirst().get().setSelectedProperty("s0::value");
 
     ProcessorParams params = new ProcessorParams(graph);
     processor.onInvocation(params, null, null);
@@ -170,31 +167,4 @@ public class TestChangedValueDetectionProcessor {
 
     return EventFactory.fromMap(map, new SourceInfo("", "s0"), new SchemaInfo(eventSchema, new ArrayList<>()));
   }
-
-  class StoreEventCollector implements SpOutputCollector {
-
-    ArrayList<Event> events = new ArrayList<Event>();
-
-    @Override
-    public void registerConsumer(String routeId, InternalEventProcessor<Map<String, Object>> consumer) {}
-
-    @Override
-    public void unregisterConsumer(String routeId) {}
-
-    @Override
-    public void connect() throws SpRuntimeException {}
-
-    @Override
-    public void disconnect() throws SpRuntimeException {}
-
-    @Override
-    public void collect(Event event) {
-      events.add(event);
-    }
-
-    public List<Event> getEvents() {
-      return this.events;
-    }
-
-  }
 }
diff --git a/streampipes-test-utils/pom.xml b/streampipes-test-utils/pom.xml
index 75c3a80d1a..de133e551b 100644
--- a/streampipes-test-utils/pom.xml
+++ b/streampipes-test-utils/pom.xml
@@ -41,6 +41,18 @@
             <artifactId>junit</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.streampipes</groupId>
+            <artifactId>streampipes-messaging</artifactId>
+            <version>0.93.0-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.streampipes</groupId>
+            <artifactId>streampipes-extensions-api</artifactId>
+            <version>0.93.0-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/streampipes-test-utils/src/main/java/org/apache/streampipes/test/extensions/api/StoreEventCollector.java b/streampipes-test-utils/src/main/java/org/apache/streampipes/test/extensions/api/StoreEventCollector.java
new file mode 100644
index 0000000000..fd4080d8c9
--- /dev/null
+++ b/streampipes-test-utils/src/main/java/org/apache/streampipes/test/extensions/api/StoreEventCollector.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ *
+ */
+
+package org.apache.streampipes.test.extensions.api;
+
+import org.apache.streampipes.commons.exceptions.SpRuntimeException;
+import org.apache.streampipes.extensions.api.pe.routing.SpOutputCollector;
+import org.apache.streampipes.messaging.InternalEventProcessor;
+import org.apache.streampipes.model.runtime.Event;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class StoreEventCollector implements SpOutputCollector {
+  private ArrayList<Event> events = new ArrayList<Event>();
+
+  @Override
+  public void registerConsumer(String routeId, InternalEventProcessor<Map<String, Object>> consumer) {
+  }
+
+  @Override
+  public void unregisterConsumer(String routeId) {
+  }
+
+  @Override
+  public void connect() throws SpRuntimeException {
+  }
+
+  @Override
+  public void disconnect() throws SpRuntimeException {
+  }
+
+  @Override
+  public void collect(Event event) {
+    events.add(event);
+  }
+
+  public List<Event> getEvents() {
+    return this.events;
+  }
+}
\ No newline at end of file
diff --git a/ui/cypress/tests/configuration/labels/general.spec.ts b/ui/cypress/tests/configuration/labels/general.spec.ts
new file mode 100644
index 0000000000..46162c7080
--- /dev/null
+++ b/ui/cypress/tests/configuration/labels/general.spec.ts
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ *
+ */
+
+describe('Change basic settings', () => {
+    beforeEach('Setup Test', () => {
+        cy.initStreamPipesTest();
+    });
+
+    it('Perform Test', () => {
+        cy.visit('#/configuration/general');
+
+        // Rename app, change localhost and port
+        cy.dataCy('general-config-app-name').clear();
+        cy.dataCy('general-config-app-name').type('TEST APP');
+        cy.dataCy('general-config-hostname').clear();
+        cy.dataCy('general-config-hostname').type('testhost');
+        cy.dataCy('general-config-port').clear();
+        cy.dataCy('general-config-port').type('123');
+        cy.dataCy('sp-element-general-config-save').click();
+
+        // Leave, Re-visit configuration and check values
+        cy.visit('#/dashboard');
+        cy.visit('#/configuration/general');
+        cy.dataCy('general-config-app-name').should('have.value', 'TEST APP');
+        cy.dataCy('general-config-hostname').should('have.value', 'testhost');
+        cy.dataCy('general-config-port').should('have.value', '123');
+    });
+});
diff --git a/ui/cypress/tests/configuration/labels/labels.spec.ts b/ui/cypress/tests/configuration/labels/labels.spec.ts
new file mode 100644
index 0000000000..703085ef7e
--- /dev/null
+++ b/ui/cypress/tests/configuration/labels/labels.spec.ts
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ *
+ */
+
+describe('Add and Delete Label', () => {
+    beforeEach('Setup Test', () => {
+        cy.initStreamPipesTest();
+    });
+
+    it('Perform Test', () => {
+        cy.visit('#/configuration/labels');
+
+        // Add new label
+        cy.dataCy('new-label-button').click();
+        cy.dataCy('label-name').type('test');
+        cy.dataCy('label-description').type('test test');
+        cy.dataCy('save-label-button').click();
+
+        // Check label
+        cy.dataCy('available-labels-list').should('have.length', 1);
+        cy.dataCy('label-text').should('have.text', ' test\n');
+
+        // Delete label
+        cy.dataCy('delete-label-button').click();
+        cy.dataCy('available-labels-list').should('have.length', 0);
+    });
+});