Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.citrusframework.exceptions;

public final class SegmentEvaluationException extends Exception {

private final String renderedObject;

public SegmentEvaluationException(String reason, String renderedObject) {
super(reason);
this.renderedObject = renderedObject;
}

public String getRenderedObject() {
return renderedObject;
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package org.citrusframework.variable;

import org.citrusframework.context.TestContext;
import org.citrusframework.exceptions.CitrusRuntimeException;
import org.citrusframework.variable.SegmentVariableExtractorRegistry.MapVariableExtractor;
import org.citrusframework.variable.SegmentVariableExtractorRegistry.ObjectFieldValueExtractor;
import org.testng.annotations.Test;

import java.util.List;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.InstanceOfAssertFactories.STRING;

public class IndexedSegmentVariableExtractorsTest {

private final TestContext context = new TestContext();

private static VariableExpressionSegmentMatcher matcher(String segmentExpr) {
VariableExpressionSegmentMatcher m = new VariableExpressionSegmentMatcher(segmentExpr);
assertThat(m.nextMatch()).as("first segment should match").isTrue();
return m;
}

@Test
public void mapExtractor_listIndex_success() {
Map<String, Object> ctx = Map.of("names", List.of("A", "B", "C"));
var extractor = MapVariableExtractor.INSTANCE;

var m = matcher("names[1]");

assertThat(extractor.canExtract(context, ctx, m)).isTrue();
assertThat(extractor.extractValue(context, ctx, m)).isEqualTo("B");
}

@Test
public void mapExtractor_arrayIndex_success() {
Map<String, Object> ctx = Map.of("nums", new int[] {10, 20, 30});
var extractor = MapVariableExtractor.INSTANCE;

var m = matcher("nums[2]");

assertThat(extractor.canExtract(context, ctx, m)).isTrue();
assertThat(extractor.extractValue(context, ctx, m)).isEqualTo(30);
}

@Test
public void mapExtractor_arrayIndex_nullElement_success() {
Map<String, Object> ctx = Map.of("nums", new Integer[] {10, 20, null});
var extractor = MapVariableExtractor.INSTANCE;

var m = matcher("nums[2]");

assertThat(extractor.canExtract(context, ctx, m)).isTrue();
assertThat(extractor.extractValue(context, ctx, m)).isNull();
}

@Test
public void mapExtractor_unknownKey_failsWithHelpfulMessage() {
Map<String, Object> ctx = Map.of("names", List.of("A", "B"));
var extractor = MapVariableExtractor.INSTANCE;

var m = matcher("missing");

assertThatThrownBy(() -> extractor.extractValue(context, ctx, m))
.isInstanceOf(CitrusRuntimeException.class)
.extracting("message", STRING)
.isEqualToIgnoringWhitespace("""
Unable to extract value using expression 'missing'!
Reason: Unknown key 'missing' in Map.
From object (java.util.ImmutableCollections$Map1):
{names=[A, B]}""");
}

@Test
public void mapExtractor_indexOutOfBounds_failsWithSizeInfo() {
Map<String, Object> ctx = Map.of("names", List.of("A", "B", "C"));
var extractor = MapVariableExtractor.INSTANCE;

var m = matcher("names[3]"); // OOB

assertThatThrownBy(() -> extractor.extractValue(context, ctx, m))
.isInstanceOf(CitrusRuntimeException.class)
.hasMessageContaining("Unable to extract value using expression 'names[3]'")
.hasMessageContaining("Index 3 out of bounds (list size 3) for segment 'names'");
}

@Test
public void mapExtractor_wrongTypeForIndexing_failsWithTypeInfo() {
Map<String, Object> ctx = Map.of("names", 42); // not list/array
var extractor = MapVariableExtractor.INSTANCE;

var m = matcher("names[0]");

assertThatThrownBy(() -> extractor.extractValue(context, ctx, m))
.isInstanceOf(CitrusRuntimeException.class)
.hasMessageContaining("Unable to extract value using expression 'names[0]'")
.hasMessageContaining("Expected array or List for indexed access, but was java.lang.Integer (segment 'names')");
}

public static class Person {
int[] numbers = {10, 20, 30};
List<String> tags = List.of("alpha", "beta");
String name = "Peter";
String nullField = null;
}

@Test
public void objectFieldExtractor_arrayIndex_success() {
var person = new Person();
var extractor = ObjectFieldValueExtractor.INSTANCE;

var m = matcher("numbers[2]");

assertThat(extractor.canExtract(context, person, m)).isTrue();
assertThat(extractor.extractValue(context, person, m)).isEqualTo(30);
}

@Test
public void objectFieldExtractor_listIndex_success() {
var person = new Person();
var extractor = ObjectFieldValueExtractor.INSTANCE;

var m = matcher("tags[0]");

assertThat(extractor.canExtract(context, person, m)).isTrue();
assertThat(extractor.extractValue(context, person, m)).isEqualTo("alpha");
}

@Test
public void objectFieldExtractor_nullValueFromField_success() {
var person = new Person();
var extractor = ObjectFieldValueExtractor.INSTANCE;

var m = matcher("nullField");

assertThat(extractor.canExtract(context, person, m)).isTrue();
assertThat(extractor.extractValue(context, person, m)).isNull();
}

@Test
public void objectFieldExtractor_unknownField_failsWithHelpfulMessage() {
var person = new Person();
var extractor = ObjectFieldValueExtractor.INSTANCE;

var m = matcher("missing");

assertThatThrownBy(() -> extractor.extractValue(context, person, m))
.isInstanceOf(CitrusRuntimeException.class)
.hasMessageContaining("Unable to extract value using expression 'missing'")
.hasMessageContaining("Reason: Unknown field 'missing' on type org.citrusframework.variable.IndexedSegmentVariableExtractorsTest$Person");
}

@Test
public void objectFieldExtractor_wrongTypeForIndexing_failsWithTypeInfo() {
var person = new Person(); // field 'name' is String
var extractor = ObjectFieldValueExtractor.INSTANCE;

var m = matcher("name[0]");

assertThatThrownBy(() -> extractor.extractValue(context, person, m))
.isInstanceOf(CitrusRuntimeException.class)
.hasMessageContaining("Unable to extract value using expression 'name[0]'")
.hasMessageContaining("Expected array or List for indexed access, but was java.lang.String (segment 'name')");
}

@Test
public void objectFieldExtractor_indexOutOfBounds_failsWithLengthInfo() {
var person = new Person();
var extractor = ObjectFieldValueExtractor.INSTANCE;

var m = matcher("numbers[9]");

assertThatThrownBy(() -> extractor.extractValue(context, person, m))
.isInstanceOf(CitrusRuntimeException.class)
.hasMessageContaining("Unable to extract value using expression 'numbers[9]'")
.hasMessageContaining("Index 9 out of bounds (array length 3) for segment 'numbers'");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,48 +16,50 @@

package org.citrusframework.actions;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.citrusframework.UnitTestSupport;
import org.citrusframework.exceptions.CitrusRuntimeException;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.text.SimpleDateFormat;
import java.util.Date;

import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class LoadPropertiesActionTest extends UnitTestSupport {

@Test
public void testLoadProperties() {
LoadPropertiesAction loadProperties = new LoadPropertiesAction.Builder()
.filePath("classpath:org/citrusframework/actions/load.properties")
.build();
@Test
public void testLoadProperties() {
LoadPropertiesAction loadProperties = new LoadPropertiesAction.Builder()
.filePath("classpath:org/citrusframework/actions/load.properties")
.build();

loadProperties.execute(context);
loadProperties.execute(context);

Assert.assertNotNull(context.getVariable("${myVariable}"));
Assert.assertEquals(context.getVariable("${myVariable}"), "test");
Assert.assertNotNull(context.getVariable("${user}"));
Assert.assertNotNull(context.getVariable("${myVariable}"));
Assert.assertEquals(context.getVariable("${myVariable}"), "test");
Assert.assertNotNull(context.getVariable("${user}"));
Assert.assertEquals(context.getVariable("${user}"), "Citrus");
Assert.assertNotNull(context.getVariable("${welcomeText}"));
Assert.assertEquals(context.getVariable("${welcomeText}"), "Hello Citrus!");
Assert.assertNotNull(context.getVariable("${todayDate}"));
Assert.assertNotNull(context.getVariable("${welcomeText}"));
Assert.assertEquals(context.getVariable("${welcomeText}"), "Hello Citrus!");
Assert.assertNotNull(context.getVariable("${todayDate}"));
Assert.assertEquals(context.getVariable("${todayDate}"),
"Today is " + new SimpleDateFormat("yyyy-MM-dd").format(new Date(System.currentTimeMillis())) + "!");
}
}

@Test
@Test
public void testUnknownVariableInLoadProperties() {
LoadPropertiesAction loadProperties = new LoadPropertiesAction.Builder()
.filePath("classpath:org/citrusframework/actions/load-error.properties")
.build();

try {
loadProperties.execute(context);
} catch(CitrusRuntimeException e) {
Assert.assertEquals(e.getMessage(), "Unknown variable 'unknownVar'");
return;
}

Assert.fail("Missing exception for unkown variable in property file");
}
LoadPropertiesAction loadProperties = new LoadPropertiesAction.Builder()
.filePath("classpath:org/citrusframework/actions/load-error.properties")
.build();

assertThatThrownBy(() -> loadProperties.execute(context))
.isInstanceOf(CitrusRuntimeException.class)
.hasMessage(
format(
"Unable to extract value using expression 'unknownVar'!%nReason: Unknown key 'unknownVar' in Map.%nFrom object (java.util.concurrent.ConcurrentHashMap):%n{}"
)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@
import java.util.List;
import java.util.Map;

import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.citrusframework.message.MessageType.JSON;
import static org.citrusframework.message.MessageType.PLAINTEXT;
import static org.citrusframework.message.MessageType.XHTML;
Expand Down Expand Up @@ -526,11 +528,14 @@ public void testReceiveMessageWithUnknownVariablesInMessageHeaders() {
.endpoint(endpoint)
.message(controlMessageBuilder)
.build();
try {
receiveAction.execute(context);
} catch (CitrusRuntimeException e) {
Assert.assertEquals(e.getMessage(), "Unknown variable 'myOperation'");
}

assertThatThrownBy(() -> receiveAction.execute(context))
.isInstanceOf(CitrusRuntimeException.class)
.hasMessage(
format(
"Unable to extract value using expression 'myOperation'!%nReason: Unknown key 'myOperation' in Map.%nFrom object (java.util.concurrent.ConcurrentHashMap):%n{}"
)
);
}

@Test
Expand Down Expand Up @@ -563,11 +568,14 @@ public void testReceiveMessageWithUnknownVariableInMessagePayload() {
.endpoint(endpoint)
.message(controlMessageBuilder)
.build();
try {
receiveAction.execute(context);
} catch (CitrusRuntimeException e) {
Assert.assertEquals(e.getMessage(), "Unknown variable 'myText'");
}

assertThatThrownBy(() -> receiveAction.execute(context))
.isInstanceOf(CitrusRuntimeException.class)
.hasMessage(
format(
"Unable to extract value using expression 'myText'!%nReason: Unknown key 'myText' in Map.%nFrom object (java.util.concurrent.ConcurrentHashMap):%n{}"
)
);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@

package org.citrusframework.actions;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.citrusframework.DefaultTestCase;
import org.citrusframework.TestActor;
import org.citrusframework.TestCase;
Expand All @@ -48,6 +42,14 @@
import org.testng.Assert;
import org.testng.annotations.Test;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer;
Expand Down Expand Up @@ -314,14 +316,14 @@ public void testSendMessageWithUnknownVariableInMessagePayload() {
.endpoint(endpoint)
.message(messageBuilder)
.build();
try {
sendAction.execute(context);
} catch(CitrusRuntimeException e) {
Assert.assertEquals(e.getMessage(), "Unknown variable 'myText'");
return;
}

Assert.fail("Missing " + CitrusRuntimeException.class + " with unknown variable error message");
assertThatThrownBy(() -> sendAction.execute(context))
.isInstanceOf(CitrusRuntimeException.class)
.hasMessage(
format(
"Unable to extract value using expression 'myText'!%nReason: Unknown key 'myText' in Map.%nFrom object (java.util.concurrent.ConcurrentHashMap):%n{}"
)
);
}

@Test
Expand All @@ -342,14 +344,14 @@ public void testSendMessageWithUnknownVariableInHeaders() {
.endpoint(endpoint)
.message(messageBuilder)
.build();
try {
sendAction.execute(context);
} catch(CitrusRuntimeException e) {
Assert.assertEquals(e.getMessage(), "Unknown variable 'myOperation'");
return;
}

Assert.fail("Missing " + CitrusRuntimeException.class + " with unknown variable error message");
assertThatThrownBy(() -> sendAction.execute(context))
.isInstanceOf(CitrusRuntimeException.class)
.hasMessage(
format(
"Unable to extract value using expression 'myOperation'!%nReason: Unknown key 'myOperation' in Map.%nFrom object (java.util.concurrent.ConcurrentHashMap):%n{}"
)
);
}

@Test
Expand Down
Loading
Loading