diff --git a/src/test/scala/utils/Samples.scala b/src/test/scala/utils/Samples.scala index 8111687..4d5c47b 100644 --- a/src/test/scala/utils/Samples.scala +++ b/src/test/scala/utils/Samples.scala @@ -5,6 +5,7 @@ import TestData.shapeMapStr import Utils.{dateFormatter, mkRdfItem} import data.DataFormat import data.DataFormat.* +import exception.stream.timed.StreamTimeoutException import implicits.RDFElementImplicits.rdfFromString import schema.ShExSchemaFormat import schema.ShExSchemaFormat.{SHEXC, SHEXJ} @@ -21,6 +22,7 @@ import es.weso.schema.{Schema, Schemas} import java.text.SimpleDateFormat import java.util.{Date, Locale} +import scala.concurrent.duration.FiniteDuration import scala.util.Random /** @@ -67,17 +69,20 @@ object Samples { * but here the RDF string is not passed manually but created from a template * given its desired format * - * @param rdfFormat Format of the RDF item that we want to get validated, - * generated from template (see [[RdfSamples]]) - * @param schemaFormat Format of the Schema to be used for validation, - * generated from template (see [[SchemaSamples]]) - * @param valid Whether if the produced RDF item should comply with - * the produced validation schema or not - * Used to control de output status of the validation - * @param haltOnInvalid Whether if the underlying validator should halt on - * INVALID validation results - * @param haltOnError Whether if the underlying validator should halt on - * ERRORED validation results + * @param rdfFormat Format of the RDF item that we want to get validated, + * generated from template (see [[RdfSamples]]) + * @param schemaFormat Format of the Schema to be used for validation, + * generated from template (see [[SchemaSamples]]) + * @param valid Whether if the produced RDF item should comply with + * the produced validation schema or not + * Used to control de output status of the validation + * @param haltOnInvalid Whether if the underlying validator should halt on + * INVALID validation results + * @param haltOnError Whether if the underlying validator should halt on + * ERRORED validation results + * @param extractorTimeout Time for the item extractor to wait without + * receiving items before erroring and closing + * the stream (see [[StreamTimeoutException]]) * @return The [[ValidationResult]] of getting an RDF item (of format [[rdfFormat]]) * through a validator using a Schema (of format/engine [[schemaFormat]]) * following the data, schema and trigger templates in [[Samples]] @@ -86,12 +91,15 @@ object Samples { schemaFormat: DataFormat | ShExSchemaFormat, valid: Boolean = true, haltOnInvalid: Boolean = false, - haltOnError: Boolean = false + haltOnError: Boolean = false, + extractorTimeout: Option[FiniteDuration] = None ): IO[ValidationResult] = { // Make the RDF item val rdfItem = RdfSamples.mkRdfItem(rdfFormat, valid = valid) // Resort to alternative implementation - mkSingleValidationResult(rdfItem, rdfFormat, schemaFormat, haltOnInvalid, haltOnError) + mkSingleValidationResult( + rdfItem, rdfFormat, schemaFormat, haltOnInvalid, haltOnError, extractorTimeout + ) } /** @@ -102,24 +110,31 @@ object Samples { * this creates a validation stream that complies with it and gets its eventual * result back * - * @param rdfItem Custom string of RDF data provided for validation - * @param rdfFormat Format of the RDF string provided for validation - * @param schemaFormat Format of the Schema to be used for validation, - * generated from template (see [[SchemaSamples]]) - * @param haltOnInvalid Whether if the underlying validator should halt on - * INVALID validation results - * @param haltOnError Whether if the underlying validator should halt on - * ERRORED validation results + * @param rdfItem Custom string of RDF data provided for validation + * @param rdfFormat Format of the RDF string provided for validation + * @param schemaFormat Format of the Schema to be used for validation, + * generated from template (see [[SchemaSamples]]) + * @param haltOnInvalid Whether if the underlying validator should halt on + * INVALID validation results + * @param haltOnError Whether if the underlying validator should halt on + * ERRORED validation results + * @param extractorTimeout Time for the item extractor to wait without + * receiving items before erroring and closing + * the stream (see [[StreamTimeoutException]]) * @return The [[ValidationResult]] of getting a custom RDF string, expected * to have format [[rdfFormat]], * through a validator using a Schema (of format/engine [[schemaFormat]]) * following the schema and trigger templates in [[Samples]] + * + * @note The List extractor is used for testing, since it is the simplest + * and cheapest way we have to test in-memory data */ def mkSingleValidationResult(rdfItem: String, rdfFormat: DataFormat, schemaFormat: DataFormat | ShExSchemaFormat, haltOnInvalid: Boolean, - haltOnError: Boolean + haltOnError: Boolean, + extractorTimeout: Option[FiniteDuration] ): IO[ValidationResult] = { for { // Make the schema @@ -133,7 +148,8 @@ object Samples { case _: ShExSchemaFormat => TriggerSamples.mkTriggerShex(COMPACT) } // Get the RDF item into a list extractor - extractor = ListExtractor(items = List(rdfItem), format = rdfFormat) + extractor = ListExtractor(items = List(rdfItem), format = rdfFormat, + itemTimeout = extractorTimeout) // Open validation stream and collect the validation results // Validator settings diff --git a/src/test/scala/validation/halting/HaltingTests.scala b/src/test/scala/validation/halting/HaltingTests.scala index addfdd4..8b9c964 100644 --- a/src/test/scala/validation/halting/HaltingTests.scala +++ b/src/test/scala/validation/halting/HaltingTests.scala @@ -34,12 +34,6 @@ import org.scalatest.matchers.should.Matchers * - The same RDF data example will be validated against a given schema, * though slightly modified to test both invalid and erroring validations * - * - Single RDF items will be tested as a single item stream - * fed to a stream-validator to check that the results are the expected ones - * - * - The List extractor will be used for testing, since it is the simplest way - * we have to test in-memory data - * * Tests are nested as follows to cover all possibilities: * * - Per expected behaviour (halt on invalid, halt on errored) @@ -82,7 +76,9 @@ class HaltingTests extends AsyncFreeSpec with AsyncIOSpec with Matchers { rdfFormat = TURTLE, schemaFormat = SHEXC, haltOnInvalid = false, - haltOnError = true) + haltOnError = true, + None + ) .assertThrows[StreamErroredItemException] } @@ -92,7 +88,9 @@ class HaltingTests extends AsyncFreeSpec with AsyncIOSpec with Matchers { rdfFormat = TURTLE, schemaFormat = TURTLE, haltOnInvalid = false, - haltOnError = true) + haltOnError = true, + None + ) .assertThrows[StreamErroredItemException] } } diff --git a/src/test/scala/validation/ouputs/SchemaTests.scala b/src/test/scala/validation/ouputs/SchemaTests.scala index 71db34e..af17674 100644 --- a/src/test/scala/validation/ouputs/SchemaTests.scala +++ b/src/test/scala/validation/ouputs/SchemaTests.scala @@ -32,12 +32,6 @@ import org.scalatest.matchers.should.Matchers * - The same RDF data example will be validated against a given schema, * though slightly modified to test both valid and invalid validations * - * - Single RDF items will be tested as a single item stream - * fed to a stream-validator to check that the results are the expected ones - * - * - The List extractor will be used for testing, since it is the simplest way - * we have to test in-memory data - * * Tests are nested as follows to cover all possibilities: * * - Per Schema type/engine (ShEx, SHACL, etc.) diff --git a/src/test/scala/validation/timeout/TimeoutTests.scala b/src/test/scala/validation/timeout/TimeoutTests.scala new file mode 100644 index 0000000..ea4796f --- /dev/null +++ b/src/test/scala/validation/timeout/TimeoutTests.scala @@ -0,0 +1,50 @@ +package org.ragna.comet +package validation.timeout + +import data.DataFormat +import data.DataFormat.* +import exception.stream.timed.StreamTimeoutException +import exception.stream.validations.{StreamErroredItemException, StreamInvalidItemException} +import implicits.RDFElementImplicits.rdfFromString +import schema.ShExSchemaFormat +import schema.ShExSchemaFormat.* +import stream.extractors.StreamExtractor +import stream.extractors.list.ListExtractor +import trigger.ShapeMapFormat.* +import trigger.TriggerModeType.{SHAPEMAP, TARGET_DECLARATIONS} +import trigger.{ShapeMapFormat, TriggerModeType, ValidationTrigger} +import utils.Samples.StreamSamples.mkSingleValidationResult +import validation.Validator +import validation.configuration.ValidatorConfiguration +import validation.ouputs.SchemaTests +import validation.result.ResultStatus.* +import validation.result.ValidationResult + +import cats.effect.IO +import cats.effect.testing.scalatest.AsyncIOSpec +import es.weso.schema.Schema +import org.scalatest.freespec.AsyncFreeSpec +import org.scalatest.matchers.should.Matchers + +import scala.concurrent.duration.* + +/** + * Test suite checking that the validation mechanism forcibly halts according + * to its extractor timeout when no items are received for some time + * + * The testing goes as follows: + * + * - A single trivial validator will be run with a custom item timeout and + * then checked for timeout exceptions + */ +//noinspection RedundantDefaultArgument +class TimeoutTests extends AsyncFreeSpec with AsyncIOSpec with Matchers { + "Validation halts on extractor TIMEOUT" in { + // Generate valid data, although with a minimal unsatisfiable timeout + mkSingleValidationResult( + rdfFormat = TURTLE, + schemaFormat = SHEXC, + extractorTimeout = Some(1.micro)) + .assertThrows[StreamTimeoutException] + } +}