From 9db5621a72e470bcb6d7dfaabb98d7056968e275 Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Wed, 11 Nov 2026 12:24:57 +0000 Subject: [PATCH 1/2] Test the exact JSON Builder error text with no sequence number --- .../JsonBuilderSequenceMessageTests.java | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 pipeline/pipeline.jsonbuilder/src/test/java/fiftyone/pipeline/jsonbuilder/JsonBuilderSequenceMessageTests.java diff --git a/pipeline/pipeline.jsonbuilder/src/test/java/fiftyone/pipeline/jsonbuilder/JsonBuilderSequenceMessageTests.java b/pipeline/pipeline.jsonbuilder/src/test/java/fiftyone/pipeline/jsonbuilder/JsonBuilderSequenceMessageTests.java new file mode 100644 index 00000000..17d72611 --- /dev/null +++ b/pipeline/pipeline.jsonbuilder/src/test/java/fiftyone/pipeline/jsonbuilder/JsonBuilderSequenceMessageTests.java @@ -0,0 +1,108 @@ +/* ********************************************************************* + * This Original Work is copyright of 51 Degrees Mobile Experts Limited. + * Copyright 2026 51 Degrees Mobile Experts Limited, Davidson House, + * Forbury Square, Reading, Berkshire, United Kingdom RG1 3EU. + * + * This Original Work is licensed under the European Union Public Licence + * (EUPL) v.1.2 and is subject to its terms as set out below. + * + * If a copy of the EUPL was not distributed with this file, You can obtain + * one at https://opensource.org/licenses/EUPL-1.2. + * + * The 'Compatible Licences' set out in the Appendix to the EUPL (as may be + * amended by the European Commission) shall be deemed incompatible for + * the purposes of the Work and the provisions of the compatibility + * clause in Article 5 of the EUPL shall not apply. + * + * If using the Work as, or as part of, a network application, by + * including the attribution notice(s) required under Article 5 of the EUPL + * in the end user terms of the application under an appropriate heading, + * such notice(s) shall fulfill the requirements of that article. + * ********************************************************************* */ + +package fiftyone.pipeline.jsonbuilder; + +import fiftyone.common.testhelpers.TestLoggerFactory; +import fiftyone.pipeline.core.data.FlowData; +import fiftyone.pipeline.core.data.FlowError; +import fiftyone.pipeline.core.exceptions.PipelineConfigurationException; +import fiftyone.pipeline.core.flowelements.Pipeline; +import fiftyone.pipeline.core.flowelements.PipelineBuilder; +import fiftyone.pipeline.exceptions.AggregateException; +import fiftyone.pipeline.jsonbuilder.flowelements.JsonBuilderElementBuilder; +import org.junit.jupiter.api.Test; +import org.slf4j.ILoggerFactory; +import org.slf4j.Logger; + +import java.util.Collection; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * With no Sequence Element before it, the JSON Builder fails with the message + * the specification gives, which is the same in every language. + * @see Specification + */ +public class JsonBuilderSequenceMessageTests { + private static final String MESSAGE = + "The JSON Builder needs a sequence number. Place a Sequence Element " + + "before the JSON Builder in the Pipeline."; + + private final TestLoggerFactory loggerFactory; + + public JsonBuilderSequenceMessageTests() { + ILoggerFactory internalLogger = mock(ILoggerFactory.class); + when(internalLogger.getLogger(anyString())) + .thenReturn(mock(Logger.class)); + loggerFactory = new TestLoggerFactory(internalLogger); + } + + private Pipeline buildPipeline(boolean suppress) throws Exception { + return new PipelineBuilder(loggerFactory) + .addFlowElement(new JsonBuilderElementBuilder(loggerFactory).build()) + .setAutoCloseElements(true) + .setSuppressProcessException(suppress) + .build(); + } + + /** + * The recorded error and its cause both carry the message. + */ + @Test + public void JsonBuilder_NoSequenceElement_RecordedMessage() + throws Exception { + try (Pipeline pipeline = buildPipeline(true); + FlowData flowData = pipeline.createFlowData()) { + flowData.process(); + + Collection errors = flowData.getErrors(); + assertEquals(1, errors.size()); + Throwable error = errors.iterator().next().getThrowable(); + assertInstanceOf(PipelineConfigurationException.class, error); + assertEquals(MESSAGE, error.getMessage()); + assertEquals(MESSAGE, error.getCause().getMessage()); + } + } + + /** + * With exceptions not suppressed, the error the caller catches carries + * the message. + */ + @Test + public void JsonBuilder_NoSequenceElement_ThrownMessage() + throws Exception { + try (Pipeline pipeline = buildPipeline(false); + FlowData flowData = pipeline.createFlowData()) { + AggregateException thrown = assertThrows( + AggregateException.class, + flowData::process); + assertEquals(1, thrown.getSuppressed().length); + assertEquals(MESSAGE, thrown.getSuppressed()[0].getMessage()); + } + } +} \ No newline at end of file From 86140ae0ce3af4bfe2d23a2db87223c83861f119 Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Wed, 11 Nov 2026 12:24:59 +0000 Subject: [PATCH 2/2] Give the specification's JSON Builder error text with no sequence number Every language gives the same text when no Sequence Element has produced a sequence number, as the JSON Builder page of the specification states. --- .../flowelements/JsonBuilderElement.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pipeline/pipeline.jsonbuilder/src/main/java/fiftyone/pipeline/jsonbuilder/flowelements/JsonBuilderElement.java b/pipeline/pipeline.jsonbuilder/src/main/java/fiftyone/pipeline/jsonbuilder/flowelements/JsonBuilderElement.java index fcf92033..d69fb76e 100644 --- a/pipeline/pipeline.jsonbuilder/src/main/java/fiftyone/pipeline/jsonbuilder/flowelements/JsonBuilderElement.java +++ b/pipeline/pipeline.jsonbuilder/src/main/java/fiftyone/pipeline/jsonbuilder/flowelements/JsonBuilderElement.java @@ -65,6 +65,13 @@ public class JsonBuilderElement private static final String JAVASCRIPT_PROPERTIES_NAME = "javascriptProperties"; private static final String RAW_WEIGHTING_KEY = "rawweighting"; private static final String VALUE_KEY = "value"; + /** + * The error when no Sequence Element has produced a sequence number, + * worded as the specification gives it for every language. + */ + private static final String NO_SEQUENCE_MESSAGE = + "The JSON Builder needs a sequence number. Place a Sequence Element " + + "before the JSON Builder in the Pipeline."; private final EvidenceKeyFilter evidenceKeyFilter; private final List properties; private final List blacklist; @@ -203,9 +210,7 @@ private String buildJson(FlowData data, PipelineConfig config) throws Exception try { sequenceNumber = getSequenceNumber(data); } catch (Exception e) { - throw new PipelineConfigurationException("Make sure there is a " - + "SequenceElement placed before this JsonBuilderElement " - + "in the pipeline", e); + throw new PipelineConfigurationException(NO_SEQUENCE_MESSAGE, e); } Map allProperties = getAllProperties(data, config); @@ -225,8 +230,7 @@ private int getSequenceNumber(FlowData data) throws Exception { "query.sequence", Integer.class); if(sequence.hasValue() == false) { - throw new Exception("Sequence number not present in evidence. " + - "this is mandatory."); + throw new Exception(NO_SEQUENCE_MESSAGE); } return sequence.getValue(); }