From 0683c2d58259074fb54c8808eedf397c013443b4 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Sun, 10 Dec 2023 11:41:39 +0100 Subject: [PATCH 01/19] feat(WIP): migrate JSON-LD processing lib to Titanium - use the same (poorly typed) contract as with current lib - integrate library into JsonLdUtils - improve typing of some expanded form structures - redo all the JSON-LD processing of temporal entities (do it once before rendering, as it is done for entities) - use local JSON-LD context server extension for JUnit5 based on https://www.mock-server.com/ --- build.gradle.kts | 5 +- search-service/config/detekt/baseline.xml | 1 + .../search/model/TemporalEntityAttribute.kt | 12 +- .../search/service/EntityEventService.kt | 7 +- .../stellio/search/service/QueryService.kt | 10 +- .../service/TemporalEntityAttributeService.kt | 2 +- .../search/util/TemporalEntityBuilder.kt | 112 +- .../search/web/TemporalEntityHandler.kt | 27 +- .../web/TemporalEntityOperationsHandler.kt | 19 +- .../db/migration/V0_29__JsonLd_migration.kt | 16 +- .../AuthorizationServiceTests.kt | 6 +- .../EnabledAuthorizationServiceTests.kt | 7 +- .../EntityAccessRightsServiceTests.kt | 3 +- .../search/service/AttributeServiceTests.kt | 21 +- .../search/service/EntityEventServiceTests.kt | 8 +- .../service/EntityPayloadServiceTests.kt | 17 +- .../search/service/EntityTypeServiceTests.kt | 18 +- .../search/service/QueryServiceTests.kt | 30 +- .../egm/stellio/search/support/TestUtils.kt | 60 +- .../util/AttributeInstanceUtilsTests.kt | 113 +- .../search/util/EntitiesQueryUtilsTests.kt | 5 +- ...=> TemporalEntitiesParameterizedSource.kt} | 2 +- .../TemporalEntityBuilderTests.kt | 30 +- ...t => TemporalEntityParameterizedSource.kt} | 2 +- .../web/EntityAccessControlHandlerTests.kt | 39 +- .../stellio/search/web/EntityHandlerTests.kt | 45 +- .../search/web/TemporalEntityHandlerTests.kt | 84 +- .../test/resources/junit-platform.properties | 1 + .../src/test/resources/ngsild/apiary.jsonld | 2 +- .../ngsild/aquac/BreedingService.json | 4 +- .../src/test/resources/ngsild/beehive.jsonld | 2 +- .../resources/ngsild/beehive_minimal.jsonld | 2 +- .../beehive_multi_instance_property.jsonld | 2 +- .../beehive_two_temporal_properties.jsonld | 2 +- .../resources/ngsild/beehive_with_sap.jsonld | 4 +- .../ngsild/beehive_with_scope.jsonld | 2 +- ...h_two_temporal_attributes_evolution.jsonld | 3 + ...ttributes_evolution_temporal_values.jsonld | 13 +- .../test/resources/ngsild/beekeeper.jsonld | 2 +- .../entity_with_all_attributes_1.jsonld | 2 +- .../entity_with_all_attributes_2.jsonld | 2 +- .../ngsild/entity_with_multi_types.jsonld | 2 +- .../beehive_aggregated_outgoing.jsonld | 20 +- .../beehive_empty_outgoing.jsonld | 14 +- .../beehive_incoming_multi_instances.jsonld | 137 +- ...ti_instances_string_temporal_values.jsonld | 33 +- ...oming_multi_instances_string_values.jsonld | 73 +- ..._instances_string_values_with_audit.jsonld | 99 +- ...ing_multi_instances_temporal_values.jsonld | 57 +- ...g_multi_instances_without_datasetId.jsonld | 61 +- ...ut_datasetId_string_temporal_values.jsonld | 27 +- ...ces_without_datasetId_string_values.jsonld | 61 +- ...s_without_datasetId_temporal_values.jsonld | 27 +- ...p_multi_instances_without_datasetId.jsonld | 61 +- .../beehive_scope_multi_instances.jsonld | 32 +- ...ope_multi_instances_temporal_values.jsonld | 26 +- .../expectations/query/two_beehives.json | 75 +- .../query/two_beehives_temporal_values.json | 52 +- ...oral_values_property_and_relationship.json | 92 +- .../resources/ngsild/hcmr/HCMR_test_file.json | 6 +- ..._test_file_one_entity_missing_context.json | 8 +- .../beehive_create_temporal_entity.jsonld | 2 +- ...eate_temporal_entity_first_instance.jsonld | 2 +- .../beehive_update_temporal_entity.jsonld | 4 +- ...alid_beehive_create_temporal_entity.jsonld | 2 +- .../ngsild/two_sensors_one_invalid.jsonld | 4 +- shared/build.gradle.kts | 2 + .../egm/stellio/shared/model/ApiExceptions.kt | 6 +- .../egm/stellio/shared/model/JsonLdEntity.kt | 2 +- .../egm/stellio/shared/model/NgsiLdEntity.kt | 22 +- .../com/egm/stellio/shared/util/AuthUtils.kt | 3 +- .../egm/stellio/shared/util/JsonLdUtils.kt | 215 +- .../com/egm/stellio/shared/util/JsonUtils.kt | 3 - .../stellio/shared/web/ExceptionHandler.kt | 4 +- .../contexts/fiware-datamodels-context.jsonld | 1891 ----------------- .../contexts/ngsi-ld-core-context-v1.3.jsonld | 223 -- .../contexts/ngsi-ld-core-context-v1.7.jsonld | 312 --- .../ngsi-ld-test-suite-compound.jsonld | 6 - .../contexts/ngsi-ld-test-suite.jsonld | 15 - shared/src/main/resources/jarcache.json | 27 - .../stellio/shared/model/NgsiLdEntityTests.kt | 25 +- .../egm/stellio/shared/util/ApiUtilsTests.kt | 6 +- .../stellio/shared/util/GeoQueryUtilsTests.kt | 23 +- .../stellio/shared/util/JsonLdUtilsTests.kt | 22 +- .../test/resources/junit-platform.properties | 2 + .../support/JsonLdContextServerExtension.kt | 59 + .../stellio/shared/util/JsonLdContextUtils.kt | 14 +- .../com/egm/stellio/shared/util/TestUtils.kt | 13 +- .../org.junit.jupiter.api.extension.Extension | 1 + .../resources/contexts/apic.jsonld | 38 - .../resources/contexts/egm.jsonld | 36 - .../src/testFixtures/resources/jarcache.json | 11 - .../jsonld-contexts/apic-compound.jsonld | 7 + .../resources/jsonld-contexts/apic.jsonld | 39 + .../jsonld-contexts/aquac-compound.jsonld | 7 + .../resources/jsonld-contexts/aquac.jsonld | 75 + .../authorization-compound.jsonld | 6 + .../jsonld-contexts/authorization.jsonld | 23 + .../resources/jsonld-contexts/egm.jsonld | 37 + .../ngsi-ld-core-context-v1.8.jsonld | 361 ++++ .../authorization/RightAddOnEntity.json | 2 +- .../authorization/RightRemoveOnEntity.json | 2 +- ...ributeAppendNumericPropDatasetIdEvent.json | 2 +- .../attributeAppendNumericPropEvent.json | 2 +- .../entity/attributeAppendRelEvent.json | 2 +- .../entity/attributeAppendTextPropEvent.json | 2 +- .../entity/attributeAppendTypeEvent.json | 2 +- .../attributeDeleteAllInstancesEvent.json | 2 +- .../events/entity/attributeDeleteEvent.json | 2 +- .../attributeReplaceNumericPropEvent.json | 2 +- .../entity/attributeReplaceRelEvent.json | 2 +- .../entity/attributeReplaceTextPropEvent.json | 2 +- ...ributeUpdateNumericPropDatasetIdEvent.json | 2 +- .../attributeUpdateNumericPropEvent.json | 2 +- .../entity/attributeUpdateRelEvent.json | 2 +- .../entity/attributeUpdateTextPropEvent.json | 2 +- .../events/entity/entityCreateEvent.json | 4 +- .../events/entity/entityDeleteEvent.json | 4 +- .../events/entity/entityReplaceEvent.json | 2 +- .../entity/invalid/humidityAppendEvent.jsonld | 2 +- subscription-service/build.gradle.kts | 1 - .../config/detekt/baseline.xml | 2 +- .../job/TimeIntervalNotificationJobTest.kt | 8 +- .../subscription/model/SubscriptionTest.kt | 23 +- .../service/NotificationServiceTests.kt | 12 +- .../service/SubscriptionServiceTests.kt | 25 +- .../subscription/support/FixtureUtils.kt | 8 +- .../subscription/utils/ParsingUtilsTests.kt | 5 +- .../test/resources/junit-platform.properties | 1 + .../ngsild/aquac/FeedingService.json | 7 +- .../src/test/resources/ngsild/beehive.jsonld | 2 +- .../src/test/resources/ngsild/beehive2.jsonld | 2 +- .../test/resources/ngsild/subscription.jsonld | 2 +- .../ngsild/subscription_update.jsonld | 2 +- ...icting_timeInterval_watchedAttributes.json | 2 +- 135 files changed, 2054 insertions(+), 3349 deletions(-) rename search-service/src/test/kotlin/com/egm/stellio/search/util/{QueryParameterizedTests.kt => TemporalEntitiesParameterizedSource.kt} (99%) rename search-service/src/test/kotlin/com/egm/stellio/search/{service => util}/TemporalEntityBuilderTests.kt (90%) rename search-service/src/test/kotlin/com/egm/stellio/search/util/{ParameterizedTests.kt => TemporalEntityParameterizedSource.kt} (99%) delete mode 100644 shared/src/main/resources/contexts/fiware-datamodels-context.jsonld delete mode 100644 shared/src/main/resources/contexts/ngsi-ld-core-context-v1.3.jsonld delete mode 100644 shared/src/main/resources/contexts/ngsi-ld-core-context-v1.7.jsonld delete mode 100644 shared/src/main/resources/contexts/ngsi-ld-test-suite-compound.jsonld delete mode 100644 shared/src/main/resources/contexts/ngsi-ld-test-suite.jsonld delete mode 100644 shared/src/main/resources/jarcache.json create mode 100644 shared/src/test/resources/junit-platform.properties create mode 100644 shared/src/testFixtures/kotlin/com/egm/stellio/shared/support/JsonLdContextServerExtension.kt create mode 100644 shared/src/testFixtures/resources/META-INF/services/org.junit.jupiter.api.extension.Extension delete mode 100644 shared/src/testFixtures/resources/contexts/apic.jsonld delete mode 100644 shared/src/testFixtures/resources/contexts/egm.jsonld delete mode 100644 shared/src/testFixtures/resources/jarcache.json create mode 100644 shared/src/testFixtures/resources/jsonld-contexts/apic-compound.jsonld create mode 100644 shared/src/testFixtures/resources/jsonld-contexts/apic.jsonld create mode 100644 shared/src/testFixtures/resources/jsonld-contexts/aquac-compound.jsonld create mode 100644 shared/src/testFixtures/resources/jsonld-contexts/aquac.jsonld create mode 100644 shared/src/testFixtures/resources/jsonld-contexts/authorization-compound.jsonld create mode 100644 shared/src/testFixtures/resources/jsonld-contexts/authorization.jsonld create mode 100644 shared/src/testFixtures/resources/jsonld-contexts/egm.jsonld create mode 100644 shared/src/testFixtures/resources/jsonld-contexts/ngsi-ld-core-context-v1.8.jsonld diff --git a/build.gradle.kts b/build.gradle.kts index 09c1ee862..0273717ce 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -63,7 +63,9 @@ subprojects { implementation("org.springframework.kafka:spring-kafka") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") - implementation("com.github.jsonld-java:jsonld-java:0.13.6") + + implementation("com.apicatalog:titanium-json-ld:1.3.3") + implementation("org.glassfish:jakarta.json:2.0.1") implementation("io.arrow-kt:arrow-fx-coroutines:1.2.1") @@ -82,6 +84,7 @@ subprojects { testImplementation("io.projectreactor:reactor-test") testImplementation("org.springframework.security:spring-security-test") testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test") + testImplementation("org.wiremock:wiremock-standalone:3.3.1") } tasks.withType { diff --git a/search-service/config/detekt/baseline.xml b/search-service/config/detekt/baseline.xml index 5efad94c5..263c11be1 100644 --- a/search-service/config/detekt/baseline.xml +++ b/search-service/config/detekt/baseline.xml @@ -10,6 +10,7 @@ LongMethod:AttributeInstanceService.kt$AttributeInstanceService$@Transactional suspend fun create(attributeInstance: AttributeInstance): Either<APIException, Unit> LongMethod:EntityAccessControlHandler.kt$EntityAccessControlHandler$@PostMapping("/{subjectId}/attrs", consumes = [MediaType.APPLICATION_JSON_VALUE, JSON_LD_CONTENT_TYPE]) suspend fun addRightsOnEntities( @RequestHeader httpHeaders: HttpHeaders, @PathVariable subjectId: String, @RequestBody requestBody: Mono<String> ): ResponseEntity<*> LongMethod:QueryServiceTests.kt$QueryServiceTests$@Test fun `it should query temporal entities as requested by query params`() + LongMethod:QueryServiceTests.kt$QueryServiceTests$@Test fun `it should return an empty list for an attribute if it has no temporal values`() LongMethod:TemporalEntityBuilderTests.kt$TemporalEntityBuilderTests$@Test fun `it should return a temporal entity with values aggregated`() LongMethod:TemporalScopeBuilderTests.kt$TemporalScopeBuilderTests$@Test fun `it should build an aggregated temporal representation of scopes`() LongMethod:V0_29__JsonLd_migration.kt$V0_29__JsonLd_migration$override fun migrate(context: Context) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/model/TemporalEntityAttribute.kt b/search-service/src/main/kotlin/com/egm/stellio/search/model/TemporalEntityAttribute.kt index 46e198142..aebef447e 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/model/TemporalEntityAttribute.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/model/TemporalEntityAttribute.kt @@ -1,6 +1,9 @@ package com.egm.stellio.search.model import com.egm.stellio.shared.util.ExpandedTerm +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_GEOPROPERTY_TYPE +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_TYPE +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_TYPE import io.r2dbc.postgresql.codec.Json import org.springframework.data.annotation.Id import java.net.URI @@ -35,6 +38,13 @@ data class TemporalEntityAttribute( enum class AttributeType { Property, Relationship, - GeoProperty + GeoProperty; + + fun toNgsiLdExpanded(): String = + when (this) { + Property -> NGSILD_PROPERTY_TYPE.uri + Relationship -> NGSILD_RELATIONSHIP_TYPE.uri + GeoProperty -> NGSILD_GEOPROPERTY_TYPE.uri + } } } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityEventService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityEventService.kt index 2fa67b034..b66486f5a 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityEventService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityEventService.kt @@ -6,6 +6,7 @@ import com.egm.stellio.search.model.UpdateOperationResult import com.egm.stellio.search.model.UpdateResult import com.egm.stellio.search.model.UpdatedDetails import com.egm.stellio.shared.model.* +import com.egm.stellio.shared.util.ExpandedAttributes import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.getAttributeFromExpandedAttributes @@ -254,7 +255,11 @@ class EntityEventService( when (attributeName) { JSONLD_TYPE -> Pair(JSONLD_TYPE, serializeObject(jsonLdAttributes[JSONLD_TYPE]!!)) else -> { - val extractedPayload = getAttributeFromExpandedAttributes(jsonLdAttributes, attributeName, datasetId)!! + val extractedPayload = getAttributeFromExpandedAttributes( + jsonLdAttributes as ExpandedAttributes, + attributeName, + datasetId + )!! Pair(attributeName, serializeObject(extractedPayload)) } } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/QueryService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/QueryService.kt index 3ee97c9af..66a23e219 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/QueryService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/QueryService.kt @@ -9,7 +9,9 @@ import com.egm.stellio.search.model.* import com.egm.stellio.search.scope.ScopeService import com.egm.stellio.search.util.TemporalEntityBuilder import com.egm.stellio.search.util.deserializeAsMap -import com.egm.stellio.shared.model.* +import com.egm.stellio.shared.model.APIException +import com.egm.stellio.shared.model.JsonLdEntity +import com.egm.stellio.shared.model.ResourceNotFoundException import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY import com.egm.stellio.shared.util.entityOrAttrsNotFoundMessage import com.egm.stellio.shared.util.wktToGeoJson @@ -55,7 +57,7 @@ class QueryService( entityId: URI, temporalEntitiesQuery: TemporalEntitiesQuery, contextLink: String - ): Either = either { + ): Either = either { val attrs = temporalEntitiesQuery.entitiesQuery.attrs val temporalEntityAttributes = temporalEntityAttributeService.getForEntity(entityId, attrs).let { if (it.isEmpty()) @@ -124,7 +126,7 @@ class QueryService( suspend fun queryTemporalEntities( temporalEntitiesQuery: TemporalEntitiesQuery, accessRightFilter: () -> String? - ): Either, Int>> = either { + ): Either, Int>> = either { val attrs = temporalEntitiesQuery.entitiesQuery.attrs val entitiesIds = entityPayloadService.queryEntities(temporalEntitiesQuery.entitiesQuery, accessRightFilter) val count = entityPayloadService.queryEntitiesCount(temporalEntitiesQuery.entitiesQuery, accessRightFilter) @@ -132,7 +134,7 @@ class QueryService( // we can have an empty list of entities with a non-zero count (e.g., offset too high) if (entitiesIds.isEmpty()) - return@either Pair, Int>(emptyList(), count) + return@either Pair, Int>(emptyList(), count) val temporalEntityAttributes = temporalEntityAttributeService.getForTemporalEntities( entitiesIds, diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt index 96a6e4130..2e1089641 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt @@ -150,7 +150,7 @@ class TemporalEntityAttributeService( .forEach { val (expandedAttributeName, attributeMetadata) = it val attributePayload = getAttributeFromExpandedAttributes( - jsonLdEntity.members, + jsonLdEntity.getAttributes(), expandedAttributeName, attributeMetadata.datasetId )!! diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt index 524011dc0..4295c3686 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt @@ -2,14 +2,20 @@ package com.egm.stellio.search.util import com.egm.stellio.search.model.* import com.egm.stellio.search.scope.TemporalScopeBuilder -import com.egm.stellio.shared.model.CompactedJsonLdEntity -import com.egm.stellio.shared.util.* -import com.egm.stellio.shared.util.AuthContextModel.AUTH_TERM_SUB -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_CONTEXT +import com.egm.stellio.shared.model.JsonLdEntity +import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SUB +import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE_TERM +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE_TERM -import com.egm.stellio.shared.util.JsonLdUtils.compactFragment +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_GEOPROPERTY_TYPE +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PREFIX +import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue +import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedPropertyValue +import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue +import com.egm.stellio.shared.util.JsonUtils +import com.egm.stellio.shared.util.wktToGeoJson typealias SimplifiedTemporalAttribute = Map typealias TemporalEntityAttributeInstancesResult = Map> @@ -20,7 +26,7 @@ object TemporalEntityBuilder { queryResult: List, temporalEntitiesQuery: TemporalEntitiesQuery, contexts: List - ): List = + ): List = queryResult.map { buildTemporalEntity(it, temporalEntitiesQuery, contexts) } @@ -29,11 +35,10 @@ object TemporalEntityBuilder { entityTemporalResult: EntityTemporalResult, temporalEntitiesQuery: TemporalEntitiesQuery, contexts: List - ): CompactedJsonLdEntity { + ): JsonLdEntity { val temporalAttributes = buildTemporalAttributes( entityTemporalResult.teaInstancesResult, - temporalEntitiesQuery, - contexts + temporalEntitiesQuery ) val scopeAttributeInstances = TemporalScopeBuilder.buildScopeAttributeInstances( @@ -42,69 +47,47 @@ object TemporalEntityBuilder { temporalEntitiesQuery ) - return entityTemporalResult.entityPayload.serializeProperties( - withCompactTerms = true, - contexts - ).plus(temporalAttributes) + val expandedTemporalEntity = entityTemporalResult.entityPayload.serializeProperties() + .plus(temporalAttributes) .plus(scopeAttributeInstances) + return JsonLdEntity(expandedTemporalEntity, contexts) } private fun buildTemporalAttributes( attributeAndResultsMap: TemporalEntityAttributeInstancesResult, temporalEntitiesQuery: TemporalEntitiesQuery, - contexts: List ): Map = if (temporalEntitiesQuery.withTemporalValues) { val attributes = buildAttributesSimplifiedRepresentation(attributeAndResultsMap) mergeSimplifiedTemporalAttributesOnAttributeName(attributes) - .mapKeys { JsonLdUtils.compactTerm(it.key, contexts) } - .mapValues { - if (it.value.size == 1) it.value.first() - else it.value - } } else if (temporalEntitiesQuery.withAggregatedValues) { val attributes = buildAttributesAggregatedRepresentation( attributeAndResultsMap, temporalEntitiesQuery.temporalQuery.aggrMethods!! ) mergeSimplifiedTemporalAttributesOnAttributeName(attributes) - .mapKeys { JsonLdUtils.compactTerm(it.key, contexts) } - .mapValues { - if (it.value.size == 1) it.value.first() - else it.value - } } else { mergeFullTemporalAttributesOnAttributeName(attributeAndResultsMap) - .mapKeys { JsonLdUtils.compactTerm(it.key, contexts) } .mapValues { (_, attributeInstanceResults) -> attributeInstanceResults.map { attributeInstanceResult -> JsonUtils.deserializeObject(attributeInstanceResult.payload) .let { instancePayload -> injectSub(temporalEntitiesQuery, attributeInstanceResult, instancePayload) - }.let { instancePayload -> - compactAttributeInstance(instancePayload, contexts) }.let { instancePayload -> convertGeoProperty(instancePayload) }.plus( - attributeInstanceResult.timeproperty to attributeInstanceResult.time.toNgsiLdFormat() + Pair( + NGSILD_PREFIX + attributeInstanceResult.timeproperty, + buildNonReifiedTemporalValue(attributeInstanceResult.time) + ) ) } } } - // FIXME in the history of attributes, we have a mix of - // - compacted fragments (before v2) - // - expanded fragments (since v2) - // to avoid un-necessary (expensive) compactions, quick check to see if the fragment - // is already compacted - private fun compactAttributeInstance(instancePayload: Map, contexts: List): Map = - if (instancePayload.containsKey(JSONLD_TYPE)) - compactFragment(instancePayload, contexts).minus(JSONLD_CONTEXT) - else instancePayload - private fun convertGeoProperty(instancePayload: Map): Map = - if (instancePayload[JSONLD_TYPE_TERM] == "GeoProperty") - instancePayload.plus(JSONLD_VALUE_TERM to wktToGeoJson(instancePayload[JSONLD_VALUE_TERM]!! as String)) + if (instancePayload[JSONLD_TYPE] == NGSILD_GEOPROPERTY_TYPE.uri) + instancePayload.plus(JSONLD_VALUE to wktToGeoJson(instancePayload[JSONLD_VALUE_TERM]!! as String)) else instancePayload private fun injectSub( @@ -113,7 +96,7 @@ object TemporalEntityBuilder { instancePayload: Map ): Map = if (temporalEntitiesQuery.withAudit && attributeInstanceResult.sub != null) - instancePayload.plus(Pair(AUTH_TERM_SUB, attributeInstanceResult.sub)) + instancePayload.plus(Pair(AUTH_PROP_SUB, buildExpandedPropertyValue(attributeInstanceResult.sub))) else instancePayload /** @@ -129,9 +112,11 @@ object TemporalEntityBuilder { ): Map { return attributeAndResultsMap.mapValues { val attributeInstance = mutableMapOf( - JSONLD_TYPE_TERM to it.key.attributeType.toString() + JSONLD_TYPE to listOf(it.key.attributeType.toNgsiLdExpanded()) ) - it.key.datasetId?.let { datasetId -> attributeInstance["datasetId"] = datasetId } + it.key.datasetId?.let { datasetId -> + attributeInstance[NGSILD_DATASET_ID_PROPERTY] = buildNonReifiedPropertyValue(datasetId.toString()) + } val valuesKey = when (it.key.attributeType) { TemporalEntityAttribute.AttributeType.Property -> "values" @@ -160,21 +145,24 @@ object TemporalEntityBuilder { ): Map { return attributeAndResultsMap.mapValues { val attributeInstance = mutableMapOf( - JSONLD_TYPE_TERM to it.key.attributeType.toString() + JSONLD_TYPE to listOf(it.key.attributeType.toNgsiLdExpanded()) ) - it.key.datasetId?.let { datasetId -> attributeInstance["datasetId"] = datasetId } + it.key.datasetId?.let { datasetId -> + attributeInstance[NGSILD_DATASET_ID_PROPERTY] = buildNonReifiedPropertyValue(datasetId.toString()) + } + + val aggregatedResultsForTEA = it.value + .map { attributeInstanceResult -> + attributeInstanceResult as AggregatedAttributeInstanceResult + attributeInstanceResult.values + } + .flatten() aggrMethods.forEach { aggregate -> - val valuesForAggregate = it.value - .map { attributeInstanceResult -> - attributeInstanceResult as AggregatedAttributeInstanceResult - attributeInstanceResult.values - } - .flatten() - .filter { aggregateResult -> - aggregateResult.aggregate == aggregate - } - attributeInstance[aggregate.method] = valuesForAggregate.map { aggregateResult -> + val resultsForAggregate = aggregatedResultsForTEA.filter { aggregateResult -> + aggregateResult.aggregate.method == aggregate.method + } + attributeInstance[aggregate.method] = resultsForAggregate.map { aggregateResult -> listOf(aggregateResult.value, aggregateResult.startDateTime, aggregateResult.endDateTime) } } @@ -221,15 +209,3 @@ object TemporalEntityBuilder { } } } - -/** - * A specific application of sysAttrs option to temporal entities, that only applies it to the entity and not to the - * attributes. Currently, this is not clear what should be done for attributes who already convey specifically asked - * temporal information. - */ -fun CompactedJsonLdEntity.applySysAttrs(includeSysAttrs: Boolean) = - this.let { - if (!includeSysAttrs) - it.minus(JsonLdUtils.NGSILD_SYSATTRS_TERMS) - else it - } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt index c8b636549..d474e8e8a 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt @@ -3,12 +3,10 @@ package com.egm.stellio.search.web import arrow.core.raise.either import com.egm.stellio.search.authorization.AuthorizationService import com.egm.stellio.search.service.* -import com.egm.stellio.search.util.applySysAttrs import com.egm.stellio.search.util.composeTemporalEntitiesQuery import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.* -import com.egm.stellio.shared.util.JsonLdUtils.addContextsToEntity import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute import com.egm.stellio.shared.util.JsonLdUtils.expandAttributes import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity @@ -145,16 +143,20 @@ class TemporalEntityHandler( val accessRightFilter = authorizationService.computeAccessRightFilter(sub) - val includeSysAttrs = params.contains(QUERY_PARAM_OPTIONS_SYSATTRS_VALUE) val (temporalEntities, total) = queryService.queryTemporalEntities( temporalEntitiesQuery, accessRightFilter - ).bind().let { - Pair(it.first.map { it.applySysAttrs(includeSysAttrs) }, it.second) - } + ).bind() + + val compactedEntities = JsonLdUtils.compactEntities( + temporalEntities, + contextLink, + mediaType + ) + val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) buildQueryResponse( - serializeObject(temporalEntities.map { addContextsToEntity(it, listOf(contextLink), mediaType) }), + compactedEntities.toFinalRepresentation(ngsiLdDataRepresentation), total, "/ngsi-ld/v1/temporal/entities", temporalEntitiesQuery.entitiesQuery.paginationQuery, @@ -174,7 +176,7 @@ class TemporalEntityHandler( suspend fun getForEntity( @RequestHeader httpHeaders: HttpHeaders, @PathVariable entityId: URI, - @RequestParam requestParams: MultiValueMap + @RequestParam params: MultiValueMap ): ResponseEntity<*> = either { val sub = getSubFromSecurityContext() @@ -186,18 +188,19 @@ class TemporalEntityHandler( authorizationService.userCanReadEntity(entityId, sub).bind() val temporalEntitiesQuery = - composeTemporalEntitiesQuery(applicationProperties.pagination, requestParams, contextLink).bind() + composeTemporalEntitiesQuery(applicationProperties.pagination, params, contextLink).bind() - val includeSysAttrs = requestParams.contains(QUERY_PARAM_OPTIONS_SYSATTRS_VALUE) val temporalEntity = queryService.queryTemporalEntity( entityId, temporalEntitiesQuery, contextLink ).bind() - .applySysAttrs(includeSysAttrs) + val compactedEntity = JsonLdUtils.compactEntity(temporalEntity, contextLink, mediaType).toMutableMap() + + val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) prepareGetSuccessResponse(mediaType, contextLink) - .body(serializeObject(addContextsToEntity(temporalEntity, listOf(contextLink), mediaType))) + .body(serializeObject(compactedEntity.toFinalRepresentation(ngsiLdDataRepresentation))) }.fold( { it.toErrorResponse() }, { it } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityOperationsHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityOperationsHandler.kt index d0b596ec4..7844afe9e 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityOperationsHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityOperationsHandler.kt @@ -3,12 +3,10 @@ package com.egm.stellio.search.web import arrow.core.raise.either import com.egm.stellio.search.authorization.AuthorizationService import com.egm.stellio.search.service.QueryService -import com.egm.stellio.search.util.applySysAttrs import com.egm.stellio.search.util.composeTemporalEntitiesQueryFromPostRequest import com.egm.stellio.shared.config.ApplicationProperties +import com.egm.stellio.shared.model.toFinalRepresentation import com.egm.stellio.shared.util.* -import com.egm.stellio.shared.util.JsonLdUtils.addContextsToEntity -import com.egm.stellio.shared.util.JsonUtils.serializeObject import kotlinx.coroutines.reactive.awaitFirst import org.springframework.http.HttpHeaders import org.springframework.http.MediaType @@ -48,16 +46,21 @@ class TemporalEntityOperationsHandler( val accessRightFilter = authorizationService.computeAccessRightFilter(sub) - val includeSysAttrs = params.contains(QUERY_PARAM_OPTIONS_SYSATTRS_VALUE) val (temporalEntities, total) = queryService.queryTemporalEntities( temporalEntitiesQuery, accessRightFilter - ).bind().let { - Pair(it.first.map { it.applySysAttrs(includeSysAttrs) }, it.second) - } + ).bind() + + val compactedEntities = JsonLdUtils.compactEntities( + temporalEntities, + contextLink, + mediaType + ) + + val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) buildQueryResponse( - serializeObject(temporalEntities.map { addContextsToEntity(it, listOf(contextLink), mediaType) }), + compactedEntities.toFinalRepresentation(ngsiLdDataRepresentation), total, "/ngsi-ld/v1/temporal/entities", temporalEntitiesQuery.entitiesQuery.paginationQuery, diff --git a/search-service/src/main/kotlin/db/migration/V0_29__JsonLd_migration.kt b/search-service/src/main/kotlin/db/migration/V0_29__JsonLd_migration.kt index c1be0aabf..72848583b 100644 --- a/search-service/src/main/kotlin/db/migration/V0_29__JsonLd_migration.kt +++ b/search-service/src/main/kotlin/db/migration/V0_29__JsonLd_migration.kt @@ -6,11 +6,8 @@ import com.egm.stellio.search.model.TemporalEntityAttribute import com.egm.stellio.search.util.guessPropertyValueType import com.egm.stellio.search.util.toTemporalAttributeMetadata import com.egm.stellio.shared.model.* -import com.egm.stellio.shared.util.AuthContextModel +import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SAP -import com.egm.stellio.shared.util.ExpandedAttributeInstance -import com.egm.stellio.shared.util.ExpandedTerm -import com.egm.stellio.shared.util.JsonLdUtils.EGM_BASE_CONTEXT_URL import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_EXPANDED_ENTITY_CORE_MEMBERS import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY @@ -23,7 +20,6 @@ import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMapAsDateTime import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMapAsString import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import com.egm.stellio.shared.util.JsonUtils.serializeObject -import com.egm.stellio.shared.util.toUri import kotlinx.coroutines.runBlocking import org.flywaydb.core.api.migration.BaseJavaMigration import org.flywaydb.core.api.migration.Context @@ -38,6 +34,8 @@ import java.util.UUID const val EGM_NO_BRANCH_BASE_CONTEXT_URL = "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models" +const val EGM_BASE_CONTEXT_URL = "https://dataflow.stellio.io/jsonld-contexts" + @Suppress("unused") class V0_29__JsonLd_migration : BaseJavaMigration() { @@ -96,7 +94,11 @@ class V0_29__JsonLd_migration : BaseJavaMigration() { // extract specific access policy (if any) from the payload to be able to store it in entity_payload // then remove it from the expanded payload val specificAccessPolicy = - getAttributeFromExpandedAttributes(originalExpandedEntity, AUTH_PROP_SAP, null)?.let { + getAttributeFromExpandedAttributes( + originalExpandedEntity as ExpandedAttributes, + AUTH_PROP_SAP, + null + )?.let { getPropertyValueFromMapAsString(it, NGSILD_PROPERTY_VALUE) }?.let { AuthContextModel.SpecificAccessPolicy.valueOf(it) @@ -148,7 +150,7 @@ class V0_29__JsonLd_migration : BaseJavaMigration() { ngsiLdAttribute.getAttributeInstances().forEach { ngsiLdAttributeInstance -> val datasetId = ngsiLdAttributeInstance.datasetId val attributePayload = getAttributeFromExpandedAttributes( - jsonLdEntity.members, + jsonLdEntity.getAttributes(), attributeName, datasetId )!! diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/AuthorizationServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/AuthorizationServiceTests.kt index 3b2b68514..71bf18013 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/AuthorizationServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/AuthorizationServiceTests.kt @@ -3,7 +3,7 @@ package com.egm.stellio.search.authorization import arrow.core.None import com.egm.stellio.search.model.EntitiesQuery import com.egm.stellio.shared.model.PaginationQuery -import com.egm.stellio.shared.util.AuthContextModel.AUTHORIZATION_COMPOUND_CONTEXT +import com.egm.stellio.shared.util.AUTHZ_TEST_COMPOUND_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT import com.egm.stellio.shared.util.shouldSucceedWith import com.egm.stellio.shared.util.toUri @@ -47,7 +47,7 @@ class AuthorizationServiceTests { authorizationService.getGroupsMemberships( 0, 0, - AUTHORIZATION_COMPOUND_CONTEXT, + AUTHZ_TEST_COMPOUND_CONTEXT, None ).shouldSucceedWith { assertEquals(-1, it.first) @@ -60,7 +60,7 @@ class AuthorizationServiceTests { authorizationService.getUsers( 0, 0, - AUTHORIZATION_COMPOUND_CONTEXT + AUTHZ_TEST_COMPOUND_CONTEXT ).shouldSucceedWith { assertEquals(-1, it.first) assertEquals(0, it.second.size) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationServiceTests.kt index f1b3508c9..2a466805d 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationServiceTests.kt @@ -8,7 +8,6 @@ import com.egm.stellio.search.model.EntitiesQuery import com.egm.stellio.shared.model.AccessDeniedException import com.egm.stellio.shared.model.PaginationQuery import com.egm.stellio.shared.util.* -import com.egm.stellio.shared.util.AuthContextModel.AUTHORIZATION_COMPOUND_CONTEXT import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_USERNAME import com.egm.stellio.shared.util.AuthContextModel.AUTH_REL_CAN_WRITE import com.egm.stellio.shared.util.AuthContextModel.GROUP_ENTITY_PREFIX @@ -251,7 +250,7 @@ class EnabledAuthorizationServiceTests { ) coEvery { subjectReferentialService.getCountAllGroups() } returns Either.Right(2) - enabledAuthorizationService.getGroupsMemberships(0, 2, AUTHORIZATION_COMPOUND_CONTEXT, Some(subjectUuid)) + enabledAuthorizationService.getGroupsMemberships(0, 2, AUTHZ_TEST_COMPOUND_CONTEXT, Some(subjectUuid)) .shouldSucceedWith { assertEquals(2, it.first) it.second.forEach { jsonLdEntity -> @@ -276,7 +275,7 @@ class EnabledAuthorizationServiceTests { ) coEvery { subjectReferentialService.getCountGroups(any()) } returns Either.Right(1) - enabledAuthorizationService.getGroupsMemberships(0, 2, AUTHORIZATION_COMPOUND_CONTEXT, Some(subjectUuid)) + enabledAuthorizationService.getGroupsMemberships(0, 2, AUTHZ_TEST_COMPOUND_CONTEXT, Some(subjectUuid)) .shouldSucceedWith { assertEquals(1, it.first) assertEquals(1, it.second[0].types.size) @@ -310,7 +309,7 @@ class EnabledAuthorizationServiceTests { ) coEvery { subjectReferentialService.getUsersCount() } returns Either.Right(2) - enabledAuthorizationService.getUsers(0, 2, AUTHORIZATION_COMPOUND_CONTEXT) + enabledAuthorizationService.getUsers(0, 2, AUTHZ_TEST_COMPOUND_CONTEXT) .shouldSucceedWith { assertEquals(2, it.first) it.second.forEach { jsonLdEntity -> diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt index 83c03c1ea..a569415a5 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt @@ -8,7 +8,6 @@ import com.egm.stellio.search.support.WithTimescaleContainer import com.egm.stellio.shared.model.AccessDeniedException import com.egm.stellio.shared.model.PaginationQuery import com.egm.stellio.shared.util.* -import com.egm.stellio.shared.util.AuthContextModel.AUTHORIZATION_COMPOUND_CONTEXT import com.egm.stellio.shared.util.AuthContextModel.AUTH_TERM_NAME import com.egm.stellio.shared.util.AuthContextModel.CLIENT_ENTITY_PREFIX import com.egm.stellio.shared.util.AuthContextModel.GROUP_ENTITY_PREFIX @@ -544,7 +543,7 @@ class EntityAccessRightsServiceTests : WithTimescaleContainer { ) { val rawEntity = if (specificAccessPolicy != null) - loadMinimalEntityWithSap(entityId, types, specificAccessPolicy, setOf(AUTHORIZATION_COMPOUND_CONTEXT)) + loadMinimalEntityWithSap(entityId, types, specificAccessPolicy, setOf(AUTHZ_TEST_COMPOUND_CONTEXT)) else loadMinimalEntity(entityId, types) rawEntity.sampleDataToNgsiLdEntity().map { entityPayloadService.createEntityPayload( diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeServiceTests.kt index 16c039ffb..75860f489 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeServiceTests.kt @@ -16,7 +16,8 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_TERM import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired @@ -42,13 +43,9 @@ class AttributeServiceTests : WithTimescaleContainer, WithKafkaContainer { private val now = Instant.now().atZone(ZoneOffset.UTC) - private val entityPayload1 = newEntityPayload( - "urn:ngsi-ld:BeeHive:TESTA", - listOf(BEEHIVE_TYPE, SENSOR_TYPE), - DEVICE_COMPACT_TYPE - ) - private val entityPayload2 = newEntityPayload("urn:ngsi-ld:Sensor:TESTB", listOf(SENSOR_TYPE), DEVICE_COMPACT_TYPE) - private val entityPayload3 = newEntityPayload("urn:ngsi-ld:Apiary:TESTC", listOf(APIARY_TYPE), DEVICE_COMPACT_TYPE) + private val entityPayload1 = newEntityPayload("urn:ngsi-ld:BeeHive:TESTA", listOf(BEEHIVE_TYPE, SENSOR_TYPE)) + private val entityPayload2 = newEntityPayload("urn:ngsi-ld:Sensor:TESTB", listOf(SENSOR_TYPE)) + private val entityPayload3 = newEntityPayload("urn:ngsi-ld:Apiary:TESTC", listOf(APIARY_TYPE)) private val temporalEntityAttribute1 = newTemporalEntityAttribute( "urn:ngsi-ld:BeeHive:TESTA", INCOMING_PROPERTY, @@ -233,12 +230,16 @@ class AttributeServiceTests : WithTimescaleContainer, WithKafkaContainer { .execute() } - private fun newEntityPayload(id: String, types: List, contexts: String): EntityPayload = + private fun newEntityPayload( + id: String, + types: List, + context: String = APIC_COMPOUND_CONTEXT + ): EntityPayload = EntityPayload( entityId = toUri(id), types = types, createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(contexts) + contexts = listOf(context) ) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityEventServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityEventServiceTests.kt index 1dff12870..695a8e1a0 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityEventServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityEventServiceTests.kt @@ -9,7 +9,7 @@ import com.egm.stellio.search.support.EMPTY_PAYLOAD import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute -import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdFragment +import com.egm.stellio.shared.util.JsonLdUtils.expandAttributes import com.egm.stellio.shared.util.JsonUtils.serializeObject import com.egm.stellio.shared.web.DEFAULT_TENANT_URI import com.ninjasquad.springmockk.MockkBean @@ -212,7 +212,7 @@ class EntityEventServiceTests { "$fishNumberTerm": $fishNumberAttributeFragment } """.trimIndent() - val jsonLdAttributes = expandJsonLdFragment(attributesPayload, listOf(AQUAC_COMPOUND_CONTEXT)) + val jsonLdAttributes = expandAttributes(attributesPayload, listOf(AQUAC_COMPOUND_CONTEXT)) val appendResult = UpdateResult( listOf( UpdatedDetails(fishNumberProperty, null, UpdateOperationResult.APPENDED), @@ -278,7 +278,7 @@ class EntityEventServiceTests { "$fishNumberTerm": $fishNumberAttributeFragment } """.trimIndent() - val jsonLdAttributes = expandJsonLdFragment(attributesPayload, listOf(AQUAC_COMPOUND_CONTEXT)) + val jsonLdAttributes = expandAttributes(attributesPayload, listOf(AQUAC_COMPOUND_CONTEXT)) val updateResult = UpdateResult( updated = arrayListOf( UpdatedDetails(fishNameProperty, fishName1DatasetUri, UpdateOperationResult.REPLACED), @@ -338,7 +338,7 @@ class EntityEventServiceTests { "$fishNameTerm": [$fishNameAttributeFragment, $fishNameAttributeFragment2] } """.trimIndent() - val jsonLdAttributes = expandJsonLdFragment(attributePayload, listOf(AQUAC_COMPOUND_CONTEXT)) + val jsonLdAttributes = expandAttributes(attributePayload, listOf(AQUAC_COMPOUND_CONTEXT)) val updateResult = UpdateResult( updated = arrayListOf( UpdatedDetails(fishNameProperty, fishName1DatasetUri, UpdateOperationResult.REPLACED), diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityPayloadServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityPayloadServiceTests.kt index c5e6b83ca..fedfcbb76 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityPayloadServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityPayloadServiceTests.kt @@ -2,19 +2,14 @@ package com.egm.stellio.search.service import arrow.core.right import com.egm.stellio.search.model.* -import com.egm.stellio.search.support.EMPTY_PAYLOAD -import com.egm.stellio.search.support.WithKafkaContainer -import com.egm.stellio.search.support.WithTimescaleContainer -import com.egm.stellio.search.support.buildSapAttribute +import com.egm.stellio.search.support.* import com.egm.stellio.search.util.deserializeAsMap import com.egm.stellio.shared.model.AlreadyExistsException import com.egm.stellio.shared.model.ResourceNotFoundException import com.egm.stellio.shared.util.* -import com.egm.stellio.shared.util.AuthContextModel.AUTHORIZATION_COMPOUND_CONTEXT import com.egm.stellio.shared.util.AuthContextModel.SpecificAccessPolicy.AUTH_READ import com.egm.stellio.shared.util.AuthContextModel.SpecificAccessPolicy.AUTH_WRITE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DEFAULT_VOCAB import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute @@ -84,7 +79,7 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should create an entity payload from string with specificAccessPolicy`() = runTest { - loadMinimalEntityWithSap(entity01Uri, setOf(BEEHIVE_TYPE), AUTH_READ, setOf(AUTHORIZATION_COMPOUND_CONTEXT)) + loadMinimalEntityWithSap(entity01Uri, setOf(BEEHIVE_TYPE), AUTH_READ, setOf(AUTHZ_TEST_COMPOUND_CONTEXT)) .sampleDataToNgsiLdEntity() .map { entityPayloadService.createEntityPayload( @@ -93,7 +88,7 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { now ) } - loadMinimalEntityWithSap(entity02Uri, setOf(BEEHIVE_TYPE), AUTH_WRITE, setOf(AUTHORIZATION_COMPOUND_CONTEXT)) + loadMinimalEntityWithSap(entity02Uri, setOf(BEEHIVE_TYPE), AUTH_WRITE, setOf(AUTHZ_TEST_COMPOUND_CONTEXT)) .sampleDataToNgsiLdEntity() .map { entityPayloadService.createEntityPayload( @@ -434,14 +429,14 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { .hasFieldOrPropertyWithValue("types", listOf(BEEHIVE_TYPE)) .hasFieldOrPropertyWithValue("createdAt", now) .hasFieldOrPropertyWithValue("modifiedAt", null) - .hasFieldOrPropertyWithValue("contexts", listOf(NGSILD_CORE_CONTEXT)) + .hasFieldOrPropertyWithValue("contexts", listOf(NGSILD_TEST_CORE_CONTEXT)) .hasFieldOrPropertyWithValue("specificAccessPolicy", null) } } @Test fun `it should retrieve an entity payload with specificAccesPolicy`() = runTest { - loadMinimalEntityWithSap(entity01Uri, setOf(BEEHIVE_TYPE), AUTH_READ, setOf(AUTHORIZATION_COMPOUND_CONTEXT)) + loadMinimalEntityWithSap(entity01Uri, setOf(BEEHIVE_TYPE), AUTH_READ, setOf(AUTHZ_TEST_COMPOUND_CONTEXT)) .sampleDataToNgsiLdEntity() .map { entityPayloadService.createEntityPayload( @@ -712,7 +707,7 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should remove a specific access policy from a entity payload`() = runTest { - loadMinimalEntityWithSap(entity01Uri, setOf(BEEHIVE_TYPE), AUTH_READ, setOf(AUTHORIZATION_COMPOUND_CONTEXT)) + loadMinimalEntityWithSap(entity01Uri, setOf(BEEHIVE_TYPE), AUTH_READ, setOf(AUTHZ_TEST_COMPOUND_CONTEXT)) .sampleDataToNgsiLdEntity() .map { entityPayloadService.createEntityPayload( diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityTypeServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityTypeServiceTests.kt index 5e68807e3..b5551d30d 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityTypeServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityTypeServiceTests.kt @@ -43,13 +43,9 @@ class EntityTypeServiceTests : WithTimescaleContainer, WithKafkaContainer { private val now = Instant.now().atZone(ZoneOffset.UTC) - private val entityPayload1 = newEntityPayload( - "urn:ngsi-ld:BeeHive:TESTA", - listOf(BEEHIVE_TYPE, SENSOR_TYPE), - DEVICE_COMPACT_TYPE - ) - private val entityPayload2 = newEntityPayload("urn:ngsi-ld:Sensor:TESTB", listOf(SENSOR_TYPE), DEVICE_COMPACT_TYPE) - private val entityPayload3 = newEntityPayload("urn:ngsi-ld:Apiary:TESTC", listOf(APIARY_TYPE), DEVICE_COMPACT_TYPE) + private val entityPayload1 = newEntityPayload("urn:ngsi-ld:BeeHive:TESTA", listOf(BEEHIVE_TYPE, SENSOR_TYPE)) + private val entityPayload2 = newEntityPayload("urn:ngsi-ld:Sensor:TESTB", listOf(SENSOR_TYPE)) + private val entityPayload3 = newEntityPayload("urn:ngsi-ld:Apiary:TESTC", listOf(APIARY_TYPE)) private val temporalEntityAttribute1 = newTemporalEntityAttribute( "urn:ngsi-ld:BeeHive:TESTA", INCOMING_PROPERTY, @@ -242,12 +238,16 @@ class EntityTypeServiceTests : WithTimescaleContainer, WithKafkaContainer { .execute() } - private fun newEntityPayload(id: String, types: List, contexts: String): EntityPayload = + private fun newEntityPayload( + id: String, + types: List, + context: String = APIC_COMPOUND_CONTEXT + ): EntityPayload = EntityPayload( entityId = toUri(id), types = types, createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(contexts) + contexts = listOf(context) ) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/QueryServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/QueryServiceTests.kt index 5e28a05ed..1a1c3c834 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/QueryServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/QueryServiceTests.kt @@ -11,6 +11,7 @@ import com.egm.stellio.search.support.buildDefaultQueryParams import com.egm.stellio.shared.model.PaginationQuery import com.egm.stellio.shared.model.ResourceNotFoundException import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_TERM import com.ninjasquad.springmockk.MockkBean import io.mockk.coEvery @@ -382,17 +383,28 @@ class QueryServiceTests { assertJsonPayloadsAreEqual( """ { - "id": "urn:ngsi-ld:BeeHive:TESTC", - "type": "BeeHive", - "createdAt": "$now", - "incoming": { - "type": "Property", - "avg": [] - } + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://uri.etsi.org/ngsi-ld/createdAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "$now" + } + ], + "https://ontology.eglobalmark.com/apic#incoming":[ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "avg": [] + } + ] } """.trimIndent(), - JsonUtils.serializeObject(it.first[0]), - setOf(NGSILD_CREATED_AT_TERM) + JsonUtils.serializeObject(it.first[0].members), + setOf(NGSILD_CREATED_AT_PROPERTY) ) }) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/support/TestUtils.kt b/search-service/src/test/kotlin/com/egm/stellio/search/support/TestUtils.kt index 7baad6380..10e2c3752 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/support/TestUtils.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/support/TestUtils.kt @@ -2,10 +2,20 @@ package com.egm.stellio.search.support import com.egm.stellio.search.model.TemporalEntityAttribute import com.egm.stellio.shared.model.NgsiLdAttribute -import com.egm.stellio.shared.model.toNgsiLdAttribute +import com.egm.stellio.shared.model.toNgsiLdAttributes import com.egm.stellio.shared.util.AuthContextModel -import com.egm.stellio.shared.util.AuthContextModel.AUTH_TERM_SAP -import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute +import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SAP +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_INSTANCE_ID_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_HAS_OBJECT +import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue +import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedPropertyValue +import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue import com.egm.stellio.shared.util.JsonUtils.serializeObject import com.egm.stellio.shared.util.shouldSucceedAndResult import io.r2dbc.postgresql.codec.Json @@ -16,35 +26,27 @@ fun buildAttributeInstancePayload( value: Any, observedAt: ZonedDateTime, datasetId: URI? = null, - instanceId: URI? = null, + instanceId: URI, attributeType: TemporalEntityAttribute.AttributeType = TemporalEntityAttribute.AttributeType.Property -) = serializeObject( - mapOf( - "type" to attributeType.toString(), - "datasetId" to datasetId, - "instanceId" to instanceId, - "observedAt" to observedAt - ) - .let { - if (attributeType == TemporalEntityAttribute.AttributeType.Property) - it.plus("value" to value) - else - it.plus("object" to value) - } +): String = serializeObject( + mutableMapOf( + JSONLD_TYPE to listOf(attributeType.toNgsiLdExpanded()), + NGSILD_OBSERVED_AT_PROPERTY to buildNonReifiedTemporalValue(observedAt), + NGSILD_INSTANCE_ID_PROPERTY to buildNonReifiedPropertyValue(instanceId.toString()) + ).apply { + if (datasetId != null) + put(NGSILD_DATASET_ID_PROPERTY, buildNonReifiedPropertyValue(datasetId.toString())) + if (attributeType == TemporalEntityAttribute.AttributeType.Property) + put(NGSILD_PROPERTY_VALUE, listOf(mapOf(JSONLD_VALUE to value))) + else + put(NGSILD_RELATIONSHIP_HAS_OBJECT, listOf(mapOf(JSONLD_ID to value.toString()))) + } ) -suspend fun buildSapAttribute(specificAccessPolicy: AuthContextModel.SpecificAccessPolicy): NgsiLdAttribute { - val sapPropertyFragment = - """ - { - "type": "Property", - "value": "$specificAccessPolicy" - } - """.trimIndent() - - return expandAttribute(AUTH_TERM_SAP, sapPropertyFragment, AuthContextModel.AUTHORIZATION_API_DEFAULT_CONTEXTS) - .toNgsiLdAttribute().shouldSucceedAndResult() -} +suspend fun buildSapAttribute(specificAccessPolicy: AuthContextModel.SpecificAccessPolicy): NgsiLdAttribute = + mapOf(AUTH_PROP_SAP to buildExpandedPropertyValue(specificAccessPolicy)) + .toNgsiLdAttributes() + .shouldSucceedAndResult()[0] const val EMPTY_PAYLOAD = "{}" val EMPTY_JSON_PAYLOAD = Json.of(EMPTY_PAYLOAD) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/util/AttributeInstanceUtilsTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/util/AttributeInstanceUtilsTests.kt index ebe8938aa..c03031768 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/util/AttributeInstanceUtilsTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/util/AttributeInstanceUtilsTests.kt @@ -3,6 +3,7 @@ package com.egm.stellio.search.util import com.egm.stellio.search.model.TemporalEntityAttribute import com.egm.stellio.shared.util.DEFAULT_CONTEXTS import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute +import com.egm.stellio.shared.util.ngsiLdDateTime import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @@ -14,25 +15,119 @@ import java.time.LocalTime class AttributeInstanceUtilsTests { @Test - fun `it should guess the value type of a property`() = runTest { + fun `it should guess the value type of a string property`() = runTest { val expandedStringProperty = expandAttribute( "property", mapOf("type" to "Property", "value" to "A string"), DEFAULT_CONTEXTS ) assertEquals( - guessAttributeValueType(TemporalEntityAttribute.AttributeType.Property, expandedStringProperty.second[0]), - TemporalEntityAttribute.AttributeValueType.STRING + TemporalEntityAttribute.AttributeValueType.STRING, + guessAttributeValueType(TemporalEntityAttribute.AttributeType.Property, expandedStringProperty.second[0]) ) + } + + @Test + fun `it should guess the value type of a double property`() = runTest { + val expandedBooleanProperty = expandAttribute( + "property", + mapOf("type" to "Property", "value" to 20.0), + DEFAULT_CONTEXTS + ) + assertEquals( + TemporalEntityAttribute.AttributeValueType.NUMBER, + guessAttributeValueType(TemporalEntityAttribute.AttributeType.Property, expandedBooleanProperty.second[0]) + ) + } + @Test + fun `it should guess the value type of an int property`() = runTest { + val expandedBooleanProperty = expandAttribute( + "property", + mapOf("type" to "Property", "value" to 20), + DEFAULT_CONTEXTS + ) + assertEquals( + TemporalEntityAttribute.AttributeValueType.NUMBER, + guessAttributeValueType(TemporalEntityAttribute.AttributeType.Property, expandedBooleanProperty.second[0]) + ) + } + + @Test + fun `it should guess the value type of a boolean property`() = runTest { + val expandedBooleanProperty = expandAttribute( + "property", + mapOf("type" to "Property", "value" to true), + DEFAULT_CONTEXTS + ) + assertEquals( + TemporalEntityAttribute.AttributeValueType.BOOLEAN, + guessAttributeValueType(TemporalEntityAttribute.AttributeType.Property, expandedBooleanProperty.second[0]) + ) + } + + @Test + fun `it should guess the value type of an object property`() = runTest { + val expandedListProperty = expandAttribute( + "property", + mapOf("type" to "Property", "value" to mapOf("key1" to "value1", "key2" to "value3")), + DEFAULT_CONTEXTS + ) + assertEquals( + TemporalEntityAttribute.AttributeValueType.OBJECT, + guessAttributeValueType(TemporalEntityAttribute.AttributeType.Property, expandedListProperty.second[0]) + ) + } + + @Test + fun `it should guess the value type of an array property`() = runTest { + val expandedListProperty = expandAttribute( + "property", + mapOf("type" to "Property", "value" to listOf("A", "B")), + DEFAULT_CONTEXTS + ) + assertEquals( + TemporalEntityAttribute.AttributeValueType.ARRAY, + guessAttributeValueType(TemporalEntityAttribute.AttributeType.Property, expandedListProperty.second[0]) + ) + } + + @Test + fun `it should guess the value type of a time property`() = runTest { val expandedTimeProperty = expandAttribute( "property", mapOf("type" to "Property", "value" to LocalTime.now()), DEFAULT_CONTEXTS ) assertEquals( - guessAttributeValueType(TemporalEntityAttribute.AttributeType.Property, expandedTimeProperty.second[0]), - TemporalEntityAttribute.AttributeValueType.TIME + TemporalEntityAttribute.AttributeValueType.TIME, + guessAttributeValueType(TemporalEntityAttribute.AttributeType.Property, expandedTimeProperty.second[0]) + ) + } + + @Test + fun `it should guess the value type of a datetime property`() = runTest { + val expandedTimeProperty = expandAttribute( + "property", + mapOf("type" to "Property", "value" to mapOf("@type" to "DateTime", "@value" to ngsiLdDateTime())), + DEFAULT_CONTEXTS + ) + assertEquals( + TemporalEntityAttribute.AttributeValueType.DATETIME, + guessAttributeValueType(TemporalEntityAttribute.AttributeType.Property, expandedTimeProperty.second[0]) + ) + } + + @Test + fun `it should guess the value type of an URI property`() = runTest { + val expandedTimeProperty = expandAttribute( + "property", + mapOf("type" to "Property", "value" to "urn:ngsi-ld:uri"), + DEFAULT_CONTEXTS + ) + assertEquals( + TemporalEntityAttribute.AttributeValueType.URI, + guessAttributeValueType(TemporalEntityAttribute.AttributeType.Property, expandedTimeProperty.second[0]) ) } @@ -47,8 +142,8 @@ class AttributeInstanceUtilsTests { DEFAULT_CONTEXTS ) assertEquals( - guessAttributeValueType(TemporalEntityAttribute.AttributeType.GeoProperty, expandedGeoProperty.second[0]), - TemporalEntityAttribute.AttributeValueType.GEOMETRY + TemporalEntityAttribute.AttributeValueType.GEOMETRY, + guessAttributeValueType(TemporalEntityAttribute.AttributeType.GeoProperty, expandedGeoProperty.second[0]) ) } @@ -60,11 +155,11 @@ class AttributeInstanceUtilsTests { DEFAULT_CONTEXTS ) assertEquals( + TemporalEntityAttribute.AttributeValueType.URI, guessAttributeValueType( TemporalEntityAttribute.AttributeType.Relationship, expandedGeoRelationship.second[0] - ), - TemporalEntityAttribute.AttributeValueType.URI + ) ) } } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/util/EntitiesQueryUtilsTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/util/EntitiesQueryUtilsTests.kt index 6027f7b76..9efd1f0b1 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/util/EntitiesQueryUtilsTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/util/EntitiesQueryUtilsTests.kt @@ -6,7 +6,6 @@ import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.BadRequestDataException import com.egm.stellio.shared.model.GeoQuery import com.egm.stellio.shared.util.* -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DEFAULT_VOCAB import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVATION_SPACE_PROPERTY import io.mockk.every @@ -51,7 +50,7 @@ class EntitiesQueryUtilsTests { val entitiesQuery = composeEntitiesQuery( ApplicationProperties.Pagination(30, 100), requestParams, - NGSILD_CORE_CONTEXT + NGSILD_TEST_CORE_CONTEXT ).shouldSucceedAndResult() assertEquals("speed>50;foodName==dietary fibres", entitiesQuery.q) @@ -63,7 +62,7 @@ class EntitiesQueryUtilsTests { val entitiesQuery = composeEntitiesQuery( ApplicationProperties.Pagination(30, 100), requestParams, - NGSILD_CORE_CONTEXT + NGSILD_TEST_CORE_CONTEXT ).shouldSucceedAndResult() assertEquals(null, entitiesQuery.typeSelection) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/util/QueryParameterizedTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntitiesParameterizedSource.kt similarity index 99% rename from search-service/src/test/kotlin/com/egm/stellio/search/util/QueryParameterizedTests.kt rename to search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntitiesParameterizedSource.kt index 765680e71..c48202a83 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/util/QueryParameterizedTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntitiesParameterizedSource.kt @@ -12,7 +12,7 @@ import java.util.UUID import java.util.stream.Stream @Suppress("unused", "UtilityClassWithPublicConstructor") -class QueryParameterizedTests { +class TemporalEntitiesParameterizedSource { companion object { private val now = Instant.now().atZone(ZoneOffset.UTC) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/TemporalEntityBuilderTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityBuilderTests.kt similarity index 90% rename from search-service/src/test/kotlin/com/egm/stellio/search/service/TemporalEntityBuilderTests.kt rename to search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityBuilderTests.kt index 82ccb979e..d94ac2a14 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/TemporalEntityBuilderTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityBuilderTests.kt @@ -1,14 +1,12 @@ -package com.egm.stellio.search.service +package com.egm.stellio.search.util import com.egm.stellio.search.model.* import com.egm.stellio.search.model.AggregatedAttributeInstanceResult.AggregateResult import com.egm.stellio.search.scope.ScopeInstanceResult import com.egm.stellio.search.support.EMPTY_JSON_PAYLOAD import com.egm.stellio.search.support.buildDefaultQueryParams -import com.egm.stellio.search.util.TemporalEntityAttributeInstancesResult -import com.egm.stellio.search.util.TemporalEntityBuilder import com.egm.stellio.shared.util.* -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_TERM +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY import com.egm.stellio.shared.util.JsonUtils.serializeObject import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest @@ -55,13 +53,13 @@ class TemporalEntityBuilderTests { ) assertJsonPayloadsAreEqual( loadSampleData("expectations/beehive_empty_outgoing.jsonld"), - serializeObject(temporalEntity), - setOf(NGSILD_CREATED_AT_TERM) + serializeObject(temporalEntity.members), + setOf(NGSILD_CREATED_AT_PROPERTY) ) } @ParameterizedTest - @MethodSource("com.egm.stellio.search.util.ParameterizedTests#rawResultsProvider") + @MethodSource("com.egm.stellio.search.util.TemporalEntityParameterizedSource#rawResultsProvider") fun `it should correctly build a temporal entity`( scopeHistory: List, attributeAndResultsMap: TemporalEntityAttributeInstancesResult, @@ -88,11 +86,15 @@ class TemporalEntityBuilderTests { ), listOf(APIC_COMPOUND_CONTEXT) ) - assertJsonPayloadsAreEqual(expectation, serializeObject(temporalEntity), setOf(NGSILD_CREATED_AT_TERM)) + assertJsonPayloadsAreEqual( + expectation, + serializeObject(temporalEntity.members), + setOf(NGSILD_CREATED_AT_PROPERTY) + ) } @ParameterizedTest - @MethodSource("com.egm.stellio.search.util.QueryParameterizedTests#rawResultsProvider") + @MethodSource("com.egm.stellio.search.util.TemporalEntitiesParameterizedSource#rawResultsProvider") fun `it should correctly build temporal entities`( entityTemporalResults: List, withTemporalValues: Boolean, @@ -110,7 +112,11 @@ class TemporalEntityBuilderTests { ), listOf(APIC_COMPOUND_CONTEXT) ) - assertJsonPayloadsAreEqual(expectation, serializeObject(temporalEntity), setOf(NGSILD_CREATED_AT_TERM)) + assertJsonPayloadsAreEqual( + expectation, + serializeObject(temporalEntity.map { it.members }), + setOf(NGSILD_CREATED_AT_PROPERTY) + ) } @Test @@ -189,8 +195,8 @@ class TemporalEntityBuilderTests { assertJsonPayloadsAreEqual( loadSampleData("expectations/beehive_aggregated_outgoing.jsonld"), - serializeObject(temporalEntity), - setOf(NGSILD_CREATED_AT_TERM) + serializeObject(temporalEntity.members), + setOf(NGSILD_CREATED_AT_PROPERTY) ) } } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/util/ParameterizedTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityParameterizedSource.kt similarity index 99% rename from search-service/src/test/kotlin/com/egm/stellio/search/util/ParameterizedTests.kt rename to search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityParameterizedSource.kt index e41519878..496606c42 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/util/ParameterizedTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityParameterizedSource.kt @@ -17,7 +17,7 @@ import java.util.UUID import java.util.stream.Stream @Suppress("unused", "UtilityClassWithPublicConstructor") -class ParameterizedTests { +class TemporalEntityParameterizedSource { companion object { private val now = Instant.now().atZone(ZoneOffset.UTC) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt index 92f195f6c..6cc5655cb 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt @@ -13,7 +13,6 @@ import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.AuthContextModel.AUTHORIZATION_COMPOUND_CONTEXT -import com.egm.stellio.shared.util.AuthContextModel.AUTHORIZATION_CONTEXT import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SAP import com.egm.stellio.shared.util.AuthContextModel.AUTH_TERM_CAN_READ import com.egm.stellio.shared.util.AuthContextModel.AUTH_TERM_FAMILY_NAME @@ -58,7 +57,7 @@ import java.time.Duration @Import(WebSecurityTestConfig::class) class EntityAccessControlHandlerTests { - private val authzHeaderLink = buildContextLinkHeader(AUTHORIZATION_CONTEXT) + private val authzHeaderLink = buildContextLinkHeader(AUTHZ_TEST_CONTEXT) @Autowired private lateinit var webClient: WebTestClient @@ -99,7 +98,7 @@ class EntityAccessControlHandlerTests { "type": "Relationship", "object": "$entityUri1" }, - "@context": ["$AUTHORIZATION_CONTEXT", "$NGSILD_CORE_CONTEXT"] + "@context": ["$AUTHZ_TEST_CONTEXT", "$NGSILD_TEST_CORE_CONTEXT"] } """.trimIndent() @@ -145,7 +144,7 @@ class EntityAccessControlHandlerTests { "type": "Relationship", "object": "$entityUri3" }, - "@context": ["$AUTHORIZATION_CONTEXT", "$NGSILD_CORE_CONTEXT"] + "@context": ["$AUTHZ_TEST_CONTEXT", "$NGSILD_TEST_CORE_CONTEXT"] } """.trimIndent() @@ -199,7 +198,7 @@ class EntityAccessControlHandlerTests { "object": "$entityUri2", "datasetId": "$entityUri2" }], - "@context": ["$AUTHORIZATION_CONTEXT", "$NGSILD_CORE_CONTEXT"] + "@context": ["$AUTHZ_TEST_CONTEXT", "$NGSILD_TEST_CORE_CONTEXT"] } """.trimIndent() @@ -251,7 +250,7 @@ class EntityAccessControlHandlerTests { "type": "Property", "value": "$entityUri2" }, - "@context": ["$AUTHORIZATION_CONTEXT", "$NGSILD_CORE_CONTEXT"] + "@context": ["$AUTHZ_TEST_CONTEXT", "$NGSILD_TEST_CORE_CONTEXT"] } """.trimIndent() @@ -324,7 +323,7 @@ class EntityAccessControlHandlerTests { webClient.delete() .uri("/ngsi-ld/v1/entityAccessControl/$otherUserSub/attrs/$entityUri1") - .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHORIZATION_CONTEXT)) + .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHZ_TEST_CONTEXT)) .exchange() .expectStatus().isNoContent @@ -386,7 +385,7 @@ class EntityAccessControlHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entityAccessControl/$entityUri1/attrs/specificAccessPolicy") - .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHORIZATION_CONTEXT)) + .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHZ_TEST_CONTEXT)) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue(requestPayload) .exchange() @@ -414,7 +413,7 @@ class EntityAccessControlHandlerTests { { "type": "Property", "value": "AUTH_READ", - "@context": ["$AUTHORIZATION_CONTEXT"] + "@context": ["$AUTHZ_TEST_CONTEXT"] } """.trimIndent() @@ -491,7 +490,7 @@ class EntityAccessControlHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entityAccessControl/$entityUri1/attrs/specificAccessPolicy") - .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHORIZATION_CONTEXT)) + .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHZ_TEST_CONTEXT)) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue(requestPayload) .exchange() @@ -514,7 +513,7 @@ class EntityAccessControlHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entityAccessControl/$entityUri1/attrs/specificAccessPolicy") - .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHORIZATION_CONTEXT)) + .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHZ_TEST_CONTEXT)) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue(requestPayload) .exchange() @@ -529,7 +528,7 @@ class EntityAccessControlHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entityAccessControl/$entityUri1/attrs/specificAccessPolicy") - .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHORIZATION_CONTEXT)) + .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHZ_TEST_CONTEXT)) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue("{}") .exchange() @@ -543,7 +542,7 @@ class EntityAccessControlHandlerTests { webClient.delete() .uri("/ngsi-ld/v1/entityAccessControl/$entityUri1/attrs/specificAccessPolicy") - .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHORIZATION_CONTEXT)) + .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHZ_TEST_CONTEXT)) .exchange() .expectStatus().isNoContent @@ -697,7 +696,7 @@ class EntityAccessControlHandlerTests { "@type" to listOf(GROUP_TYPE), NGSILD_NAME_PROPERTY to buildExpandedProperty("egm") ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ) ) ).right() @@ -738,7 +737,7 @@ class EntityAccessControlHandlerTests { NGSILD_NAME_PROPERTY to buildExpandedProperty("egm"), AuthContextModel.AUTH_REL_IS_MEMBER_OF to buildExpandedProperty("true") ), - listOf(AUTHORIZATION_CONTEXT) + listOf(AUTHZ_TEST_CONTEXT) ) ) ).right() @@ -757,7 +756,7 @@ class EntityAccessControlHandlerTests { "type": "Group", "name": {"type":"Property", "value": "egm"}, "isMemberOf": {"type":"Property", "value": "true"}, - "@context": ["$AUTHORIZATION_CONTEXT", "$NGSILD_CORE_CONTEXT"] + "@context": ["$AUTHZ_TEST_CONTEXT", "$NGSILD_CORE_CONTEXT"] } ] """.trimMargin() @@ -837,8 +836,8 @@ class EntityAccessControlHandlerTests { "givenName", "familyName", mapOf("profile" to "stellio-user", "username" to "username") - ).serializeProperties(AUTHORIZATION_COMPOUND_CONTEXT), - listOf(NGSILD_CORE_CONTEXT) + ).serializeProperties(AUTHZ_TEST_COMPOUND_CONTEXT), + listOf(NGSILD_TEST_CORE_CONTEXT) ) ) ).right() @@ -870,9 +869,9 @@ class EntityAccessControlHandlerTests { private suspend fun createJsonLdEntity( entityAccessRights: EntityAccessRights, - context: String = NGSILD_CORE_CONTEXT + context: String = NGSILD_TEST_CORE_CONTEXT ): JsonLdEntity { - val earSerialized = entityAccessRights.serializeProperties(AUTHORIZATION_COMPOUND_CONTEXT) + val earSerialized = entityAccessRights.serializeProperties(AUTHZ_TEST_COMPOUND_CONTEXT) return JsonLdEntity(earSerialized, listOf(context)) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt index ee690c6e7..06a9d85db 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt @@ -89,13 +89,6 @@ class EntityHandlerTests { private val deadFishesType = "https://ontology.eglobalmark.com/aquac#DeadFishes" private val fishNumberAttribute = "https://ontology.eglobalmark.com/aquac#fishNumber" private val fishSizeAttribute = "https://ontology.eglobalmark.com/aquac#fishSize" - private val hcmrContext = listOf( - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/" + - "master/shared-jsonld-contexts/egm.jsonld", - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/" + - "master/aquac/jsonld-contexts/aquac.jsonld", - "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld" - ) @Test fun `create entity should return a 201 if JSON-LD payload is correct`() { @@ -134,7 +127,7 @@ class EntityHandlerTests { eq("60AAEBA3-C0C7-42B6-8CB0-0D30857F210E"), eq(breedingServiceId), eq(listOf(breedingServiceType)), - eq(hcmrContext) + eq(listOf(AQUAC_COMPOUND_CONTEXT)) ) } } @@ -320,7 +313,7 @@ class EntityHandlerTests { "@id" to beehiveId.toString(), "@type" to listOf("Beehive") ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ).right() webClient.get() @@ -359,7 +352,7 @@ class EntityHandlerTests { ) ) ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ).right() webClient.get() @@ -393,7 +386,7 @@ class EntityHandlerTests { ) ) ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ).right() webClient.get() @@ -424,7 +417,7 @@ class EntityHandlerTests { "@id" to beehiveId.toString(), "@type" to listOf(BEEHIVE_TYPE) ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ).right() val expectedMessage = entityOrAttrsNotFoundMessage( @@ -456,7 +449,7 @@ class EntityHandlerTests { "@id" to beehiveId.toString(), "@type" to listOf("Beehive") ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ).right() webClient.get() @@ -499,7 +492,7 @@ class EntityHandlerTests { "@id" to beehiveId.toString(), "@type" to listOf("Beehive") ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ).right() webClient.get() @@ -542,7 +535,7 @@ class EntityHandlerTests { "@id" to beehiveId.toString(), "@type" to listOf("Beehive") ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ).right() webClient.get() @@ -582,7 +575,7 @@ class EntityHandlerTests { "@id" to "urn:ngsi-ld:Beehive:4567", "@type" to listOf("Beehive") ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ).right() webClient.get() @@ -623,7 +616,7 @@ class EntityHandlerTests { JSONLD_ID to "urn:ngsi-ld:Beehive:4567", JSONLD_TYPE to listOf("Beehive") ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ).right() webClient.get() @@ -669,7 +662,7 @@ class EntityHandlerTests { JSONLD_ID to "urn:ngsi-ld:Beehive:4567", JSONLD_TYPE to listOf("Beehive") ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ).right() webClient.get() @@ -715,7 +708,7 @@ class EntityHandlerTests { JSONLD_ID to "urn:ngsi-ld:Beehive:4567", JSONLD_TYPE to listOf("Beehive") ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ).right() webClient.get() @@ -768,7 +761,7 @@ class EntityHandlerTests { JSONLD_ID to "urn:ngsi-ld:Beehive:4567", JSONLD_TYPE to listOf("Beehive") ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ).right() webClient.get() @@ -808,7 +801,7 @@ class EntityHandlerTests { JSONLD_ID to "urn:ngsi-ld:Beehive:4567", JSONLD_TYPE to listOf("Beehive") ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ).right() webClient.get() @@ -889,7 +882,7 @@ class EntityHandlerTests { "@id" to beehiveId.toString(), "@type" to listOf("Beehive") ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ) ), 1 @@ -938,7 +931,7 @@ class EntityHandlerTests { "@id" to beehiveId.toString(), "@type" to listOf("Beehive") ), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ) ), 1 @@ -969,7 +962,7 @@ class EntityHandlerTests { listOf( JsonLdEntity( mapOf("@id" to "urn:ngsi-ld:Beehive:TESTC", "@type" to listOf("Beehive")), - listOf(NGSILD_CORE_CONTEXT) + listOf(NGSILD_TEST_CORE_CONTEXT) ) ), 3 @@ -1186,7 +1179,7 @@ class EntityHandlerTests { eq("60AAEBA3-C0C7-42B6-8CB0-0D30857F210E"), eq(breedingServiceId), eq(listOf(breedingServiceType)), - eq(hcmrContext) + eq(listOf(AQUAC_COMPOUND_CONTEXT)) ) } } @@ -2073,7 +2066,7 @@ class EntityHandlerTests { { "type": "https://uri.etsi.org/ngsi-ld/errors/LdContextNotAvailable", "title": "A remote JSON-LD @context referenced in a request cannot be retrieved by the NGSI-LD Broker and expansion or compaction cannot be performed", - "detail": "Unable to load remote context (cause was: com.github.jsonldjava.core.JsonLdError: loading remote context failed: https://easyglobalmarket.com/contexts/diat.jsonld)" + "detail": "Unable to load remote context (cause was: JsonLdError[code=There was a problem encountered loading a remote context [code=LOADING_REMOTE_CONTEXT_FAILED]., message=There was a problem encountered loading a remote context [code=LOADING_REMOTE_CONTEXT_FAILED].])" } """.trimIndent() ) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt index 738a02b21..1983a0886 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt @@ -16,19 +16,11 @@ import com.egm.stellio.search.service.QueryService import com.egm.stellio.search.service.TemporalEntityAttributeService import com.egm.stellio.search.support.EMPTY_JSON_PAYLOAD import com.egm.stellio.shared.config.ApplicationProperties -import com.egm.stellio.shared.model.AccessDeniedException -import com.egm.stellio.shared.model.BadRequestDataException -import com.egm.stellio.shared.model.NgsiLdEntity -import com.egm.stellio.shared.model.ResourceNotFoundException +import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.* -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap -import com.egm.stellio.shared.util.JsonUtils.deserializeObject import com.ninjasquad.springmockk.MockkBean -import io.mockk.Called -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.confirmVerified +import io.mockk.* import kotlinx.coroutines.test.runTest import org.hamcrest.core.Is import org.junit.jupiter.api.BeforeAll @@ -377,9 +369,10 @@ class TemporalEntityHandlerTests { fun `it should give a 200 if no timerel and no time query params are in the request`() { buildDefaultMockResponsesForGetEntity() + val returnedJsonLdEntity = mockkClass(JsonLdEntity::class, relaxed = true) coEvery { queryService.queryTemporalEntity(any(), any(), any()) - } returns emptyMap().right() + } returns returnedJsonLdEntity.right() webClient.get() .uri("/ngsi-ld/v1/temporal/entities/$entityUri") @@ -566,9 +559,10 @@ class TemporalEntityHandlerTests { fun `it should return a 200 if minimal required parameters are valid`() { buildDefaultMockResponsesForGetEntity() + val returnedJsonLdEntity = mockkClass(JsonLdEntity::class, relaxed = true) coEvery { queryService.queryTemporalEntity(any(), any(), any()) - } returns emptyMap().right() + } returns returnedJsonLdEntity.right() webClient.get() .uri( @@ -600,9 +594,10 @@ class TemporalEntityHandlerTests { fun `it should return a 200 if minimal required parameters are valid and entity is publicly readable`() { buildDefaultMockResponsesForGetEntity() + val returnedJsonLdEntity = mockkClass(JsonLdEntity::class, relaxed = true) coEvery { queryService.queryTemporalEntity(any(), any(), any()) - } returns emptyMap().right() + } returns returnedJsonLdEntity.right() webClient.get() .uri( @@ -620,9 +615,10 @@ class TemporalEntityHandlerTests { fun `it should return a 200 if minimal required parameters are valid and user can read the entity`() { buildDefaultMockResponsesForGetEntity() + val returnedJsonLdEntity = mockkClass(JsonLdEntity::class, relaxed = true) coEvery { queryService.queryTemporalEntity(any(), any(), any()) - } returns emptyMap().right() + } returns returnedJsonLdEntity.right() webClient.get() .uri( @@ -639,7 +635,7 @@ class TemporalEntityHandlerTests { } @Test - fun `it should return an entity with two temporal properties evolution`() { + fun `it should return an entity with two temporal properties evolution`() = runTest { buildDefaultMockResponsesForGetEntity() mockWithIncomingAndOutgoingTemporalProperties(false) @@ -661,7 +657,7 @@ class TemporalEntityHandlerTests { } @Test - fun `it should return a json entity with two temporal properties evolution`() { + fun `it should return a json entity with two temporal properties evolution`() = runTest { buildDefaultMockResponsesForGetEntity() mockWithIncomingAndOutgoingTemporalProperties(false) @@ -685,7 +681,7 @@ class TemporalEntityHandlerTests { } @Test - fun `it should return an entity with two temporal properties evolution with temporalValues option`() { + fun `it should return an entity with two temporal properties evolution with temporalValues option`() = runTest { buildDefaultMockResponsesForGetEntity() mockWithIncomingAndOutgoingTemporalProperties(true) @@ -702,11 +698,11 @@ class TemporalEntityHandlerTests { .jsonPath("$.id").exists() .jsonPath("$.type").exists() .jsonPath("$..observedAt").doesNotExist() - .jsonPath("$.incoming[0].values.length()").isEqualTo(2) - .jsonPath("$.outgoing[0].values.length()").isEqualTo(2) + .jsonPath("$.incoming.values.length()").isEqualTo(2) + .jsonPath("$.outgoing.values.length()").isEqualTo(2) } - private fun mockWithIncomingAndOutgoingTemporalProperties(withTemporalValues: Boolean) { + private suspend fun mockWithIncomingAndOutgoingTemporalProperties(withTemporalValues: Boolean) { val entityTemporalProperties = listOf(INCOMING_PROPERTY, OUTGOING_PROPERTY) .map { TemporalEntityAttribute( @@ -722,7 +718,7 @@ class TemporalEntityHandlerTests { else "beehive_with_two_temporal_attributes_evolution.jsonld" - val entityWith2temporalEvolutions = deserializeObject(loadSampleData(entityFileName)) + val entityWith2temporalEvolutions = loadAndExpandSampleData(entityFileName) coEvery { temporalEntityAttributeService.getForEntity(any(), any()) } returns listOf(entityTemporalProperties[0], entityTemporalProperties[1]) @@ -808,11 +804,9 @@ class TemporalEntityHandlerTests { } @Test - fun `it should return 200 with jsonld response body for query temporal entities`() { - val firstTemporalEntity = deserializeObject( - loadSampleData("beehive_with_two_temporal_attributes_evolution.jsonld") - ).minus("@context") - val secondTemporalEntity = deserializeObject(loadSampleData("beehive.jsonld")).minus("@context") + fun `it should return 200 with jsonld response body for query temporal entities`() = runTest { + val firstTemporalEntity = loadAndExpandSampleData("beehive_with_two_temporal_attributes_evolution.jsonld") + val secondTemporalEntity = loadAndExpandSampleData("beehive.jsonld") coEvery { authorizationService.computeAccessRightFilter(any()) } returns { null } coEvery { @@ -836,11 +830,9 @@ class TemporalEntityHandlerTests { } @Test - fun `it should return 200 with json response body for query temporal entities`() { - val firstTemporalEntity = deserializeObject( - loadSampleData("beehive_with_two_temporal_attributes_evolution.jsonld") - ).minus("@context") - val secondTemporalEntity = deserializeObject(loadSampleData("beehive.jsonld")).minus("@context") + fun `it should return 200 with json response body for query temporal entities`() = runTest { + val firstTemporalEntity = loadAndExpandSampleData("beehive_with_two_temporal_attributes_evolution.jsonld") + val secondTemporalEntity = loadAndExpandSampleData("beehive.jsonld") coEvery { authorizationService.computeAccessRightFilter(any()) } returns { null } coEvery { @@ -866,11 +858,9 @@ class TemporalEntityHandlerTests { } @Test - fun `query temporal entity should return 200 with prev link header if exists`() { - val firstTemporalEntity = deserializeObject( - loadSampleData("beehive_with_two_temporal_attributes_evolution.jsonld") - ).minus("@context") - val secondTemporalEntity = deserializeObject(loadSampleData("beehive.jsonld")).minus("@context") + fun `query temporal entity should return 200 with prev link header if exists`() = runTest { + val firstTemporalEntity = loadAndExpandSampleData("beehive_with_two_temporal_attributes_evolution.jsonld") + val secondTemporalEntity = loadAndExpandSampleData("beehive.jsonld") coEvery { authorizationService.computeAccessRightFilter(any()) } returns { null } coEvery { @@ -928,11 +918,9 @@ class TemporalEntityHandlerTests { } @Test - fun `query temporal entity should return 200 with next link header if exists`() { - val firstTemporalEntity = deserializeObject( - loadSampleData("beehive_with_two_temporal_attributes_evolution.jsonld") - ).minus("@context") - val secondTemporalEntity = deserializeObject(loadSampleData("beehive.jsonld")).minus("@context") + fun `query temporal entity should return 200 with next link header if exists`() = runTest { + val firstTemporalEntity = loadAndExpandSampleData("beehive_with_two_temporal_attributes_evolution.jsonld") + val secondTemporalEntity = loadAndExpandSampleData("beehive.jsonld") coEvery { authorizationService.computeAccessRightFilter(any()) } returns { null } coEvery { @@ -957,11 +945,9 @@ class TemporalEntityHandlerTests { } @Test - fun `query temporal entity should return 200 with prev and next link header if exists`() { - val firstTemporalEntity = deserializeObject( - loadSampleData("beehive_with_two_temporal_attributes_evolution.jsonld") - ).minus("@context") - val secondTemporalEntity = deserializeObject(loadSampleData("beehive.jsonld")).minus("@context") + fun `query temporal entity should return 200 with prev and next link header if exists`() = runTest { + val firstTemporalEntity = loadAndExpandSampleData("beehive_with_two_temporal_attributes_evolution.jsonld") + val secondTemporalEntity = loadAndExpandSampleData("beehive.jsonld") coEvery { authorizationService.computeAccessRightFilter(any()) } returns { null } coEvery { @@ -1165,7 +1151,7 @@ class TemporalEntityHandlerTests { fun `modify attribute instance should return a 404 if attributeInstanceId or attribute name is not found`() { val instanceTemporalFragment = loadSampleData("fragments/temporal_instance_fragment.jsonld") - val expandedAttr = JsonLdUtils.expandJsonLdTerm(temporalEntityAttributeName, NGSILD_CORE_CONTEXT) + val expandedAttr = JsonLdUtils.expandJsonLdTerm(temporalEntityAttributeName, NGSILD_TEST_CORE_CONTEXT) coEvery { entityPayloadService.checkEntityExistence(any()) } returns Unit.right() coEvery { authorizationService.userCanUpdateEntity(any(), sub) } returns Unit.right() @@ -1542,7 +1528,7 @@ class TemporalEntityHandlerTests { @Test fun `delete attribute instance temporal should return 204`() { - val expandedAttr = JsonLdUtils.expandJsonLdTerm(temporalEntityAttributeName, NGSILD_CORE_CONTEXT) + val expandedAttr = JsonLdUtils.expandJsonLdTerm(temporalEntityAttributeName, NGSILD_TEST_CORE_CONTEXT) coEvery { entityPayloadService.checkEntityExistence(any()) } returns Unit.right() @@ -1599,7 +1585,7 @@ class TemporalEntityHandlerTests { @Test fun `delete attribute instance temporal should return 404 if attributeInstanceId or attribute name is not found`() { - val expandedAttr = JsonLdUtils.expandJsonLdTerm(temporalEntityAttributeName, NGSILD_CORE_CONTEXT) + val expandedAttr = JsonLdUtils.expandJsonLdTerm(temporalEntityAttributeName, NGSILD_TEST_CORE_CONTEXT) coEvery { entityPayloadService.checkEntityExistence(any()) diff --git a/search-service/src/test/resources/junit-platform.properties b/search-service/src/test/resources/junit-platform.properties index 2af5bf864..9911aeba0 100644 --- a/search-service/src/test/resources/junit-platform.properties +++ b/search-service/src/test/resources/junit-platform.properties @@ -1 +1,2 @@ junit.jupiter.testinstance.lifecycle.default=per_class +junit.jupiter.extensions.autodetection.enabled=true diff --git a/search-service/src/test/resources/ngsild/apiary.jsonld b/search-service/src/test/resources/ngsild/apiary.jsonld index 1efc5e6bd..e9ed32250 100644 --- a/search-service/src/test/resources/ngsild/apiary.jsonld +++ b/search-service/src/test/resources/ngsild/apiary.jsonld @@ -2,6 +2,6 @@ "id":"urn:ngsi-ld:Apiary:05", "type":"Apiary", "@context":[ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/aquac/BreedingService.json b/search-service/src/test/resources/ngsild/aquac/BreedingService.json index 9ef25f9ce..7a0294978 100644 --- a/search-service/src/test/resources/ngsild/aquac/BreedingService.json +++ b/search-service/src/test/resources/ngsild/aquac/BreedingService.json @@ -12,8 +12,6 @@ } }, "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/shared-jsonld-contexts/egm.jsonld", - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/aquac/jsonld-contexts/aquac.jsonld", - "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld" + "http://localhost:8093/jsonld-contexts/aquac-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/beehive.jsonld b/search-service/src/test/resources/ngsild/beehive.jsonld index d67e1ffa5..cc172a46a 100644 --- a/search-service/src/test/resources/ngsild/beehive.jsonld +++ b/search-service/src/test/resources/ngsild/beehive.jsonld @@ -26,6 +26,6 @@ "object": "urn:ngsi-ld:Beekeeper:Pascal" }, "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/beehive_minimal.jsonld b/search-service/src/test/resources/ngsild/beehive_minimal.jsonld index 4b0f4cc89..649ef1afd 100644 --- a/search-service/src/test/resources/ngsild/beehive_minimal.jsonld +++ b/search-service/src/test/resources/ngsild/beehive_minimal.jsonld @@ -2,6 +2,6 @@ "id": "urn:ngsi-ld:BeeHive:TESTC", "type": "BeeHive", "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/beehive_multi_instance_property.jsonld b/search-service/src/test/resources/ngsild/beehive_multi_instance_property.jsonld index e78dacf95..3f12aa000 100644 --- a/search-service/src/test/resources/ngsild/beehive_multi_instance_property.jsonld +++ b/search-service/src/test/resources/ngsild/beehive_multi_instance_property.jsonld @@ -27,6 +27,6 @@ } ], "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/beehive_two_temporal_properties.jsonld b/search-service/src/test/resources/ngsild/beehive_two_temporal_properties.jsonld index defd6eaf8..4075c3119 100644 --- a/search-service/src/test/resources/ngsild/beehive_two_temporal_properties.jsonld +++ b/search-service/src/test/resources/ngsild/beehive_two_temporal_properties.jsonld @@ -33,6 +33,6 @@ "object": "urn:ngsi-ld:Beekeeper:Pascal" }, "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/beehive_with_sap.jsonld b/search-service/src/test/resources/ngsild/beehive_with_sap.jsonld index cc7f5dba9..bd297bcd7 100644 --- a/search-service/src/test/resources/ngsild/beehive_with_sap.jsonld +++ b/search-service/src/test/resources/ngsild/beehive_with_sap.jsonld @@ -10,7 +10,7 @@ "value": "AUTH_READ" }, "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/authorization/jsonld-contexts/authorization.jsonld", - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/authorization.jsonld", + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/beehive_with_scope.jsonld b/search-service/src/test/resources/ngsild/beehive_with_scope.jsonld index de6b2e03f..df43d3f6a 100644 --- a/search-service/src/test/resources/ngsild/beehive_with_scope.jsonld +++ b/search-service/src/test/resources/ngsild/beehive_with_scope.jsonld @@ -3,6 +3,6 @@ "type": "BeeHive", "scope": "/A", "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/beehive_with_two_temporal_attributes_evolution.jsonld b/search-service/src/test/resources/ngsild/beehive_with_two_temporal_attributes_evolution.jsonld index 008c1d7ea..413ea392b 100644 --- a/search-service/src/test/resources/ngsild/beehive_with_two_temporal_attributes_evolution.jsonld +++ b/search-service/src/test/resources/ngsild/beehive_with_two_temporal_attributes_evolution.jsonld @@ -40,5 +40,8 @@ "object": "urn:ngsi-ld:Sensor:IncomingSensor" } } + ], + "@context":[ + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/beehive_with_two_temporal_attributes_evolution_temporal_values.jsonld b/search-service/src/test/resources/ngsild/beehive_with_two_temporal_attributes_evolution_temporal_values.jsonld index 4551fa75b..64722ed5a 100644 --- a/search-service/src/test/resources/ngsild/beehive_with_two_temporal_attributes_evolution_temporal_values.jsonld +++ b/search-service/src/test/resources/ngsild/beehive_with_two_temporal_attributes_evolution_temporal_values.jsonld @@ -1,22 +1,21 @@ { "id": "urn:ngsi-ld:BeeHive:TESTC", "type": "BeeHive", - "incoming": [ - { + "incoming": { "type": "Property", "values": [ [1543.0, "2020-01-24T13:01:22.066Z"], [1600.0, "2020-01-24T14:01:22.066Z"] ] - } - ], - "outgoing": [ - { + }, + "outgoing": { "type": "Property", "values": [ [133.0, "2020-01-24T13:01:22.066Z"], [100.0, "2020-01-24T14:01:22.066Z"] ] - } + }, + "@context":[ + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/beekeeper.jsonld b/search-service/src/test/resources/ngsild/beekeeper.jsonld index 84db148e7..abfe62f9c 100644 --- a/search-service/src/test/resources/ngsild/beekeeper.jsonld +++ b/search-service/src/test/resources/ngsild/beekeeper.jsonld @@ -2,6 +2,6 @@ "id":"urn:ngsi-ld:Beekeeper:04", "type":"Beekeeper", "@context":[ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/entity_with_all_attributes_1.jsonld b/search-service/src/test/resources/ngsild/entity_with_all_attributes_1.jsonld index 3c55f875e..c719fa323 100644 --- a/search-service/src/test/resources/ngsild/entity_with_all_attributes_1.jsonld +++ b/search-service/src/test/resources/ngsild/entity_with_all_attributes_1.jsonld @@ -103,6 +103,6 @@ } }, "@context": [ - "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld" + "http://localhost:8093/jsonld-contexts/ngsi-ld-core-context-v1.8.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/entity_with_all_attributes_2.jsonld b/search-service/src/test/resources/ngsild/entity_with_all_attributes_2.jsonld index 099292586..bb578e686 100644 --- a/search-service/src/test/resources/ngsild/entity_with_all_attributes_2.jsonld +++ b/search-service/src/test/resources/ngsild/entity_with_all_attributes_2.jsonld @@ -103,6 +103,6 @@ } }, "@context": [ - "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld" + "http://localhost:8093/jsonld-contexts/ngsi-ld-core-context-v1.8.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/entity_with_multi_types.jsonld b/search-service/src/test/resources/ngsild/entity_with_multi_types.jsonld index 2e0d84f4e..ddb937baf 100644 --- a/search-service/src/test/resources/ngsild/entity_with_multi_types.jsonld +++ b/search-service/src/test/resources/ngsild/entity_with_multi_types.jsonld @@ -2,6 +2,6 @@ "id": "urn:ngsi-ld:MultiTypes:03", "type": ["Beekeeper", "Sensor"], "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_aggregated_outgoing.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_aggregated_outgoing.jsonld index 645bd52dc..c43c7446a 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_aggregated_outgoing.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_aggregated_outgoing.jsonld @@ -1,8 +1,18 @@ { - "id": "urn:ngsi-ld:Beehive:1234", - "type": "BeeHive", - "outgoing": { - "type": "Property", + "@id": "urn:ngsi-ld:Beehive:1234", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://uri.etsi.org/ngsi-ld/createdAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "$now" + } + ], + "https://ontology.eglobalmark.com/apic#outgoing": [{ + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], "sum": [ [ 12, @@ -27,5 +37,5 @@ "2020-03-25T12:29:17.965206Z" ] ] - } + }] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_empty_outgoing.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_empty_outgoing.jsonld index 6a376ea9d..bdd2e80c1 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_empty_outgoing.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_empty_outgoing.jsonld @@ -1,5 +1,13 @@ { - "id":"urn:ngsi-ld:Beehive:1234", - "type":"BeeHive", - "outgoing": [] + "@id": "urn:ngsi-ld:Beehive:1234", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://uri.etsi.org/ngsi-ld/createdAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "$now" + } + ], + "https://ontology.eglobalmark.com/apic#outgoing": [] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances.jsonld index e514cb9e9..0928207b7 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances.jsonld @@ -1,29 +1,112 @@ { - "id" : "urn:ngsi-ld:BeeHive:TESTC", - "type" : "BeeHive", - "incoming" : [ { - "type" : "Property", - "datasetId" : "urn:ngsi-ld:Dataset:01234", - "value" : 550.0, - "instanceId" : "urn:ngsi-ld:Instance:01234", - "observedAt" : "2020-03-25T08:29:17.965206Z" - }, { - "type" : "Property", - "datasetId" : "urn:ngsi-ld:Dataset:01234", - "value" : 650.0, - "instanceId" : "urn:ngsi-ld:Instance:01235", - "observedAt" : "2020-03-25T08:33:17.965206Z" - }, { - "type" : "Property", - "datasetId" : "urn:ngsi-ld:Dataset:45678", - "value" : 487.0, - "instanceId" : "urn:ngsi-ld:Instance:45678", - "observedAt" : "2020-03-25T08:29:17.965206Z" - }, { - "type" : "Property", - "datasetId" : "urn:ngsi-ld:Dataset:45678", - "value" : 698.0, - "instanceId" : "urn:ngsi-ld:Instance:45679", - "observedAt" : "2020-03-25T08:33:17.965206Z" - } ] + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:29:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:01234" + } + ], + "https://uri.etsi.org/ngsi-ld/datasetId": [ + { + "@id": "urn:ngsi-ld:Dataset:01234" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": 550.0 + } + ] + }, + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:33:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:01235" + } + ], + "https://uri.etsi.org/ngsi-ld/datasetId": [ + { + "@id": "urn:ngsi-ld:Dataset:01234" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": 650.0 + } + ] + }, + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:29:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/datasetId": [ + { + "@id": "urn:ngsi-ld:Dataset:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": 487.0 + } + ] + }, + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:33:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45679" + } + ], + "https://uri.etsi.org/ngsi-ld/datasetId": [ + { + "@id": "urn:ngsi-ld:Dataset:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": 698.0 + } + ] + } + ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_temporal_values.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_temporal_values.jsonld index ce8b9fb6e..c5db8bad0 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_temporal_values.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_temporal_values.jsonld @@ -1,9 +1,28 @@ { - "id" : "urn:ngsi-ld:BeeHive:TESTC", - "type" : "BeeHive", - "incoming" : { - "type" : "Property", - "datasetId" : "urn:ngsi-ld:Dataset:45678", - "values" : [ ["Beehive_incoming_123","2020-03-25T08:29:17.965206Z"], ["Beehive_incoming_124","2020-03-25T08:33:17.965206Z"] ] - } + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/datasetId": [ + { + "@id": "urn:ngsi-ld:Dataset:45678" + } + ], + "values": [ + [ + "Beehive_incoming_123", + "2020-03-25T08:29:17.965206Z" + ], + [ + "Beehive_incoming_124", + "2020-03-25T08:33:17.965206Z" + ] + ] + } + ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_values.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_values.jsonld index d5fe27e52..4e2c7c542 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_values.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_values.jsonld @@ -1,17 +1,60 @@ { - "id" : "urn:ngsi-ld:BeeHive:TESTC", - "type" : "BeeHive", - "incoming" : [ { - "type" : "Property", - "datasetId" : "urn:ngsi-ld:Dataset:45678", - "value" : "Beehive_incoming_123", - "instanceId" : "urn:ngsi-ld:Instance:45678", - "observedAt" : "2020-03-25T08:29:17.965206Z" - }, { - "type" : "Property", - "datasetId" : "urn:ngsi-ld:Dataset:45678", - "value" : "Beehive_incoming_124", - "instanceId" : "urn:ngsi-ld:Instance:45679", - "observedAt" : "2020-03-25T08:33:17.965206Z" - } ] + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:29:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/datasetId": [ + { + "@id": "urn:ngsi-ld:Dataset:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": "Beehive_incoming_123" + } + ] + }, + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:33:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45679" + } + ], + "https://uri.etsi.org/ngsi-ld/datasetId": [ + { + "@id": "urn:ngsi-ld:Dataset:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": "Beehive_incoming_124" + } + ] + } + ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_values_with_audit.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_values_with_audit.jsonld index 93034293e..5271c0ba5 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_values_with_audit.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_values_with_audit.jsonld @@ -1,19 +1,84 @@ { - "id" : "urn:ngsi-ld:BeeHive:TESTC", - "type" : "BeeHive", - "incoming" : [ { - "type" : "Property", - "datasetId" : "urn:ngsi-ld:Dataset:45678", - "value" : "Beehive_incoming_123", - "instanceId" : "urn:ngsi-ld:Instance:45678", - "observedAt" : "2020-03-25T08:29:17.965206Z", - "sub": "sub1" - }, { - "type" : "Property", - "datasetId" : "urn:ngsi-ld:Dataset:45678", - "value" : "Beehive_incoming_124", - "instanceId" : "urn:ngsi-ld:Instance:45679", - "observedAt" : "2020-03-25T08:33:17.965206Z", - "sub": "sub2" - } ] + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:29:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/datasetId": [ + { + "@id": "urn:ngsi-ld:Dataset:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": "Beehive_incoming_123" + } + ], + "https://ontology.eglobalmark.com/authorization#sub": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": "sub1" + } + ] + } + ] + }, + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:33:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45679" + } + ], + "https://uri.etsi.org/ngsi-ld/datasetId": [ + { + "@id": "urn:ngsi-ld:Dataset:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": "Beehive_incoming_124" + } + ], + "https://ontology.eglobalmark.com/authorization#sub": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": "sub2" + } + ] + } + ] + } + ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_temporal_values.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_temporal_values.jsonld index 21a2e1e7b..7c8daa4c4 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_temporal_values.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_temporal_values.jsonld @@ -1,13 +1,48 @@ { - "id" : "urn:ngsi-ld:BeeHive:TESTC", - "type" : "BeeHive", - "incoming" : [ { - "type" : "Property", - "datasetId" : "urn:ngsi-ld:Dataset:01234", - "values" : [ [550.0,"2020-03-25T08:29:17.965206Z"], [650.0,"2020-03-25T08:33:17.965206Z"] ] - }, { - "type" : "Property", - "datasetId" : "urn:ngsi-ld:Dataset:45678", - "values" : [ [487.0,"2020-03-25T08:29:17.965206Z"], [698.0,"2020-03-25T08:33:17.965206Z"] ] - } ] + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/datasetId": [ + { + "@id": "urn:ngsi-ld:Dataset:01234" + } + ], + "values": [ + [ + 550.0, + "2020-03-25T08:29:17.965206Z" + ], + [ + 650.0, + "2020-03-25T08:33:17.965206Z" + ] + ] + }, + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/datasetId": [ + { + "@id": "urn:ngsi-ld:Dataset:45678" + } + ], + "values": [ + [ + 487.0, + "2020-03-25T08:29:17.965206Z" + ], + [ + 698.0, + "2020-03-25T08:33:17.965206Z" + ] + ] + } + ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId.jsonld index 4c6c11ec3..052ac8d03 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId.jsonld @@ -1,15 +1,50 @@ { - "id" : "urn:ngsi-ld:BeeHive:TESTC", - "type" : "BeeHive", - "incoming" : [ { - "type" : "Property", - "value" : 550.0, - "instanceId" : "urn:ngsi-ld:Instance:45678", - "observedAt" : "2020-03-25T08:29:17.965206Z" - }, { - "type" : "Property", - "value" : 650.0, - "instanceId" : "urn:ngsi-ld:Instance:45679", - "observedAt" : "2020-03-25T08:33:17.965206Z" - } ] + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:29:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": 550.0 + } + ] + }, + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:33:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45679" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": 650.0 + } + ] + } + ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_string_temporal_values.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_string_temporal_values.jsonld index 598b60fd7..3052c693a 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_string_temporal_values.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_string_temporal_values.jsonld @@ -1,8 +1,23 @@ { - "id" : "urn:ngsi-ld:BeeHive:TESTC", - "type" : "BeeHive", - "incoming" : { - "type" : "Property", - "values" : [ ["Beehive_incoming_123","2020-03-25T08:29:17.965206Z"], ["Beehive_incoming_124","2020-03-25T08:33:17.965206Z"] ] - } + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "values": [ + [ + "Beehive_incoming_123", + "2020-03-25T08:29:17.965206Z" + ], + [ + "Beehive_incoming_124", + "2020-03-25T08:33:17.965206Z" + ] + ] + } + ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_string_values.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_string_values.jsonld index 852fe621c..728087365 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_string_values.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_string_values.jsonld @@ -1,15 +1,50 @@ { - "id" : "urn:ngsi-ld:BeeHive:TESTC", - "type" : "BeeHive", - "incoming" : [ { - "type" : "Property", - "value" : "Beehive_incoming_123", - "instanceId" : "urn:ngsi-ld:Instance:45678", - "observedAt" : "2020-03-25T08:29:17.965206Z" - }, { - "type" : "Property", - "value" : "Beehive_incoming_124", - "instanceId" : "urn:ngsi-ld:Instance:45679", - "observedAt" : "2020-03-25T08:33:17.965206Z" - } ] + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:29:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": "Beehive_incoming_123" + } + ] + }, + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:33:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45679" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": "Beehive_incoming_124" + } + ] + } + ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_temporal_values.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_temporal_values.jsonld index 45dc973b2..dee0dde72 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_temporal_values.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_temporal_values.jsonld @@ -1,8 +1,23 @@ { - "id" : "urn:ngsi-ld:BeeHive:TESTC", - "type" : "BeeHive", - "incoming" : { - "type" : "Property", - "values" : [ [550.0,"2020-03-25T08:29:17.965206Z"], [650.0,"2020-03-25T08:33:17.965206Z"] ] - } + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "values": [ + [ + 550.0, + "2020-03-25T08:29:17.965206Z" + ], + [ + 650.0, + "2020-03-25T08:33:17.965206Z" + ] + ] + } + ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_relationship_multi_instances_without_datasetId.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_relationship_multi_instances_without_datasetId.jsonld index d45ace0bd..5f015132c 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_relationship_multi_instances_without_datasetId.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_relationship_multi_instances_without_datasetId.jsonld @@ -1,15 +1,50 @@ { - "id" : "urn:ngsi-ld:BeeHive:TESTC", - "type" : "BeeHive", - "incoming" : [ { - "type" : "Relationship", - "object" : "urn:ngsi-ld:Entity:1234", - "instanceId" : "urn:ngsi-ld:Instance:45678", - "observedAt" : "2020-03-25T08:29:17.965206Z" - }, { - "type" : "Relationship", - "object" : "urn:ngsi-ld:Entity:5678", - "instanceId" : "urn:ngsi-ld:Instance:45679", - "observedAt" : "2020-03-25T08:33:17.965206Z" - } ] + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Relationship" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:29:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/hasObject": [ + { + "@id": "urn:ngsi-ld:Entity:1234" + } + ] + }, + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Relationship" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:33:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45679" + } + ], + "https://uri.etsi.org/ngsi-ld/hasObject": [ + { + "@id": "urn:ngsi-ld:Entity:5678" + } + ] + } + ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances.jsonld index 94b5f66c7..eb7de4823 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances.jsonld @@ -1,13 +1,23 @@ { - "id" : "urn:ngsi-ld:BeeHive:TESTC", - "type" : "BeeHive", - "scope" : [{ - "type": "Property", - "value": ["/A/B", "/C/D"], - "modifiedAt": "2020-03-25T08:29:17.965206Z" - }, { - "type": "Property", - "value": ["/C/D"], - "modifiedAt": "2020-03-25T09:29:17.965206Z" - }] + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "scope": [ + { + "type": "Property", + "value": [ + "/A/B", + "/C/D" + ], + "modifiedAt": "2020-03-25T08:29:17.965206Z" + }, + { + "type": "Property", + "value": [ + "/C/D" + ], + "modifiedAt": "2020-03-25T09:29:17.965206Z" + } + ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances_temporal_values.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances_temporal_values.jsonld index 60cbfc466..da45f53f1 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances_temporal_values.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances_temporal_values.jsonld @@ -1,8 +1,24 @@ { - "id" : "urn:ngsi-ld:BeeHive:TESTC", - "type" : "BeeHive", - "scope" : { - "type" : "Property", - "values" : [ [["/A/B", "/C/D"],"2020-03-25T08:29:17.965206Z"], [["/C/D"],"2020-03-25T09:29:17.965206Z"] ] + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "scope": { + "type": "Property", + "values": [ + [ + [ + "/A/B", + "/C/D" + ], + "2020-03-25T08:29:17.965206Z" + ], + [ + [ + "/C/D" + ], + "2020-03-25T09:29:17.965206Z" + ] + ] } } diff --git a/search-service/src/test/resources/ngsild/expectations/query/two_beehives.json b/search-service/src/test/resources/ngsild/expectations/query/two_beehives.json index 7fea5dc75..49ffe76c3 100644 --- a/search-service/src/test/resources/ngsild/expectations/query/two_beehives.json +++ b/search-service/src/test/resources/ngsild/expectations/query/two_beehives.json @@ -1,26 +1,71 @@ [ { - "id":"urn:ngsi-ld:BeeHive:TESTC", - "type":"BeeHive", - "incoming":[ + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ { - "type":"Property", - "value":20, - "instanceId":"urn:ngsi-ld:Instance:45678", - "observedAt":"2020-03-25T08:33:17.965206Z", - "sub": "sub" + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:33:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": 20 + } + ], + "https://ontology.eglobalmark.com/authorization#sub": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": "sub" + } + ] + } + ] } ] }, { - "id":"urn:ngsi-ld:BeeHive:TESTD", - "type":"BeeHive", - "outgoing":[ + "@id": "urn:ngsi-ld:BeeHive:TESTD", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#outgoing": [ { - "type":"Property", - "value":25, - "instanceId":"urn:ngsi-ld:Instance:45679", - "observedAt":"2020-03-25T08:33:17.965206Z" + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:33:17.965206Z" + } + ], + "https://uri.etsi.org/ngsi-ld/instanceId": [ + { + "@id": "urn:ngsi-ld:Instance:45679" + } + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": 25 + } + ] } ] } diff --git a/search-service/src/test/resources/ngsild/expectations/query/two_beehives_temporal_values.json b/search-service/src/test/resources/ngsild/expectations/query/two_beehives_temporal_values.json index b1bd89f81..3a2c3cee7 100644 --- a/search-service/src/test/resources/ngsild/expectations/query/two_beehives_temporal_values.json +++ b/search-service/src/test/resources/ngsild/expectations/query/two_beehives_temporal_values.json @@ -1,28 +1,40 @@ [ { - "id":"urn:ngsi-ld:BeeHive:TESTC", - "type":"BeeHive", - "incoming": { - "type":"Property", - "values":[ - [ - 20, - "2020-03-25T08:33:17.965206Z" + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "values": [ + [ + 20, + "2020-03-25T08:33:17.965206Z" + ] ] - ] - } + } + ] }, { - "id":"urn:ngsi-ld:BeeHive:TESTD", - "type":"BeeHive", - "outgoing": { - "type":"Property", - "values":[ - [ - 25, - "2020-03-25T08:33:17.965206Z" + "@id": "urn:ngsi-ld:BeeHive:TESTD", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#outgoing": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "values": [ + [ + 25, + "2020-03-25T08:33:17.965206Z" + ] ] - ] - } + } + ] } ] diff --git a/search-service/src/test/resources/ngsild/expectations/query/two_entities_temporal_values_property_and_relationship.json b/search-service/src/test/resources/ngsild/expectations/query/two_entities_temporal_values_property_and_relationship.json index 91143499e..4984fdd85 100644 --- a/search-service/src/test/resources/ngsild/expectations/query/two_entities_temporal_values_property_and_relationship.json +++ b/search-service/src/test/resources/ngsild/expectations/query/two_entities_temporal_values_property_and_relationship.json @@ -1,46 +1,66 @@ [ { - "id":"urn:ngsi-ld:BeeHive:TESTC", - "type":"BeeHive", - "incoming": { - "type":"Property", - "values":[ - [ - 20, - "2020-03-25T08:33:17.965206Z" + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "values": [ + [ + 20, + "2020-03-25T08:33:17.965206Z" + ] ] - ] - }, - "managedBy": { - "type": "Relationship", - "objects": [ - [ - "urn:ngsi-ld:Beekeeper:1234", - "2020-03-25T08:33:17.965206Z" + } + ], + "https://ontology.eglobalmark.com/egm#managedBy": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Relationship" + ], + "objects": [ + [ + "urn:ngsi-ld:Beekeeper:1234", + "2020-03-25T08:33:17.965206Z" + ] ] - ] - } + } + ] }, { - "id":"urn:ngsi-ld:BeeHive:TESTD", - "type":"BeeHive", - "outgoing": { - "type":"Property", - "values":[ - [ - 25, - "2020-03-25T08:33:17.965206Z" + "@id": "urn:ngsi-ld:BeeHive:TESTD", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#outgoing": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "values": [ + [ + 25, + "2020-03-25T08:33:17.965206Z" + ] ] - ] - }, - "managedBy": { - "type": "Relationship", - "objects": [ - [ - "urn:ngsi-ld:Beekeeper:5678", - "2020-03-25T08:33:17.965206Z" + } + ], + "https://ontology.eglobalmark.com/egm#managedBy": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Relationship" + ], + "objects": [ + [ + "urn:ngsi-ld:Beekeeper:5678", + "2020-03-25T08:33:17.965206Z" + ] ] - ] - } + } + ] } ] diff --git a/search-service/src/test/resources/ngsild/hcmr/HCMR_test_file.json b/search-service/src/test/resources/ngsild/hcmr/HCMR_test_file.json index 5ccb0f6e3..694ae2682 100644 --- a/search-service/src/test/resources/ngsild/hcmr/HCMR_test_file.json +++ b/search-service/src/test/resources/ngsild/hcmr/HCMR_test_file.json @@ -11,7 +11,7 @@ "object": "urn:ngsi-ld:Device:HCMR-AQUABOX1" }, "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/aquac/jsonld-contexts/aquac-compound.jsonld" + "http://localhost:8093/jsonld-contexts/aquac-compound.jsonld" ] }, { @@ -26,7 +26,7 @@ "object": "urn:ngsi-ld:Device:HCMR-AQUABOX1" }, "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/aquac/jsonld-contexts/aquac-compound.jsonld" + "http://localhost:8093/jsonld-contexts/aquac-compound.jsonld" ] }, { @@ -37,7 +37,7 @@ "value": "BIOCEANOR" }, "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/aquac/jsonld-contexts/aquac-compound.jsonld" + "http://localhost:8093/jsonld-contexts/aquac-compound.jsonld" ] } ] diff --git a/search-service/src/test/resources/ngsild/hcmr/HCMR_test_file_one_entity_missing_context.json b/search-service/src/test/resources/ngsild/hcmr/HCMR_test_file_one_entity_missing_context.json index 491624867..d601b8cf0 100644 --- a/search-service/src/test/resources/ngsild/hcmr/HCMR_test_file_one_entity_missing_context.json +++ b/search-service/src/test/resources/ngsild/hcmr/HCMR_test_file_one_entity_missing_context.json @@ -3,9 +3,7 @@ "id": "urn:ngsi-ld:Sensor:HCMR-AQUABOX1temperature", "type": "Sensor", "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/shared-jsonld-contexts/egm.jsonld", - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/aquac/jsonld-contexts/aquac.jsonld", - "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld" + "http://localhost:8093/jsonld-contexts/aquac-compound.jsonld" ] }, { @@ -16,9 +14,7 @@ "id": "urn:ngsi-ld:Device:HCMR-AQUABOX1", "type": "Device", "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/shared-jsonld-contexts/egm.jsonld", - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/aquac/jsonld-contexts/aquac.jsonld", - "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld" + "http://localhost:8093/jsonld-contexts/aquac-compound.jsonld" ] } ] diff --git a/search-service/src/test/resources/ngsild/temporal/beehive_create_temporal_entity.jsonld b/search-service/src/test/resources/ngsild/temporal/beehive_create_temporal_entity.jsonld index 20475a7c4..431948fb6 100644 --- a/search-service/src/test/resources/ngsild/temporal/beehive_create_temporal_entity.jsonld +++ b/search-service/src/test/resources/ngsild/temporal/beehive_create_temporal_entity.jsonld @@ -52,6 +52,6 @@ } ], "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/temporal/beehive_create_temporal_entity_first_instance.jsonld b/search-service/src/test/resources/ngsild/temporal/beehive_create_temporal_entity_first_instance.jsonld index 22eff0cf4..be48f58e5 100644 --- a/search-service/src/test/resources/ngsild/temporal/beehive_create_temporal_entity_first_instance.jsonld +++ b/search-service/src/test/resources/ngsild/temporal/beehive_create_temporal_entity_first_instance.jsonld @@ -24,6 +24,6 @@ } ], "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/temporal/beehive_update_temporal_entity.jsonld b/search-service/src/test/resources/ngsild/temporal/beehive_update_temporal_entity.jsonld index acad55aab..1b235ef66 100644 --- a/search-service/src/test/resources/ngsild/temporal/beehive_update_temporal_entity.jsonld +++ b/search-service/src/test/resources/ngsild/temporal/beehive_update_temporal_entity.jsonld @@ -71,6 +71,6 @@ } ], "@context":[ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] -} \ No newline at end of file +} diff --git a/search-service/src/test/resources/ngsild/temporal/invalid_beehive_create_temporal_entity.jsonld b/search-service/src/test/resources/ngsild/temporal/invalid_beehive_create_temporal_entity.jsonld index 977a2c8a3..3397aae90 100644 --- a/search-service/src/test/resources/ngsild/temporal/invalid_beehive_create_temporal_entity.jsonld +++ b/search-service/src/test/resources/ngsild/temporal/invalid_beehive_create_temporal_entity.jsonld @@ -51,6 +51,6 @@ } ], "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/two_sensors_one_invalid.jsonld b/search-service/src/test/resources/ngsild/two_sensors_one_invalid.jsonld index 43b7a6771..1f96193d6 100644 --- a/search-service/src/test/resources/ngsild/two_sensors_one_invalid.jsonld +++ b/search-service/src/test/resources/ngsild/two_sensors_one_invalid.jsonld @@ -3,13 +3,13 @@ "id": "urn:ngsi-ld:Sensor:HCMR-AQUABOX1temperature", "type": "Sensor", "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/aquac/jsonld-contexts/aquac-compound.jsonld" + "http://localhost:8093/jsonld-contexts/aquac-compound.jsonld" ] }, { "id": "urn:ngsi-ld:Sensor:HCMR-AQUABOX2temperature", "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/aquac/jsonld-contexts/aquac-compound.jsonld" + "http://localhost:8093/jsonld-contexts/aquac-compound.jsonld" ] } ] diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 0b186007d..112b58960 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -31,6 +31,8 @@ dependencies { // to ensure we are using mocks and spies from springmockk lib instead exclude(module = "mockito-core") } + testFixturesImplementation("org.mock-server:mockserver-netty-no-dependencies:5.15.0") + testFixturesImplementation("org.mock-server:mockserver-client-java-no-dependencies:5.15.0") detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.4") diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt index 96b9dc168..ef84e6c1f 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt @@ -1,6 +1,7 @@ package com.egm.stellio.shared.model -import com.github.jsonldjava.core.JsonLdError +import com.apicatalog.jsonld.JsonLdError +import com.apicatalog.jsonld.JsonLdErrorCode sealed class APIException( override val message: String @@ -22,8 +23,9 @@ data class NotAcceptableException(override val message: String) : APIException(m fun Throwable.toAPIException(fallbackMessage: String = ""): APIException = when (this) { + is APIException -> this is JsonLdError -> - if (this.type == JsonLdError.Error.LOADING_REMOTE_CONTEXT_FAILED) + if (this.code == JsonLdErrorCode.LOADING_REMOTE_CONTEXT_FAILED) LdContextNotAvailableException("Unable to load remote context (cause was: $this)") else BadRequestDataException("Unexpected error while parsing payload (cause was: $this)") else -> BadRequestDataException(this.message ?: fallbackMessage) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/JsonLdEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/JsonLdEntity.kt index 556a10037..99a8352f5 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/JsonLdEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/JsonLdEntity.kt @@ -117,7 +117,7 @@ private fun simplifyValue(value: Map): Any { } } -fun CompactedJsonLdEntity.toGeoJson(geometryProperty: String): Any { +fun CompactedJsonLdEntity.toGeoJson(geometryProperty: String): Map { val geometryAttributeContent = this[geometryProperty] as? Map val geometryPropertyValue = geometryAttributeContent?.let { if (it.containsKey(JSONLD_VALUE_TERM)) it[JSONLD_VALUE_TERM] diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt index ae7abe31f..5ea38c174 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt @@ -29,6 +29,8 @@ import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMap import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMapAsDateTime import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMapAsString import java.net.URI +import java.time.LocalDate +import java.time.LocalTime import java.time.ZonedDateTime class NgsiLdEntity private constructor( @@ -399,8 +401,24 @@ fun ExpandedAttributeInstance.getScopes(): List? = else -> null } -fun ExpandedAttributeInstance.getPropertyValue(): Any = - (this[NGSILD_PROPERTY_VALUE]!![0] as Map)[JSONLD_VALUE]!! +fun ExpandedAttributeInstance.getPropertyValue(): Any { + val hasValueEntry = this[NGSILD_PROPERTY_VALUE]!! + + return if (hasValueEntry.size == 1 && (hasValueEntry[0] as Map).containsKey(JSONLD_VALUE)) { + val rawValue = (hasValueEntry[0] as Map)[JSONLD_VALUE]!! + if (rawValue is String) { + when { + rawValue.isURI() -> rawValue.toUri() + rawValue.isTime() -> LocalTime.parse(rawValue) + rawValue.isDate() -> LocalDate.parse(rawValue) + rawValue.isDateTime() -> ZonedDateTime.parse(rawValue) + else -> rawValue + } + } else rawValue + } else if (hasValueEntry.size == 1) + hasValueEntry[0] as Map + else hasValueEntry.map { (it as Map)[JSONLD_VALUE]!! } +} fun List.flatOnInstances(): List> = this.flatMap { ngsiLdAttribute -> diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/AuthUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/AuthUtils.kt index 4b6fda015..2e5c9232f 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/AuthUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/AuthUtils.kt @@ -9,7 +9,6 @@ import com.egm.stellio.shared.util.AuthContextModel.AUTH_REL_CAN_READ import com.egm.stellio.shared.util.AuthContextModel.AUTH_REL_CAN_WRITE import com.egm.stellio.shared.util.GlobalRole.STELLIO_ADMIN import com.egm.stellio.shared.util.GlobalRole.STELLIO_CREATOR -import com.egm.stellio.shared.util.JsonLdUtils.EGM_BASE_CONTEXT_URL import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT import kotlinx.coroutines.reactive.awaitFirst import org.springframework.http.HttpHeaders @@ -22,6 +21,7 @@ val ADMIN_ROLES: Set = setOf(STELLIO_ADMIN) val CREATION_ROLES: Set = setOf(STELLIO_CREATOR).plus(ADMIN_ROLES) object AuthContextModel { + private const val EGM_BASE_CONTEXT_URL = "https://easy-global-market.github.io/ngsild-api-data-models" const val AUTHORIZATION_CONTEXT = "$EGM_BASE_CONTEXT_URL/authorization/jsonld-contexts/authorization.jsonld" const val AUTHORIZATION_COMPOUND_CONTEXT = "$EGM_BASE_CONTEXT_URL/authorization/jsonld-contexts/authorization-compound.jsonld" @@ -40,6 +40,7 @@ object AuthContextModel { const val GROUP_ENTITY_PREFIX = "urn:ngsi-ld:Group:" const val AUTH_TERM_SUB = "sub" + const val AUTH_PROP_SUB = AUTHORIZATION_ONTOLOGY + AUTH_TERM_SUB const val AUTH_TERM_CLIENT_ID = "clientId" const val AUTH_TERM_NAME = "name" const val AUTH_TERM_SID = "serviceAccountId" diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt index 18f47f065..1cc69dd77 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt @@ -4,6 +4,11 @@ import arrow.core.Either import arrow.core.flatMap import arrow.core.left import arrow.core.right +import com.apicatalog.jsonld.JsonLd +import com.apicatalog.jsonld.JsonLdError +import com.apicatalog.jsonld.JsonLdOptions +import com.apicatalog.jsonld.context.cache.LruCache +import com.apicatalog.jsonld.document.JsonDocument import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE @@ -15,13 +20,14 @@ import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMapAsDateTime import com.egm.stellio.shared.util.JsonUtils.deserializeAs import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import com.egm.stellio.shared.util.JsonUtils.deserializeObject -import com.github.jsonldjava.core.JsonLdError -import com.github.jsonldjava.core.JsonLdOptions -import com.github.jsonldjava.core.JsonLdProcessor +import com.egm.stellio.shared.util.JsonUtils.serializeObject +import jakarta.json.Json +import jakarta.json.JsonObject +import jakarta.json.JsonStructure import org.slf4j.Logger import org.slf4j.LoggerFactory -import org.springframework.core.io.ClassPathResource import org.springframework.http.MediaType +import java.io.ByteArrayOutputStream import java.net.URI import java.time.LocalDate import java.time.LocalTime @@ -33,10 +39,8 @@ value class AttributeType(val uri: String) object JsonLdUtils { - const val NGSILD_CORE_CONTEXT = "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld" - const val EGM_BASE_CONTEXT_URL = - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master" - const val NGSILD_EGM_CONTEXT = "$EGM_BASE_CONTEXT_URL/shared-jsonld-contexts/egm.jsonld" + const val NGSILD_CORE_CONTEXT = "https://easy-global-market.github.io/ngsild-api-data-models/" + + "shared-jsonld-contexts/ngsi-ld-core-context-v1.8.jsonld" const val NGSILD_PREFIX = "https://uri.etsi.org/ngsi-ld/" const val NGSILD_DEFAULT_VOCAB = "https://uri.etsi.org/ngsi-ld/default-context/" @@ -100,18 +104,24 @@ object JsonLdUtils { val logger: Logger = LoggerFactory.getLogger(javaClass) - private val localCoreContextPayload = - ClassPathResource("/contexts/ngsi-ld-core-context-v1.7.jsonld").inputStream.readBytes().toString(Charsets.UTF_8) - private var BASE_CONTEXT: Map = mapOf() + private const val DEFAULT_CORE_CONTEXT_PATH = NGSILD_CORE_CONTEXT - init { - val coreContext: Map = deserializeObject(localCoreContextPayload) - BASE_CONTEXT = coreContext[JSONLD_CONTEXT] as Map - logger.info("Core context loaded") + private const val CONTEXT_CACHE_CAPACITY = 128 + private const val DOCUMENT_CACHE_CAPACITY = 256 + + private val jsonLdOptions = JsonLdOptions().apply { + contextCache = LruCache(CONTEXT_CACHE_CAPACITY) + documentCache = LruCache(DOCUMENT_CACHE_CAPACITY) + } + + private fun buildContextDocument(contexts: List): JsonStructure { + val contextsArray = Json.createArrayBuilder() + contexts.forEach { contextsArray.add(it) } + return contextsArray.build() } - private fun addCoreContext(contexts: List): List = - contexts.plus(BASE_CONTEXT) + private fun addCoreContext(contexts: List): List = + contexts.plus(DEFAULT_CORE_CONTEXT_PATH) internal fun addCoreContextIfMissing(contexts: List): List = when { @@ -124,12 +134,6 @@ object JsonLdUtils { else -> contexts.plus(NGSILD_CORE_CONTEXT) } - private fun defaultJsonLdOptions(contexts: List): JsonLdOptions = - JsonLdOptions() - .apply { - expandContext = mapOf(JSONLD_CONTEXT to addCoreContext(contexts)) - } - suspend fun expandDeserializedPayload( deserializedPayload: Map, contexts: List @@ -171,13 +175,29 @@ object JsonLdUtils { fun expandJsonLdTerm(term: String, context: String): String = expandJsonLdTerm(term, listOf(context)) - fun expandJsonLdTerm(term: String, contexts: List): String { - val expandedType = JsonLdProcessor.expand(mapOf(term to mapOf()), defaultJsonLdOptions(contexts)) - return if (expandedType.isNotEmpty()) - (expandedType[0] as Map).keys.first() - else - term - } + fun expandJsonLdTerm(term: String, contexts: List): String = + try { + JsonLd.expand( + JsonDocument.of( + serializeObject( + mapOf( + term to mapOf(), + JSONLD_CONTEXT to addCoreContext(contexts) + ) + ).byteInputStream() + ) + ) + .options(jsonLdOptions) + .get() + .let { + if (it.isNotEmpty()) + (it[0] as JsonObject).keys.first() + else term + } + } catch (e: JsonLdError) { + logger.error("Unable to expand term $term with context $contexts: ${e.message}") + throw e.toAPIException() + } suspend fun expandJsonLdFragment(fragment: Map, contexts: List): Map> = doJsonLdExpansion(fragment, contexts) as Map> @@ -224,26 +244,29 @@ object JsonLdUtils { val parsedFragment = geoPropertyToWKT(fragment) val usedContext = addCoreContext(contexts) - val jsonLdOptions = JsonLdOptions().apply { expandContext = mapOf(JSONLD_CONTEXT to usedContext) } - val expandedFragment = try { - // ensure there is no @context in the payload since it overrides the one from JsonLdOptions - JsonLdProcessor.expand(parsedFragment.minus(JSONLD_CONTEXT), jsonLdOptions) + try { + val expandedFragment = JsonLd.expand( + JsonDocument.of( + serializeObject(parsedFragment.plus(JSONLD_CONTEXT to usedContext)).byteInputStream() + ) + ) + .options(jsonLdOptions) + .get() + + if (expandedFragment.isEmpty()) + throw BadRequestDataException("Unable to expand input payload") + + val outputStream = ByteArrayOutputStream() + val jsonWriter = Json.createWriter(outputStream) + jsonWriter.write(expandedFragment.getJsonObject(0)) + return deserializeObject(outputStream.toString()) } catch (e: JsonLdError) { + logger.error("Unable to expand fragment with context $contexts: ${e.message}") throw e.toAPIException() } - if (expandedFragment.isEmpty()) - throw BadRequestDataException("Unable to expand input payload") - - return expandedFragment[0] as Map } - fun addContextsToEntity(element: CompactedJsonLdEntity, contexts: List, mediaType: MediaType) = - if (mediaType == MediaType.APPLICATION_JSON) - element - else - element.plus(Pair(JSONLD_CONTEXT, contexts)) - fun extractContextFromInput(input: Map): List { return if (!input.containsKey(JSONLD_CONTEXT)) emptyList() @@ -331,29 +354,34 @@ object JsonLdUtils { String::class.safeCast(getPropertyValueFromMap(values, propertyKey)) fun getAttributeFromExpandedAttributes( - expandedAttributes: Map, - expandedAttributeName: String, + expandedAttributes: ExpandedAttributes, + expandedAttributeName: ExpandedTerm, datasetId: URI? - ): ExpandedAttributeInstance? { - if (!expandedAttributes.containsKey(expandedAttributeName)) - return null - - return (expandedAttributes[expandedAttributeName]!! as List>>) - .find { + ): ExpandedAttributeInstance? = + expandedAttributes[expandedAttributeName]?.let { expandedAttributeInstances -> + expandedAttributeInstances.find { expandedAttributeInstance -> if (datasetId == null) - !it.containsKey(NGSILD_DATASET_ID_PROPERTY) + !expandedAttributeInstance.containsKey(NGSILD_DATASET_ID_PROPERTY) else - getPropertyValueFromMap(it, NGSILD_DATASET_ID_PROPERTY) == datasetId.toString() + getPropertyValueFromMap( + expandedAttributeInstance, + NGSILD_DATASET_ID_PROPERTY + ) == datasetId.toString() } - } + } /** * Utility but basic method to find if given contexts can resolve a known term from the core context. */ private fun canExpandJsonLdKeyFromCore(contexts: List): Boolean { - val jsonLdOptions = JsonLdOptions() - jsonLdOptions.expandContext = mapOf(JSONLD_CONTEXT to contexts) - val expandedType = JsonLdProcessor.expand(mapOf("datasetId" to mapOf()), jsonLdOptions) + val jsonDocument = JsonDocument.of( + serializeObject( + mapOf("datasetId" to mapOf(), JSONLD_CONTEXT to contexts) + ).byteInputStream() + ) + val expandedType = JsonLd.expand(jsonDocument) + .options(jsonLdOptions) + .get() return expandedType.isNotEmpty() && (expandedType[0] as? Map<*, *>)?.containsKey(NGSILD_DATASET_ID_PROPERTY) ?: false } @@ -384,19 +412,8 @@ object JsonLdUtils { jsonLdEntity: JsonLdEntity, context: String? = null, mediaType: MediaType = JSON_LD_MEDIA_TYPE - ): CompactedJsonLdEntity { - val contexts = addCoreContextIfMissing(listOfNotNull(context)) - - return if (mediaType == MediaType.APPLICATION_JSON) - JsonLdProcessor.compact(jsonLdEntity.members, mapOf(JSONLD_CONTEXT to contexts), JsonLdOptions()) - .minus(JSONLD_CONTEXT) - .mapValues(restoreGeoPropertyValue()) - else - JsonLdProcessor.compact(jsonLdEntity.members, mapOf(JSONLD_CONTEXT to contexts), JsonLdOptions()) - .minus(JSONLD_CONTEXT) - .plus(JSONLD_CONTEXT to contexts) - .mapValues(restoreGeoPropertyValue()) - } + ): CompactedJsonLdEntity = + compactEntity(jsonLdEntity, context?.let { listOf(context) } ?: emptyList(), mediaType) fun compactEntity( jsonLdEntity: JsonLdEntity, @@ -406,16 +423,35 @@ object JsonLdUtils { val allContexts = addCoreContextIfMissing(contexts) return if (mediaType == MediaType.APPLICATION_JSON) - JsonLdProcessor.compact(jsonLdEntity.members, mapOf(JSONLD_CONTEXT to allContexts), JsonLdOptions()) + JsonLd.compact( + JsonDocument.of(serializeObject(jsonLdEntity.members).byteInputStream()), + JsonDocument.of(buildContextDocument(allContexts)) + ) + .options(jsonLdOptions) + .get() + .toPrimitiveMap() .minus(JSONLD_CONTEXT) .mapValues(restoreGeoPropertyValue()) else - JsonLdProcessor.compact(jsonLdEntity.members, mapOf(JSONLD_CONTEXT to allContexts), JsonLdOptions()) + JsonLd.compact( + JsonDocument.of(serializeObject(jsonLdEntity.members).byteInputStream()), + JsonDocument.of(buildContextDocument(allContexts)) + ) + .options(jsonLdOptions) + .get() + .toPrimitiveMap() .minus(JSONLD_CONTEXT) .plus(JSONLD_CONTEXT to allContexts) .mapValues(restoreGeoPropertyValue()) } + private fun JsonObject.toPrimitiveMap(): Map { + val outputStream = ByteArrayOutputStream() + val jsonWriter = Json.createWriter(outputStream) + jsonWriter.write(this) + return deserializeObject(outputStream.toString()) + } + fun compactEntities( entities: List, context: String, @@ -433,24 +469,31 @@ object JsonLdUtils { /** * Compact a term (type, attribute name, ...) using the provided context. */ - fun compactTerm(term: String, contexts: List): String { - val compactedFragment = - JsonLdProcessor.compact( - mapOf(term to emptyMap()), - mapOf(JSONLD_CONTEXT to addCoreContextIfMissing(contexts)), - JsonLdOptions() - ) - return compactedFragment.keys.first() - } + fun compactTerm(term: String, contexts: List): String = + JsonLd.compact( + JsonDocument.of(serializeObject(mapOf(term to emptyMap())).byteInputStream()), + JsonDocument.of(buildContextDocument(addCoreContextIfMissing(contexts))) + ) + .options(jsonLdOptions) + .get() + .toPrimitiveMap() + .keys + .elementAtOrElse(0) { _ -> term } fun compactFragment(value: Map, contexts: List): Map = - JsonLdProcessor.compact(value, mapOf(JSONLD_CONTEXT to addCoreContextIfMissing(contexts)), JsonLdOptions()) + JsonLd.compact( + JsonDocument.of(serializeObject(value).byteInputStream()), + JsonDocument.of(buildContextDocument(addCoreContextIfMissing(contexts))) + ) + .options(jsonLdOptions) + .get() + .toPrimitiveMap() .mapValues(restoreGeoPropertyValue()) fun filterCompactedEntityOnAttributes( input: CompactedJsonLdEntity, includedAttributes: Set - ): Map { + ): CompactedJsonLdEntity { val identity: (CompactedJsonLdEntity) -> CompactedJsonLdEntity = { it } return filterEntityOnAttributes(input, identity, includedAttributes, false) } @@ -575,7 +618,7 @@ object JsonLdUtils { mapOf( JSONLD_TYPE to listOf(NGSILD_PROPERTY_TYPE.uri), NGSILD_PROPERTY_VALUE to listOf( - expandJsonLdFragment(value, contexts).mapValues { it.value } + expandJsonLdFragment(value, contexts) ) ) ) @@ -653,7 +696,7 @@ fun ExpandedAttribute.toExpandedAttributes() = fun ExpandedAttributeInstances.addSubAttribute( subAttributeName: ExpandedTerm, - subAttributePayload: List> + subAttributePayload: ExpandedAttributeInstances ): ExpandedAttributeInstances { if (this.isEmpty() || this.size > 1) throw BadRequestDataException("Cannot add a sub-attribute into empty or multi-instance attribute: $this") diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonUtils.kt index 8eb56484e..ce46ee852 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonUtils.kt @@ -71,9 +71,6 @@ object JsonUtils { fun serializeObject(input: Any): String = mapper.writeValueAsString(input) - fun Map.serialize(): String = - mapper.writeValueAsString(this) - fun serializeObject( input: Any, inputClass: KClass<*>, diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/web/ExceptionHandler.kt b/shared/src/main/kotlin/com/egm/stellio/shared/web/ExceptionHandler.kt index 412d791bf..3484872a2 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/web/ExceptionHandler.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/web/ExceptionHandler.kt @@ -1,8 +1,8 @@ package com.egm.stellio.shared.web +import com.apicatalog.jsonld.JsonLdError import com.egm.stellio.shared.model.* import com.fasterxml.jackson.core.JsonParseException -import com.github.jsonldjava.core.JsonLdError import org.slf4j.LoggerFactory import org.springframework.core.codec.CodecException import org.springframework.http.HttpStatus @@ -40,7 +40,7 @@ class ExceptionHandler { ) is JsonLdError -> generateErrorResponse( HttpStatus.BAD_REQUEST, - JsonLdErrorResponse(cause.type.toString(), cause.message.orEmpty()) + JsonLdErrorResponse(cause.code.toString(), cause.message.orEmpty()) ) is JsonParseException, is CodecException -> generateErrorResponse( HttpStatus.BAD_REQUEST, diff --git a/shared/src/main/resources/contexts/fiware-datamodels-context.jsonld b/shared/src/main/resources/contexts/fiware-datamodels-context.jsonld deleted file mode 100644 index cf4d381f8..000000000 --- a/shared/src/main/resources/contexts/fiware-datamodels-context.jsonld +++ /dev/null @@ -1,1891 +0,0 @@ -{ - "@context": { - "0": "https://uri.fiware.org/ns/data-models#0", - "1": "https://uri.fiware.org/ns/data-models#1", - "2": "https://uri.fiware.org/ns/data-models#2", - "3": "https://uri.fiware.org/ns/data-models#3", - "37": "https://uri.fiware.org/ns/data-models#37", - "37,38": "https://uri.fiware.org/ns/data-models#37,38", - "37,38,39": "https://uri.fiware.org/ns/data-models#37,38,39", - "37,39": "https://uri.fiware.org/ns/data-models#37,39", - "38": "https://uri.fiware.org/ns/data-models#38", - "38,39": "https://uri.fiware.org/ns/data-models#38,39", - "39": "https://uri.fiware.org/ns/data-models#39", - "4": "https://uri.fiware.org/ns/data-models#4", - "5": "https://uri.fiware.org/ns/data-models#5", - "6": "https://uri.fiware.org/ns/data-models#6", - "7": "https://uri.fiware.org/ns/data-models#7", - "AeroAllergenObserved": "https://uri.fiware.org/ns/data-models#AeroAllergenObserved", - "AgriApp": "https://uri.fiware.org/ns/data-models#AgriApp", - "AgriCrop": "https://uri.fiware.org/ns/data-models#AgriCrop", - "AgriFarm": "https://uri.fiware.org/ns/data-models#AgriFarm", - "AgriGreenhouse": "https://uri.fiware.org/ns/data-models#AgriGreenhouse", - "AgriParcel": "https://uri.fiware.org/ns/data-models#AgriParcel", - "AgriParcelOperation": "https://uri.fiware.org/ns/data-models#AgriParcelOperation", - "AgriParcelRecord": "https://uri.fiware.org/ns/data-models#AgriParcelRecord", - "AgriPest": "https://uri.fiware.org/ns/data-models#AgriPest", - "AgriProductType": "https://uri.fiware.org/ns/data-models#AgriProductType", - "AgriSoil": "https://uri.fiware.org/ns/data-models#AgriSoil", - "AirQualityObserved": "https://uri.fiware.org/ns/data-models#AirQualityObserved", - "Alert": "https://uri.fiware.org/ns/data-models#Alert", - "Animal": "https://uri.fiware.org/ns/data-models#Animal", - "ArrivalEstimation": "https://uri.fiware.org/ns/data-models#ArrivalEstimation", - "Beach": "https://uri.fiware.org/ns/data-models#Beach", - "BikeHireDockingStation": "https://uri.fiware.org/ns/data-models#BikeHireDockingStation", - "Building": "https://uri.fiware.org/ns/data-models#Building", - "BuildingOperation": "https://uri.fiware.org/ns/data-models#BuildingOperation", - "ByBankTransferInAdvance": "http://purl.org/goodrelations/v1#ByBankTransferInAdvance", - "ByInvoice": "http://purl.org/goodrelations/v1#ByInvoice", - "C0": "https://uri.fiware.org/ns/data-models#C0", - "C1": "https://uri.fiware.org/ns/data-models#C1", - "C2": "https://uri.fiware.org/ns/data-models#C2", - "CCS/SAE": "https://uri.fiware.org/ns/data-models#CCS/SAE", - "CHAdeMO": "https://uri.fiware.org/ns/data-models#CHAdeMO", - "COD": "http://purl.org/goodrelations/v1#COD", - "Caravan_Mains_Socket": "https://uri.fiware.org/ns/data-models#Caravan_Mains_Socket", - "Cash": "http://purl.org/goodrelations/v1#Cash", - "CheckInAdvance": "http://purl.org/goodrelations/v1#CheckInAdvance", - "Chla": "https://uri.fiware.org/ns/data-models#Chla", - "Cl-": "https://uri.fiware.org/ns/data-models#Cl-", - "CrowdFlowObserved": "https://uri.fiware.org/ns/data-models#CrowdFlowObserved", - "Device": "https://uri.fiware.org/ns/data-models#Device", - "DeviceModel": "https://uri.fiware.org/ns/data-models#DeviceModel", - "DirectDebit": "http://purl.org/goodrelations/v1#DirectDebit", - "Dual_CHAdeMO": "https://uri.fiware.org/ns/data-models#Dual_CHAdeMO", - "Dual_J-1772": "https://uri.fiware.org/ns/data-models#Dual_J-1772", - "Dual_Mennekes": "https://uri.fiware.org/ns/data-models#Dual_Mennekes", - "E0": "https://uri.fiware.org/ns/data-models#E0", - "E1": "https://uri.fiware.org/ns/data-models#E1", - "E2": "https://uri.fiware.org/ns/data-models#E2", - "E9": "https://uri.fiware.org/ns/data-models#E9", - "EVChargingStation": "https://uri.fiware.org/ns/data-models#EVChargingStation", - "FlowerBed": "https://uri.fiware.org/ns/data-models#FlowerBed", - "Garden": "https://uri.fiware.org/ns/data-models#Garden", - "GoogleCheckout": "http://purl.org/goodrelations/v1#GoogleCheckout", - "GreenspaceRecord": "https://uri.fiware.org/ns/data-models#GreenspaceRecord", - "GtfsAccessPoint": "https://uri.fiware.org/ns/data-models#GtfsAccessPoint", - "GtfsAgency": "https://uri.fiware.org/ns/data-models#GtfsAgency", - "GtfsCalendarDateRule": "https://uri.fiware.org/ns/data-models#GtfsCalendarDateRule", - "GtfsCalendarRule": "https://uri.fiware.org/ns/data-models#GtfsCalendarRule", - "GtfsFrequency": "https://uri.fiware.org/ns/data-models#GtfsFrequency", - "GtfsRoute": "https://uri.fiware.org/ns/data-models#GtfsRoute", - "GtfsService": "https://uri.fiware.org/ns/data-models#GtfsService", - "GtfsShape": "https://uri.fiware.org/ns/data-models#GtfsShape", - "GtfsStation": "https://uri.fiware.org/ns/data-models#GtfsStation", - "GtfsStop": "https://uri.fiware.org/ns/data-models#GtfsStop", - "GtfsStopTime": "https://uri.fiware.org/ns/data-models#GtfsStopTime", - "GtfsTransferRule": "https://uri.fiware.org/ns/data-models#GtfsTransferRule", - "GtfsTrip": "https://uri.fiware.org/ns/data-models#GtfsTrip", - "HPS": "https://uri.fiware.org/ns/data-models#HPS", - "J-1772": "https://uri.fiware.org/ns/data-models#J-1772", - "KeyPerformanceIndicator": "https://uri.fiware.org/ns/data-models#KeyPerformanceIndicator", - "LED": "https://uri.fiware.org/ns/data-models#LED", - "LPS": "https://uri.fiware.org/ns/data-models#LPS", - "Mennekes": "https://uri.fiware.org/ns/data-models#Mennekes", - "Museum": "https://uri.fiware.org/ns/data-models#Museum", - "NH3": "https://uri.fiware.org/ns/data-models#NH3", - "NH4": "https://uri.fiware.org/ns/data-models#NH4", - "NO3": "https://uri.fiware.org/ns/data-models#NO3", - "NoiseLevelObserved": "https://uri.fiware.org/ns/data-models#NoiseLevelObserved", - "O2": "https://uri.fiware.org/ns/data-models#O2", - "OffStreetParking": "https://uri.fiware.org/ns/data-models#OffStreetParking", - "OnStreetParking": "https://uri.fiware.org/ns/data-models#OnStreetParking", - "Open311ServiceRequest": "https://uri.fiware.org/ns/data-models#Open311ServiceRequest", - "Open311ServiceType": "https://uri.fiware.org/ns/data-models#Open311ServiceType", - "Other": "https://uri.fiware.org/ns/data-models#Other", - "PC": "https://uri.fiware.org/ns/data-models#PC", - "PE": "https://uri.fiware.org/ns/data-models#PE", - "ParkingAccess": "https://uri.fiware.org/ns/data-models#ParkingAccess", - "ParkingGroup": "https://uri.fiware.org/ns/data-models#ParkingGroup", - "ParkingSpot": "https://uri.fiware.org/ns/data-models#ParkingSpot", - "PayPal": "http://purl.org/goodrelations/v1#PayPal", - "PaySwarm": "http://purl.org/goodrelations/v1#PaySwarm", - "Point": "https://uri.fiware.org/ns/data-models#Point", - "PointOfInterest": "https://uri.fiware.org/ns/data-models#PointOfInterest", - "Q-Quality": "https://uri.fiware.org/ns/data-models#Q-Quality", - "Road": "https://uri.fiware.org/ns/data-models#Road", - "RoadSegment": "https://uri.fiware.org/ns/data-models#RoadSegment", - "SmartPointOfInteraction": "https://uri.fiware.org/ns/data-models#SmartPointOfInteraction", - "SmartSpot": "https://uri.fiware.org/ns/data-models#SmartSpot", - "Streetlight": "https://uri.fiware.org/ns/data-models#Streetlight", - "StreetlightControlCabinet": "https://uri.fiware.org/ns/data-models#StreetlightControlCabinet", - "StreetlightGroup": "https://uri.fiware.org/ns/data-models#StreetlightGroup", - "StreetlightModel": "https://uri.fiware.org/ns/data-models#StreetlightModel", - "TBD": "https://uri.fiware.org/ns/data-models#TBD", - "Tesla": "https://uri.fiware.org/ns/data-models#Tesla", - "ThreePhaseAcMeasurement": "https://uri.fiware.org/ns/data-models#ThreePhaseAcMeasurement", - "TimeInstant": { - "@id": "https://uri.fiware.org/ns/data-models#TimeInstant", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "TrafficFlowObserved": "https://uri.fiware.org/ns/data-models#TrafficFlowObserved", - "Type2": "https://uri.fiware.org/ns/data-models#Type2", - "Type3": "https://uri.fiware.org/ns/data-models#Type3", - "UserActivity": "https://uri.fiware.org/ns/data-models#UserActivity", - "UserContext": "https://uri.fiware.org/ns/data-models#UserContext", - "Vehicle": "https://uri.fiware.org/ns/data-models#Vehicle", - "VehicleModel": "https://uri.fiware.org/ns/data-models#VehicleModel", - "Wall_Euro": "https://uri.fiware.org/ns/data-models#Wall_Euro", - "WasteContainer": "https://uri.fiware.org/ns/data-models#WasteContainer", - "WasteContainerIsle": "https://uri.fiware.org/ns/data-models#WasteContainerIsle", - "WasteContainerModel": "https://uri.fiware.org/ns/data-models#WasteContainerModel", - "WaterQualityObserved": "https://uri.fiware.org/ns/data-models#WaterQualityObserved", - "WeatherForecast": "https://uri.fiware.org/ns/data-models#WeatherForecast", - "WeatherObserved": "https://uri.fiware.org/ns/data-models#WeatherObserved", - "aborted": "https://uri.fiware.org/ns/data-models#aborted", - "abs": "https://uri.fiware.org/ns/data-models#abs", - "acceptedPaymentMethod": { - "@id": "https://uri.fiware.org/ns/data-models#acceptedPaymentMethod", - "@type": "@vocab" - }, - "accessType": { - "@id": "https://uri.fiware.org/ns/data-models#accessType", - "@type": "@vocab" - }, - "accessforDisabled": "https://uri.fiware.org/ns/data-models#accessforDisabled", - "acropolis": "https://uri.fiware.org/ns/data-models#acropolis", - "actionable": "https://uri.fiware.org/ns/data-models#actionable", - "active": "https://uri.fiware.org/ns/data-models#active", - "activeEnergyExport": "https://uri.fiware.org/ns/data-models#activeEnergyExport", - "activeEnergyImport": "https://uri.fiware.org/ns/data-models#activeEnergyImport", - "activePower": "https://uri.fiware.org/ns/data-models#activePower", - "activeProgramId": "https://uri.fiware.org/ns/data-models#activeProgramId", - "activityType": "https://uri.fiware.org/ns/data-models#activityType", - "actuationHours": "https://uri.fiware.org/ns/data-models#actuationHours", - "additionalIntervalPrice": "https://uri.fiware.org/ns/data-models#additionalIntervalPrice", - "address": "https://schema.org/address", - "adequate": "https://uri.fiware.org/ns/data-models#adequate", - "aggregateRating": "https://schema.org/aggregateRating", - "aggregatedData": "https://uri.fiware.org/ns/data-models#aggregatedData", - "agriculturalVehicle": "https://uri.fiware.org/ns/data-models#agriculturalVehicle", - "agriculture": "https://uri.fiware.org/ns/data-models#agriculture", - "agroVocConcept": "https://uri.fiware.org/ns/data-models#agroVocConcept", - "airPollution": "https://uri.fiware.org/ns/data-models#airPollution", - "airQualityIndex": "https://uri.fiware.org/ns/data-models#airQualityIndex", - "airQualityLevel": "https://uri.fiware.org/ns/data-models#airQualityLevel", - "airbag": "https://uri.fiware.org/ns/data-models#airbag", - "airportTerminal": "https://uri.fiware.org/ns/data-models#airportTerminal", - "alarm": "https://uri.fiware.org/ns/data-models#alarm", - "alcazaba": "https://uri.fiware.org/ns/data-models#alcazaba", - "alcazar": "https://uri.fiware.org/ns/data-models#alcazar", - "alertSource": { - "@id": "https://uri.fiware.org/ns/data-models#alertSource", - "@type": "@id" - }, - "allergenRisk": { - "@id": "https://uri.fiware.org/ns/data-models#allergenRisk", - "@type": "@vocab" - }, - "allowedVehicleType": { - "@id": "https://uri.fiware.org/ns/data-models#allowedVehicleType", - "@type": "@vocab" - }, - "almostEmpty": "https://uri.fiware.org/ns/data-models#almostEmpty", - "almostFull": "https://uri.fiware.org/ns/data-models#almostFull", - "alternateName": "https://schema.org/alternateName", - "aluminium": "https://uri.fiware.org/ns/data-models#aluminium", - "always-ON": "https://uri.fiware.org/ns/data-models#always-ON", - "ambulance": "https://uri.fiware.org/ns/data-models#ambulance", - "amperage": "https://uri.fiware.org/ns/data-models#amperage", - "amphitheatre": "https://uri.fiware.org/ns/data-models#amphitheatre", - "annotations": "https://uri.fiware.org/ns/data-models#annotations", - "announcedUrl": "https://uri.fiware.org/ns/data-models#announcedUrl", - "announcementPeriod": "https://uri.fiware.org/ns/data-models#announcementPeriod", - "annualPayment": "https://uri.fiware.org/ns/data-models#annualPayment", - "anyVehicle": "https://uri.fiware.org/ns/data-models#anyVehicle", - "apartments": "https://uri.fiware.org/ns/data-models#apartments", - "apparentEnergyExport": "https://uri.fiware.org/ns/data-models#apparentEnergyExport", - "apparentEnergyImport": "https://uri.fiware.org/ns/data-models#apparentEnergyImport", - "apparentPower": "https://uri.fiware.org/ns/data-models#apparentPower", - "applicationUrl": "https://uri.fiware.org/ns/data-models#applicationUrl", - "appliedArts": "https://uri.fiware.org/ns/data-models#appliedArts", - "appliesOn": "https://uri.fiware.org/ns/data-models#appliesOn", - "aqueduct": "https://uri.fiware.org/ns/data-models#aqueduct", - "arcade": "https://uri.fiware.org/ns/data-models#arcade", - "arch": "https://uri.fiware.org/ns/data-models#arch", - "archaeology": "https://uri.fiware.org/ns/data-models#archaeology", - "archeologicalSite": "https://uri.fiware.org/ns/data-models#archeologicalSite", - "architecture": "https://uri.fiware.org/ns/data-models#architecture", - "area": "https://uri.fiware.org/ns/data-models#area", - "areaCovered": "https://uri.fiware.org/ns/data-models#areaCovered", - "areaSeperatedFromSurroundings": "https://uri.fiware.org/ns/data-models#areaSeperatedFromSurroundings", - "areaServed": "https://schema.org/areaServed", - "arrivalEstimationUpdate": { - "@id": "https://uri.fiware.org/ns/data-models#arrivalEstimationUpdate", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "arrivalTime": "https://uri.fiware.org/ns/data-models#arrivalTime", - "artPeriod": "https://uri.fiware.org/ns/data-models#artPeriod", - "assault": "https://uri.fiware.org/ns/data-models#assault", - "asthmaAttack": "https://uri.fiware.org/ns/data-models#asthmaAttack", - "astronomicalClock": "https://uri.fiware.org/ns/data-models#astronomicalClock", - "atmosphericPressure": "https://uri.fiware.org/ns/data-models#atmosphericPressure", - "audioguide": "https://uri.fiware.org/ns/data-models#audioguide", - "auditory": "https://uri.fiware.org/ns/data-models#auditory", - "autogas": "https://uri.fiware.org/ns/data-models#autogas", - "automatedParkingGarage": "https://uri.fiware.org/ns/data-models#automatedParkingGarage", - "automatic": "https://uri.fiware.org/ns/data-models#automatic", - "automaticParkingGuidance": "https://uri.fiware.org/ns/data-models#automaticParkingGuidance", - "auxiliaryServices": "https://uri.fiware.org/ns/data-models#auxiliaryServices", - "availability": "https://uri.fiware.org/ns/data-models#availability", - "availableBikeNumber": "https://uri.fiware.org/ns/data-models#availableBikeNumber", - "availableCapacity": "https://uri.fiware.org/ns/data-models#availableCapacity", - "availableSpotNumber": "https://uri.fiware.org/ns/data-models#availableSpotNumber", - "avalancheRisk": "https://uri.fiware.org/ns/data-models#avalancheRisk", - "averageCrowdSpeed": "https://uri.fiware.org/ns/data-models#averageCrowdSpeed", - "averageGapDistance": "https://uri.fiware.org/ns/data-models#averageGapDistance", - "averageHeadwayTime": "https://uri.fiware.org/ns/data-models#averageHeadwayTime", - "averageSpotLength": "https://uri.fiware.org/ns/data-models#averageSpotLength", - "averageSpotWidth": "https://uri.fiware.org/ns/data-models#averageSpotWidth", - "averageVehicleLength": "https://uri.fiware.org/ns/data-models#averageVehicleLength", - "averageVehicleSpeed": "https://uri.fiware.org/ns/data-models#averageVehicleSpeed", - "backCamera": "https://uri.fiware.org/ns/data-models#backCamera", - "backward": "https://uri.fiware.org/ns/data-models#backward", - "bacteria": "https://uri.fiware.org/ns/data-models#bacteria", - "bad": "https://uri.fiware.org/ns/data-models#bad", - "bakehouse": "https://uri.fiware.org/ns/data-models#bakehouse", - "balancing": "https://uri.fiware.org/ns/data-models#balancing", - "bandalized": "https://uri.fiware.org/ns/data-models#bandalized", - "barn": "https://uri.fiware.org/ns/data-models#barn", - "barrierAccess": "https://uri.fiware.org/ns/data-models#barrierAccess", - "basilica": "https://uri.fiware.org/ns/data-models#basilica", - "batteries": "https://uri.fiware.org/ns/data-models#batteries", - "batteryLevel": "https://uri.fiware.org/ns/data-models#batteryLevel", - "bbox": { - "@container": "@list", - "@id": "https://purl.org/geojson/vocab#bbox" - }, - "beachType": { - "@id": "https://uri.fiware.org/ns/data-models#beachType", - "@type": "@vocab" - }, - "belongsTo": { - "@id": "https://uri.fiware.org/ns/data-models#belongsTo", - "@type": "@id" - }, - "bicycle": "https://uri.fiware.org/ns/data-models#bicycle", - "bikeParking": "https://uri.fiware.org/ns/data-models#bikeParking", - "bimonthly": "https://uri.fiware.org/ns/data-models#bimonthly", - "binTrolley": "https://uri.fiware.org/ns/data-models#binTrolley", - "biodiesel ethanol": "https://uri.fiware.org/ns/data-models#biodiesel ethanol", - "birthdate": { - "@id": "https://uri.fiware.org/ns/data-models#birthdate", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "biweekly": "https://uri.fiware.org/ns/data-models#biweekly", - "blackSand": "https://uri.fiware.org/ns/data-models#blackSand", - "block": "https://uri.fiware.org/ns/data-models#block", - "blueFlag": "https://uri.fiware.org/ns/data-models#blueFlag", - "bluetoothChannel": { - "@id": "https://uri.fiware.org/ns/data-models#bluetoothChannel", - "@type": "@vocab" - }, - "boat": "https://uri.fiware.org/ns/data-models#boat", - "bollard": "https://uri.fiware.org/ns/data-models#bollard", - "bootingUp": "https://uri.fiware.org/ns/data-models#bootingUp", - "borehole": "https://uri.fiware.org/ns/data-models#borehole", - "botanical": "https://uri.fiware.org/ns/data-models#botanical", - "brandName": "https://uri.fiware.org/ns/data-models#brandName", - "breed": "https://uri.fiware.org/ns/data-models#breed", - "bridge": "https://uri.fiware.org/ns/data-models#bridge", - "broken": "https://uri.fiware.org/ns/data-models#broken", - "brokenLantern": "https://uri.fiware.org/ns/data-models#brokenLantern", - "buildingFire": "https://uri.fiware.org/ns/data-models#buildingFire", - "buildingType": { - "@id": "https://uri.fiware.org/ns/data-models#buildingType", - "@type": "@vocab" - }, - "bullfighting": "https://uri.fiware.org/ns/data-models#bullfighting", - "bullfightingRing": "https://uri.fiware.org/ns/data-models#bullfightingRing", - "bumpedPatient": "https://uri.fiware.org/ns/data-models#bumpedPatient", - "bungalow": "https://uri.fiware.org/ns/data-models#bungalow", - "bunker": "https://uri.fiware.org/ns/data-models#bunker", - "burialMound": "https://uri.fiware.org/ns/data-models#burialMound", - "burning": "https://uri.fiware.org/ns/data-models#burning", - "bus": "https://uri.fiware.org/ns/data-models#bus", - "businessTarget": "https://uri.fiware.org/ns/data-models#businessTarget", - "cabin": "https://uri.fiware.org/ns/data-models#cabin", - "cableCarStation": "https://uri.fiware.org/ns/data-models#cableCarStation", - "cafeteria": "https://uri.fiware.org/ns/data-models#cafeteria", - "calculatedBy": "https://uri.fiware.org/ns/data-models#calculatedBy", - "calculationFormula": "https://uri.fiware.org/ns/data-models#calculationFormula", - "calculationFrequency": { - "@id": "https://uri.fiware.org/ns/data-models#calculationFrequency", - "@type": "@vocab" - }, - "calculationMethod": { - "@id": "https://uri.fiware.org/ns/data-models#calculationMethod", - "@type": "@vocab" - }, - "calculationPeriod": "https://uri.fiware.org/ns/data-models#calculationPeriod", - "calmWaters": "https://uri.fiware.org/ns/data-models#calmWaters", - "calvedBy": { - "@id": "https://uri.fiware.org/ns/data-models#calvedBy", - "@type": "@id" - }, - "campground": "https://uri.fiware.org/ns/data-models#campground", - "cancelled": "https://uri.fiware.org/ns/data-models#cancelled", - "capacity": "https://uri.fiware.org/ns/data-models#capacity", - "car": "https://uri.fiware.org/ns/data-models#car", - "carAccident": "https://uri.fiware.org/ns/data-models#carAccident", - "carSharing": "https://uri.fiware.org/ns/data-models#carSharing", - "carStopped": "https://uri.fiware.org/ns/data-models#carStopped", - "carWithCaravan": "https://uri.fiware.org/ns/data-models#carWithCaravan", - "carWithTrailer": "https://uri.fiware.org/ns/data-models#carWithTrailer", - "carWrongDirection": "https://uri.fiware.org/ns/data-models#carWrongDirection", - "caravan": "https://uri.fiware.org/ns/data-models#caravan", - "cargoTransport": "https://uri.fiware.org/ns/data-models#cargoTransport", - "cargoVolume": "https://uri.fiware.org/ns/data-models#cargoVolume", - "cargoWeight": "https://uri.fiware.org/ns/data-models#cargoWeight", - "carport": "https://uri.fiware.org/ns/data-models#carport", - "carports": "https://uri.fiware.org/ns/data-models#carports", - "cartuja": "https://uri.fiware.org/ns/data-models#cartuja", - "cashMachine": "https://uri.fiware.org/ns/data-models#cashMachine", - "castle": "https://uri.fiware.org/ns/data-models#castle", - "castro": "https://uri.fiware.org/ns/data-models#castro", - "catacombs": "https://uri.fiware.org/ns/data-models#catacombs", - "category": { - "@id": "https://uri.fiware.org/ns/data-models#category", - "@type": "@vocab" - }, - "cathedral": "https://uri.fiware.org/ns/data-models#cathedral", - "cathedralMuseum": "https://uri.fiware.org/ns/data-models#cathedralMuseum", - "cavesAndTouristicMines": "https://uri.fiware.org/ns/data-models#cavesAndTouristicMines", - "cctv": "https://uri.fiware.org/ns/data-models#cctv", - "cdom": "https://uri.fiware.org/ns/data-models#cdom", - "centralIsland": "https://uri.fiware.org/ns/data-models#centralIsland", - "ceramics": "https://uri.fiware.org/ns/data-models#ceramics", - "chapel": "https://uri.fiware.org/ns/data-models#chapel", - "chargeType": { - "@id": "https://uri.fiware.org/ns/data-models#chargeType", - "@type": "@vocab" - }, - "chinese": "https://uri.fiware.org/ns/data-models#chinese", - "church": "https://uri.fiware.org/ns/data-models#church", - "cinema": "https://uri.fiware.org/ns/data-models#cinema", - "circuit": "https://uri.fiware.org/ns/data-models#circuit", - "circular": "https://uri.fiware.org/ns/data-models#circular", - "circus": "https://uri.fiware.org/ns/data-models#circus", - "civic": "https://uri.fiware.org/ns/data-models#civic", - "civilDisorder": "https://uri.fiware.org/ns/data-models#civilDisorder", - "civilEngineering": "https://uri.fiware.org/ns/data-models#civilEngineering", - "cleaningServices": "https://uri.fiware.org/ns/data-models#cleaningServices", - "cleaningTrolley": "https://uri.fiware.org/ns/data-models#cleaningTrolley", - "cloakRoom": "https://uri.fiware.org/ns/data-models#cloakRoom", - "cloister": "https://uri.fiware.org/ns/data-models#cloister", - "closed": "https://uri.fiware.org/ns/data-models#closed", - "closedAbnormal": "https://uri.fiware.org/ns/data-models#closedAbnormal", - "cng": "https://uri.fiware.org/ns/data-models#cng", - "co-creation": "https://uri.fiware.org/ns/data-models#co-creation", - "co2": "https://uri.fiware.org/ns/data-models#co2", - "coachStation": "https://uri.fiware.org/ns/data-models#coachStation", - "coastalEvent": "https://uri.fiware.org/ns/data-models#coastalEvent", - "code": "https://uri.fiware.org/ns/data-models#code", - "coldWave": "https://uri.fiware.org/ns/data-models#coldWave", - "color": "https://uri.fiware.org/ns/data-models#color", - "colorRenderingIndex": "https://uri.fiware.org/ns/data-models#colorRenderingIndex", - "colorTemperature": "https://uri.fiware.org/ns/data-models#colorTemperature", - "columnBrandName": "https://uri.fiware.org/ns/data-models#columnBrandName", - "columnColor": "https://uri.fiware.org/ns/data-models#columnColor", - "columnIssue": "https://uri.fiware.org/ns/data-models#columnIssue", - "columnMadeOf": { - "@id": "https://uri.fiware.org/ns/data-models#columnMadeOf", - "@type": "@vocab" - }, - "columnManufacturerName": "https://uri.fiware.org/ns/data-models#columnManufacturerName", - "columnModelName": "https://uri.fiware.org/ns/data-models#columnModelName", - "commercial": "https://uri.fiware.org/ns/data-models#commercial", - "commercial supply": "https://uri.fiware.org/ns/data-models#commercial supply", - "community": "https://uri.fiware.org/ns/data-models#community", - "compliantWith": "https://uri.fiware.org/ns/data-models#compliantWith", - "concrete": "https://uri.fiware.org/ns/data-models#concrete", - "conductance": "https://uri.fiware.org/ns/data-models#conductance", - "conductivity": "https://uri.fiware.org/ns/data-models#conductivity", - "conferenceRoom": "https://uri.fiware.org/ns/data-models#conferenceRoom", - "configuration": "https://uri.fiware.org/ns/data-models#configuration", - "congested": "https://uri.fiware.org/ns/data-models#congested", - "conservatory": "https://uri.fiware.org/ns/data-models#conservatory", - "construction": "https://uri.fiware.org/ns/data-models#construction", - "constructionOrMaintenanceVehicle": "https://uri.fiware.org/ns/data-models#constructionOrMaintenanceVehicle", - "contactPoint": "https://uri.fiware.org/ns/data-models#contactPoint", - "containedInPlace": "https://uri.fiware.org/ns/data-models#containedInPlace", - "containerFix": "https://uri.fiware.org/ns/data-models#containerFix", - "contemporaryArt": "https://uri.fiware.org/ns/data-models#contemporaryArt", - "controlledAsset": { - "@id": "https://uri.fiware.org/ns/data-models#controlledAsset", - "@type": "@id" - }, - "controlledProperty": { - "@id": "https://uri.fiware.org/ns/data-models#controlledProperty", - "@type": "@vocab" - }, - "controllingMethod": { - "@id": "https://uri.fiware.org/ns/data-models#controllingMethod", - "@type": "@vocab" - }, - "convent": "https://uri.fiware.org/ns/data-models#convent", - "conventionCentre": "https://uri.fiware.org/ns/data-models#conventionCentre", - "coordinates": { - "@container": "@list", - "@id": "https://purl.org/geojson/vocab#coordinates" - }, - "copyMachineOrService": "https://uri.fiware.org/ns/data-models#copyMachineOrService", - "cosPhi": "https://uri.fiware.org/ns/data-models#cosPhi", - "coverageRadius": "https://uri.fiware.org/ns/data-models#coverageRadius", - "covered": "https://uri.fiware.org/ns/data-models#covered", - "cow": "https://uri.fiware.org/ns/data-models#cow", - "cowshed": "https://uri.fiware.org/ns/data-models#cowshed", - "critical": "https://uri.fiware.org/ns/data-models#critical", - "cropNutrition": "https://uri.fiware.org/ns/data-models#cropNutrition", - "cropProtection": "https://uri.fiware.org/ns/data-models#cropProtection", - "cropStatus": { - "@id": "https://uri.fiware.org/ns/data-models#cropStatus", - "@type": "@vocab" - }, - "cropVariety": "https://uri.fiware.org/ns/data-models#cropVariety", - "cupboardMadeOf": { - "@id": "https://uri.fiware.org/ns/data-models#cupboardMadeOf", - "@type": "@vocab" - }, - "current": "https://uri.fiware.org/ns/data-models#current", - "currentStanding": { - "@id": "https://uri.fiware.org/ns/data-models#currentStanding", - "@type": "@vocab" - }, - "daily": "https://uri.fiware.org/ns/data-models#daily", - "dailyLight": "https://uri.fiware.org/ns/data-models#dailyLight", - "data": "https://uri.fiware.org/ns/data-models#data", - "dataProvider": "https://uri.fiware.org/ns/data-models#dataProvider", - "dateActivityEnded": { - "@id": "https://uri.fiware.org/ns/data-models#dateActivityEnded", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateActivityStarted": { - "@id": "https://uri.fiware.org/ns/data-models#dateActivityStarted", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateCreated": { - "@id": "https://uri.fiware.org/ns/data-models#dateCreated", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateEnergyMeteringStarted": { - "@id": "https://uri.fiware.org/ns/data-models#dateEnergyMeteringStarted", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateExpires": { - "@id": "https://uri.fiware.org/ns/data-models#dateExpires", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateFinished": { - "@id": "https://uri.fiware.org/ns/data-models#dateFinished", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateFirstUsed": { - "@id": "https://uri.fiware.org/ns/data-models#dateFirstUsed", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateInstalled": { - "@id": "https://uri.fiware.org/ns/data-models#dateInstalled", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateIssued": { - "@id": "https://uri.fiware.org/ns/data-models#dateIssued", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateLastCalibration": { - "@id": "https://uri.fiware.org/ns/data-models#dateLastCalibration", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateLastCleaning": { - "@id": "https://uri.fiware.org/ns/data-models#dateLastCleaning", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateLastEmptying": { - "@id": "https://uri.fiware.org/ns/data-models#dateLastEmptying", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateLastLampChange": { - "@id": "https://uri.fiware.org/ns/data-models#dateLastLampChange", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateLastProgramming": { - "@id": "https://uri.fiware.org/ns/data-models#dateLastProgramming", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateLastSwitchingOff": { - "@id": "https://uri.fiware.org/ns/data-models#dateLastSwitchingOff", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateLastSwitchingOn": { - "@id": "https://uri.fiware.org/ns/data-models#dateLastSwitchingOn", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateLastValueReported": { - "@id": "https://uri.fiware.org/ns/data-models#dateLastValueReported", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateLastWatering": { - "@id": "https://uri.fiware.org/ns/data-models#dateLastWatering", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateManufactured": { - "@id": "https://uri.fiware.org/ns/data-models#dateManufactured", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateMeteringStarted": { - "@id": "https://uri.fiware.org/ns/data-models#dateMeteringStarted", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateModified": { - "@id": "https://uri.fiware.org/ns/data-models#dateModified", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateNextCalculation": "https://uri.fiware.org/ns/data-models#dateNextCalculation", - "dateObserved": { - "@id": "https://uri.fiware.org/ns/data-models#dateObserved", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateObservedFrom": { - "@id": "https://uri.fiware.org/ns/data-models#dateObservedFrom", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateObservedTo": { - "@id": "https://uri.fiware.org/ns/data-models#dateObservedTo", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateRetrieved": { - "@id": "https://uri.fiware.org/ns/data-models#dateRetrieved", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateServiceStarted": { - "@id": "https://uri.fiware.org/ns/data-models#dateServiceStarted", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateStarted": { - "@id": "https://uri.fiware.org/ns/data-models#dateStarted", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "dateVehicleFirstRegistered": "https://uri.fiware.org/ns/data-models#dateVehicleFirstRegistered", - "day-LOW": "https://uri.fiware.org/ns/data-models#day-LOW", - "day-OFF": "https://uri.fiware.org/ns/data-models#day-OFF", - "day-ON": "https://uri.fiware.org/ns/data-models#day-ON", - "dayMaximum": "https://uri.fiware.org/ns/data-models#dayMaximum", - "dayMinimum": "https://uri.fiware.org/ns/data-models#dayMinimum", - "decorativeArts": "https://uri.fiware.org/ns/data-models#decorativeArts", - "defectiveLamp": "https://uri.fiware.org/ns/data-models#defectiveLamp", - "defibrillator": "https://uri.fiware.org/ns/data-models#defibrillator", - "departureTime": "https://uri.fiware.org/ns/data-models#departureTime", - "depth": "https://uri.fiware.org/ns/data-models#depth", - "description": "https://uri.etsi.org/ngsi-ld/description", - "detached": "https://uri.fiware.org/ns/data-models#detached", - "deviceClass": { - "@id": "https://uri.fiware.org/ns/data-models#deviceClass", - "@type": "@vocab" - }, - "deviceState": "https://uri.fiware.org/ns/data-models#deviceState", - "dewPoint": "https://uri.fiware.org/ns/data-models#dewPoint", - "diesel": "https://uri.fiware.org/ns/data-models#diesel", - "digester": "https://uri.fiware.org/ns/data-models#digester", - "diocesanMuseum": "https://uri.fiware.org/ns/data-models#diocesanMuseum", - "direction": { - "@id": "https://uri.fiware.org/ns/data-models#direction", - "@type": "@vocab" - }, - "directional": "https://uri.fiware.org/ns/data-models#directional", - "disabledRamp": "https://uri.fiware.org/ns/data-models#disabledRamp", - "displacementPowerFactor": "https://uri.fiware.org/ns/data-models#displacementPowerFactor", - "distanceTravelled": "https://uri.fiware.org/ns/data-models#distanceTravelled", - "documentation": "https://uri.fiware.org/ns/data-models#documentation", - "dog": "https://uri.fiware.org/ns/data-models#dog", - "dolmen": "https://uri.fiware.org/ns/data-models#dolmen", - "dormitory": "https://uri.fiware.org/ns/data-models#dormitory", - "drainFlow": "https://uri.fiware.org/ns/data-models#drainFlow", - "dropOff": "https://uri.fiware.org/ns/data-models#dropOff", - "dropOffMechanical": "https://uri.fiware.org/ns/data-models#dropOffMechanical", - "dropOffType": { - "@id": "https://uri.fiware.org/ns/data-models#dropOffType", - "@type": "@vocab" - }, - "dropOffWithValet": "https://uri.fiware.org/ns/data-models#dropOffWithValet", - "dropped": "https://uri.fiware.org/ns/data-models#dropped", - "dumpingStation": "https://uri.fiware.org/ns/data-models#dumpingStation", - "dumpster": "https://uri.fiware.org/ns/data-models#dumpster", - "earthquake": "https://uri.fiware.org/ns/data-models#earthquake", - "echelonParking": "https://uri.fiware.org/ns/data-models#echelonParking", - "effectiveSince": { - "@id": "https://uri.fiware.org/ns/data-models#effectiveSince", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "electric": "https://uri.fiware.org/ns/data-models#electric", - "electricChargingStation": "https://uri.fiware.org/ns/data-models#electricChargingStation", - "electricityConsumption": "https://uri.fiware.org/ns/data-models#electricityConsumption", - "electronics": "https://uri.fiware.org/ns/data-models#electronics", - "elevator": "https://uri.fiware.org/ns/data-models#elevator", - "elliptic": "https://uri.fiware.org/ns/data-models#elliptic", - "employeePermit": "https://uri.fiware.org/ns/data-models#employeePermit", - "empty": "https://uri.fiware.org/ns/data-models#empty", - "endDate": "https://uri.fiware.org/ns/data-models#endDate", - "endKilometer": "https://uri.fiware.org/ns/data-models#endKilometer", - "endPoint": "https://uri.fiware.org/ns/data-models#endPoint", - "endTime": "https://uri.fiware.org/ns/data-models#endTime", - "endedAt": { - "@id": "https://uri.fiware.org/ns/data-models#endedAt", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "endpoint": "https://uri.fiware.org/ns/data-models#endpoint", - "energy": "https://uri.fiware.org/ns/data-models#energy", - "energyConsumed": "https://uri.fiware.org/ns/data-models#energyConsumed", - "energyCost": "https://uri.fiware.org/ns/data-models#energyCost", - "energyLimitationClass": { - "@id": "https://uri.fiware.org/ns/data-models#energyLimitationClass", - "@type": "@vocab" - }, - "english": "https://uri.fiware.org/ns/data-models#english", - "entertainment": "https://uri.fiware.org/ns/data-models#entertainment", - "environment": "https://uri.fiware.org/ns/data-models#environment", - "ethnology": "https://uri.fiware.org/ns/data-models#ethnology", - "eventNotification": "https://uri.fiware.org/ns/data-models#eventNotification", - "eventParking": "https://uri.fiware.org/ns/data-models#eventParking", - "exactTimes": "https://uri.fiware.org/ns/data-models#exactTimes", - "exceptionType": { - "@id": "https://uri.fiware.org/ns/data-models#exceptionType", - "@type": "@vocab" - }, - "exhibitonCentre": "https://uri.fiware.org/ns/data-models#exhibitonCentre", - "extCategory": "https://uri.fiware.org/ns/data-models#extCategory", - "externalSecurity": "https://uri.fiware.org/ns/data-models#externalSecurity", - "extraSpotNumber": "https://uri.fiware.org/ns/data-models#extraSpotNumber", - "facilities": { - "@id": "https://uri.fiware.org/ns/data-models#facilities", - "@type": "@vocab" - }, - "failed": "https://uri.fiware.org/ns/data-models#failed", - "fair": "https://uri.fiware.org/ns/data-models#fair", - "fairPermit": "https://uri.fiware.org/ns/data-models#fairPermit", - "fairground": "https://uri.fiware.org/ns/data-models#fairground", - "fallenPatient": "https://uri.fiware.org/ns/data-models#fallenPatient", - "falling": "https://uri.fiware.org/ns/data-models#falling", - "farm": "https://uri.fiware.org/ns/data-models#farm", - "farm_auxiliary": "https://uri.fiware.org/ns/data-models#farm_auxiliary", - "faxMachineOrService": "https://uri.fiware.org/ns/data-models#faxMachineOrService", - "fa\u00e7ade": "https://uri.fiware.org/ns/data-models#fa\u00e7ade", - "feature": { - "@id": "https://uri.fiware.org/ns/data-models#feature", - "@type": "@vocab" - }, - "featuredArtist": { - "@id": "https://uri.fiware.org/ns/data-models#featuredArtist", - "@type": "@id" - }, - "features": { - "@id": "https://uri.fiware.org/ns/data-models#features", - "@type": "@vocab" - }, - "fedWith": { - "@id": "https://uri.fiware.org/ns/data-models#fedWith", - "@type": "@id" - }, - "feeCharged": "https://uri.fiware.org/ns/data-models#feeCharged", - "feelLikesTemperature": "https://uri.fiware.org/ns/data-models#feelLikesTemperature", - "female": "https://uri.fiware.org/ns/data-models#female", - "femaleAdult": "https://uri.fiware.org/ns/data-models#femaleAdult", - "femaleYoung": "https://uri.fiware.org/ns/data-models#femaleYoung", - "fenced": "https://uri.fiware.org/ns/data-models#fenced", - "fencedOff": "https://uri.fiware.org/ns/data-models#fencedOff", - "fences": "https://uri.fiware.org/ns/data-models#fences", - "ferryTerminal": "https://uri.fiware.org/ns/data-models#ferryTerminal", - "fertilisation": "https://uri.fiware.org/ns/data-models#fertilisation", - "fertiliser": "https://uri.fiware.org/ns/data-models#fertiliser", - "field": "https://uri.fiware.org/ns/data-models#field", - "fillingLevel": "https://uri.fiware.org/ns/data-models#fillingLevel", - "financial": "https://uri.fiware.org/ns/data-models#financial", - "fineArts": "https://uri.fiware.org/ns/data-models#fineArts", - "finished": "https://uri.fiware.org/ns/data-models#finished", - "fireBrigade": "https://uri.fiware.org/ns/data-models#fireBrigade", - "fireExtinguisher": "https://uri.fiware.org/ns/data-models#fireExtinguisher", - "fireHose": "https://uri.fiware.org/ns/data-models#fireHose", - "fireHydrant": "https://uri.fiware.org/ns/data-models#fireHydrant", - "fireRisk": "https://uri.fiware.org/ns/data-models#fireRisk", - "firmwareVersion": "https://uri.fiware.org/ns/data-models#firmwareVersion", - "firstAidEquipment": "https://uri.fiware.org/ns/data-models#firstAidEquipment", - "firstAvailableFloor": "https://uri.fiware.org/ns/data-models#firstAvailableFloor", - "firstIntervalPrice": "https://uri.fiware.org/ns/data-models#firstIntervalPrice", - "fishMarket": "https://uri.fiware.org/ns/data-models#fishMarket", - "fixed": "https://uri.fiware.org/ns/data-models#fixed", - "flashingBeacon": "https://uri.fiware.org/ns/data-models#flashingBeacon", - "flat": "https://uri.fiware.org/ns/data-models#flat", - "fleetVehicleId": "https://uri.fiware.org/ns/data-models#fleetVehicleId", - "flood": "https://uri.fiware.org/ns/data-models#flood", - "floodLight": "https://uri.fiware.org/ns/data-models#floodLight", - "floodRisk": "https://uri.fiware.org/ns/data-models#floodRisk", - "floorsAboveGround": "https://uri.fiware.org/ns/data-models#floorsAboveGround", - "floorsBelowGround": "https://uri.fiware.org/ns/data-models#floorsBelowGround", - "fog": "https://uri.fiware.org/ns/data-models#fog", - "forBabies": "https://uri.fiware.org/ns/data-models#forBabies", - "forCustomers": "https://uri.fiware.org/ns/data-models#forCustomers", - "forDisabled": "https://uri.fiware.org/ns/data-models#forDisabled", - "forElectricalCharging": "https://uri.fiware.org/ns/data-models#forElectricalCharging", - "forEmployees": "https://uri.fiware.org/ns/data-models#forEmployees", - "forMembers": "https://uri.fiware.org/ns/data-models#forMembers", - "forResidents": "https://uri.fiware.org/ns/data-models#forResidents", - "forStudents": "https://uri.fiware.org/ns/data-models#forStudents", - "forVisitors": "https://uri.fiware.org/ns/data-models#forVisitors", - "forestFire": "https://uri.fiware.org/ns/data-models#forestFire", - "fortifiedTemple": "https://uri.fiware.org/ns/data-models#fortifiedTemple", - "fortress": "https://uri.fiware.org/ns/data-models#fortress", - "forward": "https://uri.fiware.org/ns/data-models#forward", - "free": "https://uri.fiware.org/ns/data-models#free", - "freeAccess": "https://uri.fiware.org/ns/data-models#freeAccess", - "freeSlotNumber": "https://uri.fiware.org/ns/data-models#freeSlotNumber", - "french": "https://uri.fiware.org/ns/data-models#french", - "frequencies": "https://uri.fiware.org/ns/data-models#frequencies", - "frequency": "https://uri.fiware.org/ns/data-models#frequency", - "freshWater": "https://uri.fiware.org/ns/data-models#freshWater", - "friday": "https://uri.fiware.org/ns/data-models#friday", - "fuelConsumption": "https://uri.fiware.org/ns/data-models#fuelConsumption", - "fuelType": { - "@id": "https://uri.fiware.org/ns/data-models#fuelType", - "@type": "@vocab" - }, - "full": "https://uri.fiware.org/ns/data-models#full", - "fullAtEntrance": "https://uri.fiware.org/ns/data-models#fullAtEntrance", - "function": { - "@id": "https://uri.fiware.org/ns/data-models#function", - "@type": "@vocab" - }, - "fungus": "https://uri.fiware.org/ns/data-models#fungus", - "garage": "https://uri.fiware.org/ns/data-models#garage", - "garageBoxes": "https://uri.fiware.org/ns/data-models#garageBoxes", - "garages": "https://uri.fiware.org/ns/data-models#garages", - "garbageCollection": "https://uri.fiware.org/ns/data-models#garbageCollection", - "garbage_shed": "https://uri.fiware.org/ns/data-models#garbage_shed", - "garden": "https://uri.fiware.org/ns/data-models#garden", - "gasComsumption": "https://uri.fiware.org/ns/data-models#gasComsumption", - "gasoline": "https://uri.fiware.org/ns/data-models#gasoline", - "gate": "https://uri.fiware.org/ns/data-models#gate", - "gateAccess": "https://uri.fiware.org/ns/data-models#gateAccess", - "glass": "https://uri.fiware.org/ns/data-models#glass", - "goat": "https://uri.fiware.org/ns/data-models#goat", - "good": "https://uri.fiware.org/ns/data-models#good", - "goodsSelling": "https://uri.fiware.org/ns/data-models#goodsSelling", - "governmentPermit": "https://uri.fiware.org/ns/data-models#governmentPermit", - "gps": "https://uri.fiware.org/ns/data-models#gps", - "grandstand": "https://uri.fiware.org/ns/data-models#grandstand", - "grave": "https://uri.fiware.org/ns/data-models#grave", - "graveyard": "https://uri.fiware.org/ns/data-models#graveyard", - "grazingBaby": "https://uri.fiware.org/ns/data-models#grazingBaby", - "greenhouse": "https://uri.fiware.org/ns/data-models#greenhouse", - "ground": "https://uri.fiware.org/ns/data-models#ground", - "group": "https://uri.fiware.org/ns/data-models#group", - "growing": "https://uri.fiware.org/ns/data-models#growing", - "guard24hours": "https://uri.fiware.org/ns/data-models#guard24hours", - "guarded": "https://uri.fiware.org/ns/data-models#guarded", - "guidedTour": "https://uri.fiware.org/ns/data-models#guidedTour", - "hangar": "https://uri.fiware.org/ns/data-models#hangar", - "hardwareVersion": "https://uri.fiware.org/ns/data-models#hardwareVersion", - "harvestCommodity": "https://uri.fiware.org/ns/data-models#harvestCommodity", - "harvestingInterval": "https://uri.fiware.org/ns/data-models#harvestingInterval", - "hasAccessPoint": "https://uri.fiware.org/ns/data-models#hasAccessPoint", - "hasAgriCrop": { - "@id": "https://uri.fiware.org/ns/data-models#hasAgriCrop", - "@type": "@id" - }, - "hasAgriFertiliser": { - "@id": "https://uri.fiware.org/ns/data-models#hasAgriFertiliser", - "@type": "@id" - }, - "hasAgriParcel": { - "@id": "https://uri.fiware.org/ns/data-models#hasAgriParcel", - "@type": "@id" - }, - "hasAgriParcelChildren": { - "@id": "https://uri.fiware.org/ns/data-models#hasAgriParcelChildren", - "@type": "@id" - }, - "hasAgriParcelParent": { - "@id": "https://uri.fiware.org/ns/data-models#hasAgriParcelParent", - "@type": "@id" - }, - "hasAgriPest": { - "@id": "https://uri.fiware.org/ns/data-models#hasAgriPest", - "@type": "@id" - }, - "hasAgriProductType": { - "@id": "https://uri.fiware.org/ns/data-models#hasAgriProductType", - "@type": "@id" - }, - "hasAgriProductTypeChildren": { - "@id": "https://uri.fiware.org/ns/data-models#hasAgriProductTypeChildren", - "@type": "@id" - }, - "hasAgriProductTypeParent": { - "@id": "https://uri.fiware.org/ns/data-models#hasAgriProductTypeParent", - "@type": "@id" - }, - "hasAgriSoil": { - "@id": "https://uri.fiware.org/ns/data-models#hasAgriSoil", - "@type": "@id" - }, - "hasBuilding": { - "@id": "https://uri.fiware.org/ns/data-models#hasBuilding", - "@type": "@id" - }, - "hasDestination": "https://uri.fiware.org/ns/data-models#hasDestination", - "hasDevice": { - "@id": "https://uri.fiware.org/ns/data-models#hasDevice", - "@type": "@id" - }, - "hasDevices": { - "@id": "https://uri.fiware.org/ns/data-models#hasDevices", - "@type": "@id" - }, - "hasOperator": { - "@id": "https://uri.fiware.org/ns/data-models#hasOperator", - "@type": "@id" - }, - "hasOrigin": "https://uri.fiware.org/ns/data-models#hasOrigin", - "hasParentStation": "https://uri.fiware.org/ns/data-models#hasParentStation", - "hasProvider": { - "@id": "https://uri.fiware.org/ns/data-models#hasProvider", - "@type": "@id" - }, - "hasRoute": "https://uri.fiware.org/ns/data-models#hasRoute", - "hasService": "https://uri.fiware.org/ns/data-models#hasService", - "hasShape": "https://uri.fiware.org/ns/data-models#hasShape", - "hasStop": "https://uri.fiware.org/ns/data-models#hasStop", - "hasTrip": "https://uri.fiware.org/ns/data-models#hasTrip", - "hasWaterQualityObserved": { - "@id": "https://uri.fiware.org/ns/data-models#hasWaterQualityObserved", - "@type": "@id" - }, - "hasWeatherObserved": { - "@id": "https://uri.fiware.org/ns/data-models#hasWeatherObserved", - "@type": "@id" - }, - "hazardOnRoad": "https://uri.fiware.org/ns/data-models#hazardOnRoad", - "hazardous": "https://uri.fiware.org/ns/data-models#hazardous", - "headSign": "https://uri.fiware.org/ns/data-models#headSign", - "heading": "https://uri.fiware.org/ns/data-models#heading", - "headsign": "https://uri.fiware.org/ns/data-models#headsign", - "headwaySeconds": "https://uri.fiware.org/ns/data-models#headwaySeconds", - "health": "https://uri.fiware.org/ns/data-models#health", - "healthCondition": { - "@id": "https://uri.fiware.org/ns/data-models#healthCondition", - "@type": "@vocab" - }, - "healthy": "https://uri.fiware.org/ns/data-models#healthy", - "heartAttack": "https://uri.fiware.org/ns/data-models#heartAttack", - "heatWave": "https://uri.fiware.org/ns/data-models#heatWave", - "hedge": "https://uri.fiware.org/ns/data-models#hedge", - "height": "https://uri.fiware.org/ns/data-models#height", - "herb_garden": "https://uri.fiware.org/ns/data-models#herb_garden", - "hermitage": "https://uri.fiware.org/ns/data-models#hermitage", - "high": "https://uri.fiware.org/ns/data-models#high", - "highTemperature": "https://uri.fiware.org/ns/data-models#highTemperature", - "highest": "https://uri.fiware.org/ns/data-models#highest", - "highestFloor": "https://uri.fiware.org/ns/data-models#highestFloor", - "historicalPeriod": "https://uri.fiware.org/ns/data-models#historicalPeriod", - "history": "https://uri.fiware.org/ns/data-models#history", - "horse": "https://uri.fiware.org/ns/data-models#horse", - "hospital": "https://uri.fiware.org/ns/data-models#hospital", - "hostelry": "https://uri.fiware.org/ns/data-models#hostelry", - "hotel": "https://uri.fiware.org/ns/data-models#hotel", - "hourly": "https://uri.fiware.org/ns/data-models#hourly", - "house": "https://uri.fiware.org/ns/data-models#house", - "houseBuilding": "https://uri.fiware.org/ns/data-models#houseBuilding", - "houseboat": "https://uri.fiware.org/ns/data-models#houseboat", - "household": "https://uri.fiware.org/ns/data-models#household", - "humidity": "https://uri.fiware.org/ns/data-models#humidity", - "hurricane": "https://uri.fiware.org/ns/data-models#hurricane", - "hut": "https://uri.fiware.org/ns/data-models#hut", - "hybrid electric/diesel": "https://uri.fiware.org/ns/data-models#hybrid electric/diesel", - "hybrid electric/petrol": "https://uri.fiware.org/ns/data-models#hybrid electric/petrol", - "hydrogen": "https://uri.fiware.org/ns/data-models#hydrogen", - "ice": "https://uri.fiware.org/ns/data-models#ice", - "iceFreeScaffold": "https://uri.fiware.org/ns/data-models#iceFreeScaffold", - "illuminance": "https://uri.fiware.org/ns/data-models#illuminance", - "illuminanceLevel": "https://uri.fiware.org/ns/data-models#illuminanceLevel", - "image": "https://schema.org/image", - "inCalf": "https://uri.fiware.org/ns/data-models#inCalf", - "inHeat": "https://uri.fiware.org/ns/data-models#inHeat", - "inTreatment": "https://uri.fiware.org/ns/data-models#inTreatment", - "inactive": "https://uri.fiware.org/ns/data-models#inactive", - "inbound": "https://uri.fiware.org/ns/data-models#inbound", - "individual": "https://uri.fiware.org/ns/data-models#individual", - "individualControl": "https://uri.fiware.org/ns/data-models#individualControl", - "industrial": "https://uri.fiware.org/ns/data-models#industrial", - "industrialBuilding": "https://uri.fiware.org/ns/data-models#industrialBuilding", - "information": "https://uri.fiware.org/ns/data-models#information", - "informationPoint": "https://uri.fiware.org/ns/data-models#informationPoint", - "informational": "https://uri.fiware.org/ns/data-models#informational", - "infotainment": "https://uri.fiware.org/ns/data-models#infotainment", - "injuredBiker": "https://uri.fiware.org/ns/data-models#injuredBiker", - "inorganic": "https://uri.fiware.org/ns/data-models#inorganic", - "input": "https://uri.fiware.org/ns/data-models#input", - "insect": "https://uri.fiware.org/ns/data-models#insect", - "insertHoles": "https://uri.fiware.org/ns/data-models#insertHoles", - "insertHolesNumber": "https://uri.fiware.org/ns/data-models#insertHolesNumber", - "inspection": "https://uri.fiware.org/ns/data-models#inspection", - "intensity": "https://uri.fiware.org/ns/data-models#intensity", - "internetConnection": "https://uri.fiware.org/ns/data-models#internetConnection", - "internetWireless": "https://uri.fiware.org/ns/data-models#internetWireless", - "ipAddress": "https://uri.fiware.org/ns/data-models#ipAddress", - "irrigation": "https://uri.fiware.org/ns/data-models#irrigation", - "irrigationRecord": "https://uri.fiware.org/ns/data-models#irrigationRecord", - "isleId": "https://uri.fiware.org/ns/data-models#isleId", - "isolated": "https://uri.fiware.org/ns/data-models#isolated", - "issue": "https://uri.fiware.org/ns/data-models#issue", - "japanese": "https://uri.fiware.org/ns/data-models#japanese", - "justBorn": "https://uri.fiware.org/ns/data-models#justBorn", - "kindergarten": "https://uri.fiware.org/ns/data-models#kindergarten", - "kiosk": "https://uri.fiware.org/ns/data-models#kiosk", - "kissAndRide": "https://uri.fiware.org/ns/data-models#kissAndRide", - "kitchen": "https://uri.fiware.org/ns/data-models#kitchen", - "kpiValue": "https://uri.fiware.org/ns/data-models#kpiValue", - "lactatingBaby": "https://uri.fiware.org/ns/data-models#lactatingBaby", - "lagging": "https://uri.fiware.org/ns/data-models#lagging", - "lampBrandName": "https://uri.fiware.org/ns/data-models#lampBrandName", - "lampManufacturerName": "https://uri.fiware.org/ns/data-models#lampManufacturerName", - "lampModelName": "https://uri.fiware.org/ns/data-models#lampModelName", - "lampTechnology": { - "@id": "https://uri.fiware.org/ns/data-models#lampTechnology", - "@type": "@vocab" - }, - "lampWeight": "https://uri.fiware.org/ns/data-models#lampWeight", - "lamppost": "https://uri.fiware.org/ns/data-models#lamppost", - "landLocation": "https://uri.fiware.org/ns/data-models#landLocation", - "laneDirection": { - "@id": "https://uri.fiware.org/ns/data-models#laneDirection", - "@type": "@vocab" - }, - "laneId": "https://uri.fiware.org/ns/data-models#laneId", - "laneUsage": { - "@id": "https://uri.fiware.org/ns/data-models#laneUsage", - "@type": "@vocab" - }, - "language": "https://uri.fiware.org/ns/data-models#language", - "lanternBrandName": "https://uri.fiware.org/ns/data-models#lanternBrandName", - "lanternManufacturerName": "https://uri.fiware.org/ns/data-models#lanternManufacturerName", - "lanternModelName": "https://uri.fiware.org/ns/data-models#lanternModelName", - "lanternWeight": "https://uri.fiware.org/ns/data-models#lanternWeight", - "lastMeterReading": "https://uri.fiware.org/ns/data-models#lastMeterReading", - "lastPlantedAt": { - "@id": "https://uri.fiware.org/ns/data-models#lastPlantedAt", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "lastupdatedAt": { - "@id": "https://uri.fiware.org/ns/data-models#lastupdatedAt", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "laternHeight": "https://uri.fiware.org/ns/data-models#laternHeight", - "lawnArea": "https://uri.fiware.org/ns/data-models#lawnArea", - "layout": { - "@id": "https://uri.fiware.org/ns/data-models#layout", - "@type": "@vocab" - }, - "leading": "https://uri.fiware.org/ns/data-models#leading", - "leafRelativeHumidity": "https://uri.fiware.org/ns/data-models#leafRelativeHumidity", - "leafTemperature": "https://uri.fiware.org/ns/data-models#leafTemperature", - "leafWetness": "https://uri.fiware.org/ns/data-models#leafWetness", - "legalId": "https://uri.fiware.org/ns/data-models#legalId", - "length": "https://uri.fiware.org/ns/data-models#length", - "levelControl": "https://uri.fiware.org/ns/data-models#levelControl", - "lid": "https://uri.fiware.org/ns/data-models#lid", - "lidOpen": "https://uri.fiware.org/ns/data-models#lidOpen", - "lifeGuard": "https://uri.fiware.org/ns/data-models#lifeGuard", - "liftshare": "https://uri.fiware.org/ns/data-models#liftshare", - "light": "https://uri.fiware.org/ns/data-models#light", - "lightTower": "https://uri.fiware.org/ns/data-models#lightTower", - "lighting": "https://uri.fiware.org/ns/data-models#lighting", - "link": "https://uri.fiware.org/ns/data-models#link", - "literature": "https://uri.fiware.org/ns/data-models#literature", - "litterBins": "https://uri.fiware.org/ns/data-models#litterBins", - "loadingBay": "https://uri.fiware.org/ns/data-models#loadingBay", - "locatedAt": { - "@id": "https://uri.fiware.org/ns/data-models#locatedAt", - "@type": "@id" - }, - "location": "http://uri.etsi.org/ngsi-ld/location", - "locationCategory": { - "@id": "https://uri.fiware.org/ns/data-models#locationCategory", - "@type": "@vocab" - }, - "lockable": "https://uri.fiware.org/ns/data-models#lockable", - "longTerm": "https://uri.fiware.org/ns/data-models#longTerm", - "lorry": "https://uri.fiware.org/ns/data-models#lorry", - "low": "https://uri.fiware.org/ns/data-models#low", - "lowTemperature": "https://uri.fiware.org/ns/data-models#lowTemperature", - "lowest": "https://uri.fiware.org/ns/data-models#lowest", - "lowestFloor": "https://uri.fiware.org/ns/data-models#lowestFloor", - "lpg": "https://uri.fiware.org/ns/data-models#lpg", - "luggageLocker": "https://uri.fiware.org/ns/data-models#luggageLocker", - "luminousFlux": "https://uri.fiware.org/ns/data-models#luminousFlux", - "macAddress": "https://uri.fiware.org/ns/data-models#macAddress", - "madeOf": { - "@id": "https://uri.fiware.org/ns/data-models#madeOf", - "@type": "@vocab" - }, - "madeOfCode": "https://uri.fiware.org/ns/data-models#madeOfCode", - "maintenance": "https://uri.fiware.org/ns/data-models#maintenance", - "male": "https://uri.fiware.org/ns/data-models#male", - "maleAdult": "https://uri.fiware.org/ns/data-models#maleAdult", - "maleYoung": "https://uri.fiware.org/ns/data-models#maleYoung", - "mandatory": "https://uri.fiware.org/ns/data-models#mandatory", - "mansion": "https://uri.fiware.org/ns/data-models#mansion", - "manual": "https://uri.fiware.org/ns/data-models#manual", - "manufacturerName": "https://uri.fiware.org/ns/data-models#manufacturerName", - "maritime": "https://uri.fiware.org/ns/data-models#maritime", - "market": "https://uri.fiware.org/ns/data-models#market", - "masia": "https://uri.fiware.org/ns/data-models#masia", - "masiaFortificada": "https://uri.fiware.org/ns/data-models#masiaFortificada", - "maturing": "https://uri.fiware.org/ns/data-models#maturing", - "maxPowerConsumption": "https://uri.fiware.org/ns/data-models#maxPowerConsumption", - "maximum": "https://uri.fiware.org/ns/data-models#maximum", - "maximumAllowedDuration": "https://uri.fiware.org/ns/data-models#maximumAllowedDuration", - "maximumAllowedHeight": "https://uri.fiware.org/ns/data-models#maximumAllowedHeight", - "maximumAllowedSpeed": "https://uri.fiware.org/ns/data-models#maximumAllowedSpeed", - "maximumAllowedWeight": "https://uri.fiware.org/ns/data-models#maximumAllowedWeight", - "maximumAllowedWidth": "https://uri.fiware.org/ns/data-models#maximumAllowedWidth", - "maximumLoad": "https://uri.fiware.org/ns/data-models#maximumLoad", - "maximumPowerAvailable": "https://uri.fiware.org/ns/data-models#maximumPowerAvailable", - "measurand": "https://uri.fiware.org/ns/data-models#measurand", - "measuresPeriod": "https://uri.fiware.org/ns/data-models#measuresPeriod", - "measuresPeriodUnit": "https://uri.fiware.org/ns/data-models#measuresPeriodUnit", - "medicineAndPharmacy": "https://uri.fiware.org/ns/data-models#medicineAndPharmacy", - "medium": "https://uri.fiware.org/ns/data-models#medium", - "mediumTerm": "https://uri.fiware.org/ns/data-models#mediumTerm", - "menhir": "https://uri.fiware.org/ns/data-models#menhir", - "metal": "https://uri.fiware.org/ns/data-models#metal", - "meterReadingPeriod": "https://uri.fiware.org/ns/data-models#meterReadingPeriod", - "metering": "https://uri.fiware.org/ns/data-models#metering", - "methaneConcentration": "https://uri.fiware.org/ns/data-models#methaneConcentration", - "microbe": "https://uri.fiware.org/ns/data-models#microbe", - "mileageFromOdometer": "https://uri.fiware.org/ns/data-models#mileageFromOdometer", - "military": "https://uri.fiware.org/ns/data-models#military", - "militaryBuilding": "https://uri.fiware.org/ns/data-models#militaryBuilding", - "minPowerConsumption": "https://uri.fiware.org/ns/data-models#minPowerConsumption", - "minaret": "https://uri.fiware.org/ns/data-models#minaret", - "minibus": "https://uri.fiware.org/ns/data-models#minibus", - "minimum": "https://uri.fiware.org/ns/data-models#minimum", - "minimumAllowedSpeed": "https://uri.fiware.org/ns/data-models#minimumAllowedSpeed", - "minimumTransferTime": "https://uri.fiware.org/ns/data-models#minimumTransferTime", - "mining": "https://uri.fiware.org/ns/data-models#mining", - "mite": "https://uri.fiware.org/ns/data-models#mite", - "mnc": "https://uri.fiware.org/ns/data-models#mnc", - "modelBased": "https://uri.fiware.org/ns/data-models#modelBased", - "modelName": "https://uri.fiware.org/ns/data-models#modelName", - "moderate": "https://uri.fiware.org/ns/data-models#moderate", - "modernArt": "https://uri.fiware.org/ns/data-models#modernArt", - "monastary": "https://uri.fiware.org/ns/data-models#monastary", - "monastery": "https://uri.fiware.org/ns/data-models#monastery", - "monday": "https://uri.fiware.org/ns/data-models#monday", - "monolith": "https://uri.fiware.org/ns/data-models#monolith", - "monthly": "https://uri.fiware.org/ns/data-models#monthly", - "monthlyPayment": "https://uri.fiware.org/ns/data-models#monthlyPayment", - "moped": "https://uri.fiware.org/ns/data-models#moped", - "mosque": "https://uri.fiware.org/ns/data-models#mosque", - "motion": "https://uri.fiware.org/ns/data-models#motion", - "motorcycle": "https://uri.fiware.org/ns/data-models#motorcycle", - "motorcycleWithSideCar": "https://uri.fiware.org/ns/data-models#motorcycleWithSideCar", - "motorscooter": "https://uri.fiware.org/ns/data-models#motorscooter", - "motorway": "https://uri.fiware.org/ns/data-models#motorway", - "moved": "https://uri.fiware.org/ns/data-models#moved", - "multiDisciplinar": "https://uri.fiware.org/ns/data-models#multiDisciplinar", - "multiLevel": "https://uri.fiware.org/ns/data-models#multiLevel", - "multiStorey": "https://uri.fiware.org/ns/data-models#multiStorey", - "municipal": "https://uri.fiware.org/ns/data-models#municipal", - "municipalServices": "https://uri.fiware.org/ns/data-models#municipalServices", - "museumHouse": "https://uri.fiware.org/ns/data-models#museumHouse", - "museumType": { - "@id": "https://uri.fiware.org/ns/data-models#museumType", - "@type": "@vocab" - }, - "music": "https://uri.fiware.org/ns/data-models#music", - "name": "https://uri.etsi.org/ngsi-ld/name", - "naturalDisaster": "https://uri.fiware.org/ns/data-models#naturalDisaster", - "naturalScience": "https://uri.fiware.org/ns/data-models#naturalScience", - "necropolis": "https://uri.fiware.org/ns/data-models#necropolis", - "nematodes": "https://uri.fiware.org/ns/data-models#nematodes", - "nested": "https://uri.fiware.org/ns/data-models#nested", - "network": "https://uri.fiware.org/ns/data-models#network", - "nextActuationDeadline": { - "@id": "https://uri.fiware.org/ns/data-models#nextActuationDeadline", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "nextCleaningDeadline": { - "@id": "https://uri.fiware.org/ns/data-models#nextCleaningDeadline", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "nextWateringDeadline": { - "@id": "https://uri.fiware.org/ns/data-models#nextWateringDeadline", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "night-LOW": "https://uri.fiware.org/ns/data-models#night-LOW", - "night-OFF": "https://uri.fiware.org/ns/data-models#night-OFF", - "night-ON": "https://uri.fiware.org/ns/data-models#night-ON", - "noPermitNeeded": "https://uri.fiware.org/ns/data-models#noPermitNeeded", - "noStatus": "https://uri.fiware.org/ns/data-models#noStatus", - "nobleHouse": "https://uri.fiware.org/ns/data-models#nobleHouse", - "noiseLevel": "https://uri.fiware.org/ns/data-models#noiseLevel", - "nonTracked": "https://uri.fiware.org/ns/data-models#nonTracked", - "none": "https://uri.fiware.org/ns/data-models#none", - "notAvailable": "https://uri.fiware.org/ns/data-models#notAvailable", - "noxiousWeed": "https://uri.fiware.org/ns/data-models#noxiousWeed", - "numismatic": "https://uri.fiware.org/ns/data-models#numismatic", - "observedAt": { - "@id": "https://uri.fiware.org/ns/data-models#observedAt", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "occupancy": "https://uri.fiware.org/ns/data-models#occupancy", - "occupancyDetectionType": { - "@id": "https://uri.fiware.org/ns/data-models#occupancyDetectionType", - "@type": "@vocab" - }, - "occupationRate": { - "@id": "https://uri.fiware.org/ns/data-models#occupationRate", - "@type": "@vocab" - }, - "occupied": "https://uri.fiware.org/ns/data-models#occupied", - "occupier": { - "@id": "https://uri.fiware.org/ns/data-models#occupier", - "@type": "@id" - }, - "off": "https://uri.fiware.org/ns/data-models#off", - "office": "https://uri.fiware.org/ns/data-models#office", - "officeBuilding": "https://uri.fiware.org/ns/data-models#officeBuilding", - "offstreet": "https://uri.fiware.org/ns/data-models#offstreet", - "oil": "https://uri.fiware.org/ns/data-models#oil", - "ok": "https://uri.fiware.org/ns/data-models#ok", - "on": "https://uri.fiware.org/ns/data-models#on", - "onDemand": "https://uri.fiware.org/ns/data-models#onDemand", - "onFoot": "https://uri.fiware.org/ns/data-models#onFoot", - "onOff": "https://uri.fiware.org/ns/data-models#onOff", - "onRoute": "https://uri.fiware.org/ns/data-models#onRoute", - "oneway": "https://uri.fiware.org/ns/data-models#oneway", - "ongoing": "https://uri.fiware.org/ns/data-models#ongoing", - "onlyResidents": "https://uri.fiware.org/ns/data-models#onlyResidents", - "onlyWithPermit": "https://uri.fiware.org/ns/data-models#onlyWithPermit", - "onstreet": "https://uri.fiware.org/ns/data-models#onstreet", - "open": "https://uri.fiware.org/ns/data-models#open", - "openClose": "https://uri.fiware.org/ns/data-models#openClose", - "openSpace": "https://uri.fiware.org/ns/data-models#openSpace", - "openingHours": "https://schema.org/openingHours", - "openingHoursSpecification": "https://uri.fiware.org/ns/data-models#openingHoursSpecification", - "openingTimesInForce": "https://uri.fiware.org/ns/data-models#openingTimesInForce", - "operatedBy": "https://uri.fiware.org/ns/data-models#operatedBy", - "operationSequence": "https://uri.fiware.org/ns/data-models#operationSequence", - "operationType": { - "@id": "https://uri.fiware.org/ns/data-models#operationType", - "@type": "@vocab" - }, - "operator": "https://uri.fiware.org/ns/data-models#operator", - "optional": "https://uri.fiware.org/ns/data-models#optional", - "organic": "https://uri.fiware.org/ns/data-models#organic", - "organization": "https://uri.fiware.org/ns/data-models#organization", - "ornamentalLantern": "https://uri.fiware.org/ns/data-models#ornamentalLantern", - "orp": "https://uri.fiware.org/ns/data-models#orp", - "osVersion": "https://uri.fiware.org/ns/data-models#osVersion", - "other": "https://uri.fiware.org/ns/data-models#other", - "outOfService": "https://uri.fiware.org/ns/data-models#outOfService", - "outOfServiceSlotNumber": "https://uri.fiware.org/ns/data-models#outOfServiceSlotNumber", - "outbound": "https://uri.fiware.org/ns/data-models#outbound", - "output": "https://uri.fiware.org/ns/data-models#output", - "overnightParking": "https://uri.fiware.org/ns/data-models#overnightParking", - "overspeed": "https://uri.fiware.org/ns/data-models#overspeed", - "ownedBy": { - "@id": "https://uri.fiware.org/ns/data-models#ownedBy", - "@type": "@id" - }, - "owner": { - "@id": "https://uri.fiware.org/ns/data-models#owner", - "@type": "@id" - }, - "pH": "https://uri.fiware.org/ns/data-models#pH", - "page": "https://uri.fiware.org/ns/data-models#page", - "painting": "https://uri.fiware.org/ns/data-models#painting", - "palace": "https://uri.fiware.org/ns/data-models#palace", - "paleonthology": "https://uri.fiware.org/ns/data-models#paleonthology", - "pantheon": "https://uri.fiware.org/ns/data-models#pantheon", - "paper": "https://uri.fiware.org/ns/data-models#paper", - "parallelParking": "https://uri.fiware.org/ns/data-models#parallelParking", - "park": "https://uri.fiware.org/ns/data-models#park", - "parkAndCycle": "https://uri.fiware.org/ns/data-models#parkAndCycle", - "parkAndRide": "https://uri.fiware.org/ns/data-models#parkAndRide", - "parkAndWalk": "https://uri.fiware.org/ns/data-models#parkAndWalk", - "parked": "https://uri.fiware.org/ns/data-models#parked", - "parking": "https://uri.fiware.org/ns/data-models#parking", - "parkingGarage": "https://uri.fiware.org/ns/data-models#parkingGarage", - "parkingLot": "https://uri.fiware.org/ns/data-models#parkingLot", - "parkingMode": { - "@id": "https://uri.fiware.org/ns/data-models#parkingMode", - "@type": "@vocab" - }, - "parksAndGardens": "https://uri.fiware.org/ns/data-models#parksAndGardens", - "partly": "https://uri.fiware.org/ns/data-models#partly", - "patrolled": "https://uri.fiware.org/ns/data-models#patrolled", - "pavilion": "https://uri.fiware.org/ns/data-models#pavilion", - "payDesk": "https://uri.fiware.org/ns/data-models#payDesk", - "paymentMachine": "https://uri.fiware.org/ns/data-models#paymentMachine", - "pazo": "https://uri.fiware.org/ns/data-models#pazo", - "pedestrianPath": "https://uri.fiware.org/ns/data-models#pedestrianPath", - "peopleCount": "https://uri.fiware.org/ns/data-models#peopleCount", - "perpendicularParking": "https://uri.fiware.org/ns/data-models#perpendicularParking", - "pesticide": "https://uri.fiware.org/ns/data-models#pesticide", - "petrol": "https://uri.fiware.org/ns/data-models#petrol", - "petrol(leaded)": "https://uri.fiware.org/ns/data-models#petrol(leaded)", - "petrol(unleaded)": "https://uri.fiware.org/ns/data-models#petrol(unleaded)", - "phaseToPhaseVoltage": "https://uri.fiware.org/ns/data-models#phaseToPhaseVoltage", - "phaseVoltage": "https://uri.fiware.org/ns/data-models#phaseVoltage", - "phenologicalCondition": { - "@id": "https://uri.fiware.org/ns/data-models#phenologicalCondition", - "@type": "@vocab" - }, - "phone": "https://uri.fiware.org/ns/data-models#phone", - "pickupType": { - "@id": "https://uri.fiware.org/ns/data-models#pickupType", - "@type": "@vocab" - }, - "pig": "https://uri.fiware.org/ns/data-models#pig", - "planned": "https://uri.fiware.org/ns/data-models#planned", - "plannedEndAt": { - "@id": "https://uri.fiware.org/ns/data-models#plannedEndAt", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "plannedStartAt": { - "@id": "https://uri.fiware.org/ns/data-models#plannedStartAt", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "plantingFrom": "https://uri.fiware.org/ns/data-models#plantingFrom", - "plastic": "https://uri.fiware.org/ns/data-models#plastic", - "playground": "https://uri.fiware.org/ns/data-models#playground", - "police": "https://uri.fiware.org/ns/data-models#police", - "pollenConcentration": "https://uri.fiware.org/ns/data-models#pollenConcentration", - "polularArchitecture": "https://uri.fiware.org/ns/data-models#polularArchitecture", - "polygon": "https://uri.fiware.org/ns/data-models#polygon", - "popularArtsAndTraditions": "https://uri.fiware.org/ns/data-models#popularArtsAndTraditions", - "portable": "https://uri.fiware.org/ns/data-models#portable", - "postTop": "https://uri.fiware.org/ns/data-models#postTop", - "pothole": "https://uri.fiware.org/ns/data-models#pothole", - "power": "https://uri.fiware.org/ns/data-models#power", - "powerConsumption": "https://uri.fiware.org/ns/data-models#powerConsumption", - "powerFactor": "https://uri.fiware.org/ns/data-models#powerFactor", - "powerState": { - "@id": "https://uri.fiware.org/ns/data-models#powerState", - "@type": "@vocab" - }, - "practical": "https://uri.fiware.org/ns/data-models#practical", - "precipitation": "https://uri.fiware.org/ns/data-models#precipitation", - "prehistoric": "https://uri.fiware.org/ns/data-models#prehistoric", - "prehistoricCave": "https://uri.fiware.org/ns/data-models#prehistoricCave", - "prehistoricPlace": "https://uri.fiware.org/ns/data-models#prehistoricPlace", - "pressure": "https://uri.fiware.org/ns/data-models#pressure", - "pressureTendency": { - "@id": "https://uri.fiware.org/ns/data-models#pressureTendency", - "@type": "@vocab" - }, - "previousLocation": "https://uri.fiware.org/ns/data-models#previousLocation", - "priceCurrency": "https://uri.fiware.org/ns/data-models#priceCurrency", - "priceRatePerMinute": "https://uri.fiware.org/ns/data-models#priceRatePerMinute", - "primary": "https://uri.fiware.org/ns/data-models#primary", - "private": "https://uri.fiware.org/ns/data-models#private", - "privateVehicle": "https://uri.fiware.org/ns/data-models#privateVehicle", - "proCathedral": "https://uri.fiware.org/ns/data-models#proCathedral", - "process": "https://uri.fiware.org/ns/data-models#process", - "product": "https://uri.fiware.org/ns/data-models#product", - "promenade": "https://uri.fiware.org/ns/data-models#promenade", - "provider": "https://uri.fiware.org/ns/data-models#provider", - "proximitySensor": "https://uri.fiware.org/ns/data-models#proximitySensor", - "public": "https://uri.fiware.org/ns/data-models#public", - "publicBuilding": "https://uri.fiware.org/ns/data-models#publicBuilding", - "publicPhone": "https://uri.fiware.org/ns/data-models#publicPhone", - "publicPrivate": "https://uri.fiware.org/ns/data-models#publicPrivate", - "publicTransport": "https://uri.fiware.org/ns/data-models#publicTransport", - "publicTransportStation": "https://uri.fiware.org/ns/data-models#publicTransportStation", - "purchaseDate": { - "@id": "https://uri.fiware.org/ns/data-models#purchaseDate", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "pyramid": "https://uri.fiware.org/ns/data-models#pyramid", - "qualitative": "https://uri.fiware.org/ns/data-models#qualitative", - "quantitative": "https://uri.fiware.org/ns/data-models#quantitative", - "quantity": "https://uri.fiware.org/ns/data-models#quantity", - "quarterly": "https://uri.fiware.org/ns/data-models#quarterly", - "railway": "https://uri.fiware.org/ns/data-models#railway", - "rainfall": "https://uri.fiware.org/ns/data-models#rainfall", - "rainwater capture": "https://uri.fiware.org/ns/data-models#rainwater capture", - "raising": "https://uri.fiware.org/ns/data-models#raising", - "ramp": "https://uri.fiware.org/ns/data-models#ramp", - "reactiveEnergyConsumed": "https://uri.fiware.org/ns/data-models#reactiveEnergyConsumed", - "reactiveEnergyExport": "https://uri.fiware.org/ns/data-models#reactiveEnergyExport", - "reactiveEnergyImport": "https://uri.fiware.org/ns/data-models#reactiveEnergyImport", - "reactivePower": "https://uri.fiware.org/ns/data-models#reactivePower", - "readyForHarvesting": "https://uri.fiware.org/ns/data-models#readyForHarvesting", - "recommendedLoad": "https://uri.fiware.org/ns/data-models#recommendedLoad", - "rectangular": "https://uri.fiware.org/ns/data-models#rectangular", - "refActivity": { - "@id": "https://uri.fiware.org/ns/data-models#refActivity", - "@type": "@id" - }, - "refAgent": { - "@id": "https://uri.fiware.org/ns/data-models#refAgent", - "@type": "@id" - }, - "refBuilding": { - "@id": "https://uri.fiware.org/ns/data-models#refBuilding", - "@type": "@id" - }, - "refDevice": { - "@id": "https://uri.fiware.org/ns/data-models#refDevice", - "@type": "@id" - }, - "refDeviceModel": { - "@id": "https://uri.fiware.org/ns/data-models#refDeviceModel", - "@type": "@id" - }, - "refGarden": { - "@id": "https://uri.fiware.org/ns/data-models#refGarden", - "@type": "@id" - }, - "refGreenspace": { - "@id": "https://uri.fiware.org/ns/data-models#refGreenspace", - "@type": "@id" - }, - "refGtfsTransitFeedFile": "https://uri.fiware.org/ns/data-models#refGtfsTransitFeedFile", - "refMap": "https://uri.fiware.org/ns/data-models#refMap", - "refObject": { - "@id": "https://uri.fiware.org/ns/data-models#refObject", - "@type": "@id" - }, - "refOperator": { - "@id": "https://uri.fiware.org/ns/data-models#refOperator", - "@type": "@id" - }, - "refParkingAccess": { - "@id": "https://uri.fiware.org/ns/data-models#refParkingAccess", - "@type": "@id" - }, - "refParkingGroup": { - "@id": "https://uri.fiware.org/ns/data-models#refParkingGroup", - "@type": "@id" - }, - "refParkingSite": { - "@id": "https://uri.fiware.org/ns/data-models#refParkingSite", - "@type": "@id" - }, - "refParkingSpot": { - "@id": "https://uri.fiware.org/ns/data-models#refParkingSpot", - "@type": "@id" - }, - "refPointOfInterest": { - "@id": "https://uri.fiware.org/ns/data-models#refPointOfInterest", - "@type": "@id" - }, - "refRecord": { - "@id": "https://uri.fiware.org/ns/data-models#refRecord", - "@type": "@id" - }, - "refRelatedBuildingOperation": { - "@id": "https://uri.fiware.org/ns/data-models#refRelatedBuildingOperation", - "@type": "@id" - }, - "refRelatedDeviceOperation": { - "@id": "https://uri.fiware.org/ns/data-models#refRelatedDeviceOperation", - "@type": "@id" - }, - "refRelatedEntity": { - "@id": "https://uri.fiware.org/ns/data-models#refRelatedEntity", - "@type": "@id" - }, - "refRoad": { - "@id": "https://uri.fiware.org/ns/data-models#refRoad", - "@type": "@id" - }, - "refRoadSegment": "https://uri.fiware.org/ns/data-models#refRoadSegment", - "refSeeAlso": { - "@id": "https://uri.fiware.org/ns/data-models#refSeeAlso", - "@type": "@id" - }, - "refSmartPointOfInteraction": { - "@id": "https://uri.fiware.org/ns/data-models#refSmartPointOfInteraction", - "@type": "@id" - }, - "refSmartSpot": { - "@id": "https://uri.fiware.org/ns/data-models#refSmartSpot", - "@type": "@id" - }, - "refStreetlight": { - "@id": "https://uri.fiware.org/ns/data-models#refStreetlight", - "@type": "@id" - }, - "refStreetlightControlCabinet": { - "@id": "https://uri.fiware.org/ns/data-models#refStreetlightControlCabinet", - "@type": "@id" - }, - "refStreetlightGroup": { - "@id": "https://uri.fiware.org/ns/data-models#refStreetlightGroup", - "@type": "@id" - }, - "refStreetlightModel": { - "@id": "https://uri.fiware.org/ns/data-models#refStreetlightModel", - "@type": "@id" - }, - "refTarget": { - "@id": "https://uri.fiware.org/ns/data-models#refTarget", - "@type": "@id" - }, - "refTargetDevice": { - "@id": "https://uri.fiware.org/ns/data-models#refTargetDevice", - "@type": "@id" - }, - "refUser": { - "@id": "https://uri.fiware.org/ns/data-models#refUser", - "@type": "@id" - }, - "refUserDevice": { - "@id": "https://uri.fiware.org/ns/data-models#refUserDevice", - "@type": "@id" - }, - "refVehicleModel": { - "@id": "https://uri.fiware.org/ns/data-models#refVehicleModel", - "@type": "@id" - }, - "refWasteContainer": { - "@id": "https://uri.fiware.org/ns/data-models#refWasteContainer", - "@type": "@id" - }, - "refWasteContainerIsle": { - "@id": "https://uri.fiware.org/ns/data-models#refWasteContainerIsle", - "@type": "@id" - }, - "refWasteContainerModel": { - "@id": "https://uri.fiware.org/ns/data-models#refWasteContainerModel", - "@type": "@id" - }, - "refWeatherObserved": { - "@id": "https://uri.fiware.org/ns/data-models#refWeatherObserved", - "@type": "@id" - }, - "refuseBin": "https://uri.fiware.org/ns/data-models#refuseBin", - "regulation": "https://uri.fiware.org/ns/data-models#regulation", - "relatedSource": { - "@id": "https://uri.fiware.org/ns/data-models#relatedSource", - "@type": "@id" - }, - "relativeHumidity": "https://uri.fiware.org/ns/data-models#relativeHumidity", - "reliability": "https://uri.fiware.org/ns/data-models#reliability", - "religiousCentre": "https://uri.fiware.org/ns/data-models#religiousCentre", - "remainingDistance": "https://uri.fiware.org/ns/data-models#remainingDistance", - "remainingTime": "https://uri.fiware.org/ns/data-models#remainingTime", - "reportedAt": { - "@id": "https://uri.fiware.org/ns/data-models#reportedAt", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "reproductiveCondition": { - "@id": "https://uri.fiware.org/ns/data-models#reproductiveCondition", - "@type": "@vocab" - }, - "requiredPermit": { - "@id": "https://uri.fiware.org/ns/data-models#requiredPermit", - "@type": "@vocab" - }, - "reservation": "https://uri.fiware.org/ns/data-models#reservation", - "reservationType": { - "@id": "https://uri.fiware.org/ns/data-models#reservationType", - "@type": "@vocab" - }, - "residence": "https://uri.fiware.org/ns/data-models#residence", - "residentPermit": "https://uri.fiware.org/ns/data-models#residentPermit", - "residential": "https://uri.fiware.org/ns/data-models#residential", - "responsible": "https://uri.fiware.org/ns/data-models#responsible", - "restArea": "https://uri.fiware.org/ns/data-models#restArea", - "restaurant": "https://uri.fiware.org/ns/data-models#restaurant", - "result": { - "@id": "https://uri.fiware.org/ns/data-models#result", - "@type": "@vocab" - }, - "retail": "https://uri.fiware.org/ns/data-models#retail", - "reversedLane": "https://uri.fiware.org/ns/data-models#reversedLane", - "riding_hall": "https://uri.fiware.org/ns/data-models#riding_hall", - "river": "https://uri.fiware.org/ns/data-models#river", - "road": "https://uri.fiware.org/ns/data-models#road", - "roadClass": { - "@id": "https://uri.fiware.org/ns/data-models#roadClass", - "@type": "@vocab" - }, - "roadClosed": "https://uri.fiware.org/ns/data-models#roadClosed", - "roadSignalling": "https://uri.fiware.org/ns/data-models#roadSignalling", - "roadWorks": "https://uri.fiware.org/ns/data-models#roadWorks", - "robbery": "https://uri.fiware.org/ns/data-models#robbery", - "rodent": "https://uri.fiware.org/ns/data-models#rodent", - "roof": "https://uri.fiware.org/ns/data-models#roof", - "rooftop": "https://uri.fiware.org/ns/data-models#rooftop", - "root": "https://uri.fiware.org/ns/data-models#root", - "rosarium": "https://uri.fiware.org/ns/data-models#rosarium", - "roundedLid": "https://uri.fiware.org/ns/data-models#roundedLid", - "routeColor": "https://uri.fiware.org/ns/data-models#routeColor", - "routeId": "https://uri.fiware.org/ns/data-models#routeId", - "routeSortOrder": "https://uri.fiware.org/ns/data-models#routeSortOrder", - "routeTextColor": "https://uri.fiware.org/ns/data-models#routeTextColor", - "routeType": { - "@id": "https://uri.fiware.org/ns/data-models#routeType", - "@type": "@vocab" - }, - "rssi": "https://uri.fiware.org/ns/data-models#rssi", - "ruins": "https://uri.fiware.org/ns/data-models#ruins", - "sacredArt": "https://uri.fiware.org/ns/data-models#sacredArt", - "safeDeposit": "https://uri.fiware.org/ns/data-models#safeDeposit", - "salinity": "https://uri.fiware.org/ns/data-models#salinity", - "sanctuary": "https://uri.fiware.org/ns/data-models#sanctuary", - "saturday": "https://uri.fiware.org/ns/data-models#saturday", - "scheduled": "https://uri.fiware.org/ns/data-models#scheduled", - "school": "https://uri.fiware.org/ns/data-models#school", - "schoolTransportation": "https://uri.fiware.org/ns/data-models#schoolTransportation", - "scienceAndTechnology": "https://uri.fiware.org/ns/data-models#scienceAndTechnology", - "sculpturalGroups": "https://uri.fiware.org/ns/data-models#sculpturalGroups", - "sculpture": "https://uri.fiware.org/ns/data-models#sculpture", - "seasonTicket": "https://uri.fiware.org/ns/data-models#seasonTicket", - "secondary": "https://uri.fiware.org/ns/data-models#secondary", - "security": "https://uri.fiware.org/ns/data-models#security", - "securityStaff": "https://uri.fiware.org/ns/data-models#securityStaff", - "seeAlso": "https://uri.fiware.org/ns/data-models#seeAlso", - "seeded": "https://uri.fiware.org/ns/data-models#seeded", - "semiautomatic": "https://uri.fiware.org/ns/data-models#semiautomatic", - "seminar": "https://uri.fiware.org/ns/data-models#seminar", - "sensing": "https://uri.fiware.org/ns/data-models#sensing", - "serialNumber": "https://uri.fiware.org/ns/data-models#serialNumber", - "service": "https://uri.fiware.org/ns/data-models#service", - "serviceArea": "https://uri.fiware.org/ns/data-models#serviceArea", - "serviceProvided": { - "@id": "https://uri.fiware.org/ns/data-models#serviceProvided", - "@type": "@vocab" - }, - "serviceStatus": { - "@id": "https://uri.fiware.org/ns/data-models#serviceStatus", - "@type": "@vocab" - }, - "severity": { - "@id": "https://uri.fiware.org/ns/data-models#severity", - "@type": "@vocab" - }, - "sex": { - "@id": "https://uri.fiware.org/ns/data-models#sex", - "@type": "@vocab" - }, - "shape": { - "@id": "https://uri.fiware.org/ns/data-models#shape", - "@type": "@vocab" - }, - "shed": "https://uri.fiware.org/ns/data-models#shed", - "sheds": "https://uri.fiware.org/ns/data-models#sheds", - "sheep": "https://uri.fiware.org/ns/data-models#sheep", - "shop": "https://uri.fiware.org/ns/data-models#shop", - "shoppingCentre": "https://uri.fiware.org/ns/data-models#shoppingCentre", - "shortName": "https://uri.fiware.org/ns/data-models#shortName", - "shortTerm": "https://uri.fiware.org/ns/data-models#shortTerm", - "shower": "https://uri.fiware.org/ns/data-models#shower", - "showers": "https://uri.fiware.org/ns/data-models#showers", - "shrine": "https://uri.fiware.org/ns/data-models#shrine", - "sick": "https://uri.fiware.org/ns/data-models#sick", - "sideEntry": "https://uri.fiware.org/ns/data-models#sideEntry", - "sidewalk": "https://uri.fiware.org/ns/data-models#sidewalk", - "signLight": "https://uri.fiware.org/ns/data-models#signLight", - "signalStrength": { - "@id": "https://uri.fiware.org/ns/data-models#signalStrength", - "@type": "@vocab" - }, - "singleLevel": "https://uri.fiware.org/ns/data-models#singleLevel", - "singleSpaceDetection": "https://uri.fiware.org/ns/data-models#singleSpaceDetection", - "siredBy": { - "@id": "https://uri.fiware.org/ns/data-models#siredBy", - "@type": "@id" - }, - "skilift": "https://uri.fiware.org/ns/data-models#skilift", - "smoke": "https://uri.fiware.org/ns/data-models#smoke", - "snail": "https://uri.fiware.org/ns/data-models#snail", - "snow": "https://uri.fiware.org/ns/data-models#snow", - "snow/ice": "https://uri.fiware.org/ns/data-models#snow/ice", - "snowHeight": "https://uri.fiware.org/ns/data-models#snowHeight", - "socketNumber": "https://uri.fiware.org/ns/data-models#socketNumber", - "socketType": { - "@id": "https://uri.fiware.org/ns/data-models#socketType", - "@type": "@vocab" - }, - "softwareVersion": "https://uri.fiware.org/ns/data-models#softwareVersion", - "soilMoisture": "https://uri.fiware.org/ns/data-models#soilMoisture", - "soilMoistureEC": "https://uri.fiware.org/ns/data-models#soilMoistureEC", - "soilMoistureEc": "https://uri.fiware.org/ns/data-models#soilMoistureEc", - "soilMoistureVwc": "https://uri.fiware.org/ns/data-models#soilMoistureVwc", - "soilSalinity": "https://uri.fiware.org/ns/data-models#soilSalinity", - "soilTemperature": "https://uri.fiware.org/ns/data-models#soilTemperature", - "solarRadiation": "https://uri.fiware.org/ns/data-models#solarRadiation", - "solarRadiaton": "https://uri.fiware.org/ns/data-models#solarRadiaton", - "sonometerClass": { - "@id": "https://uri.fiware.org/ns/data-models#sonometerClass", - "@type": "@vocab" - }, - "source": "https://uri.fiware.org/ns/data-models#source", - "spacesAvailable": "https://uri.fiware.org/ns/data-models#spacesAvailable", - "specialLocation": { - "@id": "https://uri.fiware.org/ns/data-models#specialLocation", - "@type": "@vocab" - }, - "specialTransport": "https://uri.fiware.org/ns/data-models#specialTransport", - "specialUsage": "https://uri.fiware.org/ns/data-models#specialUsage", - "specials": "https://uri.fiware.org/ns/data-models#specials", - "species": { - "@id": "https://uri.fiware.org/ns/data-models#species", - "@type": "@vocab" - }, - "specificFacility": "https://uri.fiware.org/ns/data-models#specificFacility", - "specificIdentifiedVehiclePermit": "https://uri.fiware.org/ns/data-models#specificIdentifiedVehiclePermit", - "speed": "https://uri.fiware.org/ns/data-models#speed", - "spring": "https://uri.fiware.org/ns/data-models#spring", - "square": "https://uri.fiware.org/ns/data-models#square", - "stable": "https://uri.fiware.org/ns/data-models#stable", - "stadium": "https://uri.fiware.org/ns/data-models#stadium", - "staffGuidesToSpace": "https://uri.fiware.org/ns/data-models#staffGuidesToSpace", - "staffed": "https://uri.fiware.org/ns/data-models#staffed", - "startDate": "https://uri.fiware.org/ns/data-models#startDate", - "startKilometer": "https://uri.fiware.org/ns/data-models#startKilometer", - "startPoint": "https://uri.fiware.org/ns/data-models#startPoint", - "startTime": "https://uri.fiware.org/ns/data-models#startTime", - "startedAt": { - "@id": "https://uri.fiware.org/ns/data-models#startedAt", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "static_caravan": "https://uri.fiware.org/ns/data-models#static_caravan", - "status": { - "@id": "https://uri.fiware.org/ns/data-models#status", - "@type": "@vocab" - }, - "steady": "https://uri.fiware.org/ns/data-models#steady", - "steel": "https://uri.fiware.org/ns/data-models#steel", - "stopHeadsign": "https://uri.fiware.org/ns/data-models#stopHeadsign", - "stopId": "https://uri.fiware.org/ns/data-models#stopId", - "stopSequence": "https://uri.fiware.org/ns/data-models#stopSequence", - "storedWasteCode": "https://uri.fiware.org/ns/data-models#storedWasteCode", - "storedWasteKind": { - "@id": "https://uri.fiware.org/ns/data-models#storedWasteKind", - "@type": "@vocab" - }, - "storedWasteOrigin": { - "@id": "https://uri.fiware.org/ns/data-models#storedWasteOrigin", - "@type": "@vocab" - }, - "streamGauge": "https://uri.fiware.org/ns/data-models#streamGauge", - "streetCleaning": "https://uri.fiware.org/ns/data-models#streetCleaning", - "streetLighting": "https://uri.fiware.org/ns/data-models#streetLighting", - "strongWaves": "https://uri.fiware.org/ns/data-models#strongWaves", - "studentPermit": "https://uri.fiware.org/ns/data-models#studentPermit", - "sty": "https://uri.fiware.org/ns/data-models#sty", - "style": { - "@id": "https://uri.fiware.org/ns/data-models#style", - "@type": "@vocab" - }, - "subCategory": "https://uri.fiware.org/ns/data-models#subCategory", - "sumptuaryArts": "https://uri.fiware.org/ns/data-models#sumptuaryArts", - "sunLoungerRental": "https://uri.fiware.org/ns/data-models#sunLoungerRental", - "sunday": "https://uri.fiware.org/ns/data-models#sunday", - "sunshadeRental": "https://uri.fiware.org/ns/data-models#sunshadeRental", - "supportedUnits": "https://uri.fiware.org/ns/data-models#supportedUnits", - "surfPracticeArea": "https://uri.fiware.org/ns/data-models#surfPracticeArea", - "surface": "https://uri.fiware.org/ns/data-models#surface", - "suspiciousAction": "https://uri.fiware.org/ns/data-models#suspiciousAction", - "sweepingMachine": "https://uri.fiware.org/ns/data-models#sweepingMachine", - "switchingMode": { - "@id": "https://uri.fiware.org/ns/data-models#switchingMode", - "@type": "@vocab" - }, - "switchingOnHours": "https://uri.fiware.org/ns/data-models#switchingOnHours", - "synagogue": "https://uri.fiware.org/ns/data-models#synagogue", - "tanker": "https://uri.fiware.org/ns/data-models#tanker", - "taulasTalayotsNavetas": "https://uri.fiware.org/ns/data-models#taulasTalayotsNavetas", - "taxi": "https://uri.fiware.org/ns/data-models#taxi", - "taxon": "https://uri.fiware.org/ns/data-models#taxon", - "tds": "https://uri.fiware.org/ns/data-models#tds", - "telephone": "https://uri.fiware.org/ns/data-models#telephone", - "temperature": "https://uri.fiware.org/ns/data-models#temperature", - "temple": "https://uri.fiware.org/ns/data-models#temple", - "temporaryPrice": "https://uri.fiware.org/ns/data-models#temporaryPrice", - "terrace": "https://uri.fiware.org/ns/data-models#terrace", - "tertiary": "https://uri.fiware.org/ns/data-models#tertiary", - "textile": "https://uri.fiware.org/ns/data-models#textile", - "thdCurrent": "https://uri.fiware.org/ns/data-models#thdCurrent", - "thdVoltage": "https://uri.fiware.org/ns/data-models#thdVoltage", - "thdrIntensity": "https://uri.fiware.org/ns/data-models#thdrIntensity", - "thdrVoltage": "https://uri.fiware.org/ns/data-models#thdrVoltage", - "theathre": "https://uri.fiware.org/ns/data-models#theathre", - "thematic": "https://uri.fiware.org/ns/data-models#thematic", - "themePark": "https://uri.fiware.org/ns/data-models#themePark", - "thunderstorms": "https://uri.fiware.org/ns/data-models#thunderstorms", - "thursday": "https://uri.fiware.org/ns/data-models#thursday", - "timepoint": { - "@id": "https://uri.fiware.org/ns/data-models#timepoint", - "@type": "@vocab" - }, - "timezone": "https://uri.fiware.org/ns/data-models#timezone", - "toilet": "https://uri.fiware.org/ns/data-models#toilet", - "toilets": "https://uri.fiware.org/ns/data-models#toilets", - "toll": "https://uri.fiware.org/ns/data-models#toll", - "tollTerminal": "https://uri.fiware.org/ns/data-models#tollTerminal", - "tornado": "https://uri.fiware.org/ns/data-models#tornado", - "totalActiveEnergyExport": "https://uri.fiware.org/ns/data-models#totalActiveEnergyExport", - "totalActiveEnergyImport": "https://uri.fiware.org/ns/data-models#totalActiveEnergyImport", - "totalActivePower": "https://uri.fiware.org/ns/data-models#totalActivePower", - "totalApparentEnergyExport": "https://uri.fiware.org/ns/data-models#totalApparentEnergyExport", - "totalApparentEnergyImport": "https://uri.fiware.org/ns/data-models#totalApparentEnergyImport", - "totalApparentPower": "https://uri.fiware.org/ns/data-models#totalApparentPower", - "totalDisplacementPowerFactor": "https://uri.fiware.org/ns/data-models#totalDisplacementPowerFactor", - "totalLaneNumber": "https://uri.fiware.org/ns/data-models#totalLaneNumber", - "totalPowerFactor": "https://uri.fiware.org/ns/data-models#totalPowerFactor", - "totalReactiveEnergyExport": "https://uri.fiware.org/ns/data-models#totalReactiveEnergyExport", - "totalReactiveEnergyImport": "https://uri.fiware.org/ns/data-models#totalReactiveEnergyImport", - "totalReactivePower": "https://uri.fiware.org/ns/data-models#totalReactivePower", - "totalSlotNumber": "https://uri.fiware.org/ns/data-models#totalSlotNumber", - "totalSpotNumber": "https://uri.fiware.org/ns/data-models#totalSpotNumber", - "touristArea": "https://uri.fiware.org/ns/data-models#touristArea", - "touristOffice": "https://uri.fiware.org/ns/data-models#touristOffice", - "tower": "https://uri.fiware.org/ns/data-models#tower", - "town": "https://uri.fiware.org/ns/data-models#town", - "tracked": "https://uri.fiware.org/ns/data-models#tracked", - "traffic": "https://uri.fiware.org/ns/data-models#traffic", - "trafficFlow": "https://uri.fiware.org/ns/data-models#trafficFlow", - "trafficJam": "https://uri.fiware.org/ns/data-models#trafficJam", - "trailer": "https://uri.fiware.org/ns/data-models#trailer", - "trainStation": "https://uri.fiware.org/ns/data-models#trainStation", - "train_station": "https://uri.fiware.org/ns/data-models#train_station", - "tram": "https://uri.fiware.org/ns/data-models#tram", - "transferType": { - "@id": "https://uri.fiware.org/ns/data-models#transferType", - "@type": "@vocab" - }, - "transformer_tower": "https://uri.fiware.org/ns/data-models#transformer_tower", - "transportation": "https://uri.fiware.org/ns/data-models#transportation", - "transports": "https://uri.fiware.org/ns/data-models#transports", - "trashCan": "https://uri.fiware.org/ns/data-models#trashCan", - "trolley": "https://uri.fiware.org/ns/data-models#trolley", - "tropicalCyclone": "https://uri.fiware.org/ns/data-models#tropicalCyclone", - "truck": "https://uri.fiware.org/ns/data-models#truck", - "truckParking": "https://uri.fiware.org/ns/data-models#truckParking", - "trunk": "https://uri.fiware.org/ns/data-models#trunk", - "tss": "https://uri.fiware.org/ns/data-models#tss", - "tsunami": "https://uri.fiware.org/ns/data-models#tsunami", - "tuesday": "https://uri.fiware.org/ns/data-models#tuesday", - "tunnel": "https://uri.fiware.org/ns/data-models#tunnel", - "turbidity": "https://uri.fiware.org/ns/data-models#turbidity", - "uVIndexMax": "https://uri.fiware.org/ns/data-models#uVIndexMax", - "unclassified": "https://uri.fiware.org/ns/data-models#unclassified", - "underground": "https://uri.fiware.org/ns/data-models#underground", - "unesco": "https://uri.fiware.org/ns/data-models#unesco", - "universitary": "https://uri.fiware.org/ns/data-models#universitary", - "university": "https://uri.fiware.org/ns/data-models#university", - "unknown": "https://uri.fiware.org/ns/data-models#unknown", - "updatedAt": { - "@id": "https://uri.fiware.org/ns/data-models#updatedAt", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "urban": "https://uri.fiware.org/ns/data-models#urban", - "urbanDeterrentParking": "https://uri.fiware.org/ns/data-models#urbanDeterrentParking", - "urbanTransit": "https://uri.fiware.org/ns/data-models#urbanTransit", - "urbanTreeSpot": "https://uri.fiware.org/ns/data-models#urbanTreeSpot", - "url": "https://uri.fiware.org/ns/data-models#url", - "usageScenario": { - "@id": "https://uri.fiware.org/ns/data-models#usageScenario", - "@type": "@vocab" - }, - "validFrom": { - "@id": "https://uri.fiware.org/ns/data-models#validFrom", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "validTo": { - "@id": "https://uri.fiware.org/ns/data-models#validTo", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "validity": "https://uri.fiware.org/ns/data-models#validity", - "value": "https://uri.fiware.org/ns/data-models#value", - "van": "https://uri.fiware.org/ns/data-models#van", - "vehicleConfiguration": "https://uri.fiware.org/ns/data-models#vehicleConfiguration", - "vehicleEngine": "https://uri.fiware.org/ns/data-models#vehicleEngine", - "vehicleIdentificationNumber": "https://uri.fiware.org/ns/data-models#vehicleIdentificationNumber", - "vehicleLift": "https://uri.fiware.org/ns/data-models#vehicleLift", - "vehicleModelDate": { - "@id": "https://uri.fiware.org/ns/data-models#vehicleModelDate", - "@type": "https://uri.etsi.org/ngsi-ld/DateTime" - }, - "vehicleOnRailTerminal": "https://uri.fiware.org/ns/data-models#vehicleOnRailTerminal", - "vehiclePlateIdentifier": "https://uri.fiware.org/ns/data-models#vehiclePlateIdentifier", - "vehicleSpecialUsage": { - "@id": "https://uri.fiware.org/ns/data-models#vehicleSpecialUsage", - "@type": "@vocab" - }, - "vehicleSubType": "https://uri.fiware.org/ns/data-models#vehicleSubType", - "vehicleType": { - "@id": "https://uri.fiware.org/ns/data-models#vehicleType", - "@type": "@vocab" - }, - "vendingMachine": "https://uri.fiware.org/ns/data-models#vendingMachine", - "version": "https://uri.fiware.org/ns/data-models#version", - "veryBad": "https://uri.fiware.org/ns/data-models#veryBad", - "veryGood": "https://uri.fiware.org/ns/data-models#veryGood", - "veryHigh": "https://uri.fiware.org/ns/data-models#veryHigh", - "virus": "https://uri.fiware.org/ns/data-models#virus", - "visitorPermit": "https://uri.fiware.org/ns/data-models#visitorPermit", - "voltage": "https://uri.fiware.org/ns/data-models#voltage", - "walledArea": "https://uri.fiware.org/ns/data-models#walledArea", - "walls": "https://uri.fiware.org/ns/data-models#walls", - "warehouse": "https://uri.fiware.org/ns/data-models#warehouse", - "wasteContainerCleaning": "https://uri.fiware.org/ns/data-models#wasteContainerCleaning", - "wasteDisposal": "https://uri.fiware.org/ns/data-models#wasteDisposal", - "water": "https://uri.fiware.org/ns/data-models#water", - "water dam": "https://uri.fiware.org/ns/data-models#water dam", - "waterConsumption": "https://uri.fiware.org/ns/data-models#waterConsumption", - "waterCraftRental": "https://uri.fiware.org/ns/data-models#waterCraftRental", - "waterPollution": "https://uri.fiware.org/ns/data-models#waterPollution", - "waterSource": { - "@id": "https://uri.fiware.org/ns/data-models#waterSource", - "@type": "@vocab" - }, - "water_tower": "https://uri.fiware.org/ns/data-models#water_tower", - "wateringFrequency": { - "@id": "https://uri.fiware.org/ns/data-models#wateringFrequency", - "@type": "@vocab" - }, - "wax": "https://uri.fiware.org/ns/data-models#wax", - "weather": "https://uri.fiware.org/ns/data-models#weather", - "weatherConditions": "https://uri.fiware.org/ns/data-models#weatherConditions", - "wednesday": "https://uri.fiware.org/ns/data-models#wednesday", - "weekly": "https://uri.fiware.org/ns/data-models#weekly", - "weight": "https://uri.fiware.org/ns/data-models#weight", - "welfareCondition": { - "@id": "https://uri.fiware.org/ns/data-models#welfareCondition", - "@type": "@vocab" - }, - "wheelChairAccessible": { - "@id": "https://uri.fiware.org/ns/data-models#wheelChairAccessible", - "@type": "@vocab" - }, - "wheelieBin": "https://uri.fiware.org/ns/data-models#wheelieBin", - "wheels": "https://uri.fiware.org/ns/data-models#wheels", - "whiteSand": "https://uri.fiware.org/ns/data-models#whiteSand", - "width": "https://uri.fiware.org/ns/data-models#width", - "wifi": "https://uri.fiware.org/ns/data-models#wifi", - "wind": "https://uri.fiware.org/ns/data-models#wind", - "windDirection": "https://uri.fiware.org/ns/data-models#windDirection", - "windSpeed": "https://uri.fiware.org/ns/data-models#windSpeed", - "windy": "https://uri.fiware.org/ns/data-models#windy", - "withIncidence": "https://uri.fiware.org/ns/data-models#withIncidence", - "wood": "https://uri.fiware.org/ns/data-models#wood", - "workOrder": "https://uri.fiware.org/ns/data-models#workOrder", - "workRecord": "https://uri.fiware.org/ns/data-models#workRecord", - "working": "https://uri.fiware.org/ns/data-models#working", - "workingLife": "https://uri.fiware.org/ns/data-models#workingLife", - "workingMode": { - "@id": "https://uri.fiware.org/ns/data-models#workingMode", - "@type": "@vocab" - }, - "yearly": "https://uri.fiware.org/ns/data-models#yearly", - "zen": "https://uri.fiware.org/ns/data-models#zen", - "zoneCode": "https://uri.fiware.org/ns/data-models#zoneCode" - }, - "generatedAt": "2020-09-28T00:40:48+00:00" -} \ No newline at end of file diff --git a/shared/src/main/resources/contexts/ngsi-ld-core-context-v1.3.jsonld b/shared/src/main/resources/contexts/ngsi-ld-core-context-v1.3.jsonld deleted file mode 100644 index 40b5a3f2c..000000000 --- a/shared/src/main/resources/contexts/ngsi-ld-core-context-v1.3.jsonld +++ /dev/null @@ -1,223 +0,0 @@ -{ - "@context": { - - "ngsi-ld": "https://uri.etsi.org/ngsi-ld/", - "geojson": "https://purl.org/geojson/vocab#", - "id": "@id", - "type": "@type", - - "Attribute": "ngsi-ld:Attribute", - "AttributeList": "ngsi-ld:AttributeList", - "ContextSourceNotification": "ngsi-ld:ContextSourceNotification", - "ContextSourceRegistration": "ngsi-ld:ContextSourceRegistration", - "Date": "ngsi-ld:Date", - "DateTime": "ngsi-ld:DateTime", - "EntityType": "ngsi-ld:EntityType", - "EntityTypeInfo": "ngsi-ld:EntityTypeInfo", - "EntityTypeList": "ngsi-ld:EntityTypeList", - "Feature": "geojson:Feature", - "FeatureCollection": "geojson:FeatureCollection", - "GeoProperty": "ngsi-ld:GeoProperty", - "GeometryCollection": "geojson:GeometryCollection", - "LineString": "geojson:LineString", - "MultiLineString": "geojson:MultiLineString", - "MultiPoint": "geojson:MultiPoint", - "MultiPolygon": "geojson:MultiPolygon", - "Notification": "ngsi-ld:Notification", - "Point": "geojson:Point", - "Polygon": "geojson:Polygon", - "Property": "ngsi-ld:Property", - "Relationship": "ngsi-ld:Relationship", - "Subscription": "ngsi-ld:Subscription", - "TemporalProperty": "ngsi-ld:TemporalProperty", - "Time": "ngsi-ld:Time", - - "accept": "ngsi-ld:accept", - "attributeCount": "attributeCount", - "attributeDetails": "attributeDetails", - "attributeList": { - "@id": "ngsi-ld:attributeList", - "@type": "@vocab" - }, - "attributeName": { - "@id": "ngsi-ld:attributeName", - "@type": "@vocab" - }, - "attributeNames": { - "@id": "ngsi-ld:attributeNames", - "@type": "@vocab" - }, - "attributeTypes": { - "@id": "ngsi-ld:attributeTypes", - "@type": "@vocab" - }, - "attributes": { - "@id": "ngsi-ld:attributes", - "@type": "@vocab" - }, - "bbox": { - "@container": "@list", - "@id": "geojson:bbox" - }, - "coordinates": { - "@container": "@list", - "@id": "geojson:coordinates" - }, - "createdAt": { - "@id": "ngsi-ld:createdAt", - "@type": "DateTime" - }, - "csf": "ngsi-ld:csf", - "data": "ngsi-ld:data", - "datasetId": { - "@id": "ngsi-ld:datasetId", - "@type": "@id" - }, - "description": "http://purl.org/dc/terms/description", - "detail": "ngsi-ld:detail", - "endAt": { - "@id": "ngsi-ld:endAt", - "@type": "DateTime" - }, - "endTimeAt": { - "@id": "ngsi-ld:endTimeAt", - "@type": "DateTime" - }, - "endpoint": "ngsi-ld:endpoint", - "entities": "ngsi-ld:entities", - "entityCount": "ngsi-ld:entityCount", - "entityId": { - "@id": "ngsi-ld:entityId", - "@type": "@id" - }, - "error": "ngsi-ld:error", - "errors": "ngsi-ld:errors", - "expiresAt": { - "@id": "ngsi-ld:expiresAt", - "@type": "DateTime" - }, - "features": { - "@container": "@set", - "@id": "geojson:features" - }, - "format": "ngsi-ld:format", - "geoQ": "ngsi-ld:geoQ", - "geometry": "geojson:geometry", - "geoproperty": "ngsi-ld:geoproperty", - "georel": "ngsi-ld:georel", - "idPattern": "ngsi-ld:idPattern", - "information": "ngsi-ld:information", - "instanceId": { - "@id": "ngsi-ld:instanceId", - "@type": "@id" - }, - "isActive": "ngsi-ld:isActive", - "lastFailure": { - "@id": "ngsi-ld:lastFailure", - "@type": "DateTime" - }, - "lastNotification": { - "@id": "ngsi-ld:lastNotification", - "@type": "DateTime" - }, - "lastSuccess": { - "@id": "ngsi-ld:lastSuccess", - "@type": "DateTime" - }, - "location": "ngsi-ld:location", - "managementInterval": "ngsi-ld:managementInterval", - "modifiedAt": { - "@id": "ngsi-ld:modifiedAt", - "@type": "DateTime" - }, - "notification": "ngsi-ld:notification", - "notifiedAt": { - "@id": "ngsi-ld:notifiedAt", - "@type": "DateTime" - }, - "object": { - "@id": "ngsi-ld:hasObject", - "@type": "@id" - }, - "objects": { - "@id": "ngsi-ld:hasObjects", - "@type": "@id", - "@container": "@list" - }, - "observationInterval": "ngsi-ld:observationInterval", - "observationSpace": "ngsi-ld:observationSpace", - "observedAt": { - "@id": "ngsi-ld:observedAt", - "@type": "DateTime" - }, - "operationSpace": "ngsi-ld:operationSpace", - "properties": "geojson:properties", - "propertyNames": { - "@id": "ngsi-ld:propertyNames", - "@type": "@vocab" - }, - "q": "ngsi-ld:q", - "reason": "ngsi-ld:reason", - "registrationName": "ngsi-ld:registrationName", - "relationshipNames": { - "@id": "ngsi-ld:relationshipNames", - "@type": "@vocab" - }, - "startAt": { - "@id": "ngsi-ld:startAt", - "@type": "DateTime" - }, - "status": "ngsi-ld:status", - "subscriptionId": { - "@id": "ngsi-ld:subscriptionId", - "@type": "@id" - }, - "subscriptionName": "ngsi-ld:subscriptionName", - "success": { - "@id": "ngsi-ld:success", - "@type": "@id" - }, - "temporalQ": "ngsi-ld:temporalQ", - "tenant": { - "@id": "ngsi-ld:tenant", - "@type": "@id" - }, - "throttling": "ngsi-ld:throttling", - "timeAt": { - "@id": "ngsi-ld:timeAt", - "@type": "DateTime" - }, - "timeInterval": "ngsi-ld:timeInterval", - "timeproperty": "ngsi-ld:timeproperty", - "timerel": "ngsi-ld:timerel", - "timesSent": "ngsi-ld:timesSent", - "title": "http://purl.org/dc/terms/title", - "triggerReason": "ngsi-ld:triggerReason", - "typeList": { - "@id": "ngsi-ld:typeList", - "@type": "@vocab" - }, - "typeName": { - "@id": "ngsi-ld:typeName", - "@type": "@vocab" - }, - "typeNames": { - "@id": "ngsi-ld:typeNames", - "@type": "@vocab" - }, - "unchanged": "ngsi-ld:unchanged", - "unitCode": "ngsi-ld:unitCode", - "updated": "ngsi-ld:updated", - "uri": "ngsi-ld:uri", - "value": "ngsi-ld:hasValue", - "values": { - "@id": "ngsi-ld:hasValues", - "@container": "@list" - }, - "watchedAttributes": { - "@id": "ngsi-ld:watchedAttributes", - "@type": "@vocab" - }, - "@vocab": "https://uri.etsi.org/ngsi-ld/default-context/" - } -} \ No newline at end of file diff --git a/shared/src/main/resources/contexts/ngsi-ld-core-context-v1.7.jsonld b/shared/src/main/resources/contexts/ngsi-ld-core-context-v1.7.jsonld deleted file mode 100644 index 487dec1e0..000000000 --- a/shared/src/main/resources/contexts/ngsi-ld-core-context-v1.7.jsonld +++ /dev/null @@ -1,312 +0,0 @@ -{ - "@context": { - "ngsi-ld": "https://uri.etsi.org/ngsi-ld/", - "geojson": "https://purl.org/geojson/vocab#", - "id": "@id", - "type": "@type", - "Attribute": "ngsi-ld:Attribute", - "AttributeList": "ngsi-ld:AttributeList", - "ContextSourceNotification": "ngsi-ld:ContextSourceNotification", - "ContextSourceRegistration": "ngsi-ld:ContextSourceRegistration", - "Date": "ngsi-ld:Date", - "DateTime": "ngsi-ld:DateTime", - "EntityType": "ngsi-ld:EntityType", - "EntityTypeInfo": "ngsi-ld:EntityTypeInfo", - "EntityTypeList": "ngsi-ld:EntityTypeList", - "Feature": "geojson:Feature", - "FeatureCollection": "geojson:FeatureCollection", - "GeoProperty": "ngsi-ld:GeoProperty", - "GeometryCollection": "geojson:GeometryCollection", - "LineString": "geojson:LineString", - "LanguageProperty": "ngsi-ld:LanguageProperty", - "MultiLineString": "geojson:MultiLineString", - "MultiPoint": "geojson:MultiPoint", - "MultiPolygon": "geojson:MultiPolygon", - "Notification": "ngsi-ld:Notification", - "Point": "geojson:Point", - "Polygon": "geojson:Polygon", - "Property": "ngsi-ld:Property", - "Relationship": "ngsi-ld:Relationship", - "Subscription": "ngsi-ld:Subscription", - "TemporalProperty": "ngsi-ld:TemporalProperty", - "Time": "ngsi-ld:Time", - "VocabularyProperty": "ngsi-ld:VocabularyProperty", - "accept": "ngsi-ld:accept", - "attributeCount": "attributeCount", - "attributeDetails": "attributeDetails", - "attributeList": { - "@id": "ngsi-ld:attributeList", - "@type": "@vocab" - }, - "attributeName": { - "@id": "ngsi-ld:attributeName", - "@type": "@vocab" - }, - "attributeNames": { - "@id": "ngsi-ld:attributeNames", - "@type": "@vocab" - }, - "attributeTypes": { - "@id": "ngsi-ld:attributeTypes", - "@type": "@vocab" - }, - "attributes": { - "@id": "ngsi-ld:attributes", - "@type": "@vocab" - }, - "attrs": "ngsi-ld:attrs", - "avg": { - "@id": "ngsi-ld:avg", - "@container": "@list" - }, - "bbox": { - "@container": "@list", - "@id": "geojson:bbox" - }, - "cacheDuration": "ngsi-ld:cacheDuration", - "contextSourceInfo": "ngsi-ld:contextSourceInfo", - "cooldown": "ngsi-ld:cooldown", - "coordinates": { - "@container": "@list", - "@id": "geojson:coordinates" - }, - "createdAt": { - "@id": "ngsi-ld:createdAt", - "@type": "DateTime" - }, - "csf": "ngsi-ld:csf", - "data": "ngsi-ld:data", - "dataset": { - "@id": "ngsi-ld:hasDataset", - "@container": "@index" - }, - "datasetId": { - "@id": "ngsi-ld:datasetId", - "@type": "@id" - }, - "deletedAt": { - "@id": "ngsi-ld:deletedAt", - "@type": "DateTime" - }, - "description": "http://purl.org/dc/terms/description", - "detail": "ngsi-ld:detail", - "distinctCount": { - "@id": "ngsi-ld:distinctCount", - "@container": "@list" - }, - "endAt": { - "@id": "ngsi-ld:endAt", - "@type": "DateTime" - }, - "endTimeAt": { - "@id": "ngsi-ld:endTimeAt", - "@type": "DateTime" - }, - "endpoint": "ngsi-ld:endpoint", - "entities": "ngsi-ld:entities", - "entityCount": "ngsi-ld:entityCount", - "entityId": { - "@id": "ngsi-ld:entityId", - "@type": "@id" - }, - "error": "ngsi-ld:error", - "errors": "ngsi-ld:errors", - "expiresAt": { - "@id": "ngsi-ld:expiresAt", - "@type": "DateTime" - }, - "features": { - "@container": "@set", - "@id": "geojson:features" - }, - "format": "ngsi-ld:format", - "geoQ": "ngsi-ld:geoQ", - "geometry": "geojson:geometry", - "geoproperty": "ngsi-ld:geoproperty", - "georel": "ngsi-ld:georel", - "idPattern": "ngsi-ld:idPattern", - "information": "ngsi-ld:information", - "instanceId": { - "@id": "ngsi-ld:instanceId", - "@type": "@id" - }, - "isActive": "ngsi-ld:isActive", - "key": "ngsi-ld:hasKey", - "lang": "ngsi-ld:lang", - "languageMap": { - "@id": "ngsi-ld:hasLanguageMap", - "@container": "@language" - }, - "languageMaps": { - "@id": "ngsi-ld:hasLanguageMaps", - "@container": "@list" - }, - "lastFailure": { - "@id": "ngsi-ld:lastFailure", - "@type": "DateTime" - }, - "lastNotification": { - "@id": "ngsi-ld:lastNotification", - "@type": "DateTime" - }, - "lastSuccess": { - "@id": "ngsi-ld:lastSuccess", - "@type": "DateTime" - }, - "localOnly": "ngsi-ld:localOnly", - "location": "ngsi-ld:location", - "management": "ngsi-ld:management", - "managementInterval": "ngsi-ld:managementInterval", - "max": { - "@id": "ngsi-ld:max", - "@container": "@list" - }, - "min": { - "@id": "ngsi-ld:min", - "@container": "@list" - }, - "mode": "ngsi-ld:mode", - "modifiedAt": { - "@id": "ngsi-ld:modifiedAt", - "@type": "DateTime" - }, - "notification": "ngsi-ld:notification", - "notificationTrigger": "ngsi-ld:notificationTrigger", - "notifiedAt": { - "@id": "ngsi-ld:notifiedAt", - "@type": "DateTime" - }, - "notifierInfo": "ngsi-ld:notifierInfo", - "notUpdated": "ngsi-ld:notUpdated", - "object": { - "@id": "ngsi-ld:hasObject", - "@type": "@id" - }, - "objects": { - "@id": "ngsi-ld:hasObjects", - "@container": "@list" - }, - "observationInterval": "ngsi-ld:observationInterval", - "observationSpace": "ngsi-ld:observationSpace", - "observedAt": { - "@id": "ngsi-ld:observedAt", - "@type": "DateTime" - }, - "operationSpace": "ngsi-ld:operationSpace", - "operations": "ngsi-ld:operations", - "previousLanguageMap": { - "@id": "ngsi-ld:hasPreviousLanguageMap", - "@container": "@language" - }, - "previousObject": { - "@id": "ngsi-ld:hasPreviousObject", - "@type": "@id" - }, - "previousValue": "ngsi-ld:hasPreviousValue", - "previousVocab": { - "@id": "ngsi-ld:hasPreviousVocab", - "@type": "@vocab" - }, - "properties": "geojson:properties", - "propertyNames": { - "@id": "ngsi-ld:propertyNames", - "@type": "@vocab" - }, - "q": "ngsi-ld:q", - "reason": "ngsi-ld:reason", - "receiverInfo": "ngsi-ld:receiverInfo", - "refreshRate": "ngsi-ld:refreshRate", - "registrationId": "ngsi-ld:registrationId", - "registrationName": "ngsi-ld:registrationName", - "relationshipNames": { - "@id": "ngsi-ld:relationshipNames", - "@type": "@vocab" - }, - "scope": "ngsi-ld:scope", - "scopeQ": "ngsi-ld:scopeQ", - "showChanges": "ngsi-ld:showChanges", - "startAt": { - "@id": "ngsi-ld:startAt", - "@type": "DateTime" - }, - "status": "ngsi-ld:status", - "stddev": { - "@id": "ngsi-ld:stddev", - "@container": "@list" - }, - "subscriptionId": { - "@id": "ngsi-ld:subscriptionId", - "@type": "@id" - }, - "subscriptionName": "ngsi-ld:subscriptionName", - "success": { - "@id": "ngsi-ld:success", - "@type": "@id" - }, - "sum": { - "@id": "ngsi-ld:sum", - "@container": "@list" - }, - "sumsq": { - "@id": "ngsi-ld:sumsq", - "@container": "@list" - }, - "sysAttrs": "ngsi-ld:sysAttrs", - "temporalQ": "ngsi-ld:temporalQ", - "tenant": { - "@id": "ngsi-ld:tenant", - "@type": "@id" - }, - "throttling": "ngsi-ld:throttling", - "timeAt": { - "@id": "ngsi-ld:timeAt", - "@type": "DateTime" - }, - "timeInterval": "ngsi-ld:timeInterval", - "timeout": "ngsi-ld:timeout", - "timeproperty": "ngsi-ld:timeproperty", - "timerel": "ngsi-ld:timerel", - "timesFailed": "ngsi-ld:timesFailed", - "timesSent": "ngsi-ld:timesSent", - "title": "http://purl.org/dc/terms/title", - "totalCount": { - "@id": "ngsi-ld:totalCount", - "@container": "@list" - }, - "triggerReason": "ngsi-ld:triggerReason", - "typeList": { - "@id": "ngsi-ld:typeList", - "@type": "@vocab" - }, - "typeName": { - "@id": "ngsi-ld:typeName", - "@type": "@vocab" - }, - "typeNames": { - "@id": "ngsi-ld:typeNames", - "@type": "@vocab" - }, - "unchanged": "ngsi-ld:unchanged", - "unitCode": "ngsi-ld:unitCode", - "updated": "ngsi-ld:updated", - "uri": "ngsi-ld:uri", - "value": "ngsi-ld:hasValue", - "values": { - "@id": "ngsi-ld:hasValues", - "@container": "@list" - }, - "vocab": { - "@id": "ngsi-ld:hasVocab", - "@type": "@vocab" - }, - "vocabs": { - "@id": "ngsi-ld:hasVocabs", - "@container": "@list" - }, - "watchedAttributes": { - "@id": "ngsi-ld:watchedAttributes", - "@type": "@vocab" - }, - "@vocab": "https://uri.etsi.org/ngsi-ld/default-context/" - } -} diff --git a/shared/src/main/resources/contexts/ngsi-ld-test-suite-compound.jsonld b/shared/src/main/resources/contexts/ngsi-ld-test-suite-compound.jsonld deleted file mode 100644 index e9d50ea7a..000000000 --- a/shared/src/main/resources/contexts/ngsi-ld-test-suite-compound.jsonld +++ /dev/null @@ -1,6 +0,0 @@ -{ - "@context": [ - "https://forge.etsi.org/rep/cim/ngsi-ld-test-suite/-/raw/develop/resources/jsonld-contexts/ngsi-ld-test-suite.jsonld", - "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld" - ] -} diff --git a/shared/src/main/resources/contexts/ngsi-ld-test-suite.jsonld b/shared/src/main/resources/contexts/ngsi-ld-test-suite.jsonld deleted file mode 100644 index d26d4b605..000000000 --- a/shared/src/main/resources/contexts/ngsi-ld-test-suite.jsonld +++ /dev/null @@ -1,15 +0,0 @@ -{ - "@context": { - "Building": "https://ngsi-ld-test-suite/context#Building", - "Vehicle": "https://ngsi-ld-test-suite/context#Vehicle", - "OffStreetParking": "https://ngsi-ld-test-suite/context#OffStreetParking", - "airQualityLevel": "https://ngsi-ld-test-suite/context#airQualityLevel", - "almostFull": "https://ngsi-ld-test-suite/context#almostFull", - "brandName": "https://ngsi-ld-test-suite/context#brandName", - "fuelLevel": "https://ngsi-ld-test-suite/context#fuelLevel", - "name": "https://ngsi-ld-test-suite/context#name", - "source": "https://ngsi-ld-test-suite/context#source", - "speed": "https://ngsi-ld-test-suite/context#speed", - "subCategory": "https://ngsi-ld-test-suite/context#subCategory" - } -} diff --git a/shared/src/main/resources/jarcache.json b/shared/src/main/resources/jarcache.json deleted file mode 100644 index 7ee8a8d34..000000000 --- a/shared/src/main/resources/jarcache.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "Content-Location": "https://fiware.github.io/data-models/context.jsonld", - "X-Classpath": "contexts/fiware-datamodels-context.jsonld", - "Content-Type": "application/ld+json" - }, - { - "Content-Location": "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.3.jsonld", - "X-Classpath": "contexts/ngsi-ld-core-context-v1.3.jsonld", - "Content-Type": "application/ld+json" - }, - { - "Content-Location": "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld", - "X-Classpath": "contexts/ngsi-ld-core-context-v1.7.jsonld", - "Content-Type": "application/ld+json" - }, - { - "Content-Location": "https://forge.etsi.org/rep/cim/ngsi-ld-test-suite/-/raw/develop/resources/jsonld-contexts/ngsi-ld-test-suite-compound.jsonld", - "X-Classpath": "contexts/ngsi-ld-test-suite-compound.jsonld", - "Content-Type": "application/ld+json" - }, - { - "Content-Location": "https://forge.etsi.org/rep/cim/ngsi-ld-test-suite/-/raw/develop/resources/jsonld-contexts/ngsi-ld-test-suite.jsonld", - "X-Classpath": "contexts/ngsi-ld-test-suite.jsonld", - "Content-Type": "application/ld+json" - } -] diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/model/NgsiLdEntityTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/model/NgsiLdEntityTests.kt index 2bb23bf72..a93847f36 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/model/NgsiLdEntityTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/model/NgsiLdEntityTests.kt @@ -2,6 +2,7 @@ package com.egm.stellio.shared.model import com.egm.stellio.shared.util.DEFAULT_CONTEXTS import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DEFAULT_VOCAB import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.expandAttributes import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity @@ -28,7 +29,7 @@ class NgsiLdEntityTests { val ngsiLdEntity = expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS) assertEquals("urn:ngsi-ld:Device:01234", ngsiLdEntity.id) - assertEquals(listOf("https://uri.fiware.org/ns/data-models#Device"), ngsiLdEntity.types) + assertEquals(listOf("https://uri.etsi.org/ngsi-ld/default-context/Device"), ngsiLdEntity.types) } @Test @@ -82,7 +83,7 @@ class NgsiLdEntityTests { expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( - "Entity has attribute(s) with an unknown type: [https://uri.fiware.org/ns/data-models#deviceState]", + "Entity has attribute(s) with an unknown type: [${NGSILD_DEFAULT_VOCAB}deviceState]", it.message ) } @@ -106,7 +107,7 @@ class NgsiLdEntityTests { assertEquals(1, ngsiLdEntity.properties.size) val ngsiLdProperty = ngsiLdEntity.properties[0] - assertEquals("https://uri.fiware.org/ns/data-models#deviceState", ngsiLdProperty.name) + assertEquals("${NGSILD_DEFAULT_VOCAB}deviceState", ngsiLdProperty.name) assertEquals(1, ngsiLdProperty.instances.size) val ngsiLdPropertyInstance = ngsiLdProperty.instances[0] assertEquals("Open", ngsiLdPropertyInstance.value) @@ -135,7 +136,7 @@ class NgsiLdEntityTests { assertEquals(1, ngsiLdEntity.properties.size) val ngsiLdProperty = ngsiLdEntity.properties[0] - assertEquals("https://uri.fiware.org/ns/data-models#deviceState", ngsiLdProperty.name) + assertEquals("${NGSILD_DEFAULT_VOCAB}deviceState", ngsiLdProperty.name) assertEquals(1, ngsiLdProperty.instances.size) val ngsiLdPropertyInstance = ngsiLdProperty.instances[0] assertTrue(ngsiLdPropertyInstance.value is Map<*, *>) @@ -219,7 +220,7 @@ class NgsiLdEntityTests { expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( - "Property https://uri.fiware.org/ns/data-models#deviceState has an instance without a value", + "Property ${NGSILD_DEFAULT_VOCAB}deviceState has an instance without a value", it.message ) } @@ -276,7 +277,7 @@ class NgsiLdEntityTests { expandAttributes(rawProperty, DEFAULT_CONTEXTS).toNgsiLdAttributes().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( - "Attribute https://uri.fiware.org/ns/data-models#deviceState instances must have the same type", + "Attribute ${NGSILD_DEFAULT_VOCAB}deviceState instances must have the same type", it.message ) } @@ -314,7 +315,7 @@ class NgsiLdEntityTests { expandAttributes(rawProperty, DEFAULT_CONTEXTS).toNgsiLdAttributes().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( - "Attribute https://uri.fiware.org/ns/data-models#deviceState " + + "Attribute ${NGSILD_DEFAULT_VOCAB}deviceState " + "can't have more than one instance with the same datasetId", it.message ) @@ -347,7 +348,7 @@ class NgsiLdEntityTests { expandAttributes(rawProperty, DEFAULT_CONTEXTS).toNgsiLdAttributes().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( - "Attribute https://uri.fiware.org/ns/data-models#deviceState can't have more than one default instance", + "Attribute ${NGSILD_DEFAULT_VOCAB}deviceState can't have more than one default instance", it.message ) } @@ -397,7 +398,7 @@ class NgsiLdEntityTests { assertEquals(1, ngsiLdEntity.relationships.size) val ngsiLdRelationship = ngsiLdEntity.relationships[0] - assertEquals("https://uri.fiware.org/ns/data-models#refDeviceModel", ngsiLdRelationship.name) + assertEquals("https://uri.etsi.org/ngsi-ld/default-context/refDeviceModel", ngsiLdRelationship.name) assertEquals(1, ngsiLdRelationship.instances.size) val ngsiLdRelationshipInstance = ngsiLdRelationship.instances[0] assertEquals("urn:ngsi-ld:DeviceModel:09876".toUri(), ngsiLdRelationshipInstance.objectId) @@ -480,7 +481,7 @@ class NgsiLdEntityTests { expandAttributes(rawRelationship, DEFAULT_CONTEXTS).toNgsiLdAttributes().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( - "Attribute https://uri.fiware.org/ns/data-models#refDeviceModel can't have more " + + "Attribute ${NGSILD_DEFAULT_VOCAB}refDeviceModel can't have more " + "than one default instance", it.message ) @@ -510,7 +511,7 @@ class NgsiLdEntityTests { expandAttributes(rawRelationship, DEFAULT_CONTEXTS).toNgsiLdAttributes().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( - "Attribute https://uri.fiware.org/ns/data-models#refDeviceModel " + + "Attribute ${NGSILD_DEFAULT_VOCAB}refDeviceModel " + "can't have more than one instance with the same datasetId", it.message ) @@ -544,7 +545,7 @@ class NgsiLdEntityTests { expandAttributes(rawRelationship, DEFAULT_CONTEXTS).toNgsiLdAttributes().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( - "Attribute https://uri.fiware.org/ns/data-models#refDeviceModel instances must have the same type", + "Attribute ${NGSILD_DEFAULT_VOCAB}refDeviceModel instances must have the same type", it.message ) } diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/ApiUtilsTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/ApiUtilsTests.kt index d734bd0ac..8e763ed9f 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/ApiUtilsTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/ApiUtilsTests.kt @@ -52,12 +52,12 @@ class ApiUtilsTests { @Test fun `it should return an singleton list if there is one provided attrs param`() { - assertEquals(1, parseAndExpandRequestParameter("attr1", NGSILD_CORE_CONTEXT).size) + assertEquals(1, parseAndExpandRequestParameter("attr1", NGSILD_TEST_CORE_CONTEXT).size) } @Test fun `it should return a list with two elements if there are two provided attrs param`() { - assertEquals(2, parseAndExpandRequestParameter("attr1, attr2", NGSILD_CORE_CONTEXT).size) + assertEquals(2, parseAndExpandRequestParameter("attr1, attr2", NGSILD_TEST_CORE_CONTEXT).size) } @Test @@ -181,7 +181,7 @@ class ApiUtilsTests { fun `it should parse and expand entity type selection query`() { val query = "(TypeA|TypeB);(TypeC,TypeD)" val defaultExpand = "https://uri.etsi.org/ngsi-ld/default-context/" - val expandedQuery = expandTypeSelection(query, NGSILD_CORE_CONTEXT) + val expandedQuery = expandTypeSelection(query, NGSILD_TEST_CORE_CONTEXT) val expectedExpandTypeSelection = "(${defaultExpand}TypeA|${defaultExpand}TypeB);(${defaultExpand}TypeC,${defaultExpand}TypeD)" assertEquals(expectedExpandTypeSelection, expandedQuery) diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt index 3426ad86f..14d7ee6dd 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt @@ -3,7 +3,6 @@ package com.egm.stellio.shared.util import com.egm.stellio.shared.model.BadRequestDataException import com.egm.stellio.shared.model.GeoQuery import com.egm.stellio.shared.model.GeoQuery.GeometryType -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OPERATION_SPACE_PROPERTY import kotlinx.coroutines.test.runTest @@ -19,7 +18,7 @@ class GeoQueryUtilsTests { fun `it should parse geo query parameters`() = runTest { val requestParams = gimmeFullParamsMap() val geoQueryParams = - parseGeoQueryParameters(requestParams, NGSILD_CORE_CONTEXT).shouldSucceedAndResult() + parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXT).shouldSucceedAndResult() val geoQuery = GeoQuery( georel = "near;maxDistance==1500", @@ -37,7 +36,7 @@ class GeoQueryUtilsTests { georel = "near%3BmaxDistance%3D%3D1500" ).plus("coordinates" to "[57.5522%2C%20-20.3484]") val geoQueryParams = - parseGeoQueryParameters(requestParams, NGSILD_CORE_CONTEXT).shouldSucceedAndResult() + parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXT).shouldSucceedAndResult() val geoQuery = GeoQuery( georel = "near;maxDistance==1500", @@ -54,7 +53,7 @@ class GeoQueryUtilsTests { val requestParams = gimmeFullParamsMap("operationSpace") val geoQueryParams = - parseGeoQueryParameters(requestParams, NGSILD_CORE_CONTEXT).shouldSucceedAndResult() + parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXT).shouldSucceedAndResult() val geoQuery = GeoQuery( georel = "near;maxDistance==1500", @@ -69,7 +68,7 @@ class GeoQueryUtilsTests { @Test fun `it should fail to create a geoquery if georel has an invalid near clause`() = runTest { val requestParams = gimmeFullParamsMap(georel = "near;distance<100") - parseGeoQueryParameters(requestParams, NGSILD_CORE_CONTEXT).shouldFail { + parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXT).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals("Invalid expression for 'near' georel: near;distance<100", it.message) } @@ -78,7 +77,7 @@ class GeoQueryUtilsTests { @Test fun `it should fail to create a geoquery if georel is not recognized`() = runTest { val requestParams = gimmeFullParamsMap(georel = "unrecognized") - parseGeoQueryParameters(requestParams, NGSILD_CORE_CONTEXT).shouldFail { + parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXT).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals("Invalid 'georel' parameter provided: unrecognized", it.message) } @@ -87,7 +86,7 @@ class GeoQueryUtilsTests { @Test fun `it should fail to create a geoquery if geometry is not recognized`() = runTest { val requestParams = gimmeFullParamsMap(geometry = "Unrecognized") - parseGeoQueryParameters(requestParams, NGSILD_CORE_CONTEXT).shouldFail { + parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXT).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals("Unrecognized is not a recognized value for 'geometry' parameter", it.message) } @@ -99,7 +98,7 @@ class GeoQueryUtilsTests { "geometry" to "Point", "coordinates" to "[57.5522,%20-20.3484]" ) - parseGeoQueryParameters(geoQueryParameters, NGSILD_CORE_CONTEXT).shouldFail { + parseGeoQueryParameters(geoQueryParameters, NGSILD_TEST_CORE_CONTEXT).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( "Missing at least one geo parameter between 'geometry', 'georel' and 'coordinates'", @@ -115,7 +114,7 @@ class GeoQueryUtilsTests { "geometry" to "Polygon", "coordinates" to "[57.5522,%20-20.3484]" ) - parseGeoQueryParameters(geoQueryParameters, NGSILD_CORE_CONTEXT).shouldFail { + parseGeoQueryParameters(geoQueryParameters, NGSILD_TEST_CORE_CONTEXT).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEqualsIgnoringNoise( """ @@ -145,7 +144,7 @@ class GeoQueryUtilsTests { """ public.ST_disjoint( public.ST_GeomFromText('POLYGON ((0 1, 1 1, 0 1))'), - public.ST_GeomFromText((select jsonb_path_query_first('{"@id":"urn:ngsi-ld:Entity:01","https://uri.etsi.org/ngsi-ld/location":[{"@type":["https://uri.etsi.org/ngsi-ld/GeoProperty"],"https://uri.etsi.org/ngsi-ld/hasValue":[{"@value":"POINT (24.30623 60.07966)"}]}],"@type":["https://uri.etsi.org/ngsi-ld/default-context/Entity"]}', + public.ST_GeomFromText((select jsonb_path_query_first('{"@id":"urn:ngsi-ld:Entity:01","@type":["https://uri.etsi.org/ngsi-ld/default-context/Entity"],"https://uri.etsi.org/ngsi-ld/location":[{"@type":["https://uri.etsi.org/ngsi-ld/GeoProperty"],"https://uri.etsi.org/ngsi-ld/hasValue":[{"@value":"POINT (24.30623 60.07966)"}]}]}', '$."https://uri.etsi.org/ngsi-ld/location"."https://uri.etsi.org/ngsi-ld/hasValue"[0]')->>'@value')) ) """, @@ -169,7 +168,7 @@ class GeoQueryUtilsTests { """ public.ST_Distance( 'SRID=4326;POINT(60.124.6)'::geography, - ('SRID=4326;' || (select jsonb_path_query_first('{"@id":"urn:ngsi-ld:Entity:01","https://uri.etsi.org/ngsi-ld/location":[{"@type":["https://uri.etsi.org/ngsi-ld/GeoProperty"],"https://uri.etsi.org/ngsi-ld/hasValue":[{"@value":"POINT(60.0796624.30623)"}]}],"@type":["https://uri.etsi.org/ngsi-ld/default-context/Entity"]}','$."https://uri.etsi.org/ngsi-ld/location"."https://uri.etsi.org/ngsi-ld/hasValue"[0]')->>'@value'))::geography, + ('SRID=4326;' || (select jsonb_path_query_first('{"@id":"urn:ngsi-ld:Entity:01","@type":["https://uri.etsi.org/ngsi-ld/default-context/Entity"],"https://uri.etsi.org/ngsi-ld/location":[{"@type":["https://uri.etsi.org/ngsi-ld/GeoProperty"],"https://uri.etsi.org/ngsi-ld/hasValue":[{"@value":"POINT(60.0796624.30623)"}]}]}','$."https://uri.etsi.org/ngsi-ld/location"."https://uri.etsi.org/ngsi-ld/hasValue"[0]')->>'@value'))::geography, false ) <= 2000 """, @@ -193,7 +192,7 @@ class GeoQueryUtilsTests { """ public.ST_Distance( 'SRID=4326;POINT(60.124.6)'::geography, - ('SRID=4326;' || (select jsonb_path_query_first('{"@id":"urn:ngsi-ld:Entity:01","https://uri.etsi.org/ngsi-ld/location":[{"@type":["https://uri.etsi.org/ngsi-ld/GeoProperty"],"https://uri.etsi.org/ngsi-ld/hasValue":[{"@value":"POINT(60.3062330.07966)"}]}],"@type":["https://uri.etsi.org/ngsi-ld/default-context/Entity"]}','$."https://uri.etsi.org/ngsi-ld/location"."https://uri.etsi.org/ngsi-ld/hasValue"[0]')->>'@value'))::geography, + ('SRID=4326;' || (select jsonb_path_query_first('{"@id":"urn:ngsi-ld:Entity:01","@type":["https://uri.etsi.org/ngsi-ld/default-context/Entity"],"https://uri.etsi.org/ngsi-ld/location":[{"@type":["https://uri.etsi.org/ngsi-ld/GeoProperty"],"https://uri.etsi.org/ngsi-ld/hasValue":[{"@value":"POINT(60.3062330.07966)"}]}]}','$."https://uri.etsi.org/ngsi-ld/location"."https://uri.etsi.org/ngsi-ld/hasValue"[0]')->>'@value'))::geography, false ) >= 15 """, diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt index 35fc29ce3..ea29d15b8 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt @@ -4,10 +4,10 @@ import com.egm.stellio.shared.model.BadRequestDataException import com.egm.stellio.shared.model.CompactedJsonLdEntity import com.egm.stellio.shared.model.LdContextNotAvailableException import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_EGM_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_HAS_OBJECT import com.egm.stellio.shared.util.JsonLdUtils.addCoreContextIfMissing import com.egm.stellio.shared.util.JsonLdUtils.compactEntity +import com.egm.stellio.shared.util.JsonLdUtils.expandAttributes import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdFragment import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdTerm import com.egm.stellio.shared.util.JsonLdUtils.extractContextFromInput @@ -94,8 +94,9 @@ class JsonLdUtilsTests { expandJsonLdFragment(rawEntity.deserializeAsMap(), listOf("unknownContext")) } assertEquals( - "Unable to load remote context (cause was: com.github.jsonldjava.core.JsonLdError: " + - "loading remote context failed: unknownContext)", + "Unable to load remote context (cause was: JsonLdError[code=There was a problem encountered " + + "loading a remote context [code=LOADING_REMOTE_CONTEXT_FAILED]., " + + "message=Context URI is not absolute [unknownContext].])", exception.message ) } @@ -112,7 +113,7 @@ class JsonLdUtilsTests { """.trimIndent() val exception = assertThrows { - expandJsonLdFragment(rawEntity, listOf(NGSILD_CORE_CONTEXT)) + expandJsonLdFragment(rawEntity, listOf(NGSILD_TEST_CORE_CONTEXT)) } assertEquals( "Unable to expand input payload", @@ -233,7 +234,7 @@ class JsonLdUtilsTests { val jsonLdEntity = JsonLdUtils.expandJsonLdEntity(entity, DEFAULT_CONTEXTS) val compactedEntity = compactEntity(jsonLdEntity, DEFAULT_CONTEXTS, MediaType.APPLICATION_JSON) - assertTrue(mapper.writeValueAsString(compactedEntity).matchContent(entity)) + assertJsonPayloadsAreEqual(entity, mapper.writeValueAsString(compactedEntity)) } @Test @@ -251,8 +252,7 @@ class JsonLdUtilsTests { "id":"urn:ngsi-ld:Device:01234", "type":"Device", "@context":[ - "https://fiware.github.io/data-models/context.jsonld", - "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld" + "$NGSILD_TEST_CORE_CONTEXT" ] } """.trimIndent() @@ -260,7 +260,7 @@ class JsonLdUtilsTests { val jsonLdEntity = JsonLdUtils.expandJsonLdEntity(entity, DEFAULT_CONTEXTS) val compactedEntity = compactEntity(jsonLdEntity, DEFAULT_CONTEXTS) - assertTrue(mapper.writeValueAsString(compactedEntity).matchContent(expectedEntity)) + assertJsonPayloadsAreEqual(expectedEntity, mapper.writeValueAsString(compactedEntity)) } @Test @@ -274,7 +274,7 @@ class JsonLdUtilsTests { } """.trimIndent() - val expandedAttributes = expandJsonLdFragment(entityFragment, DEFAULT_CONTEXTS) + val expandedAttributes = expandAttributes(entityFragment, DEFAULT_CONTEXTS) assertNull(getAttributeFromExpandedAttributes(expandedAttributes, "unknownAttribute", null)) } @@ -293,7 +293,7 @@ class JsonLdUtilsTests { } """.trimIndent() - val expandedAttributes = expandJsonLdFragment(entityFragment, DEFAULT_CONTEXTS) + val expandedAttributes = expandAttributes(entityFragment, DEFAULT_CONTEXTS) val expandedBrandName = expandJsonLdTerm("brandName", DEFAULT_CONTEXTS) assertNotNull(getAttributeFromExpandedAttributes(expandedAttributes, expandedBrandName, null)) @@ -323,7 +323,7 @@ class JsonLdUtilsTests { } """.trimIndent() - val expandedAttributes = expandJsonLdFragment(entityFragment, DEFAULT_CONTEXTS) + val expandedAttributes = expandAttributes(entityFragment, DEFAULT_CONTEXTS) val expandedBrandName = expandJsonLdTerm("brandName", DEFAULT_CONTEXTS) val expandedName = expandJsonLdTerm("name", DEFAULT_CONTEXTS) diff --git a/shared/src/test/resources/junit-platform.properties b/shared/src/test/resources/junit-platform.properties new file mode 100644 index 000000000..9911aeba0 --- /dev/null +++ b/shared/src/test/resources/junit-platform.properties @@ -0,0 +1,2 @@ +junit.jupiter.testinstance.lifecycle.default=per_class +junit.jupiter.extensions.autodetection.enabled=true diff --git a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/support/JsonLdContextServerExtension.kt b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/support/JsonLdContextServerExtension.kt new file mode 100644 index 000000000..7d9c69200 --- /dev/null +++ b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/support/JsonLdContextServerExtension.kt @@ -0,0 +1,59 @@ +package com.egm.stellio.shared.support + +import com.egm.stellio.shared.util.JSON_LD_CONTENT_TYPE +import org.junit.jupiter.api.extension.AfterAllCallback +import org.junit.jupiter.api.extension.BeforeAllCallback +import org.junit.jupiter.api.extension.ExtensionContext +import org.mockserver.integration.ClientAndServer +import org.mockserver.integration.ClientAndServer.startClientAndServer +import org.mockserver.mock.action.ExpectationResponseCallback +import org.mockserver.model.HttpClassCallback.callback +import org.mockserver.model.HttpRequest +import org.mockserver.model.HttpRequest.request +import org.mockserver.model.HttpResponse +import org.mockserver.model.HttpResponse.notFoundResponse +import org.mockserver.model.HttpResponse.response +import org.mockserver.model.HttpStatusCode +import org.slf4j.LoggerFactory +import org.springframework.core.io.ClassPathResource + +const val MOCK_SERVER_PORT = 8093 + +class JsonLdContextServerExtension : BeforeAllCallback, AfterAllCallback { + + private val logger = LoggerFactory.getLogger(javaClass) + + private lateinit var mockServer: ClientAndServer + + override fun beforeAll(context: ExtensionContext) { + mockServer = startClientAndServer(MOCK_SERVER_PORT) + + mockServer + .`when`( + request().withMethod("GET").withPath("/jsonld-contexts/.*") + ) + .respond( + callback().withCallbackClass(JsonLdContextResponseCallback::class.java) + ) + logger.debug("WireMock server is started") + } + + override fun afterAll(context: ExtensionContext) { + mockServer.stop() + } + + class JsonLdContextResponseCallback : ExpectationResponseCallback { + override fun handle(httpRequest: HttpRequest): HttpResponse { + val contextFilename = httpRequest.path.value.substringAfterLast("/") + val resource = ClassPathResource("/jsonld-contexts/$contextFilename") + return if (resource.exists()) { + response() + .withStatusCode(HttpStatusCode.OK_200.code()) + .withHeader("Content-Type", JSON_LD_CONTENT_TYPE) + .withBody(resource.inputStream.readBytes()) + } else { + notFoundResponse() + } + } + } +} diff --git a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/JsonLdContextUtils.kt b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/JsonLdContextUtils.kt index ce5e0cc79..bd17e87e4 100644 --- a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/JsonLdContextUtils.kt +++ b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/JsonLdContextUtils.kt @@ -1,11 +1,13 @@ package com.egm.stellio.shared.util -val DEFAULT_CONTEXTS = listOf( - "https://fiware.github.io/data-models/context.jsonld", - JsonLdUtils.NGSILD_CORE_CONTEXT -) -const val AQUAC_COMPOUND_CONTEXT = "${JsonLdUtils.EGM_BASE_CONTEXT_URL}/aquac/jsonld-contexts/aquac-compound.jsonld" -const val APIC_COMPOUND_CONTEXT = "${JsonLdUtils.EGM_BASE_CONTEXT_URL}/apic/jsonld-contexts/apic-compound.jsonld" +const val EGM_TEST_BASE_CONTEXT_URL = "http://localhost:8093/jsonld-contexts" +const val NGSILD_TEST_CORE_CONTEXT = "$EGM_TEST_BASE_CONTEXT_URL/ngsi-ld-core-context-v1.8.jsonld" +val DEFAULT_CONTEXTS = listOf(NGSILD_TEST_CORE_CONTEXT) +const val NGSILD_EGM_CONTEXT = "$EGM_TEST_BASE_CONTEXT_URL/egm.jsonld" +const val AQUAC_COMPOUND_CONTEXT = "$EGM_TEST_BASE_CONTEXT_URL/aquac-compound.jsonld" +const val APIC_COMPOUND_CONTEXT = "$EGM_TEST_BASE_CONTEXT_URL/apic-compound.jsonld" +const val AUTHZ_TEST_CONTEXT = "$EGM_TEST_BASE_CONTEXT_URL/authorization.jsonld" +const val AUTHZ_TEST_COMPOUND_CONTEXT = "$EGM_TEST_BASE_CONTEXT_URL/authorization-compound.jsonld" val APIC_HEADER_LINK = buildContextLinkHeader(APIC_COMPOUND_CONTEXT) diff --git a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt index 816226c1f..5cc675c85 100644 --- a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt +++ b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt @@ -5,7 +5,7 @@ import arrow.core.Some import arrow.core.left import arrow.core.right import com.egm.stellio.shared.model.* -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT +import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity import org.springframework.core.io.ClassPathResource import java.net.URI @@ -14,10 +14,15 @@ fun loadSampleData(filename: String = "beehive.jsonld"): String { return String(sampleData.inputStream.readAllBytes()) } +suspend fun loadAndExpandSampleData(filename: String = "beehive.jsonld"): JsonLdEntity { + val sampleData = ClassPathResource("/ngsild/$filename") + return expandJsonLdEntity(String(sampleData.inputStream.readAllBytes())) +} + fun loadMinimalEntity( entityId: URI, entityTypes: Set, - contexts: Set = setOf(NGSILD_CORE_CONTEXT) + contexts: Set = setOf(NGSILD_TEST_CORE_CONTEXT) ): String = """ { @@ -31,7 +36,7 @@ fun loadMinimalEntityWithSap( entityId: URI, entityTypes: Set, specificAccessPolicy: AuthContextModel.SpecificAccessPolicy, - contexts: Set = setOf(NGSILD_CORE_CONTEXT) + contexts: Set = setOf(NGSILD_TEST_CORE_CONTEXT) ): String = """ { @@ -46,7 +51,7 @@ fun loadMinimalEntityWithSap( """.trimIndent() suspend fun String.sampleDataToNgsiLdEntity(): Either> { - val jsonLdEntity = JsonLdUtils.expandJsonLdEntity(this) + val jsonLdEntity = expandJsonLdEntity(this) return when (val ngsiLdEntity = jsonLdEntity.toNgsiLdEntity()) { is Either.Left -> BadRequestDataException("Invalid NGSI-LD input for sample data: $this").left() is Either.Right -> Pair(jsonLdEntity, ngsiLdEntity.value).right() diff --git a/shared/src/testFixtures/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/shared/src/testFixtures/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 000000000..7ab55ba81 --- /dev/null +++ b/shared/src/testFixtures/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1 @@ +com.egm.stellio.shared.support.JsonLdContextServerExtension diff --git a/shared/src/testFixtures/resources/contexts/apic.jsonld b/shared/src/testFixtures/resources/contexts/apic.jsonld deleted file mode 100644 index d97e791d7..000000000 --- a/shared/src/testFixtures/resources/contexts/apic.jsonld +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context":{ - "Beekeeper": "https://ontology.eglobalmark.com/apic#Beekeeper", - "BeeHive": "https://ontology.eglobalmark.com/apic#BeeHive", - "doorNumber": "https://ontology.eglobalmark.com/apic#doorNumber", - "Apiary": "https://ontology.eglobalmark.com/apic#Apiary", - "outgoing": "https://ontology.eglobalmark.com/apic#outgoing", - "incoming": "https://ontology.eglobalmark.com/apic#incoming", - "Door": "https://ontology.eglobalmark.com/apic#Door", - "SmartDoor": "https://ontology.eglobalmark.com/apic#SmartDoor", - "temperature": "https://ontology.eglobalmark.com/apic#temperature", - "humidity": "https://ontology.eglobalmark.com/apic#humidity", - "timeInterval": "https://ontology.eglobalmark.com/apic#timeInterval", - "timeIntervalUnit": "https://ontology.eglobalmark.com/apic#timeIntervalUnit", - "batteryLevel": "https://ontology.eglobalmark.com/apic#batteryLevel", - "voltage": "https://ontology.eglobalmark.com/apic#voltage", - "movementDetected": { - "@id": "https://ontology.eglobalmark.com/apic#movementDetected", - "@type": "http://www.w3.org/2001/XMLSchema#boolean" - }, - "hornetDetected": { - "@id": "https://ontology.eglobalmark.com/apic#hornetDetected", - "@type": "http://www.w3.org/2001/XMLSchema#boolean" - }, - "errorCode": "https://ontology.eglobalmark.com/apic#errorCode", - "rainTypeDetected":"https://ontology.eglobalmark.com/apic#rainTypeDetected", - "panelTension": "https://ontology.eglobalmark.com/apic#panelTension", - "panelCurrent": "https://ontology.eglobalmark.com/apic#panelCurrent", - "incomingSum": "https://ontology.eglobalmark.com/apic#incomingSum", - "outgoingSum": "https://ontology.eglobalmark.com/apic#outgoingSum", - "luminosity": "https://ontology.eglobalmark.com/apic#luminosity", - "usbCount": "https://ontology.eglobalmark.com/apic#usbCount", - "resetCount": "https://ontology.eglobalmark.com/apic#resetCount", - "movementCount": "https://ontology.eglobalmark.com/apic#movementCount", - "hornetCount": "https://ontology.eglobalmark.com/apic#hornetCount", - "dateOfFirstBee": "https://ontology.eglobalmark.com/apic#dateOfFirstBee" - } -} diff --git a/shared/src/testFixtures/resources/contexts/egm.jsonld b/shared/src/testFixtures/resources/contexts/egm.jsonld deleted file mode 100644 index 10ed79b92..000000000 --- a/shared/src/testFixtures/resources/contexts/egm.jsonld +++ /dev/null @@ -1,36 +0,0 @@ -{ - "@context":{ - "createdBy": "https://ontology.eglobalmark.com/egm#createdBy", - "executedBy": "https://ontology.eglobalmark.com/egm#executedBy", - "deviceParameter": "https://ontology.eglobalmark.com/egm#deviceParameter", - "vendorId": "https://ontology.eglobalmark.com/egm#vendorId", - "observedBy": "https://ontology.eglobalmark.com/egm#observedBy", - "brandName": "https://ontology.eglobalmark.com/egm#brandName", - "manages": "https://ontology.eglobalmark.com/egm#manages", - "calibrationCertif": "https://ontology.eglobalmark.com/egm#calibrationCertif", - "length": "https://ontology.eglobalmark.com/egm#length", - "connectsTo": "https://ontology.eglobalmark.com/egm#connectsTo", - "detects": "https://ontology.eglobalmark.com/egm#detects", - "observes": "https://ontology.eglobalmark.com/egm#observes", - "depth": "https://ontology.eglobalmark.com/egm#depth", - "managedBy": "https://ontology.eglobalmark.com/egm#managedBy", - "belongs": "https://ontology.eglobalmark.com/egm#belongs", - "belongsTo": "https://ontology.eglobalmark.com/egm#belongsTo", - "detectedBy": "https://ontology.eglobalmark.com/egm#detectedBy", - "heigth": "https://ontology.eglobalmark.com/egm#heigth", - "width": "https://ontology.eglobalmark.com/egm#width", - "executes": "https://ontology.eglobalmark.com/egm#executes", - "calibrationDate": { - "@type": "https://uri.etsi.org/ngsi-ld/DateTime", - "@id": "https://ontology.eglobalmark.com/egm#calibrationDate" - }, - "monitoredBy": "https://ontology.eglobalmark.com/egm#monitoredBy", - "SmartCamera": "https://ontology.eglobalmark.com/egm#SmartCamera", - "Sensor": "https://ontology.eglobalmark.com/egm#Sensor", - "Device": "https://ontology.eglobalmark.com/egm#Device", - "monitors": "https://ontology.eglobalmark.com/egm#monitors", - "voltage": "https://ontology.eglobalmark.com/egm#voltage", - "raised": "https://ontology.eglobalmark.com/egm#raised", - "name": "https://schema.org/name" - } -} diff --git a/shared/src/testFixtures/resources/jarcache.json b/shared/src/testFixtures/resources/jarcache.json deleted file mode 100644 index b45cfb712..000000000 --- a/shared/src/testFixtures/resources/jarcache.json +++ /dev/null @@ -1,11 +0,0 @@ -[ - { - "Content-Location": "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic.jsonld", - "X-Classpath": "contexts/apic.jsonld", - "Content-Type": "application/ld+json" - }, - { - "Content-Location": "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/shared-jsonld-contexts/egm.jsonld", - "X-Classpath": "contexts/egm.jsonld", - "Content-Type": "application/ld+json" - }] diff --git a/shared/src/testFixtures/resources/jsonld-contexts/apic-compound.jsonld b/shared/src/testFixtures/resources/jsonld-contexts/apic-compound.jsonld new file mode 100644 index 000000000..cc63b12e4 --- /dev/null +++ b/shared/src/testFixtures/resources/jsonld-contexts/apic-compound.jsonld @@ -0,0 +1,7 @@ +{ + "@context": [ + "http://localhost:8093/jsonld-contexts/apic.jsonld", + "http://localhost:8093/jsonld-contexts/egm.jsonld", + "http://localhost:8093/jsonld-contexts/ngsi-ld-core-context-v1.8.jsonld" + ] +} diff --git a/shared/src/testFixtures/resources/jsonld-contexts/apic.jsonld b/shared/src/testFixtures/resources/jsonld-contexts/apic.jsonld new file mode 100644 index 000000000..e20277ff6 --- /dev/null +++ b/shared/src/testFixtures/resources/jsonld-contexts/apic.jsonld @@ -0,0 +1,39 @@ +{ + "@context":{ + "Beekeeper": "https://ontology.eglobalmark.com/apic#Beekeeper", + "BeeHive": "https://ontology.eglobalmark.com/apic#BeeHive", + "doorNumber": "https://ontology.eglobalmark.com/apic#doorNumber", + "Apiary": "https://ontology.eglobalmark.com/apic#Apiary", + "outgoing": "https://ontology.eglobalmark.com/apic#outgoing", + "incoming": "https://ontology.eglobalmark.com/apic#incoming", + "Door": "https://ontology.eglobalmark.com/apic#Door", + "SmartDoor": "https://ontology.eglobalmark.com/apic#SmartDoor", + "temperature": "https://ontology.eglobalmark.com/apic#temperature", + "humidity": "https://ontology.eglobalmark.com/apic#humidity", + "timeInterval": "https://ontology.eglobalmark.com/apic#timeInterval", + "timeIntervalUnit": "https://ontology.eglobalmark.com/apic#timeIntervalUnit", + "batteryLevel": "https://ontology.eglobalmark.com/apic#batteryLevel", + "voltage": "https://ontology.eglobalmark.com/apic#voltage", + "movementDetected": { + "@id": "https://ontology.eglobalmark.com/apic#movementDetected", + "@type": "http://www.w3.org/2001/XMLSchema#boolean" + }, + "hornetDetected": { + "@id": "https://ontology.eglobalmark.com/apic#hornetDetected", + "@type": "http://www.w3.org/2001/XMLSchema#boolean" + }, + "errorCode": "https://ontology.eglobalmark.com/apic#errorCode", + "rainTypeDetected":"https://ontology.eglobalmark.com/apic#rainTypeDetected", + "panelTension": "https://ontology.eglobalmark.com/apic#panelTension", + "panelCurrent": "https://ontology.eglobalmark.com/apic#panelCurrent", + "incomingSum": "https://ontology.eglobalmark.com/apic#incomingSum", + "outgoingSum": "https://ontology.eglobalmark.com/apic#outgoingSum", + "luminosity": "https://ontology.eglobalmark.com/apic#luminosity", + "usbCount": "https://ontology.eglobalmark.com/apic#usbCount", + "resetCount": "https://ontology.eglobalmark.com/apic#resetCount", + "movementCount": "https://ontology.eglobalmark.com/apic#movementCount", + "hornetCount": "https://ontology.eglobalmark.com/apic#hornetCount", + "dateOfFirstBee": "https://ontology.eglobalmark.com/apic#dateOfFirstBee" + } + } + \ No newline at end of file diff --git a/shared/src/testFixtures/resources/jsonld-contexts/aquac-compound.jsonld b/shared/src/testFixtures/resources/jsonld-contexts/aquac-compound.jsonld new file mode 100644 index 000000000..15f5c2cdf --- /dev/null +++ b/shared/src/testFixtures/resources/jsonld-contexts/aquac-compound.jsonld @@ -0,0 +1,7 @@ +{ + "@context": [ + "http://localhost:8093/jsonld-contexts/egm.jsonld", + "http://localhost:8093/jsonld-contexts/aquac.jsonld", + "http://localhost:8093/jsonld-contexts/ngsi-ld-core-context-v1.8.jsonld" + ] + } diff --git a/shared/src/testFixtures/resources/jsonld-contexts/aquac.jsonld b/shared/src/testFixtures/resources/jsonld-contexts/aquac.jsonld new file mode 100644 index 000000000..ce2dafc34 --- /dev/null +++ b/shared/src/testFixtures/resources/jsonld-contexts/aquac.jsonld @@ -0,0 +1,75 @@ +{ + "@context": { + "fishNumber": "https://ontology.eglobalmark.com/aquac#fishNumber", + "fishName": "https://ontology.eglobalmark.com/aquac#fishName", + "foodType": "https://ontology.eglobalmark.com/aquac#foodType", + "BreedingService": "https://ontology.eglobalmark.com/aquac#BreedingService", + "fishAge": "https://ontology.eglobalmark.com/aquac#fishAge", + "Specie": "https://ontology.eglobalmark.com/aquac#Specie", + "FeedingService": "https://ontology.eglobalmark.com/aquac#FeedingService", + "foodQuantity": "https://ontology.eglobalmark.com/aquac#foodQuantity", + "target": "https://ontology.eglobalmark.com/aquac#target", + "FishContainment": "https://ontology.eglobalmark.com/aquac#FishContainment", + "MarkerBuoy": "https://ontology.eglobalmark.com/aquac#MarkerBuoy", + "MortalityRemovalService": "https://ontology.eglobalmark.com/aquac#MortalityRemovalService", + "foodName": "https://ontology.eglobalmark.com/aquac#foodName", + "filledIn": "https://ontology.eglobalmark.com/aquac#filledIn", + "removedFrom": "https://ontology.eglobalmark.com/aquac#removedFrom", + "DeadFishes": "https://ontology.eglobalmark.com/aquac#DeadFishes", + "Feeder": "https://ontology.eglobalmark.com/aquac#Feeder", + "fishSize": "https://ontology.eglobalmark.com/aquac#fishSize", + "ammonium": "https://ontology.eglobalmark.com/aquac#ammonium", + "calcium": "https://ontology.eglobalmark.com/aquac#calcium", + "carbonDioxide": "https://ontology.eglobalmark.com/aquac#carbonDioxide", + "chlorophyllA": "https://ontology.eglobalmark.com/aquac#chlorophyllA", + "chlorides": "https://ontology.eglobalmark.com/aquac#chlorides", + "coloredDissolvedOrganicMatter": "https://ontology.eglobalmark.com/aquac#coloredDissolvedOrganicMatter", + "waterLevel": "https://ontology.eglobalmark.com/aquac#waterLevel", + "dissolvedOxygen": "https://ontology.eglobalmark.com/aquac#dissolvedOxygen", + "fluorides": "https://ontology.eglobalmark.com/aquac#fluorides", + "nitrate": "https://ontology.eglobalmark.com/aquac#nitrate", + "pH": "https://ontology.eglobalmark.com/aquac#pH", + "phycoerythrin": "https://ontology.eglobalmark.com/aquac#phycoerythrin", + "redoxPotential": "https://ontology.eglobalmark.com/aquac#redoxPotential", + "rhodamin": "https://ontology.eglobalmark.com/aquac#rhodamin", + "salinity": "https://ontology.eglobalmark.com/aquac#salinity", + "temperature": "https://ontology.eglobalmark.com/aquac#temperature", + "o3InWater": "https://ontology.eglobalmark.com/aquac#o3InWater", + "turbidity": "https://ontology.eglobalmark.com/aquac#turbidity", + "waterCurrents": "https://ontology.eglobalmark.com/aquac#waterCurrents", + "activity": "https://ontology.eglobalmark.com/aquac#activity", + "behaviour": "https://ontology.eglobalmark.com/aquac#behaviour", + "distributionInWater": "https://ontology.eglobalmark.com/aquac#distributionInWater", + "visualAppearance": "https://ontology.eglobalmark.com/aquac#visualAppearance", + "heartRate": "https://ontology.eglobalmark.com/aquac#heartRate", + "parasiteLoading": "https://ontology.eglobalmark.com/aquac#parasiteLoading", + "opercularOpenning": "https://ontology.eglobalmark.com/aquac#opercularOpenning", + "light": "https://ontology.eglobalmark.com/aquac#light", + "feedConsumption": "https://ontology.eglobalmark.com/aquac#feedConsumption", + "waterFlowInput": "https://ontology.eglobalmark.com/aquac#waterFlowInput", + "waterFlowOutput": "https://ontology.eglobalmark.com/aquac#waterFlowOutput", + "oxygenInput": "https://ontology.eglobalmark.com/aquac#oxygenInput", + "underwaterNoise": "https://ontology.eglobalmark.com/aquac#underwaterNoise", + "roomTemperature": "https://ontology.eglobalmark.com/aquac#roomTemperature", + "barometricPressureForRoom": "https://ontology.eglobalmark.com/aquac#barometricPressureForRoom", + "rain": "https://ontology.eglobalmark.com/aquac#rain", + "wind": "https://ontology.eglobalmark.com/aquac#wind", + "humidity": "https://ontology.eglobalmark.com/aquac#humidity", + "totalDissolvedSolids": "https://ontology.eglobalmark.com/aquac#totalDissolvedSolids", + "chlorophyllFluorescence": "https://ontology.eglobalmark.com/aquac#chlorophyllFluorescence", + "chlorophyllConcentration": "https://ontology.eglobalmark.com/aquac#chlorophyllConcentration", + "conductivity": "https://ontology.eglobalmark.com/aquac#conductivity", + "dissolvedOxygenMG": "https://ontology.eglobalmark.com/aquac#dissolvedOxygenMG", + "dissolvedOxygenPPM": "https://ontology.eglobalmark.com/aquac#/dissolvedOxygenPPM", + "pHmV": "https://ontology.eglobalmark.com/aquac#pHmV", + "turbidityFNU": "https://ontology.eglobalmark.com/aquac#turbidityFNU", + "turbidityMG": "https://ontology.eglobalmark.com/aquac#turbidityMG", + "carbonDioxidePPM": "https://ontology.eglobalmark.com/aquac#carbonDioxidePPM", + "carbonDioxideMG": "https://ontology.eglobalmark.com/aquac#carbonDioxideMG", + "totalGasPressure": "https://ontology.eglobalmark.com/aquac#totalGasPressure", + "residualGasVol": "https://ontology.eglobalmark.com/aquac#residualGasVol", + "gasOxygenVol": "https://ontology.eglobalmark.com/aquac#gasOxygenVol", + "uvIntensity": "https://ontology.eglobalmark.com/aquac#uvIntensity", + "residualGas": "https://ontology.eglobalmark.com/aquac#residualGas" + } +} diff --git a/shared/src/testFixtures/resources/jsonld-contexts/authorization-compound.jsonld b/shared/src/testFixtures/resources/jsonld-contexts/authorization-compound.jsonld new file mode 100644 index 000000000..f264aee2e --- /dev/null +++ b/shared/src/testFixtures/resources/jsonld-contexts/authorization-compound.jsonld @@ -0,0 +1,6 @@ +{ + "@context": [ + "http://localhost:8093/jsonld-contexts/authorization.jsonld", + "http://localhost:8093/jsonld-contexts/ngsi-ld-core-context-v1.8.jsonld" + ] +} diff --git a/shared/src/testFixtures/resources/jsonld-contexts/authorization.jsonld b/shared/src/testFixtures/resources/jsonld-contexts/authorization.jsonld new file mode 100644 index 000000000..9f51c71fb --- /dev/null +++ b/shared/src/testFixtures/resources/jsonld-contexts/authorization.jsonld @@ -0,0 +1,23 @@ +{ + "@context": { + "Client": "https://ontology.eglobalmark.com/authorization#Client", + "clientId": "https://ontology.eglobalmark.com/authorization#clientId", + "familyName": "https://ontology.eglobalmark.com/authorization#familyName", + "givenName": "https://ontology.eglobalmark.com/authorization#givenName", + "Group": "https://ontology.eglobalmark.com/authorization#Group", + "isMemberOf": "https://ontology.eglobalmark.com/authorization#isMemberOf", + "name": "https://schema.org/name", + "profile": "https://ontology.eglobalmark.com/authorization#profile", + "rCanAdmin": "https://ontology.eglobalmark.com/authorization#rCanAdmin", + "rCanRead": "https://ontology.eglobalmark.com/authorization#rCanRead", + "rCanWrite": "https://ontology.eglobalmark.com/authorization#rCanWrite", + "right": "https://ontology.eglobalmark.com/authorization#right", + "roles": "https://ontology.eglobalmark.com/authorization#roles", + "serviceAccountId": "https://ontology.eglobalmark.com/authorization#serviceAccountId", + "specificAccessPolicy": "https://ontology.eglobalmark.com/authorization#specificAccessPolicy", + "subjectInfo": "https://ontology.eglobalmark.com/authorization#subjectInfo", + "User": "https://ontology.eglobalmark.com/authorization#User", + "username": "https://ontology.eglobalmark.com/authorization#username", + "kind": "https://ontology.eglobalmark.com/authorization#kind" + } +} \ No newline at end of file diff --git a/shared/src/testFixtures/resources/jsonld-contexts/egm.jsonld b/shared/src/testFixtures/resources/jsonld-contexts/egm.jsonld new file mode 100644 index 000000000..f29db5706 --- /dev/null +++ b/shared/src/testFixtures/resources/jsonld-contexts/egm.jsonld @@ -0,0 +1,37 @@ +{ + "@context":{ + "createdBy": "https://ontology.eglobalmark.com/egm#createdBy", + "executedBy": "https://ontology.eglobalmark.com/egm#executedBy", + "deviceParameter": "https://ontology.eglobalmark.com/egm#deviceParameter", + "vendorId": "https://ontology.eglobalmark.com/egm#vendorId", + "observedBy": "https://ontology.eglobalmark.com/egm#observedBy", + "brandName": "https://ontology.eglobalmark.com/egm#brandName", + "manages": "https://ontology.eglobalmark.com/egm#manages", + "calibrationCertif": "https://ontology.eglobalmark.com/egm#calibrationCertif", + "length": "https://ontology.eglobalmark.com/egm#length", + "connectsTo": "https://ontology.eglobalmark.com/egm#connectsTo", + "detects": "https://ontology.eglobalmark.com/egm#detects", + "observes": "https://ontology.eglobalmark.com/egm#observes", + "depth": "https://ontology.eglobalmark.com/egm#depth", + "managedBy": "https://ontology.eglobalmark.com/egm#managedBy", + "belongs": "https://ontology.eglobalmark.com/egm#belongs", + "belongsTo": "https://ontology.eglobalmark.com/egm#belongsTo", + "detectedBy": "https://ontology.eglobalmark.com/egm#detectedBy", + "heigth": "https://ontology.eglobalmark.com/egm#heigth", + "width": "https://ontology.eglobalmark.com/egm#width", + "executes": "https://ontology.eglobalmark.com/egm#executes", + "calibrationDate": { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@id": "https://ontology.eglobalmark.com/egm#calibrationDate" + }, + "monitoredBy": "https://ontology.eglobalmark.com/egm#monitoredBy", + "SmartCamera": "https://ontology.eglobalmark.com/egm#SmartCamera", + "Sensor": "https://ontology.eglobalmark.com/egm#Sensor", + "Device": "https://ontology.eglobalmark.com/egm#Device", + "monitors": "https://ontology.eglobalmark.com/egm#monitors", + "voltage": "https://ontology.eglobalmark.com/egm#voltage", + "raised": "https://ontology.eglobalmark.com/egm#raised", + "name": "https://schema.org/name" + } + } + \ No newline at end of file diff --git a/shared/src/testFixtures/resources/jsonld-contexts/ngsi-ld-core-context-v1.8.jsonld b/shared/src/testFixtures/resources/jsonld-contexts/ngsi-ld-core-context-v1.8.jsonld new file mode 100644 index 000000000..6a8cb2788 --- /dev/null +++ b/shared/src/testFixtures/resources/jsonld-contexts/ngsi-ld-core-context-v1.8.jsonld @@ -0,0 +1,361 @@ +{ + "@context": { + "@vocab": "https://uri.etsi.org/ngsi-ld/default-context/", + "Attribute": "ngsi-ld:Attribute", + "AttributeList": "ngsi-ld:AttributeList", + "ContextSourceIdentity": "ngsi-ld:ContextSourceIdentity", + "ContextSourceNotification": "ngsi-ld:ContextSourceNotification", + "ContextSourceRegistration": "ngsi-ld:ContextSourceRegistration", + "Date": "ngsi-ld:Date", + "DateTime": "ngsi-ld:DateTime", + "EntityType": "ngsi-ld:EntityType", + "EntityTypeInfo": "ngsi-ld:EntityTypeInfo", + "EntityTypeList": "ngsi-ld:EntityTypeList", + "Feature": "geojson:Feature", + "FeatureCollection": "geojson:FeatureCollection", + "GeoProperty": "ngsi-ld:GeoProperty", + "GeometryCollection": "geojson:GeometryCollection", + "JsonProperty": "ngsi-ld:JsonProperty", + "LanguageProperty": "ngsi-ld:LanguageProperty", + "LineString": "geojson:LineString", + "ListProperty": "ngsi-ld:ListProperty", + "ListRelationship": "ngsi-ld:ListRelationship", + "MultiLineString": "geojson:MultiLineString", + "MultiPoint": "geojson:MultiPoint", + "MultiPolygon": "geojson:MultiPolygon", + "Notification": "ngsi-ld:Notification", + "Point": "geojson:Point", + "Polygon": "geojson:Polygon", + "Property": "ngsi-ld:Property", + "Relationship": "ngsi-ld:Relationship", + "Subscription": "ngsi-ld:Subscription", + "TemporalProperty": "ngsi-ld:TemporalProperty", + "Time": "ngsi-ld:Time", + "VocabProperty": "ngsi-ld:VocabProperty", + "accept": "ngsi-ld:accept", + "attributeCount": "attributeCount", + "attributeDetails": "attributeDetails", + "attributeList": { + "@id": "ngsi-ld:attributeList", + "@type": "@vocab" + }, + "attributeName": { + "@id": "ngsi-ld:attributeName", + "@type": "@vocab" + }, + "attributeNames": { + "@id": "ngsi-ld:attributeNames", + "@type": "@vocab" + }, + "attributeTypes": { + "@id": "ngsi-ld:attributeTypes", + "@type": "@vocab" + }, + "attributes": { + "@id": "ngsi-ld:attributes", + "@type": "@vocab" + }, + "attrs": "ngsi-ld:attrs", + "avg": { + "@container": "@list", + "@id": "ngsi-ld:avg" + }, + "bbox": { + "@container": "@list", + "@id": "geojson:bbox" + }, + "cacheDuration": "ngsi-ld:cacheDuration", + "contextSourceInfo": "ngsi-ld:contextSourceInfo", + "cooldown": "ngsi-ld:cooldown", + "coordinates": { + "@container": "@list", + "@id": "geojson:coordinates" + }, + "createdAt": { + "@id": "ngsi-ld:createdAt", + "@type": "DateTime" + }, + "csf": "ngsi-ld:csf", + "data": "ngsi-ld:data", + "dataset": { + "@container": "@index", + "@id": "ngsi-ld:hasDataset" + }, + "datasetId": { + "@id": "ngsi-ld:datasetId", + "@type": "@id" + }, + "deletedAt": { + "@id": "ngsi-ld:deletedAt", + "@type": "DateTime" + }, + "description": "http://purl.org/dc/terms/description", + "detail": "ngsi-ld:detail", + "distinctCount": { + "@container": "@list", + "@id": "ngsi-ld:distinctCount" + }, + "endAt": { + "@id": "ngsi-ld:endAt", + "@type": "DateTime" + }, + "endTimeAt": { + "@id": "ngsi-ld:endTimeAt", + "@type": "DateTime" + }, + "endpoint": "ngsi-ld:endpoint", + "entities": "ngsi-ld:entities", + "entity": "ngsi-ld:entity", + "entityCount": "ngsi-ld:entityCount", + "entityId": { + "@id": "ngsi-ld:entityId", + "@type": "@id" + }, + "entityList": { + "@container": "@list", + "@id": "ngsi-ld:entityList" + }, + "error": "ngsi-ld:error", + "errors": "ngsi-ld:errors", + "expiresAt": { + "@id": "ngsi-ld:expiresAt", + "@type": "DateTime" + }, + "features": { + "@container": "@set", + "@id": "geojson:features" + }, + "format": "ngsi-ld:format", + "geoQ": "ngsi-ld:geoQ", + "geojson": "https://purl.org/geojson/vocab#", + "geometry": "geojson:geometry", + "geoproperty": "ngsi-ld:geoproperty", + "georel": "ngsi-ld:georel", + "id": "@id", + "idPattern": "ngsi-ld:idPattern", + "information": "ngsi-ld:information", + "instanceId": { + "@id": "ngsi-ld:instanceId", + "@type": "@id" + }, + "isActive": "ngsi-ld:isActive", + "json": { + "@id": "ngsi-ld:hasJSON", + "@type": "@json" + }, + "jsons": { + "@container": "@list", + "@id": "ngsi-ld:jsons" + }, + "key": "ngsi-ld:hasKey", + "lang": "ngsi-ld:lang", + "languageMap": { + "@container": "@language", + "@id": "ngsi-ld:hasLanguageMap" + }, + "languageMaps": { + "@container": "@list", + "@id": "ngsi-ld:hasLanguageMaps" + }, + "lastFailure": { + "@id": "ngsi-ld:lastFailure", + "@type": "DateTime" + }, + "lastNotification": { + "@id": "ngsi-ld:lastNotification", + "@type": "DateTime" + }, + "lastSuccess": { + "@id": "ngsi-ld:lastSuccess", + "@type": "DateTime" + }, + "localOnly": "ngsi-ld:localOnly", + "location": "ngsi-ld:location", + "management": "ngsi-ld:management", + "managementInterval": "ngsi-ld:managementInterval", + "max": { + "@container": "@list", + "@id": "ngsi-ld:max" + }, + "min": { + "@container": "@list", + "@id": "ngsi-ld:min" + }, + "mode": "ngsi-ld:mode", + "modifiedAt": { + "@id": "ngsi-ld:modifiedAt", + "@type": "DateTime" + }, + "ngsi-ld": "https://uri.etsi.org/ngsi-ld/", + "notUpdated": "ngsi-ld:notUpdated", + "notification": "ngsi-ld:notification", + "notificationTrigger": "ngsi-ld:notificationTrigger", + "notifiedAt": { + "@id": "ngsi-ld:notifiedAt", + "@type": "DateTime" + }, + "notifierInfo": "ngsi-ld:notifierInfo", + "object": { + "@id": "ngsi-ld:hasObject", + "@type": "@id" + }, + "objectList": { + "@container": "@list", + "@id": "ngsi-ld:hasObjectList" + }, + "objectType": { + "@id": "ngsi-ld:hasObjectType", + "@type": "@vocab" + }, + "objects": { + "@container": "@list", + "@id": "ngsi-ld:hasObjects" + }, + "objectsLists": { + "@container": "@list", + "@id": "ngsi-ld:hasObjectsLists" + }, + "observationInterval": "ngsi-ld:observationInterval", + "observationSpace": "ngsi-ld:observationSpace", + "observedAt": { + "@id": "ngsi-ld:observedAt", + "@type": "DateTime" + }, + "operationSpace": "ngsi-ld:operationSpace", + "operations": "ngsi-ld:operations", + "previousJson": { + "@id": "ngsi-ld:hasPreviousJson", + "@type": "@json" + }, + "previousLanguageMap": { + "@container": "@language", + "@id": "ngsi-ld:hasPreviousLanguageMap" + }, + "previousObject": { + "@id": "ngsi-ld:hasPreviousObject", + "@type": "@id" + }, + "previousObjectList": { + "@container": "@list", + "@id": "ngsi-ld:hasPreviousObjectList" + }, + "previousValue": "ngsi-ld:hasPreviousValue", + "previousValueList": { + "@container": "@list", + "@id": "ngsi-ld:hasPreviousValueList" + }, + "previousVocab": { + "@id": "ngsi-ld:hasPreviousVocab", + "@type": "@vocab" + }, + "properties": "geojson:properties", + "propertyNames": { + "@id": "ngsi-ld:propertyNames", + "@type": "@vocab" + }, + "q": "ngsi-ld:q", + "reason": "ngsi-ld:reason", + "receiverInfo": "ngsi-ld:receiverInfo", + "refreshRate": "ngsi-ld:refreshRate", + "registrationId": "ngsi-ld:registrationId", + "registrationName": "ngsi-ld:registrationName", + "relationshipNames": { + "@id": "ngsi-ld:relationshipNames", + "@type": "@vocab" + }, + "scope": "ngsi-ld:scope", + "scopeQ": "ngsi-ld:scopeQ", + "showChanges": "ngsi-ld:showChanges", + "startAt": { + "@id": "ngsi-ld:startAt", + "@type": "DateTime" + }, + "status": "ngsi-ld:status", + "stddev": { + "@container": "@list", + "@id": "ngsi-ld:stddev" + }, + "subscriptionId": { + "@id": "ngsi-ld:subscriptionId", + "@type": "@id" + }, + "subscriptionName": "ngsi-ld:subscriptionName", + "success": { + "@id": "ngsi-ld:success", + "@type": "@id" + }, + "sum": { + "@container": "@list", + "@id": "ngsi-ld:sum" + }, + "sumsq": { + "@container": "@list", + "@id": "ngsi-ld:sumsq" + }, + "sysAttrs": "ngsi-ld:sysAttrs", + "temporalQ": "ngsi-ld:temporalQ", + "tenant": { + "@id": "ngsi-ld:tenant", + "@type": "@id" + }, + "throttling": "ngsi-ld:throttling", + "timeAt": { + "@id": "ngsi-ld:timeAt", + "@type": "DateTime" + }, + "timeInterval": "ngsi-ld:timeInterval", + "timeout": "ngsi-ld:timeout", + "timeproperty": "ngsi-ld:timeproperty", + "timerel": "ngsi-ld:timerel", + "timesFailed": "ngsi-ld:timesFailed", + "timesSent": "ngsi-ld:timesSent", + "title": "http://purl.org/dc/terms/title", + "totalCount": { + "@container": "@list", + "@id": "ngsi-ld:totalCount" + }, + "triggerReason": "ngsi-ld:triggerReason", + "type": "@type", + "typeList": { + "@id": "ngsi-ld:typeList", + "@type": "@vocab" + }, + "typeName": { + "@id": "ngsi-ld:typeName", + "@type": "@vocab" + }, + "typeNames": { + "@id": "ngsi-ld:typeNames", + "@type": "@vocab" + }, + "unchanged": "ngsi-ld:unchanged", + "unitCode": "ngsi-ld:unitCode", + "updated": "ngsi-ld:updated", + "uri": "ngsi-ld:uri", + "value": "ngsi-ld:hasValue", + "valueList": { + "@container": "@list", + "@id": "ngsi-ld:hasValueList" + }, + "valueLists": { + "@container": "@list", + "@id": "ngsi-ld:hasValueLists" + }, + "values": { + "@container": "@list", + "@id": "ngsi-ld:hasValues" + }, + "vocab": { + "@id": "ngsi-ld:hasVocab", + "@type": "@vocab" + }, + "vocabs": { + "@container": "@list", + "@id": "ngsi-ld:hasVocabs" + }, + "watchedAttributes": { + "@id": "ngsi-ld:watchedAttributes", + "@type": "@vocab" + } + } +} diff --git a/shared/src/testFixtures/resources/ngsild/events/authorization/RightAddOnEntity.json b/shared/src/testFixtures/resources/ngsild/events/authorization/RightAddOnEntity.json index e9c54f7ce..21c318d29 100644 --- a/shared/src/testFixtures/resources/ngsild/events/authorization/RightAddOnEntity.json +++ b/shared/src/testFixtures/resources/ngsild/events/authorization/RightAddOnEntity.json @@ -6,7 +6,7 @@ "operationPayload": "{\"type\":\"Relationship\",\"object\":\"urn:ngsi-ld:Beekeeper:01\"}", "updatedEntity": "", "contexts": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "overwrite": true, "operationType": "ATTRIBUTE_APPEND" diff --git a/shared/src/testFixtures/resources/ngsild/events/authorization/RightRemoveOnEntity.json b/shared/src/testFixtures/resources/ngsild/events/authorization/RightRemoveOnEntity.json index da6e036db..cfdd03cc9 100644 --- a/shared/src/testFixtures/resources/ngsild/events/authorization/RightRemoveOnEntity.json +++ b/shared/src/testFixtures/resources/ngsild/events/authorization/RightRemoveOnEntity.json @@ -5,7 +5,7 @@ "attributeName": "urn:ngsi-ld:Beekeeper:01", "updatedEntity": "", "contexts": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType": "ATTRIBUTE_DELETE" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendNumericPropDatasetIdEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendNumericPropDatasetIdEvent.json index dab9a554a..46ac9c9dc 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendNumericPropDatasetIdEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendNumericPropDatasetIdEvent.json @@ -7,6 +7,6 @@ "overwrite" : true, "operationPayload" : "{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/datasetId\":[{\"@id\":\"urn:ngsi-ld:Dataset:WeatherApi\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":30}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2021-10-26T21:32:52.98601Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.011609Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.982113Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#luminosity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:57.017715Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:56.987108Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":120}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-02T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"LUX\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.063606Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.056169Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":22.2}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]},{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:05:02.239954Z\"}],\"https://uri.etsi.org/ngsi-ld/datasetId\":[{\"@id\":\"urn:ngsi-ld:Dataset:WeatherApi\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":30}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2021-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.793453Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#createdBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:07:08.429628Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Craftman:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:00:45.114035Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.359316Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:05:02.357024Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_APPEND" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendNumericPropEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendNumericPropEvent.json index 06b3693e7..82878fbff 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendNumericPropEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendNumericPropEvent.json @@ -6,6 +6,6 @@ "overwrite" : true, "operationPayload" : "{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":120}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-02T21:32:52.98601Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"LUX\"}]}", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.011609Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.982113Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#luminosity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:57.017715Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:56.987108Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":120}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-02T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"LUX\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.063606Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.056169Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":22.2}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.793453Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.939064Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.359316Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:57.066037Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_APPEND" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendRelEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendRelEvent.json index 765b2c9f2..20751d294 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendRelEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendRelEvent.json @@ -6,6 +6,6 @@ "overwrite" : true, "operationPayload" : "{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Craftman:01\"}]}", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.011609Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.982113Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#luminosity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:57.017715Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:56.987108Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":120}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-02T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"LUX\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.063606Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.056169Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":22.2}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.793453Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#createdBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:07:08.429628Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Craftman:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:05:39.532687Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.359316Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:07:08.524818Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_APPEND" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendTextPropEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendTextPropEvent.json index 111aa8b6d..a6ce25ffd 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendTextPropEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendTextPropEvent.json @@ -6,6 +6,6 @@ "overwrite" : true, "operationPayload" : "{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"BeeHiveSophia\"}]}", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.455870Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.448205Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:38:17.094923Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:38:17.045041Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":2}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:39:39.923329Z\"}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2021-12-08T10:20:30.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.389815Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.417938Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:01\"}]}],\"https://schema.org/name\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:40:29.239195Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"BeeHiveSophia\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.179446Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:40:29.316765Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_APPEND" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendTypeEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendTypeEvent.json index 5fef60a6f..277ceb7da 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendTypeEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeAppendTypeEvent.json @@ -6,6 +6,6 @@ "overwrite" : true, "operationPayload" : "[\"https://ontology.eglobalmark.com/apic#BeeHive\",\"https://ontology.eglobalmark.com/apic#Apiary\"]", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\",\"https://ontology.eglobalmark.com/apic#Apiary\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.359316Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:07:08.524818Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_APPEND" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeDeleteAllInstancesEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeDeleteAllInstancesEvent.json index 6760cd9bf..fe5354476 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeDeleteAllInstancesEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeDeleteAllInstancesEvent.json @@ -4,6 +4,6 @@ "entityTypes" : [ "https://ontology.eglobalmark.com/apic#BeeHive" ], "attributeName" : "https://ontology.eglobalmark.com/apic#temperature", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.011609Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.982113Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#luminosity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:57.017715Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:56.987108Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":120}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-02T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"LUX\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.793453Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#createdBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:07:08.429628Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Craftman:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:00:45.114035Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:02\"}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:10:16.963869Z\"}]}],\"https://schema.org/name\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:14:03.758379Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"Beehive - Biot\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.359316Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:14:03.812339Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_DELETE_ALL_INSTANCES" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeDeleteEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeDeleteEvent.json index 8f87879de..1285008cc 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeDeleteEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeDeleteEvent.json @@ -4,6 +4,6 @@ "entityTypes" : [ "https://ontology.eglobalmark.com/apic#BeeHive" ], "attributeName" : "https://schema.org/name", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.455870Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.448205Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:38:17.094923Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:38:17.045041Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":2}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:39:39.923329Z\"}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2021-12-08T10:20:30.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.389815Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.417938Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.179446Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:40:29.316765Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_DELETE" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeReplaceNumericPropEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeReplaceNumericPropEvent.json index a57dc8487..92b685b58 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeReplaceNumericPropEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeReplaceNumericPropEvent.json @@ -5,6 +5,6 @@ "attributeName" : "https://ontology.eglobalmark.com/apic#temperature", "operationPayload" : "{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":44}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2021-11-26T22:35:52.98601Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.455870Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.448205Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:38:17.094923Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:38:17.045041Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":44}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2021-11-26T22:35:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.389815Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.417938Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.179446Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.218595Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_REPLACE" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeReplaceRelEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeReplaceRelEvent.json index f36165fc7..3169f208f 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeReplaceRelEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeReplaceRelEvent.json @@ -5,6 +5,6 @@ "attributeName" : "https://ontology.eglobalmark.com/egm#managedBy", "operationPayload" : "{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:02\"}]}", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.011609Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.982113Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#luminosity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:57.017715Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:56.987108Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":120}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-02T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"LUX\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.063606Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.056169Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":22.2}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.793453Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#createdBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:07:08.429628Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Craftman:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:00:45.114035Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.359316Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:00:45.741832Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_REPLACE" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeReplaceTextPropEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeReplaceTextPropEvent.json index fbe13a306..c6d0c8bc7 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeReplaceTextPropEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeReplaceTextPropEvent.json @@ -5,6 +5,6 @@ "attributeName" : "https://schema.org/name", "operationPayload" : "{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"Beehive - Biot\"}]}", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.011609Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.982113Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#luminosity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:57.017715Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:56.987108Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":120}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-02T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"LUX\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.063606Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.056169Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":22.2}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]},{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:05:02.239954Z\"}],\"https://uri.etsi.org/ngsi-ld/datasetId\":[{\"@id\":\"urn:ngsi-ld:Dataset:WeatherApi\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":2}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:07:38.495067Z\"}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2021-12-08T10:20:30.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.793453Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#createdBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:07:08.429628Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Craftman:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:00:45.114035Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:02\"}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:10:16.963869Z\"}]}],\"https://schema.org/name\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:14:03.758379Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"Beehive - Biot\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.359316Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:14:03.812339Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_REPLACE" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateNumericPropDatasetIdEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateNumericPropDatasetIdEvent.json index 1e7c22c8c..8e18ed86c 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateNumericPropDatasetIdEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateNumericPropDatasetIdEvent.json @@ -6,6 +6,6 @@ "datasetId" : "urn:ngsi-ld:Dataset:WeatherApi", "operationPayload" : "{\"https://uri.etsi.org/ngsi-ld/datasetId\":[{\"@id\":\"urn:ngsi-ld:Dataset:WeatherApi\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":2}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2021-12-08T10:20:30.98601Z\"}]}", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.011609Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.982113Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#luminosity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:57.017715Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:56.987108Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":120}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-02T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"LUX\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.063606Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.056169Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":22.2}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]},{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:05:02.239954Z\"}],\"https://uri.etsi.org/ngsi-ld/datasetId\":[{\"@id\":\"urn:ngsi-ld:Dataset:WeatherApi\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":2}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:07:38.495067Z\"}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2021-12-08T10:20:30.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.793453Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#createdBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:07:08.429628Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Craftman:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:00:45.114035Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.359316Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:07:38.782299Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_UPDATE" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateNumericPropEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateNumericPropEvent.json index 061b10637..b3748f825 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateNumericPropEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateNumericPropEvent.json @@ -5,6 +5,6 @@ "attributeName" : "https://ontology.eglobalmark.com/apic#temperature", "operationPayload" : "{\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":2}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2021-12-08T10:20:30.98601Z\"}]}", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.455870Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.448205Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:38:17.094923Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:38:17.045041Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":2}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:39:39.923329Z\"}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2021-12-08T10:20:30.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.389815Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.417938Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:36:59.179446Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-12T08:39:39.974642Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_UPDATE" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateRelEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateRelEvent.json index fee821a7f..39e4c9f98 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateRelEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateRelEvent.json @@ -5,6 +5,6 @@ "attributeName" : "https://ontology.eglobalmark.com/egm#managedBy", "operationPayload" : "{\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:02\"}]}", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.011609Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.982113Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#luminosity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:57.017715Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:56.987108Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":120}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-02T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"LUX\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.063606Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.056169Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":22.2}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]},{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:05:02.239954Z\"}],\"https://uri.etsi.org/ngsi-ld/datasetId\":[{\"@id\":\"urn:ngsi-ld:Dataset:WeatherApi\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":2}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:07:38.495067Z\"}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2021-12-08T10:20:30.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.793453Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#createdBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:07:08.429628Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Craftman:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:00:45.114035Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:02\"}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:10:16.963869Z\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.359316Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:10:17.318630Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_UPDATE" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateTextPropEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateTextPropEvent.json index 8d3aa0347..54dcc1565 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateTextPropEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/attributeUpdateTextPropEvent.json @@ -5,6 +5,6 @@ "attributeName" : "https://schema.org/name", "operationPayload" : "{\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"Beehive - Valbonne\"}]}", "updatedEntity" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.011609Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.982113Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#luminosity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:57.017715Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:56.987108Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":120}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-02T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"LUX\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.063606Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:50.056169Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":22.2}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]},{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:05:02.239954Z\"}],\"https://uri.etsi.org/ngsi-ld/datasetId\":[{\"@id\":\"urn:ngsi-ld:Dataset:WeatherApi\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":2}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:07:38.495067Z\"}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2021-12-08T10:20:30.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.793453Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#createdBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:07:08.429628Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Craftman:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:00:45.114035Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:02\"}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:10:16.963869Z\"}]}],\"https://schema.org/name\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:11:55.143625Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"Beehive - Valbonne\"}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:12:42.361048Z\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.359316Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T14:12:42.408699Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ATTRIBUTE_UPDATE" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/entityCreateEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/entityCreateEvent.json index 9f5b58139..43789b5fd 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/entityCreateEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/entityCreateEvent.json @@ -3,7 +3,7 @@ "tenantUri": "urn:ngsi-ld:tenant:default", "entityId" : "urn:ngsi-ld:BeeHive:01", "entityTypes" : [ "https://ontology.eglobalmark.com/apic#BeeHive" ], - "operationPayload":"{\"https://ontology.eglobalmark.com/egm#belongs\":[{\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.389815Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}],\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.179446Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.448205Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@value\":\"2019-10-26T21:32:52.986010Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.455870Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}],\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"]}],\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}]}],\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.417938Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:01\"}],\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@value\":\"2022-02-12T08:36:59.218595Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.465937Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@value\":\"2019-10-26T21:32:52.986010Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.473904Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}],\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"]}],\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":22.2}]}],\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "operationPayload": "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.455870Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.448205Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@value\":\"2019-10-26T21:32:52.986010Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.473904Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.465937Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":22.2}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@value\":\"2019-10-26T21:32:52.986010Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.389815Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.417938Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.179446Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@value\":\"2022-02-12T08:36:59.218595Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}]}", + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ENTITY_CREATE" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/entityDeleteEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/entityDeleteEvent.json index 4135d5853..5634e1950 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/entityDeleteEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/entityDeleteEvent.json @@ -2,7 +2,7 @@ "tenantUri": "urn:ngsi-ld:tenant:default", "entityId" : "urn:ngsi-ld:BeeHive:01", "entityTypes" : [ "https://ontology.eglobalmark.com/apic#BeeHive" ], - "deletedEntity":"{\"https://ontology.eglobalmark.com/egm#belongs\":[{\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.389815Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}],\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.179446Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.448205Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@value\":\"2019-10-26T21:32:52.986010Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.455870Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}],\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"]}],\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}]}],\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.417938Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:01\"}],\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@value\":\"2022-02-12T08:36:59.218595Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.465937Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@value\":\"2019-10-26T21:32:52.986010Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.473904Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}],\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"]}],\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":22.2}]}],\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "deletedEntity":"{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.455870Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.448205Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@value\":\"2019-10-26T21:32:52.986010Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.473904Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.465937Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":22.2}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@value\":\"2019-10-26T21:32:52.986010Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#belongs\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.389815Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Apiary:01\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.417938Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@value\":\"2022-02-12T08:36:59.179446Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@value\":\"2022-02-12T08:36:59.218595Z\",\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\"}]}", + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ENTITY_DELETE" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/entityReplaceEvent.json b/shared/src/testFixtures/resources/ngsild/events/entity/entityReplaceEvent.json index b970771f2..3ea5d7244 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/entityReplaceEvent.json +++ b/shared/src/testFixtures/resources/ngsild/events/entity/entityReplaceEvent.json @@ -3,6 +3,6 @@ "entityId" : "urn:ngsi-ld:BeeHive:01", "entityTypes" : [ "https://ontology.eglobalmark.com/apic#BeeHive" ], "operationPayload" : "{\"@id\":\"urn:ngsi-ld:BeeHive:01\",\"@type\":[\"https://ontology.eglobalmark.com/apic#BeeHive\"],\"https://ontology.eglobalmark.com/apic#humidity\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-14T07:27:15.031664Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:02\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-14T07:27:15.018709Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":60}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"P1\"}]}],\"https://ontology.eglobalmark.com/apic#temperature\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Property\"],\"https://ontology.eglobalmark.com/egm#observedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-14T07:27:15.083398Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Sensor:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-14T07:27:15.067964Z\"}],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":22.2}],\"https://uri.etsi.org/ngsi-ld/observedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2019-10-26T21:32:52.986010Z\"}],\"https://uri.etsi.org/ngsi-ld/unitCode\":[{\"@value\":\"CEL\"}]}],\"https://ontology.eglobalmark.com/egm#managedBy\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/Relationship\"],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-14T07:27:15.109131Z\"}],\"https://uri.etsi.org/ngsi-ld/hasObject\":[{\"@id\":\"urn:ngsi-ld:Beekeeper:01\"}]}],\"https://uri.etsi.org/ngsi-ld/createdAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-13T08:02:49.359316Z\"}],\"https://uri.etsi.org/ngsi-ld/location\":[{\"@type\":[\"https://uri.etsi.org/ngsi-ld/GeoProperty\"],\"https://uri.etsi.org/ngsi-ld/hasValue\":[{\"@value\":\"POINT (24.30623 60.07966)\"}]}],\"https://uri.etsi.org/ngsi-ld/modifiedAt\":[{\"@type\":\"https://uri.etsi.org/ngsi-ld/DateTime\",\"@value\":\"2022-02-14T07:27:15.141078Z\"}]}", - "contexts" : [ "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" ], + "contexts" : [ "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ], "operationType" : "ENTITY_REPLACE" } diff --git a/shared/src/testFixtures/resources/ngsild/events/entity/invalid/humidityAppendEvent.jsonld b/shared/src/testFixtures/resources/ngsild/events/entity/invalid/humidityAppendEvent.jsonld index 301c4929c..748fd353e 100644 --- a/shared/src/testFixtures/resources/ngsild/events/entity/invalid/humidityAppendEvent.jsonld +++ b/shared/src/testFixtures/resources/ngsild/events/entity/invalid/humidityAppendEvent.jsonld @@ -7,6 +7,6 @@ "operationPayload":"{ \"value\":62, \"unitCode\": \"P1\", \"observedAt\": \"2019-11-26T22:35:52.98601Z\" }", "updatedEntity":"", "contexts":[ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/subscription-service/build.gradle.kts b/subscription-service/build.gradle.kts index 9e3f8e619..7a9b677d9 100644 --- a/subscription-service/build.gradle.kts +++ b/subscription-service/build.gradle.kts @@ -27,7 +27,6 @@ dependencies { runtimeOnly("org.postgresql:postgresql") - testImplementation("org.wiremock:wiremock-standalone:3.3.1") testImplementation("org.testcontainers:postgresql") testImplementation("org.testcontainers:r2dbc") testImplementation(testFixtures(project(":shared"))) diff --git a/subscription-service/config/detekt/baseline.xml b/subscription-service/config/detekt/baseline.xml index 1471fb12d..f1183e4a7 100644 --- a/subscription-service/config/detekt/baseline.xml +++ b/subscription-service/config/detekt/baseline.xml @@ -4,7 +4,7 @@ CyclomaticComplexMethod:SubscriptionServiceTests.kt$SubscriptionServiceTests$@Test fun `it should load a subscription with all possible members`() LongMethod:EntityEventListenerService.kt$EntityEventListenerService$internal suspend fun dispatchEntityEvent(content: String) - LongParameterList:FixtureUtils.kt$( withQueryAndGeoQuery: Pair<Boolean, Boolean> = Pair(true, true), withEndpointReceiverInfo: Boolean = true, withNotifParams: Pair<FormatType, List<String>> = Pair(FormatType.NORMALIZED, emptyList()), withModifiedAt: Boolean = false, georel: String = "within", geometry: String = "Polygon", coordinates: String = "[[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]]", timeInterval: Int? = null, contexts: List<String> = listOf(NGSILD_CORE_CONTEXT) ) + LongParameterList:FixtureUtils.kt$( withQueryAndGeoQuery: Pair<Boolean, Boolean> = Pair(true, true), withEndpointReceiverInfo: Boolean = true, withNotifParams: Pair<FormatType, List<String>> = Pair(FormatType.NORMALIZED, emptyList()), withModifiedAt: Boolean = false, georel: String = "within", geometry: String = "Polygon", coordinates: String = "[[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]]", timeInterval: Int? = null, contexts: List<String> = listOf(NGSILD_TEST_CORE_CONTEXT) ) TooGenericExceptionCaught:SubscriptionService.kt$SubscriptionService$e: Exception TooManyFunctions:SubscriptionService.kt$SubscriptionService diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/job/TimeIntervalNotificationJobTest.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/job/TimeIntervalNotificationJobTest.kt index 928347c3e..c23bc9d24 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/job/TimeIntervalNotificationJobTest.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/job/TimeIntervalNotificationJobTest.kt @@ -3,12 +3,8 @@ package com.egm.stellio.subscription.job import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.config.ApplicationProperties.TenantConfiguration import com.egm.stellio.shared.model.EntitySelector -import com.egm.stellio.shared.util.APIC_COMPOUND_CONTEXT -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT +import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap -import com.egm.stellio.shared.util.buildContextLinkHeader -import com.egm.stellio.shared.util.loadSampleData -import com.egm.stellio.shared.util.toUri import com.egm.stellio.shared.web.DEFAULT_TENANT_URI import com.egm.stellio.subscription.config.WebClientConfig import com.egm.stellio.subscription.model.Notification @@ -241,7 +237,7 @@ class TimeIntervalNotificationJobTest { applicationProperties.tenants } returns listOf(TenantConfiguration(DEFAULT_TENANT_URI, "", "public")) coEvery { subscriptionService.getRecurringSubscriptionsToNotify() } returns listOf(subscription) - coEvery { subscriptionService.getContextsLink(any()) } returns NGSILD_CORE_CONTEXT + coEvery { subscriptionService.getContextsLink(any()) } returns NGSILD_TEST_CORE_CONTEXT coEvery { notificationService.callSubscriber(any(), any()) } returns Triple(subscription, mockkClass(Notification::class), true) diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/model/SubscriptionTest.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/model/SubscriptionTest.kt index bc8205c27..1cef02955 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/model/SubscriptionTest.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/model/SubscriptionTest.kt @@ -3,7 +3,6 @@ package com.egm.stellio.subscription.model import com.egm.stellio.shared.model.EntitySelector import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_CONTEXT -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_TERM import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OPERATION_SPACE_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OPERATION_SPACE_TERM @@ -27,7 +26,7 @@ class SubscriptionTest { EntitySelector( id = null, idPattern = null, - typeSelection = BEEHIVE_COMPACT_TYPE + typeSelection = BEEHIVE_TYPE ) ), geoQ = GeoQ( @@ -35,11 +34,11 @@ class SubscriptionTest { geometry = "Polygon", coordinates = "[[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]]", pgisGeometry = "100000101000101010100010100054300", - geoproperty = "operationSpace" + geoproperty = NGSILD_OPERATION_SPACE_PROPERTY ), - watchedAttributes = listOf(INCOMING_COMPACT_PROPERTY, OUTGOING_COMPACT_PROPERTY), + watchedAttributes = listOf(INCOMING_PROPERTY, OUTGOING_PROPERTY), notification = NotificationParams( - attributes = listOf(INCOMING_COMPACT_PROPERTY), + attributes = listOf(INCOMING_PROPERTY), format = NotificationParams.FormatType.KEY_VALUES, endpoint = Endpoint( uri = "http://localhost:8089/notification".toUri(), @@ -105,7 +104,7 @@ class SubscriptionTest { fun `it should serialize a subscription as JSON and add the status attribute`() { val subscription = subscription.copy().expand(listOf(APIC_COMPOUND_CONTEXT)) - val serializedSub = subscription.serialize(NGSILD_CORE_CONTEXT, includeSysAttrs = false) + val serializedSub = subscription.serialize(NGSILD_TEST_CORE_CONTEXT, includeSysAttrs = false) val deserializedSub = deserializeObject(serializedSub) @@ -117,7 +116,7 @@ class SubscriptionTest { fun `it should serialize a subscription as JSON without createdAt and modifiedAt if not specified`() { val subscription = subscription.copy().expand(listOf(APIC_COMPOUND_CONTEXT)) - val serializedSub = subscription.serialize(NGSILD_CORE_CONTEXT, includeSysAttrs = false) + val serializedSub = subscription.serialize(NGSILD_TEST_CORE_CONTEXT, includeSysAttrs = false) val deserializedSub = deserializeObject(serializedSub) @@ -129,7 +128,7 @@ class SubscriptionTest { fun `it should serialize a subscription as JSON with createdAt and modifiedAt if specified`() { val subscription = subscription.copy().expand(listOf(APIC_COMPOUND_CONTEXT)) - val serializedSub = subscription.serialize(NGSILD_CORE_CONTEXT, includeSysAttrs = true) + val serializedSub = subscription.serialize(NGSILD_TEST_CORE_CONTEXT, includeSysAttrs = true) val deserializedSub = deserializeObject(serializedSub) @@ -140,7 +139,7 @@ class SubscriptionTest { fun `it should serialize a subscription with a context if JSON-LD media type is asked`() { val subscription = subscription.copy().expand(listOf(APIC_COMPOUND_CONTEXT)) - val serializedSub = subscription.serialize(NGSILD_CORE_CONTEXT, mediaType = JSON_LD_MEDIA_TYPE) + val serializedSub = subscription.serialize(NGSILD_TEST_CORE_CONTEXT, mediaType = JSON_LD_MEDIA_TYPE) val deserializedSub = deserializeObject(serializedSub) @@ -151,7 +150,7 @@ class SubscriptionTest { fun `it should serialize a subscription without context if JSON media type is asked`() { val subscription = subscription.copy().expand(listOf(APIC_COMPOUND_CONTEXT)) - val serializedSub = subscription.serialize(NGSILD_CORE_CONTEXT, mediaType = MediaType.APPLICATION_JSON) + val serializedSub = subscription.serialize(NGSILD_TEST_CORE_CONTEXT, mediaType = MediaType.APPLICATION_JSON) val deserializedSub = deserializeObject(serializedSub) @@ -164,7 +163,7 @@ class SubscriptionTest { val otherSubscription = subscription.copy(id = "urn:ngsi-ld:Subscription:02".toUri()) val serializedSubs = - listOf(subscription, otherSubscription).serialize(NGSILD_CORE_CONTEXT, includeSysAttrs = true) + listOf(subscription, otherSubscription).serialize(NGSILD_TEST_CORE_CONTEXT, includeSysAttrs = true) val deserializedSubs = deserializeListOfObjects(serializedSubs) @@ -182,7 +181,7 @@ class SubscriptionTest { val otherSubscription = subscription.copy(id = "urn:ngsi-ld:Subscription:02".toUri()) val serializedSubs = listOf(subscription, otherSubscription) - .serialize(NGSILD_CORE_CONTEXT, mediaType = MediaType.APPLICATION_JSON) + .serialize(NGSILD_TEST_CORE_CONTEXT, mediaType = MediaType.APPLICATION_JSON) val deserializedSubs = deserializeListOfObjects(serializedSubs) diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt index 8851824b3..79e3b2c04 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt @@ -3,7 +3,6 @@ package com.egm.stellio.subscription.service import arrow.core.right import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_COMPACTED_ENTITY_CORE_MEMBERS -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_TERM import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_PROPERTY @@ -164,7 +163,7 @@ class NotificationServiceTests { accept = Endpoint.AcceptType.JSONLD ) ), - contexts = listOf(NGSILD_CORE_CONTEXT) + contexts = listOf(NGSILD_TEST_CORE_CONTEXT) ) val jsonLdEntity = expandJsonLdEntity(rawEntity) @@ -189,7 +188,10 @@ class NotificationServiceTests { assertEquals(1, notificationResult.second.data.size) assertTrue(notificationResult.second.data[0].containsKey(NGSILD_NAME_PROPERTY)) assertTrue(notificationResult.second.data[0].containsKey(MANAGED_BY_RELATIONSHIP)) - assertEquals(listOf(NGSILD_CORE_CONTEXT), notificationResult.second.data[0][JsonLdUtils.JSONLD_CONTEXT]) + assertEquals( + listOf(NGSILD_TEST_CORE_CONTEXT), + notificationResult.second.data[0][JsonLdUtils.JSONLD_CONTEXT] + ) assertTrue(notificationResult.third) } } @@ -333,7 +335,7 @@ class NotificationServiceTests { ) ) - coEvery { subscriptionService.getContextsLink(any()) } returns buildContextLinkHeader(NGSILD_CORE_CONTEXT) + coEvery { subscriptionService.getContextsLink(any()) } returns buildContextLinkHeader(NGSILD_TEST_CORE_CONTEXT) coEvery { subscriptionService.updateSubscriptionNotification(any(), any(), any()) } returns 1 stubFor( @@ -363,7 +365,7 @@ class NotificationServiceTests { ) ) - coEvery { subscriptionService.getContextsLink(any()) } returns buildContextLinkHeader(NGSILD_CORE_CONTEXT) + coEvery { subscriptionService.getContextsLink(any()) } returns buildContextLinkHeader(NGSILD_TEST_CORE_CONTEXT) coEvery { subscriptionService.updateSubscriptionNotification(any(), any(), any()) } returns 1 stubFor( diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt index 04190a2ce..476abfa1a 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt @@ -3,13 +3,12 @@ package com.egm.stellio.subscription.service import arrow.core.Some import com.egm.stellio.shared.model.BadRequestDataException import com.egm.stellio.shared.model.EntitySelector -import com.egm.stellio.shared.model.JsonLdEntity import com.egm.stellio.shared.model.NotImplementedException import com.egm.stellio.shared.util.* -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_TERM import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SUBSCRIPTION_TERM +import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity import com.egm.stellio.subscription.model.Endpoint import com.egm.stellio.subscription.model.EndpointInfo import com.egm.stellio.subscription.model.Notification @@ -28,7 +27,6 @@ import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.CsvSource @@ -59,15 +57,6 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { private val entity = ClassPathResource("/ngsild/aquac/FeedingService.json").inputStream.readBytes().toString(Charsets.UTF_8) - private lateinit var jsonldEntity: JsonLdEntity - - @BeforeAll - fun loadTestEntity() { - runBlocking { - jsonldEntity = JsonLdUtils.expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) - } - } - @AfterEach fun deleteSubscriptions() { r2dbcEntityTemplate.delete(Subscription::class.java) @@ -940,6 +929,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should not return a subscription if q query is invalid`() = runTest { + val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -954,6 +944,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a subscription if entity matches q query`() = runTest { + val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -968,6 +959,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should not return a subscription if entity doesn't match q query`() = runTest { + val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -982,6 +974,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a subscription if entity matches a complex q query`() = runTest { + val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -996,6 +989,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a subscription if entity matches a complex q query with AND logical operator`() = runTest { + val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1010,6 +1004,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a subscription if entity matches a complex q query with OR logical operator`() = runTest { + val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1024,6 +1019,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a subscription if entity matched a q query with a boolean value`() = runTest { + val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1038,6 +1034,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a subscription if entity matches a scope query`() = runTest { + val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1052,6 +1049,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should not return a subscription if entity does not match a scope query`() = runTest { + val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1083,6 +1081,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { coordinates: String, expectedSize: Int ) = runTest { + val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(INCOMING_COMPACT_PROPERTY), @@ -1183,7 +1182,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a link to contexts endpoint if subscription has more than one context`() = runTest { val subscription = loadAndDeserializeSubscription("subscription_minimal_entities.json").copy( - contexts = listOf(APIC_COMPOUND_CONTEXT, NGSILD_CORE_CONTEXT) + contexts = listOf(APIC_COMPOUND_CONTEXT, NGSILD_TEST_CORE_CONTEXT) ) val contextLink = subscriptionService.getContextsLink(subscription) diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/support/FixtureUtils.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/support/FixtureUtils.kt index a7041dec6..cb66c37b3 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/support/FixtureUtils.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/support/FixtureUtils.kt @@ -1,12 +1,8 @@ package com.egm.stellio.subscription.support -import com.egm.stellio.shared.util.APIC_COMPOUND_CONTEXT -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT +import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SUBSCRIPTION_TERM import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap -import com.egm.stellio.shared.util.loadSampleData -import com.egm.stellio.shared.util.shouldSucceedAndResult -import com.egm.stellio.shared.util.toUri import com.egm.stellio.subscription.model.* import com.egm.stellio.subscription.model.NotificationParams.FormatType import com.egm.stellio.subscription.utils.ParsingUtils @@ -41,7 +37,7 @@ fun gimmeRawSubscription( geometry: String = "Polygon", coordinates: String = "[[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]]", timeInterval: Int? = null, - contexts: List = listOf(NGSILD_CORE_CONTEXT) + contexts: List = listOf(NGSILD_TEST_CORE_CONTEXT) ): Subscription { val q = if (withQueryAndGeoQuery.first) diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/utils/ParsingUtilsTests.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/utils/ParsingUtilsTests.kt index 1ce8e3765..76c6797d2 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/utils/ParsingUtilsTests.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/utils/ParsingUtilsTests.kt @@ -63,8 +63,9 @@ class ParsingUtilsTests { result.fold({ assertTrue(it is LdContextNotAvailableException) assertEquals( - "Unable to load remote context (cause was: com.github.jsonldjava.core.JsonLdError: " + - "loading remote context failed: $contextNonExisting)", + "Unable to load remote context (cause was: JsonLdError[code=There was a problem encountered " + + "loading a remote context [code=LOADING_REMOTE_CONTEXT_FAILED]., message=There was a problem " + + "encountered loading a remote context [code=LOADING_REMOTE_CONTEXT_FAILED].])", it.message ) }, { diff --git a/subscription-service/src/test/resources/junit-platform.properties b/subscription-service/src/test/resources/junit-platform.properties index 2af5bf864..9911aeba0 100644 --- a/subscription-service/src/test/resources/junit-platform.properties +++ b/subscription-service/src/test/resources/junit-platform.properties @@ -1 +1,2 @@ junit.jupiter.testinstance.lifecycle.default=per_class +junit.jupiter.extensions.autodetection.enabled=true diff --git a/subscription-service/src/test/resources/ngsild/aquac/FeedingService.json b/subscription-service/src/test/resources/ngsild/aquac/FeedingService.json index 3d70cfcef..6df6e4fec 100644 --- a/subscription-service/src/test/resources/ngsild/aquac/FeedingService.json +++ b/subscription-service/src/test/resources/ngsild/aquac/FeedingService.json @@ -27,10 +27,5 @@ "type": "Point", "coordinates": [100.0, 0.0] } - }, - "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/shared-jsonld-contexts/egm.jsonld", - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/aquac/jsonld-contexts/aquac.jsonld", - "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld" - ] + } } diff --git a/subscription-service/src/test/resources/ngsild/beehive.jsonld b/subscription-service/src/test/resources/ngsild/beehive.jsonld index 0a5a130bf..7183dc884 100644 --- a/subscription-service/src/test/resources/ngsild/beehive.jsonld +++ b/subscription-service/src/test/resources/ngsild/beehive.jsonld @@ -29,6 +29,6 @@ "object": "urn:ngsi-ld:Beekeeper:Pascal" }, "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/subscription-service/src/test/resources/ngsild/beehive2.jsonld b/subscription-service/src/test/resources/ngsild/beehive2.jsonld index f05db6ae8..c9185515c 100644 --- a/subscription-service/src/test/resources/ngsild/beehive2.jsonld +++ b/subscription-service/src/test/resources/ngsild/beehive2.jsonld @@ -29,6 +29,6 @@ "object": "urn:ngsi-ld:Beekeeper:Pascal" }, "@context": [ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/subscription-service/src/test/resources/ngsild/subscription.jsonld b/subscription-service/src/test/resources/ngsild/subscription.jsonld index 52443edbf..a54ea9f7f 100644 --- a/subscription-service/src/test/resources/ngsild/subscription.jsonld +++ b/subscription-service/src/test/resources/ngsild/subscription.jsonld @@ -23,6 +23,6 @@ } }, "@context":[ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/subscription-service/src/test/resources/ngsild/subscription_update.jsonld b/subscription-service/src/test/resources/ngsild/subscription_update.jsonld index 823bd08ec..49ef31d2c 100644 --- a/subscription-service/src/test/resources/ngsild/subscription_update.jsonld +++ b/subscription-service/src/test/resources/ngsild/subscription_update.jsonld @@ -15,6 +15,6 @@ } }, "@context":[ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/subscription-service/src/test/resources/ngsild/subscription_with_conflicting_timeInterval_watchedAttributes.json b/subscription-service/src/test/resources/ngsild/subscription_with_conflicting_timeInterval_watchedAttributes.json index f7f587aeb..dcd0106e0 100644 --- a/subscription-service/src/test/resources/ngsild/subscription_with_conflicting_timeInterval_watchedAttributes.json +++ b/subscription-service/src/test/resources/ngsild/subscription_with_conflicting_timeInterval_watchedAttributes.json @@ -9,6 +9,6 @@ } }, "@context":[ - "https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master/apic/jsonld-contexts/apic-compound.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } From 2876eede77d9a889e59e720ed3bcf52290673e7a Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Mon, 18 Dec 2023 12:06:51 +0100 Subject: [PATCH 02/19] refactor: improve expanded values builders - add a Value suffix to make clear they are just doing this - clean the documentation - add a specific extension functions to add non-reified properties (temporal and non-temporal ones) --- .../authorization/EntityAccessRights.kt | 13 ++--- .../egm/stellio/search/authorization/Group.kt | 6 +- .../egm/stellio/search/authorization/User.kt | 8 +-- .../stellio/search/model/AttributeInstance.kt | 8 +-- .../egm/stellio/search/model/EntityPayload.kt | 10 ++-- .../service/TemporalEntityAttributeService.kt | 4 +- .../service/AttributeInstanceServiceTests.kt | 7 +-- .../search/support/BusinessObjectsFactory.kt | 7 +-- .../web/EntityAccessControlHandlerTests.kt | 8 +-- .../egm/stellio/shared/model/JsonLdEntity.kt | 2 +- .../egm/stellio/shared/util/JsonLdUtils.kt | 56 +++++++++++++------ 11 files changed, 73 insertions(+), 56 deletions(-) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt index ba53d4dd3..d2be587cf 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt @@ -11,10 +11,9 @@ import com.egm.stellio.shared.util.JsonLdUtils.DATASET_ID_PREFIX import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedProperty import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyMapValue -import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedRelationship -import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedProperty +import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue +import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedRelationshipValue import java.net.URI data class EntityAccessRights( @@ -34,8 +33,8 @@ data class EntityAccessRights( val datasetId: URI = (DATASET_ID_PREFIX + uri.extractSub()).toUri() suspend fun serializeProperties(contextLink: String): ExpandedAttributeInstances = - buildExpandedRelationship(uri) - .addSubAttribute(NGSILD_DATASET_ID_PROPERTY, buildNonReifiedProperty(datasetId.toString())) + buildExpandedRelationshipValue(uri) + .addNonReifiedProperty(NGSILD_DATASET_ID_PROPERTY, datasetId.toString()) .addSubAttribute( AUTH_PROP_SUBJECT_INFO, buildExpandedPropertyMapValue(subjectInfo, listOf(contextLink)) @@ -47,10 +46,10 @@ data class EntityAccessRights( resultEntity[JSONLD_ID] = id.toString() resultEntity[JSONLD_TYPE] = types - resultEntity[AUTH_PROP_RIGHT] = buildExpandedProperty(right.attributeName) + resultEntity[AUTH_PROP_RIGHT] = buildExpandedPropertyValue(right.attributeName) specificAccessPolicy?.run { - resultEntity[AUTH_PROP_SAP] = buildExpandedProperty(this) + resultEntity[AUTH_PROP_SAP] = buildExpandedPropertyValue(this) } rCanAdminUsers?.run { diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/Group.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/Group.kt index 025b04988..438a65f5c 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/Group.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/Group.kt @@ -5,7 +5,7 @@ import com.egm.stellio.shared.util.AuthContextModel.GROUP_ENTITY_PREFIX import com.egm.stellio.shared.util.AuthContextModel.GROUP_TYPE import com.egm.stellio.shared.util.JsonLdUtils import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedProperty +import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue data class Group( val id: String, @@ -18,10 +18,10 @@ data class Group( resultEntity[JsonLdUtils.JSONLD_ID] = GROUP_ENTITY_PREFIX + id resultEntity[JsonLdUtils.JSONLD_TYPE] = listOf(type) - resultEntity[NGSILD_NAME_PROPERTY] = buildExpandedProperty(name) + resultEntity[NGSILD_NAME_PROPERTY] = buildExpandedPropertyValue(name) isMember.run { - resultEntity[AUTH_REL_IS_MEMBER_OF] = buildExpandedProperty(isMember.toString()) + resultEntity[AUTH_REL_IS_MEMBER_OF] = buildExpandedPropertyValue(isMember.toString()) } return resultEntity } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/User.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/User.kt index 756ccb9cf..c000d1ac5 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/User.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/User.kt @@ -12,8 +12,8 @@ import com.egm.stellio.shared.util.AuthContextModel.USER_ENTITY_PREFIX import com.egm.stellio.shared.util.AuthContextModel.USER_TYPE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE -import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedProperty import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyMapValue +import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue data class User( val id: String, @@ -28,14 +28,14 @@ data class User( resultEntity[JSONLD_ID] = USER_ENTITY_PREFIX + id resultEntity[JSONLD_TYPE] = listOf(type) - resultEntity[AUTH_PROP_USERNAME] = buildExpandedProperty(username) + resultEntity[AUTH_PROP_USERNAME] = buildExpandedPropertyValue(username) givenName?.run { - resultEntity[AUTH_PROP_GIVEN_NAME] = buildExpandedProperty(givenName) + resultEntity[AUTH_PROP_GIVEN_NAME] = buildExpandedPropertyValue(givenName) } familyName?.run { - resultEntity[AUTH_PROP_FAMILY_NAME] = buildExpandedProperty(familyName) + resultEntity[AUTH_PROP_FAMILY_NAME] = buildExpandedPropertyValue(familyName) } subjectInfo.filterKeys { diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/model/AttributeInstance.kt b/search-service/src/main/kotlin/com/egm/stellio/search/model/AttributeInstance.kt index 01a43440f..6ddd9e5d2 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/model/AttributeInstance.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/model/AttributeInstance.kt @@ -4,8 +4,8 @@ import com.egm.stellio.shared.model.WKTCoordinates import com.egm.stellio.shared.util.ExpandedAttributeInstance import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_INSTANCE_ID_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedDateTime -import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedProperty +import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedPropertyValue +import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue import com.egm.stellio.shared.util.JsonUtils.serializeObject import com.egm.stellio.shared.util.toUri import io.r2dbc.postgresql.codec.Json @@ -72,10 +72,10 @@ data class AttributeInstance private constructor( instanceId: URI, modifiedAt: ZonedDateTime? = null ): ExpandedAttributeInstance = - this.plus(NGSILD_INSTANCE_ID_PROPERTY to buildNonReifiedProperty(instanceId.toString())) + this.plus(NGSILD_INSTANCE_ID_PROPERTY to buildNonReifiedPropertyValue(instanceId.toString())) .let { if (modifiedAt != null) - it.plus(NGSILD_MODIFIED_AT_PROPERTY to buildNonReifiedDateTime(modifiedAt)) + it.plus(NGSILD_MODIFIED_AT_PROPERTY to buildNonReifiedTemporalValue(modifiedAt)) else it } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/model/EntityPayload.kt b/search-service/src/main/kotlin/com/egm/stellio/search/model/EntityPayload.kt index b36ffc818..90b95ebe7 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/model/EntityPayload.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/model/EntityPayload.kt @@ -15,8 +15,8 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_TERM import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_TERM -import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedProperty -import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedDateTime +import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue +import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue import com.egm.stellio.shared.util.JsonLdUtils.compactTerm import io.r2dbc.postgresql.codec.Json import java.net.URI @@ -71,12 +71,12 @@ data class EntityPayload( } } specificAccessPolicy?.run { - resultEntity[AuthContextModel.AUTH_PROP_SAP] = buildExpandedProperty(this) + resultEntity[AuthContextModel.AUTH_PROP_SAP] = buildExpandedPropertyValue(this) } - resultEntity[NGSILD_CREATED_AT_PROPERTY] = buildNonReifiedDateTime(createdAt) + resultEntity[NGSILD_CREATED_AT_PROPERTY] = buildNonReifiedTemporalValue(createdAt) modifiedAt?.run { - resultEntity[NGSILD_MODIFIED_AT_PROPERTY] = buildNonReifiedDateTime(this) + resultEntity[NGSILD_MODIFIED_AT_PROPERTY] = buildNonReifiedTemporalValue(this) } } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt index 2e1089641..69e7946ec 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt @@ -17,7 +17,7 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PREFIX import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_HAS_OBJECT -import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedDateTime +import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity import com.egm.stellio.shared.util.JsonLdUtils.getAttributeFromExpandedAttributes import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMap @@ -926,7 +926,7 @@ class TemporalEntityAttributeService( !attributePayload.containsKey(NGSILD_OBSERVED_AT_PROPERTY) ) { Pair( - attributePayload.plus(NGSILD_OBSERVED_AT_PROPERTY to buildNonReifiedDateTime(observedAt)), + attributePayload.plus(NGSILD_OBSERVED_AT_PROPERTY to buildNonReifiedTemporalValue(observedAt)), attributeMetadata.copy(observedAt = observedAt) ) } else Pair(attributePayload, attributeMetadata) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt index 733d27c3a..d3f451c5d 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt @@ -11,8 +11,7 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_INSTANCE_ID_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE -import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedProperty -import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedDateTime +import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue import com.egm.stellio.shared.util.JsonUtils.deserializeAsList import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import io.mockk.spyk @@ -249,8 +248,8 @@ class AttributeInstanceServiceTests : WithTimescaleContainer, WithKafkaContainer temporalEntityAttribute = temporalEntityAttribute2.id, time = observedAt, attributeMetadata = attributeMetadata, - payload = buildExpandedProperty(attributeMetadata.value!!) - .addSubAttribute(NGSILD_OBSERVED_AT_PROPERTY, buildNonReifiedDateTime(observedAt)) + payload = buildExpandedPropertyValue(attributeMetadata.value!!) + .addNonReifiedTemporalProperty(NGSILD_OBSERVED_AT_PROPERTY, observedAt) .getSingleEntry() ) attributeInstanceService.create(attributeInstance) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt b/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt index a0b52fbcd..ca4096e49 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt @@ -19,11 +19,8 @@ fun gimmeAttributeInstance( type = TemporalEntityAttribute.AttributeType.Property, observedAt = ngsiLdDateTime() ) - val payload = JsonLdUtils.buildExpandedProperty(attributeMetadata.measuredValue!!) - .addSubAttribute( - JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY, - JsonLdUtils.buildNonReifiedDateTime(attributeMetadata.observedAt!!) - ) + val payload = JsonLdUtils.buildExpandedPropertyValue(attributeMetadata.measuredValue!!) + .addNonReifiedTemporalProperty(JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY, attributeMetadata.observedAt!!) .getSingleEntry() return AttributeInstance( diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt index 6cc5655cb..515384ccf 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt @@ -29,7 +29,7 @@ import com.egm.stellio.shared.util.AuthContextModel.USER_COMPACT_TYPE import com.egm.stellio.shared.util.AuthContextModel.USER_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedProperty +import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue import com.ninjasquad.springmockk.MockkBean import io.mockk.Called import io.mockk.coEvery @@ -694,7 +694,7 @@ class EntityAccessControlHandlerTests { mapOf( "@id" to "urn:ngsi-ld:group:1", "@type" to listOf(GROUP_TYPE), - NGSILD_NAME_PROPERTY to buildExpandedProperty("egm") + NGSILD_NAME_PROPERTY to buildExpandedPropertyValue("egm") ), listOf(NGSILD_TEST_CORE_CONTEXT) ) @@ -734,8 +734,8 @@ class EntityAccessControlHandlerTests { mapOf( "@id" to "urn:ngsi-ld:group:01", "@type" to listOf(GROUP_TYPE), - NGSILD_NAME_PROPERTY to buildExpandedProperty("egm"), - AuthContextModel.AUTH_REL_IS_MEMBER_OF to buildExpandedProperty("true") + NGSILD_NAME_PROPERTY to buildExpandedPropertyValue("egm"), + AuthContextModel.AUTH_REL_IS_MEMBER_OF to buildExpandedPropertyValue("true") ), listOf(AUTHZ_TEST_CONTEXT) ) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/JsonLdEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/JsonLdEntity.kt index 99a8352f5..61c8ce219 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/JsonLdEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/JsonLdEntity.kt @@ -86,7 +86,7 @@ data class JsonLdEntity( private fun Map.addDateTimeProperty(propertyKey: String, dateTime: ZonedDateTime?): Map = if (dateTime != null) - this.plus(propertyKey to JsonLdUtils.buildNonReifiedDateTime(dateTime)) + this.plus(propertyKey to JsonLdUtils.buildNonReifiedTemporalValue(dateTime)) else this } diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt index 1cc69dd77..517746ce3 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt @@ -15,7 +15,8 @@ import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE_TERM import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_GEO_PROPERTIES_TERMS import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedDateTime +import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedPropertyValue +import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMapAsDateTime import com.egm.stellio.shared.util.JsonUtils.deserializeAs import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap @@ -560,9 +561,9 @@ object JsonLdUtils { /** * Build the expanded payload of a property. * - * For instance: + * The returned value is the following: * - * "https://uri.etsi.org/ngsi-ld/default-context/aProperty": [ + * [ * { * "@type": [ * "https://uri.etsi.org/ngsi-ld/Property" @@ -575,7 +576,7 @@ object JsonLdUtils { * } * ] */ - fun buildExpandedProperty(value: Any): ExpandedAttributeInstances = + fun buildExpandedPropertyValue(value: Any): ExpandedAttributeInstances = listOf( mapOf( JSONLD_TYPE to listOf(NGSILD_PROPERTY_TYPE.uri), @@ -584,11 +585,11 @@ object JsonLdUtils { ) /** - * Build an expanded JSON value for a property. + * Build the expanded payload of a property whose value is an object. * - * For instance: + * The returned value is the following: * - * "[ + * [ * { * "@type": [ * "https://uri.etsi.org/ngsi-ld/Property" @@ -626,7 +627,9 @@ object JsonLdUtils { /** * Build the expanded payload of a relationship. * - * "https://uri.etsi.org/ngsi-ld/default-context/aRelationship": [ + * The returned value is the following: + * + * [ * { * "https://uri.etsi.org/ngsi-ld/hasObject": [ * { @@ -639,7 +642,7 @@ object JsonLdUtils { * } * ] */ - fun buildExpandedRelationship(value: URI): ExpandedAttributeInstances = + fun buildExpandedRelationshipValue(value: URI): ExpandedAttributeInstances = listOf( mapOf( JSONLD_TYPE to listOf(NGSILD_RELATIONSHIP_TYPE.uri), @@ -650,16 +653,16 @@ object JsonLdUtils { /** * Build the expanded payload of a non-reified temporal property (createdAt, modifiedAt,...). * - * For instance: + * The returned value is the following: * - * "https://uri.etsi.org/ngsi-ld/createdAt": [ + * [ * { * "@type": "https://uri.etsi.org/ngsi-ld/DateTime", * "@value": "2022-12-01T00:00:00Z" * } * ] */ - fun buildNonReifiedDateTime(value: ZonedDateTime): List> = + fun buildNonReifiedTemporalValue(value: ZonedDateTime): ExpandedNonReifiedPropertyValue = listOf( mapOf( JSONLD_TYPE to NGSILD_DATE_TIME_TYPE, @@ -670,15 +673,15 @@ object JsonLdUtils { /** * Build the expanded payload of a non-reified core property. * - * For instance: + * The returned value is the following: * - * "https://uri.etsi.org/ngsi-ld/datasetId": [ + * [ * { * "@id": "urn:ngsi-ld:Dataset:01" * } * ] */ - fun buildNonReifiedProperty(value: String): List> = + fun buildNonReifiedPropertyValue(value: String): ExpandedNonReifiedPropertyValue = listOf( mapOf(JSONLD_ID to value) ) @@ -690,6 +693,7 @@ typealias ExpandedAttributes = Map typealias ExpandedAttribute = Pair typealias ExpandedAttributeInstances = List typealias ExpandedAttributeInstance = Map> +typealias ExpandedNonReifiedPropertyValue = List> fun ExpandedAttribute.toExpandedAttributes() = mapOf(this.first to this.second) @@ -703,6 +707,24 @@ fun ExpandedAttributeInstances.addSubAttribute( return listOf(this[0].plus(subAttributeName to subAttributePayload)) } +fun ExpandedAttributeInstances.addNonReifiedProperty( + subAttributeName: ExpandedTerm, + subAttributeValue: String +): ExpandedAttributeInstances { + if (this.isEmpty() || this.size > 1) + throw BadRequestDataException("Cannot add a sub-attribute into empty or multi-instance attribute: $this") + return listOf(this[0].plus(subAttributeName to buildNonReifiedPropertyValue(subAttributeValue))) +} + +fun ExpandedAttributeInstances.addNonReifiedTemporalProperty( + subAttributeName: ExpandedTerm, + subAttributeValue: ZonedDateTime +): ExpandedAttributeInstances { + if (this.isEmpty() || this.size > 1) + throw BadRequestDataException("Cannot add a sub-attribute into empty or multi-instance attribute: $this") + return listOf(this[0].plus(subAttributeName to buildNonReifiedTemporalValue(subAttributeValue))) +} + fun ExpandedAttributeInstances.getSingleEntry(): ExpandedAttributeInstance { if (this.isEmpty() || this.size > 1) throw BadRequestDataException("Expected a single entry but got none or more than one: $this") @@ -737,10 +759,10 @@ fun Map.addSysAttrs( modifiedAt: ZonedDateTime? ): Map = if (withSysAttrs) - this.plus(JsonLdUtils.NGSILD_CREATED_AT_PROPERTY to buildNonReifiedDateTime(createdAt)) + this.plus(JsonLdUtils.NGSILD_CREATED_AT_PROPERTY to buildNonReifiedTemporalValue(createdAt)) .let { if (modifiedAt != null) - it.plus(JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY to buildNonReifiedDateTime(modifiedAt)) + it.plus(JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY to buildNonReifiedTemporalValue(modifiedAt)) else it } else this From b9de2a1f6f8b580300caf95acaa5dfdaa7e31e35 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Wed, 20 Dec 2023 16:39:41 +0100 Subject: [PATCH 03/19] refactor: expanded / compacted entity wrappers - rename JsonLdEntity to ExpandedEntity - extract compacted entity processings in a new CompactedEntity file --- .../authorization/AuthorizationService.kt | 8 +- .../DisabledAuthorizationService.kt | 8 +- .../EnabledAuthorizationService.kt | 14 +- .../search/service/EntityPayloadService.kt | 22 +-- .../stellio/search/service/QueryService.kt | 18 +- .../service/TemporalEntityAttributeService.kt | 4 +- .../search/util/TemporalEntityBuilder.kt | 8 +- .../stellio/search/web/BatchAPIResponses.kt | 4 +- .../egm/stellio/search/web/EntityHandler.kt | 4 +- .../search/web/TemporalEntityHandler.kt | 6 +- .../db/migration/V0_29__JsonLd_migration.kt | 2 +- .../EntityAccessRightsServiceTests.kt | 2 +- .../listener/ObservationEventListenerTests.kt | 6 +- .../service/EntityOperationServiceTests.kt | 54 +++--- .../web/EntityAccessControlHandlerTests.kt | 24 +-- .../stellio/search/web/EntityHandlerTests.kt | 46 ++--- .../search/web/EntityOperationHandlerTests.kt | 68 +++---- .../search/web/TemporalEntityHandlerTests.kt | 16 +- shared/config/detekt/baseline.xml | 2 +- .../stellio/shared/model/CompactedEntity.kt | 102 ++++++++++ .../stellio/shared/model/ExpandedEntity.kt | 86 +++++++++ .../egm/stellio/shared/model/JsonLdEntity.kt | 180 ------------------ .../egm/stellio/shared/model/NgsiLdEntity.kt | 2 +- .../com/egm/stellio/shared/util/ApiUtils.kt | 2 +- .../egm/stellio/shared/util/GeoQueryUtils.kt | 2 +- .../egm/stellio/shared/util/JsonLdUtils.kt | 51 ++--- .../com/egm/stellio/shared/util/QueryUtils.kt | 6 +- ...dEntityTests.kt => ExpandedEntityTests.kt} | 10 +- .../stellio/shared/util/JsonLdUtilsTests.kt | 4 +- .../stellio/shared/util/NgsiLdTestUtils.kt | 8 +- .../com/egm/stellio/shared/util/TestUtils.kt | 4 +- .../job/TimeIntervalNotificationJob.kt | 8 +- .../listener/EntityEventListenerService.kt | 4 +- .../service/NotificationService.kt | 16 +- .../service/SubscriptionService.kt | 30 +-- 35 files changed, 421 insertions(+), 410 deletions(-) create mode 100644 shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt create mode 100644 shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedEntity.kt delete mode 100644 shared/src/main/kotlin/com/egm/stellio/shared/model/JsonLdEntity.kt rename shared/src/test/kotlin/com/egm/stellio/shared/model/{JsonLdEntityTests.kt => ExpandedEntityTests.kt} (98%) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/AuthorizationService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/AuthorizationService.kt index 98293e638..96d982d69 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/AuthorizationService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/AuthorizationService.kt @@ -4,7 +4,7 @@ import arrow.core.Either import arrow.core.Option import com.egm.stellio.search.model.EntitiesQuery import com.egm.stellio.shared.model.APIException -import com.egm.stellio.shared.model.JsonLdEntity +import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.util.Sub import java.net.URI @@ -25,18 +25,18 @@ interface AuthorizationService { entitiesQuery: EntitiesQuery, contextLink: String, sub: Option - ): Either>> + ): Either>> suspend fun getGroupsMemberships( offset: Int, limit: Int, contextLink: String, sub: Option - ): Either>> + ): Either>> suspend fun getUsers( offset: Int, limit: Int, contextLink: String, - ): Either>> + ): Either>> } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/DisabledAuthorizationService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/DisabledAuthorizationService.kt index 1fc06275f..bfbaf3d84 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/DisabledAuthorizationService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/DisabledAuthorizationService.kt @@ -5,7 +5,7 @@ import arrow.core.Option import arrow.core.right import com.egm.stellio.search.model.EntitiesQuery import com.egm.stellio.shared.model.APIException -import com.egm.stellio.shared.model.JsonLdEntity +import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.util.Sub import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.stereotype.Component @@ -43,18 +43,18 @@ class DisabledAuthorizationService : AuthorizationService { entitiesQuery: EntitiesQuery, contextLink: String, sub: Option - ): Either>> = Pair(-1, emptyList()).right() + ): Either>> = Pair(-1, emptyList()).right() override suspend fun getGroupsMemberships( offset: Int, limit: Int, contextLink: String, sub: Option - ): Either>> = Pair(-1, emptyList()).right() + ): Either>> = Pair(-1, emptyList()).right() override suspend fun getUsers( offset: Int, limit: Int, contextLink: String, - ): Either>> = Pair(-1, emptyList()).right() + ): Either>> = Pair(-1, emptyList()).right() } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationService.kt index 12e5bf971..b89f24101 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationService.kt @@ -6,7 +6,7 @@ import arrow.fx.coroutines.parMap import com.egm.stellio.search.model.EntitiesQuery import com.egm.stellio.shared.model.APIException import com.egm.stellio.shared.model.AccessDeniedException -import com.egm.stellio.shared.model.JsonLdEntity +import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.AuthContextModel.SpecificAccessPolicy import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty @@ -97,7 +97,7 @@ class EnabledAuthorizationService( entitiesQuery: EntitiesQuery, contextLink: String, sub: Option - ): Either>> = either { + ): Either>> = either { val accessRights = entitiesQuery.attrs.mapNotNull { AccessRight.forExpandedAttributeName(it).getOrNull() } val entitiesAccessControl = entityAccessRightsService.getSubjectAccessRights( sub, @@ -128,7 +128,7 @@ class EnabledAuthorizationService( } else entityAccessControl } .map { it.serializeProperties(contextLink) } - .map { JsonLdEntity(it, listOf(contextLink)) } + .map { ExpandedEntity(it, listOf(contextLink)) } val count = entityAccessRightsService.getSubjectAccessRightsCount( sub, @@ -145,7 +145,7 @@ class EnabledAuthorizationService( limit: Int, contextLink: String, sub: Option - ): Either>> = either { + ): Either>> = either { val groups = when (userIsAdmin(sub)) { is Either.Left -> { @@ -162,7 +162,7 @@ class EnabledAuthorizationService( } val jsonLdEntities = groups.second.map { - JsonLdEntity( + ExpandedEntity( it.serializeProperties(), listOf(contextLink) ) @@ -175,12 +175,12 @@ class EnabledAuthorizationService( offset: Int, limit: Int, contextLink: String - ): Either>> = either { + ): Either>> = either { val users = subjectReferentialService.getUsers(offset, limit) val usersCount = subjectReferentialService.getUsersCount().bind() val jsonLdEntities = users.map { - JsonLdEntity( + ExpandedEntity( it.serializeProperties(contextLink), listOf(contextLink) ) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityPayloadService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityPayloadService.kt index 2f5f33552..6c1aedab4 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityPayloadService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityPayloadService.kt @@ -49,17 +49,17 @@ class EntityPayloadService( @Transactional suspend fun createEntity( ngsiLdEntity: NgsiLdEntity, - jsonLdEntity: JsonLdEntity, + expandedEntity: ExpandedEntity, sub: String? = null ): Either = either { val createdAt = ZonedDateTime.now(ZoneOffset.UTC) val attributesMetadata = ngsiLdEntity.prepareTemporalAttributes().bind() logger.debug("Creating entity {}", ngsiLdEntity.id) - createEntityPayload(ngsiLdEntity, jsonLdEntity, createdAt, sub = sub).bind() + createEntityPayload(ngsiLdEntity, expandedEntity, createdAt, sub = sub).bind() temporalEntityAttributeService.createEntityTemporalReferences( ngsiLdEntity, - jsonLdEntity, + expandedEntity, attributesMetadata, createdAt, sub @@ -69,7 +69,7 @@ class EntityPayloadService( @Transactional suspend fun createEntityPayload( ngsiLdEntity: NgsiLdEntity, - jsonLdEntity: JsonLdEntity, + expandedEntity: ExpandedEntity, createdAt: ZonedDateTime, sub: Sub? = null ): Either = either { @@ -84,7 +84,7 @@ class EntityPayloadService( .bind("types", ngsiLdEntity.types.toTypedArray()) .bind("scopes", ngsiLdEntity.scopes?.toTypedArray()) .bind("created_at", createdAt) - .bind("payload", Json.of(serializeObject(jsonLdEntity.populateCreationTimeDate(createdAt).members))) + .bind("payload", Json.of(serializeObject(expandedEntity.populateCreationTimeDate(createdAt).members))) .bind("contexts", ngsiLdEntity.contexts.toTypedArray()) .bind("specific_access_policy", specificAccessPolicy?.toString()) .execute() @@ -129,7 +129,7 @@ class EntityPayloadService( suspend fun replaceEntity( entityId: URI, ngsiLdEntity: NgsiLdEntity, - jsonLdEntity: JsonLdEntity, + expandedEntity: ExpandedEntity, sub: String? = null ): Either = either { val replacedAt = ngsiLdDateTime() @@ -138,10 +138,10 @@ class EntityPayloadService( temporalEntityAttributeService.deleteTemporalAttributesOfEntity(entityId) - replaceEntityPayload(ngsiLdEntity, jsonLdEntity, replacedAt, sub).bind() + replaceEntityPayload(ngsiLdEntity, expandedEntity, replacedAt, sub).bind() temporalEntityAttributeService.createEntityTemporalReferences( ngsiLdEntity, - jsonLdEntity, + expandedEntity, attributesMetadata, replacedAt, sub @@ -151,14 +151,14 @@ class EntityPayloadService( @Transactional suspend fun replaceEntityPayload( ngsiLdEntity: NgsiLdEntity, - jsonLdEntity: JsonLdEntity, + expandedEntity: ExpandedEntity, replacedAt: ZonedDateTime, sub: Sub? = null ): Either = either { val specificAccessPolicy = ngsiLdEntity.getSpecificAccessPolicy()?.bind() val createdAt = retrieveCreatedAt(ngsiLdEntity.id).bind() val serializedPayload = - serializeObject(jsonLdEntity.populateReplacementTimeDates(createdAt, replacedAt).members) + serializeObject(expandedEntity.populateReplacementTimeDates(createdAt, replacedAt).members) databaseClient.sql( """ @@ -177,7 +177,7 @@ class EntityPayloadService( .bind("scopes", ngsiLdEntity.scopes?.toTypedArray()) .bind("modified_at", replacedAt) .bind("payload", Json.of(serializedPayload)) - .bind("contexts", jsonLdEntity.contexts.toTypedArray()) + .bind("contexts", expandedEntity.contexts.toTypedArray()) .bind("specific_access_policy", specificAccessPolicy?.toString()) .execute() .map { diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/QueryService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/QueryService.kt index 66a23e219..960a77dcd 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/QueryService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/QueryService.kt @@ -10,7 +10,7 @@ import com.egm.stellio.search.scope.ScopeService import com.egm.stellio.search.util.TemporalEntityBuilder import com.egm.stellio.search.util.deserializeAsMap import com.egm.stellio.shared.model.APIException -import com.egm.stellio.shared.model.JsonLdEntity +import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.model.ResourceNotFoundException import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY import com.egm.stellio.shared.util.entityOrAttrsNotFoundMessage @@ -29,7 +29,7 @@ class QueryService( suspend fun queryEntity( entityId: URI, contexts: List - ): Either = + ): Either = either { val entityPayload = entityPayloadService.retrieve(entityId).bind() toJsonLdEntity(entityPayload, contexts) @@ -38,13 +38,13 @@ class QueryService( suspend fun queryEntities( entitiesQuery: EntitiesQuery, accessRightFilter: () -> String? - ): Either, Int>> = either { + ): Either, Int>> = either { val entitiesIds = entityPayloadService.queryEntities(entitiesQuery, accessRightFilter) val count = entityPayloadService.queryEntitiesCount(entitiesQuery, accessRightFilter).bind() // we can have an empty list of entities with a non-zero count (e.g., offset too high) if (entitiesIds.isEmpty()) - return@either Pair, Int>(emptyList(), count) + return@either Pair, Int>(emptyList(), count) val entitiesPayloads = entityPayloadService.retrieve(entitiesIds) @@ -57,7 +57,7 @@ class QueryService( entityId: URI, temporalEntitiesQuery: TemporalEntitiesQuery, contextLink: String - ): Either = either { + ): Either = either { val attrs = temporalEntitiesQuery.entitiesQuery.attrs val temporalEntityAttributes = temporalEntityAttributeService.getForEntity(entityId, attrs).let { if (it.isEmpty()) @@ -126,7 +126,7 @@ class QueryService( suspend fun queryTemporalEntities( temporalEntitiesQuery: TemporalEntitiesQuery, accessRightFilter: () -> String? - ): Either, Int>> = either { + ): Either, Int>> = either { val attrs = temporalEntitiesQuery.entitiesQuery.attrs val entitiesIds = entityPayloadService.queryEntities(temporalEntitiesQuery.entitiesQuery, accessRightFilter) val count = entityPayloadService.queryEntitiesCount(temporalEntitiesQuery.entitiesQuery, accessRightFilter) @@ -134,7 +134,7 @@ class QueryService( // we can have an empty list of entities with a non-zero count (e.g., offset too high) if (entitiesIds.isEmpty()) - return@either Pair, Int>(emptyList(), count) + return@either Pair, Int>(emptyList(), count) val temporalEntityAttributes = temporalEntityAttributeService.getForTemporalEntities( entitiesIds, @@ -238,8 +238,8 @@ class QueryService( private fun toJsonLdEntity( entityPayload: EntityPayload, contexts: List - ): JsonLdEntity { + ): ExpandedEntity { val deserializedEntity = entityPayload.payload.deserializeAsMap() - return JsonLdEntity(deserializedEntity, contexts) + return ExpandedEntity(deserializedEntity, contexts) } } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt index 69e7946ec..14ca0b4b0 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt @@ -136,7 +136,7 @@ class TemporalEntityAttributeService( @Transactional suspend fun createEntityTemporalReferences( ngsiLdEntity: NgsiLdEntity, - jsonLdEntity: JsonLdEntity, + expandedEntity: ExpandedEntity, attributesMetadata: List>, createdAt: ZonedDateTime, sub: String? = null @@ -150,7 +150,7 @@ class TemporalEntityAttributeService( .forEach { val (expandedAttributeName, attributeMetadata) = it val attributePayload = getAttributeFromExpandedAttributes( - jsonLdEntity.getAttributes(), + expandedEntity.getAttributes(), expandedAttributeName, attributeMetadata.datasetId )!! diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt index 4295c3686..8bbfa7e71 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt @@ -2,7 +2,7 @@ package com.egm.stellio.search.util import com.egm.stellio.search.model.* import com.egm.stellio.search.scope.TemporalScopeBuilder -import com.egm.stellio.shared.model.JsonLdEntity +import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SUB import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE @@ -26,7 +26,7 @@ object TemporalEntityBuilder { queryResult: List, temporalEntitiesQuery: TemporalEntitiesQuery, contexts: List - ): List = + ): List = queryResult.map { buildTemporalEntity(it, temporalEntitiesQuery, contexts) } @@ -35,7 +35,7 @@ object TemporalEntityBuilder { entityTemporalResult: EntityTemporalResult, temporalEntitiesQuery: TemporalEntitiesQuery, contexts: List - ): JsonLdEntity { + ): ExpandedEntity { val temporalAttributes = buildTemporalAttributes( entityTemporalResult.teaInstancesResult, temporalEntitiesQuery @@ -50,7 +50,7 @@ object TemporalEntityBuilder { val expandedTemporalEntity = entityTemporalResult.entityPayload.serializeProperties() .plus(temporalAttributes) .plus(scopeAttributeInstances) - return JsonLdEntity(expandedTemporalEntity, contexts) + return ExpandedEntity(expandedTemporalEntity, contexts) } private fun buildTemporalAttributes( diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/BatchAPIResponses.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/BatchAPIResponses.kt index 552b52639..421b50bcc 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/BatchAPIResponses.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/BatchAPIResponses.kt @@ -2,7 +2,7 @@ package com.egm.stellio.search.web import com.egm.stellio.search.model.UpdateResult import com.egm.stellio.shared.model.APIException -import com.egm.stellio.shared.model.JsonLdEntity +import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.model.NgsiLdEntity import com.egm.stellio.shared.util.toUri import com.fasterxml.jackson.annotation.JsonIgnore @@ -51,7 +51,7 @@ data class BatchEntityError( val error: MutableList ) -typealias JsonLdNgsiLdEntity = Pair +typealias JsonLdNgsiLdEntity = Pair fun List.extractNgsiLdEntities(): List = this.map { it.second } fun JsonLdNgsiLdEntity.entityId(): URI = this.second.id diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityHandler.kt index 5a3d8fe0e..b02590e3c 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityHandler.kt @@ -249,11 +249,11 @@ class EntityHandler( jsonLdEntity.checkContainsAnyOf(queryParams.attrs).bind() - val filteredJsonLdEntity = JsonLdEntity( + val filteredExpandedEntity = ExpandedEntity( JsonLdUtils.filterJsonLdEntityOnAttributes(jsonLdEntity, queryParams.attrs), jsonLdEntity.contexts ) - val compactedEntity = JsonLdUtils.compactEntity(filteredJsonLdEntity, contextLink, mediaType).toMutableMap() + val compactedEntity = JsonLdUtils.compactEntity(filteredExpandedEntity, contextLink, mediaType).toMutableMap() val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) prepareGetSuccessResponse(mediaType, contextLink) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt index d474e8e8a..8740f1e1d 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt @@ -57,15 +57,15 @@ class TemporalEntityHandler( authorizationService.userCanCreateEntities(sub).bind() // create a view of the entity containing only the most recent instance of each attribute - val jsonLdEntity = JsonLdEntity( + val expandedEntity = ExpandedEntity( sortedJsonLdInstances .keepFirstInstances() .addCoreMembers(jsonLdTemporalEntity.id, jsonLdTemporalEntity.types), contexts ) - val ngsiLdEntity = jsonLdEntity.toNgsiLdEntity().bind() + val ngsiLdEntity = expandedEntity.toNgsiLdEntity().bind() - entityPayloadService.createEntity(ngsiLdEntity, jsonLdEntity, sub.getOrNull()).bind() + entityPayloadService.createEntity(ngsiLdEntity, expandedEntity, sub.getOrNull()).bind() entityPayloadService.upsertAttributes( entityUri, sortedJsonLdInstances.removeFirstInstances(), diff --git a/search-service/src/main/kotlin/db/migration/V0_29__JsonLd_migration.kt b/search-service/src/main/kotlin/db/migration/V0_29__JsonLd_migration.kt index 72848583b..af872e100 100644 --- a/search-service/src/main/kotlin/db/migration/V0_29__JsonLd_migration.kt +++ b/search-service/src/main/kotlin/db/migration/V0_29__JsonLd_migration.kt @@ -137,7 +137,7 @@ class V0_29__JsonLd_migration : BaseJavaMigration() { """.trimIndent() ) - val jsonLdEntity = JsonLdEntity(expandedEntity, contexts) + val jsonLdEntity = ExpandedEntity(expandedEntity, contexts) val ngsiLdEntity = runBlocking { jsonLdEntity.toNgsiLdEntity() } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt index a569415a5..4f4731b73 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt @@ -548,7 +548,7 @@ class EntityAccessRightsServiceTests : WithTimescaleContainer { rawEntity.sampleDataToNgsiLdEntity().map { entityPayloadService.createEntityPayload( ngsiLdEntity = it.second, - jsonLdEntity = it.first, + expandedEntity = it.first, createdAt = ngsiLdDateTime() ) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/listener/ObservationEventListenerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/listener/ObservationEventListenerTests.kt index da6ca7edb..96db6d1b7 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/listener/ObservationEventListenerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/listener/ObservationEventListenerTests.kt @@ -7,7 +7,7 @@ import com.egm.stellio.search.model.UpdateResult import com.egm.stellio.search.model.UpdatedDetails import com.egm.stellio.search.service.EntityEventService import com.egm.stellio.search.service.EntityPayloadService -import com.egm.stellio.shared.model.JsonLdEntity +import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.util.* import com.ninjasquad.springmockk.MockkBean import io.mockk.* @@ -143,8 +143,8 @@ class ObservationEventListenerTests { ), emptyList() ).right() - val mockedJsonLdEntity = mockkClass(JsonLdEntity::class, relaxed = true) - every { mockedJsonLdEntity.types } returns listOf(BEEHIVE_TYPE) + val mockedExpandedEntity = mockkClass(ExpandedEntity::class, relaxed = true) + every { mockedExpandedEntity.types } returns listOf(BEEHIVE_TYPE) coEvery { entityEventService.publishAttributeChangeEvents(any(), any(), any(), any(), any(), any()) } returns Job() diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityOperationServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityOperationServiceTests.kt index fb0cc6bf6..27c217492 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityOperationServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityOperationServiceTests.kt @@ -9,8 +9,8 @@ import com.egm.stellio.search.model.UpdateResult import com.egm.stellio.search.web.BatchEntityError import com.egm.stellio.search.web.BatchEntitySuccess import com.egm.stellio.shared.model.BadRequestDataException +import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.model.InternalErrorException -import com.egm.stellio.shared.model.JsonLdEntity import com.egm.stellio.shared.model.NgsiLdEntity import com.egm.stellio.shared.util.Sub import com.egm.stellio.shared.util.toUri @@ -46,22 +46,22 @@ class EntityOperationServiceTests { val firstEntityURI = "urn:ngsi-ld:Device:HCMR-AQUABOX1".toUri() val secondEntityURI = "urn:ngsi-ld:Device:HCMR-AQUABOX2".toUri() - private lateinit var firstJsonLdEntity: JsonLdEntity + private lateinit var firstExpandedEntity: ExpandedEntity private lateinit var firstEntity: NgsiLdEntity - private lateinit var secondJsonLdEntity: JsonLdEntity + private lateinit var secondExpandedEntity: ExpandedEntity private lateinit var secondEntity: NgsiLdEntity val sub: Sub = "60AAEBA3-C0C7-42B6-8CB0-0D30857F210E" @BeforeEach fun initNgsiLdEntitiesMocks() { - firstJsonLdEntity = mockkClass(JsonLdEntity::class, relaxed = true) { + firstExpandedEntity = mockkClass(ExpandedEntity::class, relaxed = true) { every { id } returns firstEntityURI.toString() every { members } returns emptyMap() } firstEntity = mockkClass(NgsiLdEntity::class, relaxed = true) every { firstEntity.id } returns firstEntityURI - secondJsonLdEntity = mockkClass(JsonLdEntity::class, relaxed = true) { + secondExpandedEntity = mockkClass(ExpandedEntity::class, relaxed = true) { every { id } returns secondEntityURI.toString() every { members } returns emptyMap() } @@ -77,13 +77,13 @@ class EntityOperationServiceTests { val (exist, doNotExist) = entityOperationService.splitEntitiesByExistence( listOf( - Pair(firstJsonLdEntity, firstEntity), - Pair(secondJsonLdEntity, secondEntity) + Pair(firstExpandedEntity, firstEntity), + Pair(secondExpandedEntity, secondEntity) ) ) - assertEquals(listOf(Pair(firstJsonLdEntity, firstEntity)), exist) - assertEquals(listOf(Pair(secondJsonLdEntity, secondEntity)), doNotExist) + assertEquals(listOf(Pair(firstExpandedEntity, firstEntity)), exist) + assertEquals(listOf(Pair(secondExpandedEntity, secondEntity)), doNotExist) } @Test @@ -105,8 +105,8 @@ class EntityOperationServiceTests { val batchOperationResult = entityOperationService.create( listOf( - Pair(firstJsonLdEntity, firstEntity), - Pair(secondJsonLdEntity, secondEntity) + Pair(firstExpandedEntity, firstEntity), + Pair(secondExpandedEntity, secondEntity) ), sub ) @@ -118,10 +118,10 @@ class EntityOperationServiceTests { assertTrue(batchOperationResult.errors.isEmpty()) coVerify { - entityPayloadService.createEntity(firstEntity, firstJsonLdEntity, sub) + entityPayloadService.createEntity(firstEntity, firstExpandedEntity, sub) } coVerify { - entityPayloadService.createEntity(secondEntity, secondJsonLdEntity, sub) + entityPayloadService.createEntity(secondEntity, secondExpandedEntity, sub) } } @@ -134,8 +134,8 @@ class EntityOperationServiceTests { val batchOperationResult = entityOperationService.create( listOf( - Pair(firstJsonLdEntity, firstEntity), - Pair(secondJsonLdEntity, secondEntity) + Pair(firstExpandedEntity, firstEntity), + Pair(secondExpandedEntity, secondEntity) ), sub ) @@ -157,8 +157,8 @@ class EntityOperationServiceTests { val batchOperationResult = entityOperationService.update( listOf( - Pair(firstJsonLdEntity, firstEntity), - Pair(secondJsonLdEntity, secondEntity) + Pair(firstExpandedEntity, firstEntity), + Pair(secondExpandedEntity, secondEntity) ), false, sub @@ -189,8 +189,8 @@ class EntityOperationServiceTests { val batchOperationResult = entityOperationService.update( listOf( - Pair(firstJsonLdEntity, firstEntity), - Pair(secondJsonLdEntity, secondEntity) + Pair(firstExpandedEntity, firstEntity), + Pair(secondExpandedEntity, secondEntity) ), false, sub @@ -224,8 +224,8 @@ class EntityOperationServiceTests { val batchOperationResult = entityOperationService.update( listOf( - Pair(firstJsonLdEntity, firstEntity), - Pair(secondJsonLdEntity, secondEntity) + Pair(firstExpandedEntity, firstEntity), + Pair(secondExpandedEntity, secondEntity) ), false, sub @@ -254,8 +254,8 @@ class EntityOperationServiceTests { val batchOperationResult = entityOperationService.replace( listOf( - Pair(firstJsonLdEntity, firstEntity), - Pair(secondJsonLdEntity, secondEntity) + Pair(firstExpandedEntity, firstEntity), + Pair(secondExpandedEntity, secondEntity) ), sub ) @@ -288,8 +288,8 @@ class EntityOperationServiceTests { val batchOperationResult = entityOperationService.replace( listOf( - Pair(firstJsonLdEntity, firstEntity), - Pair(secondJsonLdEntity, secondEntity) + Pair(firstExpandedEntity, firstEntity), + Pair(secondExpandedEntity, secondEntity) ), sub ) @@ -318,8 +318,8 @@ class EntityOperationServiceTests { val batchOperationResult = entityOperationService.replace( listOf( - Pair(firstJsonLdEntity, firstEntity), - Pair(secondJsonLdEntity, secondEntity) + Pair(firstExpandedEntity, firstEntity), + Pair(secondExpandedEntity, secondEntity) ), sub ) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt index 515384ccf..138cf91d6 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt @@ -557,7 +557,7 @@ class EntityAccessControlHandlerTests { fun `get authorized entities should return 200 and the number of results if requested limit is 0`() { coEvery { authorizationService.getAuthorizedEntities(any(), any(), any()) - } returns Pair(3, emptyList()).right() + } returns Pair(3, emptyList()).right() webClient.get() .uri("/ngsi-ld/v1/entityAccessControl/entities?&limit=0&offset=1&count=true") @@ -571,7 +571,7 @@ class EntityAccessControlHandlerTests { fun `get authorized entities should return 200 and empty response if requested offset does not exist`() { coEvery { authorizationService.getAuthorizedEntities(any(), any(), any()) - } returns Pair(0, emptyList()).right() + } returns Pair(0, emptyList()).right() webClient.get() .uri("/ngsi-ld/v1/entityAccessControl/entities?limit=1&offset=9") @@ -660,7 +660,7 @@ class EntityAccessControlHandlerTests { fun `get authorized entities should return 204 if authentication is not enabled`() { coEvery { authorizationService.getAuthorizedEntities(any(), any(), any()) - } returns Pair(-1, emptyList()).right() + } returns Pair(-1, emptyList()).right() webClient.get() .uri("/ngsi-ld/v1/entityAccessControl/entities") @@ -673,7 +673,7 @@ class EntityAccessControlHandlerTests { fun `get groups memberships should return 200 and the number of results if requested limit is 0`() { coEvery { authorizationService.getGroupsMemberships(any(), any(), any(), any()) - } returns Pair(3, emptyList()).right() + } returns Pair(3, emptyList()).right() webClient.get() .uri("/ngsi-ld/v1/entityAccessControl/groups?&limit=0&offset=1&count=true") @@ -690,7 +690,7 @@ class EntityAccessControlHandlerTests { } returns Pair( 1, listOf( - JsonLdEntity( + ExpandedEntity( mapOf( "@id" to "urn:ngsi-ld:group:1", "@type" to listOf(GROUP_TYPE), @@ -730,7 +730,7 @@ class EntityAccessControlHandlerTests { } returns Pair( 1, listOf( - JsonLdEntity( + ExpandedEntity( mapOf( "@id" to "urn:ngsi-ld:group:01", "@type" to listOf(GROUP_TYPE), @@ -769,7 +769,7 @@ class EntityAccessControlHandlerTests { fun `get groups memberships should return 204 if authentication is not enabled`() { coEvery { authorizationService.getGroupsMemberships(any(), any(), any(), any()) - } returns Pair(-1, emptyList()).right() + } returns Pair(-1, emptyList()).right() webClient.get() .uri("/ngsi-ld/v1/entityAccessControl/groups") @@ -796,7 +796,7 @@ class EntityAccessControlHandlerTests { coEvery { authorizationService.userIsAdmin(any()) } returns Unit.right() coEvery { authorizationService.getUsers(any(), any(), any()) - } returns Pair(3, emptyList()).right() + } returns Pair(3, emptyList()).right() webClient.get() .uri("/ngsi-ld/v1/entityAccessControl/users?&limit=0&offset=1&count=true") @@ -811,7 +811,7 @@ class EntityAccessControlHandlerTests { coEvery { authorizationService.userIsAdmin(any()) } returns Unit.right() coEvery { authorizationService.getUsers(any(), any(), any()) - } returns Pair(-1, emptyList()).right() + } returns Pair(-1, emptyList()).right() webClient.get() .uri("/ngsi-ld/v1/entityAccessControl/users") @@ -828,7 +828,7 @@ class EntityAccessControlHandlerTests { } returns Pair( 1, listOf( - JsonLdEntity( + ExpandedEntity( User( "1", USER_TYPE, @@ -870,9 +870,9 @@ class EntityAccessControlHandlerTests { private suspend fun createJsonLdEntity( entityAccessRights: EntityAccessRights, context: String = NGSILD_TEST_CORE_CONTEXT - ): JsonLdEntity { + ): ExpandedEntity { val earSerialized = entityAccessRights.serializeProperties(AUTHZ_TEST_COMPOUND_CONTEXT) - return JsonLdEntity(earSerialized, listOf(context)) + return ExpandedEntity(earSerialized, listOf(context)) } private fun createEntityAccessRight( diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt index 06a9d85db..cfb5e4bfd 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt @@ -288,9 +288,9 @@ class EntityHandlerTests { fun `get entity by id should return 200 when entity exists`() { mockkDefaultBehaviorForGetEntityById() - val returnedJsonLdEntity = mockkClass(JsonLdEntity::class, relaxed = true) - coEvery { queryService.queryEntity(any(), any()) } returns returnedJsonLdEntity.right() - every { returnedJsonLdEntity.checkContainsAnyOf(any()) } returns Unit.right() + val returnedExpandedEntity = mockkClass(ExpandedEntity::class, relaxed = true) + coEvery { queryService.queryEntity(any(), any()) } returns returnedExpandedEntity.right() + every { returnedExpandedEntity.checkContainsAnyOf(any()) } returns Unit.right() webClient.get() .uri("/ngsi-ld/v1/entities/$beehiveId") @@ -303,7 +303,7 @@ class EntityHandlerTests { fun `get entity by id should correctly serialize temporal properties`() { mockkDefaultBehaviorForGetEntityById() - coEvery { queryService.queryEntity(any(), any()) } returns JsonLdEntity( + coEvery { queryService.queryEntity(any(), any()) } returns ExpandedEntity( mapOf( NGSILD_CREATED_AT_PROPERTY to mapOf( @@ -335,7 +335,7 @@ class EntityHandlerTests { fun `get entity by id should correctly filter the asked attributes`() { mockkDefaultBehaviorForGetEntityById() - coEvery { queryService.queryEntity(any(), any()) } returns JsonLdEntity( + coEvery { queryService.queryEntity(any(), any()) } returns ExpandedEntity( mapOf( "@id" to beehiveId.toString(), "@type" to listOf("Beehive"), @@ -369,7 +369,7 @@ class EntityHandlerTests { fun `get entity by id should correctly return the simplified representation of an entity`() { mockkDefaultBehaviorForGetEntityById() - coEvery { queryService.queryEntity(any(), any()) } returns JsonLdEntity( + coEvery { queryService.queryEntity(any(), any()) } returns ExpandedEntity( mapOf( "@id" to beehiveId.toString(), "@type" to listOf("Beehive"), @@ -412,7 +412,7 @@ class EntityHandlerTests { fun `get entity by id should return 404 if the entity has none of the requested attributes`() { mockkDefaultBehaviorForGetEntityById() - coEvery { queryService.queryEntity(any(), any()) } returns JsonLdEntity( + coEvery { queryService.queryEntity(any(), any()) } returns ExpandedEntity( mapOf( "@id" to beehiveId.toString(), "@type" to listOf(BEEHIVE_TYPE) @@ -444,7 +444,7 @@ class EntityHandlerTests { fun `get entity by id should not include temporal properties if optional query param sysAttrs is not present`() { mockkDefaultBehaviorForGetEntityById() - coEvery { queryService.queryEntity(any(), any()) } returns JsonLdEntity( + coEvery { queryService.queryEntity(any(), any()) } returns ExpandedEntity( mapOf( "@id" to beehiveId.toString(), "@type" to listOf("Beehive") @@ -465,7 +465,7 @@ class EntityHandlerTests { @Test fun `get entity by id should correctly serialize properties of type DateTime and display sysAttrs asked`() { mockkDefaultBehaviorForGetEntityById() - coEvery { queryService.queryEntity(any(), any()) } returns JsonLdEntity( + coEvery { queryService.queryEntity(any(), any()) } returns ExpandedEntity( mapOf( NGSILD_CREATED_AT_PROPERTY to mapOf( @@ -523,7 +523,7 @@ class EntityHandlerTests { fun `get entity by id should correctly serialize properties of type Date`() { mockkDefaultBehaviorForGetEntityById() - coEvery { queryService.queryEntity(any(), any()) } returns JsonLdEntity( + coEvery { queryService.queryEntity(any(), any()) } returns ExpandedEntity( mapOf( "https://uri.etsi.org/ngsi-ld/default-context/testedAt" to mapOf( "@type" to "https://uri.etsi.org/ngsi-ld/Property", @@ -563,7 +563,7 @@ class EntityHandlerTests { fun `get entity by id should correctly serialize properties of type Time`() { mockkDefaultBehaviorForGetEntityById() - coEvery { queryService.queryEntity(any(), any()) } returns JsonLdEntity( + coEvery { queryService.queryEntity(any(), any()) } returns ExpandedEntity( mapOf( "https://uri.etsi.org/ngsi-ld/default-context/testedAt" to mapOf( "@type" to "https://uri.etsi.org/ngsi-ld/Property", @@ -603,7 +603,7 @@ class EntityHandlerTests { fun `get entity by id should correctly serialize multi-attribute property having one instance`() { mockkDefaultBehaviorForGetEntityById() - coEvery { queryService.queryEntity(any(), any()) } returns JsonLdEntity( + coEvery { queryService.queryEntity(any(), any()) } returns ExpandedEntity( mapOf( "https://uri.etsi.org/ngsi-ld/default-context/name" to mapOf( @@ -640,7 +640,7 @@ class EntityHandlerTests { fun `get entity by id should correctly serialize multi-attribute property having more than one instance`() { mockkDefaultBehaviorForGetEntityById() - coEvery { queryService.queryEntity(any(), any()) } returns JsonLdEntity( + coEvery { queryService.queryEntity(any(), any()) } returns ExpandedEntity( mapOf( "https://uri.etsi.org/ngsi-ld/default-context/name" to listOf( @@ -693,7 +693,7 @@ class EntityHandlerTests { fun `get entity by id should correctly serialize multi-attribute relationship having one instance`() { mockkDefaultBehaviorForGetEntityById() - coEvery { queryService.queryEntity(any(), any()) } returns JsonLdEntity( + coEvery { queryService.queryEntity(any(), any()) } returns ExpandedEntity( mapOf( "https://uri.etsi.org/ngsi-ld/default-context/managedBy" to mapOf( @@ -736,7 +736,7 @@ class EntityHandlerTests { fun `get entity by id should include createdAt & modifiedAt if query param sysAttrs is present`() { mockkDefaultBehaviorForGetEntityById() - coEvery { queryService.queryEntity(any(), any()) } returns JsonLdEntity( + coEvery { queryService.queryEntity(any(), any()) } returns ExpandedEntity( mapOf( "https://uri.etsi.org/ngsi-ld/default-context/managedBy" to mapOf( @@ -778,7 +778,7 @@ class EntityHandlerTests { fun `get entity by id should correctly serialize multi-attribute relationship having more than one instance`() { mockkDefaultBehaviorForGetEntityById() - coEvery { queryService.queryEntity(any(), any()) } returns JsonLdEntity( + coEvery { queryService.queryEntity(any(), any()) } returns ExpandedEntity( mapOf( "https://uri.etsi.org/ngsi-ld/default-context/managedBy" to listOf( @@ -877,7 +877,7 @@ class EntityHandlerTests { fun `get entities by type should not include temporal properties if query param sysAttrs is not present`() { coEvery { queryService.queryEntities(any(), any()) } returns Pair( listOf( - JsonLdEntity( + ExpandedEntity( mapOf( "@id" to beehiveId.toString(), "@type" to listOf("Beehive") @@ -921,7 +921,7 @@ class EntityHandlerTests { ) } returns Pair( listOf( - JsonLdEntity( + ExpandedEntity( mapOf( NGSILD_CREATED_AT_PROPERTY to mapOf( @@ -960,7 +960,7 @@ class EntityHandlerTests { fun `get entities should return 200 with prev and next link header if exists`() { coEvery { queryService.queryEntities(any(), any()) } returns Pair( listOf( - JsonLdEntity( + ExpandedEntity( mapOf("@id" to "urn:ngsi-ld:Beehive:TESTC", "@type" to listOf("Beehive")), listOf(NGSILD_TEST_CORE_CONTEXT) ) @@ -999,7 +999,7 @@ class EntityHandlerTests { fun `get entities should return 200 and empty response if requested offset does not exists`() { coEvery { queryService.queryEntities(any(), any()) - } returns Pair(emptyList(), 0).right() + } returns Pair(emptyList(), 0).right() webClient.get() .uri("/ngsi-ld/v1/entities/?type=Beehive&limit=1&offset=9") @@ -1056,7 +1056,7 @@ class EntityHandlerTests { ) } returns Pair( listOf( - JsonLdEntity( + ExpandedEntity( mapOf( "@id" to beehiveId.toString(), "@type" to listOf("Beehive") @@ -1088,7 +1088,7 @@ class EntityHandlerTests { @Test fun `get entities should return 200 and the number of results`() { - coEvery { queryService.queryEntities(any(), any()) } returns Pair(emptyList(), 3).right() + coEvery { queryService.queryEntities(any(), any()) } returns Pair(emptyList(), 3).right() webClient.get() .uri("/ngsi-ld/v1/entities/?type=Beehive&limit=0&offset=1&count=true") @@ -1117,7 +1117,7 @@ class EntityHandlerTests { @Test fun `get entities should allow a query not including a type request parameter`() { - coEvery { queryService.queryEntities(any(), any()) } returns Pair(emptyList(), 0).right() + coEvery { queryService.queryEntities(any(), any()) } returns Pair(emptyList(), 0).right() webClient.get() .uri("/ngsi-ld/v1/entities/?attrs=myProp") diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityOperationHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityOperationHandlerTests.kt index 4a19fc35f..a503bb35f 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityOperationHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityOperationHandlerTests.kt @@ -14,7 +14,7 @@ import com.egm.stellio.search.service.EntityPayloadService import com.egm.stellio.search.service.QueryService import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.AccessDeniedException -import com.egm.stellio.shared.model.JsonLdEntity +import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.model.NgsiLdEntity import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DEFAULT_VOCAB @@ -70,9 +70,9 @@ class EntityOperationHandlerTests { private lateinit var mockedTemperatureSensorEntity: NgsiLdEntity private lateinit var mockedDissolvedOxygenSensorEntity: NgsiLdEntity private lateinit var mockedDeviceEntity: NgsiLdEntity - private lateinit var mockedTemperatureSensorJsonLdEntity: JsonLdEntity - private lateinit var mockedDissolvedOxygenSensorJsonLdEntity: JsonLdEntity - private lateinit var mockedDeviceJsonLdEntity: JsonLdEntity + private lateinit var mockedTemperatureSensorExpandedEntity: ExpandedEntity + private lateinit var mockedDissolvedOxygenSensorExpandedEntity: ExpandedEntity + private lateinit var mockedDeviceExpandedEntity: ExpandedEntity @BeforeAll fun configureWebClientDefaults() { @@ -93,7 +93,7 @@ class EntityOperationHandlerTests { every { types } returns listOf(SENSOR_TYPE) every { contexts } returns listOf(AQUAC_COMPOUND_CONTEXT) } - mockedTemperatureSensorJsonLdEntity = mockkClass(JsonLdEntity::class) { + mockedTemperatureSensorExpandedEntity = mockkClass(ExpandedEntity::class) { every { id } returns temperatureSensorUri.toString() every { members } returns emptyMap() } @@ -102,7 +102,7 @@ class EntityOperationHandlerTests { every { types } returns listOf(SENSOR_TYPE) every { contexts } returns listOf(AQUAC_COMPOUND_CONTEXT) } - mockedDissolvedOxygenSensorJsonLdEntity = mockkClass(JsonLdEntity::class) { + mockedDissolvedOxygenSensorExpandedEntity = mockkClass(ExpandedEntity::class) { every { id } returns dissolvedOxygenSensorUri.toString() every { members } returns emptyMap() } @@ -111,7 +111,7 @@ class EntityOperationHandlerTests { every { types } returns listOf(DEVICE_TYPE) every { contexts } returns listOf(AQUAC_COMPOUND_CONTEXT) } - mockedDeviceJsonLdEntity = mockkClass(JsonLdEntity::class) { + mockedDeviceExpandedEntity = mockkClass(ExpandedEntity::class) { every { id } returns deviceUri.toString() every { members } returns emptyMap() } @@ -137,9 +137,9 @@ class EntityOperationHandlerTests { coEvery { entityOperationService.splitEntitiesByExistence(any()) } returns Pair( listOf( - Pair(mockedTemperatureSensorJsonLdEntity, mockedTemperatureSensorEntity), - Pair(mockedDissolvedOxygenSensorJsonLdEntity, mockedDissolvedOxygenSensorEntity), - Pair(mockedDeviceJsonLdEntity, mockedDeviceEntity) + Pair(mockedTemperatureSensorExpandedEntity, mockedTemperatureSensorEntity), + Pair(mockedDissolvedOxygenSensorExpandedEntity, mockedDissolvedOxygenSensorEntity), + Pair(mockedDeviceExpandedEntity, mockedDeviceEntity) ), emptyList() ) @@ -170,8 +170,8 @@ class EntityOperationHandlerTests { coEvery { entityOperationService.splitEntitiesByExistence(any()) } returns Pair( listOf( - Pair(mockedTemperatureSensorJsonLdEntity, mockedTemperatureSensorEntity), - Pair(mockedDissolvedOxygenSensorJsonLdEntity, mockedDissolvedOxygenSensorEntity), + Pair(mockedTemperatureSensorExpandedEntity, mockedTemperatureSensorEntity), + Pair(mockedDissolvedOxygenSensorExpandedEntity, mockedDissolvedOxygenSensorEntity), ), emptyList() ) @@ -210,7 +210,7 @@ class EntityOperationHandlerTests { val jsonLdFile = ClassPathResource("/ngsild/two_sensors_one_invalid.jsonld") coEvery { entityOperationService.splitEntitiesByExistence(any()) } returns Pair( - listOf(Pair(mockedTemperatureSensorJsonLdEntity, mockedTemperatureSensorEntity)), + listOf(Pair(mockedTemperatureSensorExpandedEntity, mockedTemperatureSensorEntity)), emptyList() ) coEvery { authorizationService.userCanUpdateEntity(any(), sub) } returns Unit.right() @@ -252,8 +252,8 @@ class EntityOperationHandlerTests { coEvery { entityOperationService.splitEntitiesByExistence(any()) } returns Pair( listOf( - Pair(mockedTemperatureSensorJsonLdEntity, mockedTemperatureSensorEntity), - Pair(mockedDissolvedOxygenSensorJsonLdEntity, mockedDissolvedOxygenSensorEntity), + Pair(mockedTemperatureSensorExpandedEntity, mockedTemperatureSensorEntity), + Pair(mockedDissolvedOxygenSensorExpandedEntity, mockedDissolvedOxygenSensorEntity), ), emptyList() ) @@ -279,8 +279,8 @@ class EntityOperationHandlerTests { val jsonLdFile = ClassPathResource("/ngsild/hcmr/HCMR_test_file.json") coEvery { entityOperationService.splitEntitiesByExistence(any()) } returns Pair( - listOf(Pair(mockedTemperatureSensorJsonLdEntity, mockedTemperatureSensorEntity)), - listOf(Pair(mockedDeviceJsonLdEntity, mockedDeviceEntity)) + listOf(Pair(mockedTemperatureSensorExpandedEntity, mockedTemperatureSensorEntity)), + listOf(Pair(mockedDeviceExpandedEntity, mockedDeviceEntity)) ) coEvery { authorizationService.userCanUpdateEntity(any(), sub) } returns Unit.right() coEvery { entityOperationService.update(any(), any(), any()) } returns BatchOperationResult( @@ -363,10 +363,10 @@ class EntityOperationHandlerTests { entityOperationService.splitEntitiesByExistence(any()) } answers { Pair( - listOf(Pair(mockedTemperatureSensorJsonLdEntity, mockedTemperatureSensorEntity)), + listOf(Pair(mockedTemperatureSensorExpandedEntity, mockedTemperatureSensorEntity)), listOf( - Pair(mockedDissolvedOxygenSensorJsonLdEntity, mockedDissolvedOxygenSensorEntity), - Pair(mockedDeviceJsonLdEntity, mockedDeviceEntity) + Pair(mockedDissolvedOxygenSensorExpandedEntity, mockedDissolvedOxygenSensorEntity), + Pair(mockedDeviceExpandedEntity, mockedDeviceEntity) ) ) } @@ -421,7 +421,7 @@ class EntityOperationHandlerTests { coEvery { entityOperationService.splitEntitiesByExistence(any()) - } returns Pair(emptyList(), listOf(Pair(mockedDeviceJsonLdEntity, mockedDeviceEntity))) + } returns Pair(emptyList(), listOf(Pair(mockedDeviceExpandedEntity, mockedDeviceEntity))) coEvery { authorizationService.userCanCreateEntities(sub) } returns AccessDeniedException(ENTITIY_CREATION_FORBIDDEN_MESSAGE).left() @@ -488,10 +488,10 @@ class EntityOperationHandlerTests { coEvery { entityOperationService.splitEntitiesByExistence(any()) } returns Pair( listOf( - Pair(mockedDissolvedOxygenSensorJsonLdEntity, mockedDissolvedOxygenSensorEntity), - Pair(mockedDeviceJsonLdEntity, mockedDeviceEntity) + Pair(mockedDissolvedOxygenSensorExpandedEntity, mockedDissolvedOxygenSensorEntity), + Pair(mockedDeviceExpandedEntity, mockedDeviceEntity) ), - listOf(Pair(mockedTemperatureSensorJsonLdEntity, mockedTemperatureSensorEntity)) + listOf(Pair(mockedTemperatureSensorExpandedEntity, mockedTemperatureSensorEntity)) ) coEvery { authorizationService.userCanCreateEntities(any()) } returns Unit.right() coEvery { entityOperationService.create(any(), any()) } returns createdBatchResult @@ -538,7 +538,7 @@ class EntityOperationHandlerTests { val jsonLdFile = ClassPathResource("/ngsild/hcmr/HCMR_test_file.json") coEvery { entityOperationService.splitEntitiesByExistence(any()) } returns Pair( - listOf(Pair(mockedTemperatureSensorJsonLdEntity, mockedTemperatureSensorEntity)), + listOf(Pair(mockedTemperatureSensorExpandedEntity, mockedTemperatureSensorEntity)), emptyList() ) coEvery { authorizationService.userCanUpdateEntity(any(), sub) } returns Unit.right() @@ -567,10 +567,10 @@ class EntityOperationHandlerTests { coEvery { entityOperationService.splitEntitiesByExistence(any()) } returns Pair( listOf( - Pair(mockedTemperatureSensorJsonLdEntity, mockedTemperatureSensorEntity), - Pair(mockedDissolvedOxygenSensorJsonLdEntity, mockedDissolvedOxygenSensorEntity) + Pair(mockedTemperatureSensorExpandedEntity, mockedTemperatureSensorEntity), + Pair(mockedDissolvedOxygenSensorExpandedEntity, mockedDissolvedOxygenSensorEntity) ), - listOf(Pair(mockedDeviceJsonLdEntity, mockedDeviceEntity)) + listOf(Pair(mockedDeviceExpandedEntity, mockedDeviceEntity)) ) coEvery { authorizationService.userCanCreateEntities(sub) } returns Unit.right() coEvery { entityOperationService.create(any(), any()) } returns BatchOperationResult( @@ -619,8 +619,8 @@ class EntityOperationHandlerTests { coEvery { entityOperationService.splitEntitiesByExistence(any()) } returns Pair( listOf( - Pair(mockedTemperatureSensorJsonLdEntity, mockedTemperatureSensorEntity), - Pair(mockedDissolvedOxygenSensorJsonLdEntity, mockedDissolvedOxygenSensorEntity) + Pair(mockedTemperatureSensorExpandedEntity, mockedTemperatureSensorEntity), + Pair(mockedDissolvedOxygenSensorExpandedEntity, mockedDissolvedOxygenSensorEntity) ), emptyList() ) @@ -656,7 +656,7 @@ class EntityOperationHandlerTests { coEvery { entityOperationService.splitEntitiesByExistence(any()) } returns Pair( emptyList(), - listOf(Pair(mockedTemperatureSensorJsonLdEntity, mockedTemperatureSensorEntity)) + listOf(Pair(mockedTemperatureSensorExpandedEntity, mockedTemperatureSensorEntity)) ) coEvery { authorizationService.userCanCreateEntities(sub) @@ -691,8 +691,8 @@ class EntityOperationHandlerTests { coEvery { entityOperationService.splitEntitiesByExistence(any()) } returns Pair( listOf( - Pair(mockedTemperatureSensorJsonLdEntity, mockedTemperatureSensorEntity), - Pair(mockedDissolvedOxygenSensorJsonLdEntity, mockedDissolvedOxygenSensorEntity) + Pair(mockedTemperatureSensorExpandedEntity, mockedTemperatureSensorEntity), + Pair(mockedDissolvedOxygenSensorExpandedEntity, mockedDissolvedOxygenSensorEntity) ), emptyList() ) @@ -882,7 +882,7 @@ class EntityOperationHandlerTests { @Test fun `query entities should return a 200 if the query is correct`() = runTest { coEvery { authorizationService.computeAccessRightFilter(any()) } returns { null } - coEvery { queryService.queryEntities(any(), any()) } returns Pair(emptyList(), 0).right() + coEvery { queryService.queryEntities(any(), any()) } returns Pair(emptyList(), 0).right() val query = """ { diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt index 1983a0886..d5224438b 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt @@ -369,10 +369,10 @@ class TemporalEntityHandlerTests { fun `it should give a 200 if no timerel and no time query params are in the request`() { buildDefaultMockResponsesForGetEntity() - val returnedJsonLdEntity = mockkClass(JsonLdEntity::class, relaxed = true) + val returnedExpandedEntity = mockkClass(ExpandedEntity::class, relaxed = true) coEvery { queryService.queryTemporalEntity(any(), any(), any()) - } returns returnedJsonLdEntity.right() + } returns returnedExpandedEntity.right() webClient.get() .uri("/ngsi-ld/v1/temporal/entities/$entityUri") @@ -559,10 +559,10 @@ class TemporalEntityHandlerTests { fun `it should return a 200 if minimal required parameters are valid`() { buildDefaultMockResponsesForGetEntity() - val returnedJsonLdEntity = mockkClass(JsonLdEntity::class, relaxed = true) + val returnedExpandedEntity = mockkClass(ExpandedEntity::class, relaxed = true) coEvery { queryService.queryTemporalEntity(any(), any(), any()) - } returns returnedJsonLdEntity.right() + } returns returnedExpandedEntity.right() webClient.get() .uri( @@ -594,10 +594,10 @@ class TemporalEntityHandlerTests { fun `it should return a 200 if minimal required parameters are valid and entity is publicly readable`() { buildDefaultMockResponsesForGetEntity() - val returnedJsonLdEntity = mockkClass(JsonLdEntity::class, relaxed = true) + val returnedExpandedEntity = mockkClass(ExpandedEntity::class, relaxed = true) coEvery { queryService.queryTemporalEntity(any(), any(), any()) - } returns returnedJsonLdEntity.right() + } returns returnedExpandedEntity.right() webClient.get() .uri( @@ -615,10 +615,10 @@ class TemporalEntityHandlerTests { fun `it should return a 200 if minimal required parameters are valid and user can read the entity`() { buildDefaultMockResponsesForGetEntity() - val returnedJsonLdEntity = mockkClass(JsonLdEntity::class, relaxed = true) + val returnedExpandedEntity = mockkClass(ExpandedEntity::class, relaxed = true) coEvery { queryService.queryTemporalEntity(any(), any(), any()) - } returns returnedJsonLdEntity.right() + } returns returnedExpandedEntity.right() webClient.get() .uri( diff --git a/shared/config/detekt/baseline.xml b/shared/config/detekt/baseline.xml index aa4e5a0a6..07383bca3 100644 --- a/shared/config/detekt/baseline.xml +++ b/shared/config/detekt/baseline.xml @@ -3,7 +3,7 @@ CyclomaticComplexMethod:ExceptionHandler.kt$ExceptionHandler$@ExceptionHandler fun transformErrorResponse(throwable: Throwable): ResponseEntity<ProblemDetail> - LongMethod:JsonLdEntityTests.kt$JsonLdEntityTests$@Test fun `it should return simplified GeoJSON entities`() + LongMethod:ExpandedEntityTests.kt$ExpandedEntityTests$@Test fun `it should return simplified GeoJSON entities`() LongMethod:QueryUtils.kt$private fun transformQQueryToSqlJsonPath( mainAttributePath: List<ExpandedTerm>, trailingAttributePath: List<ExpandedTerm>, operator: String, value: String ) LongParameterList:ApiResponses.kt$( body: String, count: Int, resourceUrl: String, paginationQuery: PaginationQuery, requestParams: MultiValueMap<String, String>, mediaType: MediaType, contextLink: String ) LongParameterList:ApiResponses.kt$( entities: Any, count: Int, resourceUrl: String, paginationQuery: PaginationQuery, requestParams: MultiValueMap<String, String>, mediaType: MediaType, contextLink: String ) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt new file mode 100644 index 000000000..57ee9f302 --- /dev/null +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt @@ -0,0 +1,102 @@ +package com.egm.stellio.shared.model + +import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID_TERM +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_OBJECT +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE_TERM +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE_TERM +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_GEOPROPERTY_TERM +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_TERM +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_TERM +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SYSATTRS_TERMS + +typealias CompactedEntity = Map + +fun CompactedEntity.toKeyValues(): Map = + this.mapValues { (_, value) -> simplifyRepresentation(value) } + +private fun simplifyRepresentation(value: Any): Any { + return when (value) { + // entity property value is always a Map + is Map<*, *> -> simplifyValue(value as Map) + is List<*> -> value.map { + when (it) { + is Map<*, *> -> simplifyValue(it as Map) + // we keep @context value as it is (List) + else -> it + } + } + // we keep id and type values as they are (String) + else -> value + } +} + +private fun simplifyValue(value: Map): Any { + return when (value[JSONLD_TYPE_TERM]) { + NGSILD_PROPERTY_TERM, NGSILD_GEOPROPERTY_TERM -> value.getOrDefault(JSONLD_VALUE_TERM, value) + NGSILD_RELATIONSHIP_TERM -> value.getOrDefault(JSONLD_OBJECT, value) + else -> value + } +} + +fun CompactedEntity.toGeoJson(geometryProperty: String): Map { + val geometryAttributeContent = this[geometryProperty] as? Map + val geometryPropertyValue = geometryAttributeContent?.let { + if (it.containsKey(JSONLD_VALUE_TERM)) it[JSONLD_VALUE_TERM] + else it + } + + return mapOf( + JSONLD_ID_TERM to this[JSONLD_ID_TERM]!!, + JSONLD_TYPE_TERM to FEATURE_TYPE, + GEOMETRY_PROPERTY_TERM to geometryPropertyValue, + PROPERTIES_PROPERTY_TERM to this.filter { it.key != JSONLD_ID_TERM } + ) +} + +fun CompactedEntity.withoutSysAttrs(): Map = + this.filter { + !NGSILD_SYSATTRS_TERMS.contains(it.key) + }.mapValues { + when (it.value) { + is Map<*, *> -> (it.value as Map<*, *>).minus(NGSILD_SYSATTRS_TERMS) + is List<*> -> (it.value as List<*>).map { valueInstance -> + when (valueInstance) { + is Map<*, *> -> valueInstance.minus(NGSILD_SYSATTRS_TERMS) + // we keep @context value as it is (List) + else -> valueInstance + } + } + else -> it.value + } + } + +fun CompactedEntity.toFinalRepresentation( + ngsiLdDataRepresentation: NgsiLdDataRepresentation +): Any = + this.let { + if (!ngsiLdDataRepresentation.includeSysAttrs) it.withoutSysAttrs() + else it + }.let { + if (ngsiLdDataRepresentation.attributeRepresentation == AttributeRepresentation.SIMPLIFIED) it.toKeyValues() + else it + }.let { + if (ngsiLdDataRepresentation.entityRepresentation == EntityRepresentation.GEO_JSON) + // geometryProperty is not null when GeoJSON representation is asked (defaults to location) + it.toGeoJson(ngsiLdDataRepresentation.geometryProperty!!) + else it + } + +fun List.toFinalRepresentation( + ngsiLdDataRepresentation: NgsiLdDataRepresentation +): Any = + this.map { + it.toFinalRepresentation(ngsiLdDataRepresentation) + }.let { + if (ngsiLdDataRepresentation.entityRepresentation == EntityRepresentation.GEO_JSON) { + mapOf( + JSONLD_TYPE_TERM to FEATURE_COLLECTION_TYPE, + FEATURES_PROPERTY_TERM to it + ) + } else it + } diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedEntity.kt new file mode 100644 index 000000000..00e6ab96f --- /dev/null +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedEntity.kt @@ -0,0 +1,86 @@ +package com.egm.stellio.shared.model + +import arrow.core.Either +import arrow.core.left +import arrow.core.right +import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.castAttributeValue +import java.time.ZonedDateTime + +data class ExpandedEntity( + val members: Map, + val contexts: List +) { + fun containsAnyOf(expandedAttributes: Set): Boolean = + expandedAttributes.isEmpty() || members.keys.any { expandedAttributes.contains(it) } + + fun checkContainsAnyOf(expandedAttributes: Set): Either = + if (containsAnyOf(expandedAttributes)) + Unit.right() + else ResourceNotFoundException(entityOrAttrsNotFoundMessage(id, expandedAttributes)).left() + + fun getAttributes(): ExpandedAttributes = + members.filter { !JsonLdUtils.JSONLD_EXPANDED_ENTITY_CORE_MEMBERS.contains(it.key) } + .mapValues { castAttributeValue(it.value) } + + fun getScopes(): List? = + (members as Map>).getScopes() + + /** + * Called at entity creation time to populate entity and attributes with createdAt information + */ + fun populateCreationTimeDate(createdAt: ZonedDateTime): ExpandedEntity = + ExpandedEntity( + members = members.mapValues { + if (JsonLdUtils.JSONLD_EXPANDED_ENTITY_CORE_MEMBERS.contains(it.key)) + it.value + else castAttributeValue(it.value).map { expandedAttributeInstance -> + expandedAttributeInstance.addDateTimeProperty( + NGSILD_CREATED_AT_PROPERTY, + createdAt + ) as ExpandedAttributeInstance + } + }.addDateTimeProperty(NGSILD_CREATED_AT_PROPERTY, createdAt), + contexts = contexts + ) + + /** + * Called when replacing entity to populate entity and attributes with createdAt and modifiedAt information + * for attributes, the modification date is added as the creation date + */ + fun populateReplacementTimeDates(createdAt: ZonedDateTime, replacedAt: ZonedDateTime): ExpandedEntity = + ExpandedEntity( + members = members.mapValues { + if (JsonLdUtils.JSONLD_EXPANDED_ENTITY_CORE_MEMBERS.contains(it.key)) + it.value + else castAttributeValue(it.value).map { expandedAttributeInstance -> + expandedAttributeInstance.addDateTimeProperty( + NGSILD_CREATED_AT_PROPERTY, + replacedAt + ) as ExpandedAttributeInstance + } + } + .addDateTimeProperty(NGSILD_CREATED_AT_PROPERTY, createdAt) + .addDateTimeProperty(NGSILD_MODIFIED_AT_PROPERTY, replacedAt), + contexts = contexts + ) + + // FIXME kinda hacky but we often just need the id or type... how can it be improved? + val id by lazy { + (members[JSONLD_ID] ?: InternalErrorException("Could not extract id from JSON-LD entity")) as String + } + + val types by lazy { + (members[JSONLD_TYPE] ?: InternalErrorException("Could not extract type from JSON-LD entity")) + as List + } + + private fun Map.addDateTimeProperty(propertyKey: String, dateTime: ZonedDateTime?): Map = + if (dateTime != null) + this.plus(propertyKey to JsonLdUtils.buildNonReifiedTemporalValue(dateTime)) + else this +} diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/JsonLdEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/JsonLdEntity.kt deleted file mode 100644 index 61c8ce219..000000000 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/JsonLdEntity.kt +++ /dev/null @@ -1,180 +0,0 @@ -package com.egm.stellio.shared.model - -import arrow.core.Either -import arrow.core.left -import arrow.core.right -import com.egm.stellio.shared.util.* -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID_TERM -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE_TERM -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE_TERM -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.castAttributeValue -import java.time.ZonedDateTime - -typealias CompactedJsonLdEntity = Map - -data class JsonLdEntity( - val members: Map, - val contexts: List -) { - fun containsAnyOf(expandedAttributes: Set): Boolean = - expandedAttributes.isEmpty() || members.keys.any { expandedAttributes.contains(it) } - - fun checkContainsAnyOf(expandedAttributes: Set): Either = - if (containsAnyOf(expandedAttributes)) - Unit.right() - else ResourceNotFoundException(entityOrAttrsNotFoundMessage(id, expandedAttributes)).left() - - fun getAttributes(): ExpandedAttributes = - members.filter { !JsonLdUtils.JSONLD_EXPANDED_ENTITY_CORE_MEMBERS.contains(it.key) } - .mapValues { castAttributeValue(it.value) } - - fun getScopes(): List? = - (members as Map>).getScopes() - - /** - * Called at entity creation time to populate entity and attributes with createdAt information - */ - fun populateCreationTimeDate(createdAt: ZonedDateTime): JsonLdEntity = - JsonLdEntity( - members = members.mapValues { - if (JsonLdUtils.JSONLD_EXPANDED_ENTITY_CORE_MEMBERS.contains(it.key)) - it.value - else castAttributeValue(it.value).map { expandedAttributeInstance -> - expandedAttributeInstance.addDateTimeProperty( - NGSILD_CREATED_AT_PROPERTY, - createdAt - ) as ExpandedAttributeInstance - } - }.addDateTimeProperty(NGSILD_CREATED_AT_PROPERTY, createdAt), - contexts = contexts - ) - - /** - * Called when replacing entity to populate entity and attributes with createdAt and modifiedAt information - * for attributes, the modification date is added as the creation date - */ - fun populateReplacementTimeDates(createdAt: ZonedDateTime, replacedAt: ZonedDateTime): JsonLdEntity = - JsonLdEntity( - members = members.mapValues { - if (JsonLdUtils.JSONLD_EXPANDED_ENTITY_CORE_MEMBERS.contains(it.key)) - it.value - else castAttributeValue(it.value).map { expandedAttributeInstance -> - expandedAttributeInstance.addDateTimeProperty( - NGSILD_CREATED_AT_PROPERTY, - replacedAt - ) as ExpandedAttributeInstance - } - } - .addDateTimeProperty(NGSILD_CREATED_AT_PROPERTY, createdAt) - .addDateTimeProperty(NGSILD_MODIFIED_AT_PROPERTY, replacedAt), - contexts = contexts - ) - - // FIXME kinda hacky but we often just need the id or type... how can it be improved? - val id by lazy { - (members[JSONLD_ID] ?: InternalErrorException("Could not extract id from JSON-LD entity")) as String - } - - val types by lazy { - (members[JSONLD_TYPE] ?: InternalErrorException("Could not extract type from JSON-LD entity")) - as List - } - - private fun Map.addDateTimeProperty(propertyKey: String, dateTime: ZonedDateTime?): Map = - if (dateTime != null) - this.plus(propertyKey to JsonLdUtils.buildNonReifiedTemporalValue(dateTime)) - else this -} - -fun CompactedJsonLdEntity.toKeyValues(): Map = - this.mapValues { (_, value) -> simplifyRepresentation(value) } - -private fun simplifyRepresentation(value: Any): Any { - return when (value) { - // entity property value is always a Map - is Map<*, *> -> simplifyValue(value as Map) - is List<*> -> value.map { - when (it) { - is Map<*, *> -> simplifyValue(it as Map) - // we keep @context value as it is (List) - else -> it - } - } - // we keep id and type values as they are (String) - else -> value - } -} - -private fun simplifyValue(value: Map): Any { - return when (value["type"]) { - "Property", "GeoProperty" -> value.getOrDefault("value", value) - "Relationship" -> value.getOrDefault("object", value) - else -> value - } -} - -fun CompactedJsonLdEntity.toGeoJson(geometryProperty: String): Map { - val geometryAttributeContent = this[geometryProperty] as? Map - val geometryPropertyValue = geometryAttributeContent?.let { - if (it.containsKey(JSONLD_VALUE_TERM)) it[JSONLD_VALUE_TERM] - else it - } - - return mapOf( - JSONLD_ID_TERM to this[JSONLD_ID_TERM]!!, - JSONLD_TYPE_TERM to FEATURE_TYPE, - GEOMETRY_PROPERTY_TERM to geometryPropertyValue, - PROPERTIES_PROPERTY_TERM to this.filter { it.key != JSONLD_ID_TERM } - ) -} - -fun CompactedJsonLdEntity.withoutSysAttrs(): Map = - this.filter { - !JsonLdUtils.NGSILD_SYSATTRS_TERMS.contains(it.key) - }.mapValues { - when (it.value) { - is Map<*, *> -> (it.value as Map<*, *>).minus(JsonLdUtils.NGSILD_SYSATTRS_TERMS) - is List<*> -> (it.value as List<*>).map { valueInstance -> - when (valueInstance) { - is Map<*, *> -> valueInstance.minus(JsonLdUtils.NGSILD_SYSATTRS_TERMS) - // we keep @context value as it is (List) - else -> valueInstance - } - } - else -> it.value - } - } - -fun CompactedJsonLdEntity.toFinalRepresentation( - ngsiLdDataRepresentation: NgsiLdDataRepresentation -): Any = - this.let { - if (!ngsiLdDataRepresentation.includeSysAttrs) it.withoutSysAttrs() - else it - }.let { - if (ngsiLdDataRepresentation.attributeRepresentation == AttributeRepresentation.SIMPLIFIED) it.toKeyValues() - else it - }.let { - if (ngsiLdDataRepresentation.entityRepresentation == EntityRepresentation.GEO_JSON) - // geometryProperty is not null when GeoJSON representation is asked (defaults to location) - it.toGeoJson(ngsiLdDataRepresentation.geometryProperty!!) - else it - } - -fun List.toFinalRepresentation( - ngsiLdDataRepresentation: NgsiLdDataRepresentation -): Any = - this.map { - it.toFinalRepresentation(ngsiLdDataRepresentation) - }.let { - if (ngsiLdDataRepresentation.entityRepresentation == EntityRepresentation.GEO_JSON) { - mapOf( - JSONLD_TYPE_TERM to FEATURE_COLLECTION_TYPE, - FEATURES_PROPERTY_TERM to it - ) - } else it - } diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt index 5ea38c174..3b441fb85 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt @@ -388,7 +388,7 @@ suspend fun ExpandedAttributeInstances.toNgsiLdAttribute( else -> BadRequestDataException("Unrecognized type for $attributeName").left() } -suspend fun JsonLdEntity.toNgsiLdEntity(): Either = +suspend fun ExpandedEntity.toNgsiLdEntity(): Either = NgsiLdEntity.create(this.members, this.contexts) fun ExpandedAttributeInstance.getDatasetId(): URI? = diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt index 9c1cdb66e..17006a98c 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt @@ -126,7 +126,7 @@ fun checkContext(httpHeaders: HttpHeaders, body: Map): Either, httpHeaders: HttpHeaders -): Either>> = either { +): Either>> = either { val body = requestBody.awaitFirst().deserializeAsMap() .checkNamesAreNgsiLdSupported().bind() .checkContentIsNgsiLdSupported().bind() diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/GeoQueryUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/GeoQueryUtils.kt index dbf6b1268..a82b3996f 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/GeoQueryUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/GeoQueryUtils.kt @@ -109,7 +109,7 @@ private fun prepareGeorelQuery(georel: String): Triple } } else Triple(georel, null, null) -fun buildGeoQuery(geoQuery: GeoQuery, target: JsonLdEntity? = null): String { +fun buildGeoQuery(geoQuery: GeoQuery, target: ExpandedEntity? = null): String { val targetWKTCoordinates = """ (select jsonb_path_query_first(#{TARGET}#, '$."${geoQuery.geoproperty}"."$NGSILD_GEOPROPERTY_VALUE"[0]')->>'$JSONLD_VALUE') diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt index 517746ce3..bb4eaa246 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt @@ -46,10 +46,13 @@ object JsonLdUtils { const val NGSILD_PREFIX = "https://uri.etsi.org/ngsi-ld/" const val NGSILD_DEFAULT_VOCAB = "https://uri.etsi.org/ngsi-ld/default-context/" + const val NGSILD_PROPERTY_TERM = "Property" val NGSILD_PROPERTY_TYPE = AttributeType("https://uri.etsi.org/ngsi-ld/Property") const val NGSILD_PROPERTY_VALUE = "https://uri.etsi.org/ngsi-ld/hasValue" + const val NGSILD_GEOPROPERTY_TERM = "GeoProperty" val NGSILD_GEOPROPERTY_TYPE = AttributeType("https://uri.etsi.org/ngsi-ld/GeoProperty") const val NGSILD_GEOPROPERTY_VALUE = "https://uri.etsi.org/ngsi-ld/hasValue" + const val NGSILD_RELATIONSHIP_TERM = "Relationship" val NGSILD_RELATIONSHIP_TYPE = AttributeType("https://uri.etsi.org/ngsi-ld/Relationship") const val NGSILD_RELATIONSHIP_HAS_OBJECT = "https://uri.etsi.org/ngsi-ld/hasObject" @@ -144,26 +147,26 @@ object JsonLdUtils { suspend fun expandJsonLdEntityF( input: Map, contexts: List - ): Either = + ): Either = runCatching { doJsonLdExpansion(input, contexts) }.fold({ - JsonLdEntity(it, contexts).right() + ExpandedEntity(it, contexts).right() }, { if (it is APIException) it.left() else it.toAPIException().left() }) - suspend fun expandJsonLdEntityF(input: Map): Either = + suspend fun expandJsonLdEntityF(input: Map): Either = expandJsonLdEntityF(input, extractContextFromInput(input)) - suspend fun expandJsonLdEntity(input: Map, contexts: List): JsonLdEntity = - JsonLdEntity(doJsonLdExpansion(input, contexts), contexts) + suspend fun expandJsonLdEntity(input: Map, contexts: List): ExpandedEntity = + ExpandedEntity(doJsonLdExpansion(input, contexts), contexts) - suspend fun expandJsonLdEntity(input: String, contexts: List): JsonLdEntity = + suspend fun expandJsonLdEntity(input: String, contexts: List): ExpandedEntity = expandJsonLdEntity(input.deserializeAsMap(), contexts) - suspend fun expandJsonLdEntity(input: String): JsonLdEntity { + suspend fun expandJsonLdEntity(input: String): ExpandedEntity { val jsonInput = input.deserializeAsMap() return expandJsonLdEntity(jsonInput, extractContextFromInput(jsonInput)) } @@ -410,22 +413,22 @@ object JsonLdUtils { } fun compactEntity( - jsonLdEntity: JsonLdEntity, + expandedEntity: ExpandedEntity, context: String? = null, mediaType: MediaType = JSON_LD_MEDIA_TYPE - ): CompactedJsonLdEntity = - compactEntity(jsonLdEntity, context?.let { listOf(context) } ?: emptyList(), mediaType) + ): CompactedEntity = + compactEntity(expandedEntity, context?.let { listOf(context) } ?: emptyList(), mediaType) fun compactEntity( - jsonLdEntity: JsonLdEntity, + expandedEntity: ExpandedEntity, contexts: List, mediaType: MediaType = JSON_LD_MEDIA_TYPE - ): CompactedJsonLdEntity { + ): CompactedEntity { val allContexts = addCoreContextIfMissing(contexts) return if (mediaType == MediaType.APPLICATION_JSON) JsonLd.compact( - JsonDocument.of(serializeObject(jsonLdEntity.members).byteInputStream()), + JsonDocument.of(serializeObject(expandedEntity.members).byteInputStream()), JsonDocument.of(buildContextDocument(allContexts)) ) .options(jsonLdOptions) @@ -435,7 +438,7 @@ object JsonLdUtils { .mapValues(restoreGeoPropertyValue()) else JsonLd.compact( - JsonDocument.of(serializeObject(jsonLdEntity.members).byteInputStream()), + JsonDocument.of(serializeObject(expandedEntity.members).byteInputStream()), JsonDocument.of(buildContextDocument(allContexts)) ) .options(jsonLdOptions) @@ -454,10 +457,10 @@ object JsonLdUtils { } fun compactEntities( - entities: List, + entities: List, context: String, mediaType: MediaType - ): List = + ): List = entities.map { compactEntity(it, context, mediaType) } @@ -492,27 +495,27 @@ object JsonLdUtils { .mapValues(restoreGeoPropertyValue()) fun filterCompactedEntityOnAttributes( - input: CompactedJsonLdEntity, + input: CompactedEntity, includedAttributes: Set - ): CompactedJsonLdEntity { - val identity: (CompactedJsonLdEntity) -> CompactedJsonLdEntity = { it } + ): CompactedEntity { + val identity: (CompactedEntity) -> CompactedEntity = { it } return filterEntityOnAttributes(input, identity, includedAttributes, false) } fun filterJsonLdEntitiesOnAttributes( - jsonLdEntities: List, + jsonLdEntities: List, includedAttributes: Set - ): List = + ): List = jsonLdEntities.filter { it.containsAnyOf(includedAttributes) } .map { - JsonLdEntity(filterJsonLdEntityOnAttributes(it, includedAttributes), it.contexts) + ExpandedEntity(filterJsonLdEntityOnAttributes(it, includedAttributes), it.contexts) } fun filterJsonLdEntityOnAttributes( - input: JsonLdEntity, + input: ExpandedEntity, includedAttributes: Set ): Map { - val inputToMap = { i: JsonLdEntity -> i.members } + val inputToMap = { i: ExpandedEntity -> i.members } return filterEntityOnAttributes(input, inputToMap, includedAttributes, true) } diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/QueryUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/QueryUtils.kt index a319c0b0e..8049082e4 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/QueryUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/QueryUtils.kt @@ -1,6 +1,6 @@ package com.egm.stellio.shared.util -import com.egm.stellio.shared.model.JsonLdEntity +import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE @@ -106,7 +106,7 @@ fun buildTypeQuery(rawQuery: String, target: List? = null): String } // Transforms an NGSI-LD Query Language parameter as per clause 4.9 to a query supported by JsonPath. -fun buildQQuery(rawQuery: String, contexts: List, target: JsonLdEntity? = null): String { +fun buildQQuery(rawQuery: String, contexts: List, target: ExpandedEntity? = null): String { val rawQueryWithPatternEscaped = rawQuery.escapeRegexpPattern() return rawQueryWithPatternEscaped.replace(qPattern.toRegex()) { matchResult -> @@ -221,7 +221,7 @@ private fun transformQQueryToSqlJsonPath( """.trimIndent() } -fun buildScopeQQuery(scopeQQuery: String, target: JsonLdEntity? = null): String = +fun buildScopeQQuery(scopeQQuery: String, target: ExpandedEntity? = null): String = scopeQQuery.replace(scopeSelectionRegex) { matchResult -> when { matchResult.value.endsWith('#') -> diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/model/JsonLdEntityTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt similarity index 98% rename from shared/src/test/kotlin/com/egm/stellio/shared/model/JsonLdEntityTests.kt rename to shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt index a2a3a283a..b3c1b4b8a 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/model/JsonLdEntityTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt @@ -14,7 +14,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.fail import org.springframework.http.MediaType -class JsonLdEntityTests { +class ExpandedEntityTests { private val normalizedJson = """ @@ -120,12 +120,12 @@ class JsonLdEntityTests { @Test fun `it should find an expanded attribute contained in the entity`() { - val jsonLdEntity = JsonLdEntity( + val expandedEntity = ExpandedEntity( mapOf(INCOMING_PROPERTY to "", OUTGOING_PROPERTY to ""), DEFAULT_CONTEXTS ) - val checkResult = jsonLdEntity.checkContainsAnyOf(setOf(TEMPERATURE_PROPERTY, INCOMING_PROPERTY)) + val checkResult = expandedEntity.checkContainsAnyOf(setOf(TEMPERATURE_PROPERTY, INCOMING_PROPERTY)) checkResult.fold({ fail("it should have found one of the requested attributes") @@ -134,12 +134,12 @@ class JsonLdEntityTests { @Test fun `it should not find an expanded attribute contained in the entity`() { - val jsonLdEntity = JsonLdEntity( + val expandedEntity = ExpandedEntity( mapOf(INCOMING_PROPERTY to "", OUTGOING_PROPERTY to "", JSONLD_ID to "urn:ngsi-ld:Entity:01"), DEFAULT_CONTEXTS ) - val checkResult = jsonLdEntity.checkContainsAnyOf(setOf(TEMPERATURE_PROPERTY, NGSILD_NAME_PROPERTY)) + val checkResult = expandedEntity.checkContainsAnyOf(setOf(TEMPERATURE_PROPERTY, NGSILD_NAME_PROPERTY)) checkResult.fold({ assertEquals( diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt index ea29d15b8..34dec47b0 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt @@ -1,7 +1,7 @@ package com.egm.stellio.shared.util import com.egm.stellio.shared.model.BadRequestDataException -import com.egm.stellio.shared.model.CompactedJsonLdEntity +import com.egm.stellio.shared.model.CompactedEntity import com.egm.stellio.shared.model.LdContextNotAvailableException import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_HAS_OBJECT @@ -64,7 +64,7 @@ class JsonLdUtilsTests { val normalizedMap = mapper.readValue(normalizedJson, Map::class.java) val resultMap = JsonLdUtils.filterCompactedEntityOnAttributes( - normalizedMap as CompactedJsonLdEntity, + normalizedMap as CompactedEntity, setOf("brandName", "location") ) diff --git a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/NgsiLdTestUtils.kt b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/NgsiLdTestUtils.kt index c82a9aa0f..e4d8d8160 100644 --- a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/NgsiLdTestUtils.kt +++ b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/NgsiLdTestUtils.kt @@ -1,12 +1,12 @@ package com.egm.stellio.shared.util -import com.egm.stellio.shared.model.JsonLdEntity +import com.egm.stellio.shared.model.ExpandedEntity suspend fun gimmeSimpleEntityWithGeoProperty( propertyKey: String, longitude: Double, latitude: Double -): JsonLdEntity { +): ExpandedEntity { val entityWithLocation = """ { @@ -32,14 +32,14 @@ suspend fun gimmeSimpleEntityWithAttributes( id: String, type: String, contexts: List = listOf(APIC_COMPOUND_CONTEXT) -): JsonLdEntity = +): ExpandedEntity = gimmeSimpleEntityWithAttributes(id, listOf(type), contexts) suspend fun gimmeSimpleEntityWithAttributes( id: String, types: List, contexts: List = listOf(APIC_COMPOUND_CONTEXT) -): JsonLdEntity { +): ExpandedEntity { val entity = mapOf( "id" to id, "type" to types diff --git a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt index 5cc675c85..862f9bf73 100644 --- a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt +++ b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt @@ -14,7 +14,7 @@ fun loadSampleData(filename: String = "beehive.jsonld"): String { return String(sampleData.inputStream.readAllBytes()) } -suspend fun loadAndExpandSampleData(filename: String = "beehive.jsonld"): JsonLdEntity { +suspend fun loadAndExpandSampleData(filename: String = "beehive.jsonld"): ExpandedEntity { val sampleData = ClassPathResource("/ngsild/$filename") return expandJsonLdEntity(String(sampleData.inputStream.readAllBytes())) } @@ -50,7 +50,7 @@ fun loadMinimalEntityWithSap( } """.trimIndent() -suspend fun String.sampleDataToNgsiLdEntity(): Either> { +suspend fun String.sampleDataToNgsiLdEntity(): Either> { val jsonLdEntity = expandJsonLdEntity(this) return when (val ngsiLdEntity = jsonLdEntity.toNgsiLdEntity()) { is Either.Left -> BadRequestDataException("Invalid NGSI-LD input for sample data: $this").left() diff --git a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/job/TimeIntervalNotificationJob.kt b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/job/TimeIntervalNotificationJob.kt index abb31519c..3a191a29d 100644 --- a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/job/TimeIntervalNotificationJob.kt +++ b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/job/TimeIntervalNotificationJob.kt @@ -2,7 +2,7 @@ package com.egm.stellio.subscription.job import arrow.core.flatten import com.egm.stellio.shared.config.ApplicationProperties -import com.egm.stellio.shared.model.CompactedJsonLdEntity +import com.egm.stellio.shared.model.CompactedEntity import com.egm.stellio.shared.model.EntitySelector import com.egm.stellio.shared.util.* import com.egm.stellio.shared.web.NGSILD_TENANT_HEADER @@ -62,7 +62,7 @@ class TimeIntervalNotificationJob( } suspend fun sendNotification( - compactedEntity: CompactedJsonLdEntity, + compactedEntity: CompactedEntity, subscription: Subscription ): Triple = notificationService.callSubscriber( @@ -74,7 +74,7 @@ class TimeIntervalNotificationJob( tenantUri: URI, subscription: Subscription, contextLink: String - ): Set = + ): Set = // if a subscription has a "timeInterval" member defined, it has at least one "entities" member // because it can't have a "watchedAttributes" member subscription.entities!! @@ -96,7 +96,7 @@ class TimeIntervalNotificationJob( ) } - suspend fun getEntities(tenantUri: URI, paramRequest: String, contextLink: String): List = + suspend fun getEntities(tenantUri: URI, paramRequest: String, contextLink: String): List = webClient.get() .uri("/ngsi-ld/v1/entities$paramRequest") .header(HttpHeaders.LINK, contextLink) diff --git a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/listener/EntityEventListenerService.kt b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/listener/EntityEventListenerService.kt index 81346f134..53cc9d02d 100644 --- a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/listener/EntityEventListenerService.kt +++ b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/listener/EntityEventListenerService.kt @@ -122,10 +122,10 @@ class EntityEventListenerService( contexts: List ): Either = either { logger.debug("Attributes considered in the event: {}", updatedAttributes) - val jsonLdEntity = JsonLdEntity(entityPayload.deserializeAsMap(), contexts) + val expandedEntity = ExpandedEntity(entityPayload.deserializeAsMap(), contexts) mono { notificationService.notifyMatchingSubscribers( - jsonLdEntity, + expandedEntity, updatedAttributes, notificationTrigger ) diff --git a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/NotificationService.kt b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/NotificationService.kt index 7a2dfc0fb..a38ed1d1a 100644 --- a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/NotificationService.kt +++ b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/NotificationService.kt @@ -3,8 +3,8 @@ package com.egm.stellio.subscription.service import arrow.core.Either import arrow.core.raise.either import com.egm.stellio.shared.model.APIException -import com.egm.stellio.shared.model.CompactedJsonLdEntity -import com.egm.stellio.shared.model.JsonLdEntity +import com.egm.stellio.shared.model.CompactedEntity +import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.model.toKeyValues import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.compactEntity @@ -33,16 +33,16 @@ class NotificationService( private val logger = LoggerFactory.getLogger(javaClass) suspend fun notifyMatchingSubscribers( - jsonLdEntity: JsonLdEntity, + expandedEntity: ExpandedEntity, updatedAttributes: Set, notificationTrigger: NotificationTrigger ): Either>> = either { - subscriptionService.getMatchingSubscriptions(jsonLdEntity, updatedAttributes, notificationTrigger).bind() + subscriptionService.getMatchingSubscriptions(expandedEntity, updatedAttributes, notificationTrigger).bind() .map { val filteredEntity = - filterJsonLdEntityOnAttributes(jsonLdEntity, it.notification.attributes?.toSet().orEmpty()) + filterJsonLdEntityOnAttributes(expandedEntity, it.notification.attributes?.toSet().orEmpty()) val compactedEntity = compactEntity( - JsonLdEntity(filteredEntity, it.contexts), + ExpandedEntity(filteredEntity, it.contexts), it.contexts, MediaType.valueOf(it.notification.endpoint.accept.accept) ) @@ -52,7 +52,7 @@ class NotificationService( suspend fun callSubscriber( subscription: Subscription, - entity: CompactedJsonLdEntity + entity: CompactedEntity ): Triple { val mediaType = MediaType.valueOf(subscription.notification.endpoint.accept.accept) val tenantUri = getTenantFromContext() @@ -93,7 +93,7 @@ class NotificationService( } private fun buildNotificationData( - compactedEntity: CompactedJsonLdEntity, + compactedEntity: CompactedEntity, subscription: Subscription ): List> { val processedEntity = if (subscription.notification.format == NotificationParams.FormatType.KEY_VALUES) diff --git a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/SubscriptionService.kt b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/SubscriptionService.kt index fd9f5305a..a2f92c482 100644 --- a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/SubscriptionService.kt +++ b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/SubscriptionService.kt @@ -544,16 +544,16 @@ class SubscriptionService( } suspend fun getMatchingSubscriptions( - jsonLdEntity: JsonLdEntity, + expandedEntity: ExpandedEntity, updatedAttributes: Set, notificationTrigger: NotificationTrigger ): Either> = either { getMatchingSubscriptions(updatedAttributes, notificationTrigger) .filter { - val entitiesFilter = prepareEntitiesQuery(it.entities, jsonLdEntity) - val qFilter = prepareQQuery(it.q?.decode(), jsonLdEntity, it.contexts) - val scopeFilter = prepareScopeQQuery(it.scopeQ?.decode(), jsonLdEntity) - val geoQueryFilter = prepareGeoQuery(it.geoQ, jsonLdEntity) + val entitiesFilter = prepareEntitiesQuery(it.entities, expandedEntity) + val qFilter = prepareQQuery(it.q?.decode(), expandedEntity, it.contexts) + val scopeFilter = prepareScopeQQuery(it.scopeQ?.decode(), expandedEntity) + val geoQueryFilter = prepareGeoQuery(it.geoQ, expandedEntity) val query = listOfNotNull(entitiesFilter, qFilter, scopeFilter, geoQueryFilter) if (query.isEmpty()) @@ -568,19 +568,19 @@ class SubscriptionService( suspend fun prepareEntitiesQuery( entities: Set?, - jsonLdEntity: JsonLdEntity + expandedEntity: ExpandedEntity ): String? = if (entities.isNullOrEmpty()) null else { - val entityTypes = jsonLdEntity.types + val entityTypes = expandedEntity.types entities.joinToString(" OR ") { val typeSelectionQuery = buildTypeQuery(it.typeSelection, entityTypes) val idQuery = if (it.id == null) null - else " '${jsonLdEntity.id}' = '${it.id}' " + else " '${expandedEntity.id}' = '${it.id}' " val idPatternQuery = if (it.idPattern == null) null - else " '${jsonLdEntity.id}' ~ '${it.idPattern}' " + else " '${expandedEntity.id}' ~ '${it.idPattern}' " listOfNotNull(typeSelectionQuery, idQuery, idPatternQuery) .joinToString(separator = " AND ", prefix = "(", postfix = ")") } @@ -588,22 +588,22 @@ class SubscriptionService( suspend fun prepareQQuery( query: String?, - jsonLdEntity: JsonLdEntity, + expandedEntity: ExpandedEntity, contexts: List ): String? = if (query == null) null - else buildQQuery(query, contexts, jsonLdEntity) + else buildQQuery(query, contexts, expandedEntity) suspend fun prepareScopeQQuery( scopeQ: String?, - jsonLdEntity: JsonLdEntity + expandedEntity: ExpandedEntity ): String? = if (scopeQ == null) null - else buildScopeQQuery(scopeQ, jsonLdEntity) + else buildScopeQQuery(scopeQ, expandedEntity) suspend fun prepareGeoQuery( geoQ: GeoQ?, - jsonLdEntity: JsonLdEntity + expandedEntity: ExpandedEntity ): String? = if (geoQ == null) null else buildGeoQuery( @@ -614,7 +614,7 @@ class SubscriptionService( geoproperty = geoQ.geoproperty, wktCoordinates = WKTCoordinates(geoQ.pgisGeometry!!) ), - jsonLdEntity + expandedEntity ) suspend fun updateSubscriptionNotification( From ce6a5fdd2c2469cf87b6e3758c8593deabc44793 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Sat, 23 Dec 2023 18:03:28 +0100 Subject: [PATCH 04/19] fix(temporal): sysAttrs handling for temporal queries --- .../egm/stellio/shared/model/CompactedEntity.kt | 15 +++++++++------ .../shared/model/NgsiLdDataRepresentation.kt | 4 +++- .../com/egm/stellio/shared/util/ApiUtils.kt | 4 +++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt index 57ee9f302..2f2448df5 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt @@ -54,28 +54,31 @@ fun CompactedEntity.toGeoJson(geometryProperty: String): Map { ) } -fun CompactedEntity.withoutSysAttrs(): Map = - this.filter { - !NGSILD_SYSATTRS_TERMS.contains(it.key) +fun CompactedEntity.withoutSysAttrs(sysAttrToKeep: String?): Map { + val sysAttrsToRemove = NGSILD_SYSATTRS_TERMS.minus(sysAttrToKeep) + return this.filter { + !sysAttrsToRemove.contains(it.key) }.mapValues { when (it.value) { - is Map<*, *> -> (it.value as Map<*, *>).minus(NGSILD_SYSATTRS_TERMS) + is Map<*, *> -> (it.value as Map<*, *>).minus(sysAttrsToRemove) is List<*> -> (it.value as List<*>).map { valueInstance -> when (valueInstance) { - is Map<*, *> -> valueInstance.minus(NGSILD_SYSATTRS_TERMS) + is Map<*, *> -> valueInstance.minus(sysAttrsToRemove) // we keep @context value as it is (List) else -> valueInstance } } + else -> it.value } } +} fun CompactedEntity.toFinalRepresentation( ngsiLdDataRepresentation: NgsiLdDataRepresentation ): Any = this.let { - if (!ngsiLdDataRepresentation.includeSysAttrs) it.withoutSysAttrs() + if (!ngsiLdDataRepresentation.includeSysAttrs) it.withoutSysAttrs(ngsiLdDataRepresentation.timeproperty) else it }.let { if (ngsiLdDataRepresentation.attributeRepresentation == AttributeRepresentation.SIMPLIFIED) it.toKeyValues() diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdDataRepresentation.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdDataRepresentation.kt index 8eb1a5619..4e69b84fc 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdDataRepresentation.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdDataRepresentation.kt @@ -13,7 +13,9 @@ data class NgsiLdDataRepresentation( val includeSysAttrs: Boolean, // In the case of GeoJSON Entity representation, // this parameter indicates which GeoProperty to use for the toplevel geometry field - val geometryProperty: String? = null + val geometryProperty: String? = null, + // In the case of a temporal property, do not remove this property if sysAttrs is not asked + val timeproperty: String? = null ) enum class AttributeRepresentation { diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt index 17006a98c..0bf415ccf 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt @@ -185,12 +185,14 @@ fun parseRepresentations( if (entityRepresentation == EntityRepresentation.GEO_JSON) requestParams.getFirst(QUERY_PARAM_GEOMETRY_PROPERTY) ?: NGSILD_LOCATION_TERM else null + val timeproperty = requestParams.getFirst("timeproperty") return NgsiLdDataRepresentation( entityRepresentation, attributeRepresentation, includeSysAttrs, - geometryProperty + geometryProperty, + timeproperty ) } From 8428f0e906d9731e6f22adeeba9e686d45550f4d Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Mon, 25 Dec 2023 18:03:36 +0100 Subject: [PATCH 05/19] fix(temporal): aggregated and simplified representation of attributes and scopes --- .../egm/stellio/search/model/EntityPayload.kt | 61 ++----- .../search/scope/TemporalScopeBuilder.kt | 95 ++++++++--- .../service/TemporalEntityAttributeService.kt | 4 +- .../search/util/TemporalEntityBuilder.kt | 44 +++-- .../stellio/search/model/EntityModelTests.kt | 26 +-- .../search/scope/TemporalScopeBuilderTests.kt | 12 +- .../search/service/QueryServiceTests.kt | 6 +- .../egm/stellio/search/support/TestUtils.kt | 4 +- .../util/TemporalEntityParameterizedSource.kt | 1 + .../stellio/search/web/EntityHandlerTests.kt | 12 +- .../beehive_aggregated_outgoing.jsonld | 94 +++++++--- ...ti_instances_string_temporal_values.jsonld | 34 +++- ...ing_multi_instances_temporal_values.jsonld | 68 ++++++-- ...ut_datasetId_string_temporal_values.jsonld | 34 +++- ...s_without_datasetId_temporal_values.jsonld | 34 +++- ...hip_multi_instances_temporal_values.jsonld | 49 +++++- .../beehive_scope_multi_instances.jsonld | 40 +++-- ...ope_multi_instances_temporal_values.jsonld | 56 ++++-- .../query/two_beehives_temporal_values.json | 92 ++++++---- ...oral_values_property_and_relationship.json | 160 +++++++++++------- .../scope_aggregated_instances.json | 90 +++++++--- .../expectations/scope_full_instances.json | 44 +++-- .../scope_temporal_values_instances.json | 60 +++++-- .../egm/stellio/shared/model/NgsiLdEntity.kt | 4 +- .../egm/stellio/shared/util/JsonLdUtils.kt | 14 +- .../com/egm/stellio/shared/util/QueryUtils.kt | 4 +- .../stellio/shared/util/JsonLdUtilsTests.kt | 10 +- 27 files changed, 761 insertions(+), 391 deletions(-) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/model/EntityPayload.kt b/search-service/src/main/kotlin/com/egm/stellio/search/model/EntityPayload.kt index 90b95ebe7..a7f583513 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/model/EntityPayload.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/model/EntityPayload.kt @@ -4,20 +4,13 @@ import com.egm.stellio.shared.util.AuthContextModel import com.egm.stellio.shared.util.AuthContextModel.SpecificAccessPolicy import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID_TERM import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE_TERM import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE_TERM import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_TERM import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_TERM import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_TERM import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue -import com.egm.stellio.shared.util.JsonLdUtils.compactTerm import io.r2dbc.postgresql.codec.Json import java.net.URI import java.time.ZonedDateTime @@ -34,50 +27,22 @@ data class EntityPayload( val payload: Json, val specificAccessPolicy: SpecificAccessPolicy? = null ) { - fun serializeProperties( - withCompactTerms: Boolean = false, - contexts: List = emptyList() - ): Map { + fun serializeProperties(): Map { val resultEntity = mutableMapOf() - // "manual" compaction is used for temporal entities where temporalValues representation and aggregations - // are badly handled by the normal JSON-LD compaction process (lists of lists are lost mainly) - if (withCompactTerms) { - resultEntity[JSONLD_ID_TERM] = entityId.toString() - // as we are "manually" compacting the type, handle the case where there is just one of it - // and convey it as a string (instead of a list of 1) - resultEntity[JSONLD_TYPE_TERM] = - types.map { compactTerm(it, contexts) } - .let { if (it.size > 1) it else it.first() } - scopes?.run { - resultEntity[NGSILD_SCOPE_TERM] = this - } - specificAccessPolicy?.run { - resultEntity[AuthContextModel.AUTH_TERM_SAP] = mapOf( - JSONLD_TYPE_TERM to "Property", - JSONLD_VALUE_TERM to this - ) - } - - resultEntity[NGSILD_CREATED_AT_TERM] = createdAt - modifiedAt?.run { - resultEntity[NGSILD_MODIFIED_AT_TERM] = this - } - } else { - resultEntity[JSONLD_ID] = entityId.toString() - resultEntity[JSONLD_TYPE] = types - scopes?.run { - resultEntity[NGSILD_SCOPE_PROPERTY] = this.map { - mapOf(JSONLD_VALUE to it) - } - } - specificAccessPolicy?.run { - resultEntity[AuthContextModel.AUTH_PROP_SAP] = buildExpandedPropertyValue(this) + resultEntity[JSONLD_ID] = entityId.toString() + resultEntity[JSONLD_TYPE] = types + scopes?.run { + resultEntity[NGSILD_SCOPE_PROPERTY] = this.map { + mapOf(JSONLD_VALUE to it) } + } + specificAccessPolicy?.run { + resultEntity[AuthContextModel.AUTH_PROP_SAP] = buildExpandedPropertyValue(this) + } - resultEntity[NGSILD_CREATED_AT_PROPERTY] = buildNonReifiedTemporalValue(createdAt) - modifiedAt?.run { - resultEntity[NGSILD_MODIFIED_AT_PROPERTY] = buildNonReifiedTemporalValue(this) - } + resultEntity[NGSILD_CREATED_AT_PROPERTY] = buildNonReifiedTemporalValue(createdAt) + modifiedAt?.run { + resultEntity[NGSILD_MODIFIED_AT_PROPERTY] = buildNonReifiedTemporalValue(this) } return resultEntity diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilder.kt b/search-service/src/main/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilder.kt index 5d1e8f346..828052a70 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilder.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilder.kt @@ -3,9 +3,15 @@ package com.egm.stellio.search.scope import com.egm.stellio.search.model.EntityPayload import com.egm.stellio.search.model.TemporalEntitiesQuery import com.egm.stellio.search.model.TemporalQuery -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE_TERM -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE_TERM -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_TERM +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_LIST +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PREFIX +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_TYPE +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUES +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue object TemporalScopeBuilder { @@ -19,40 +25,23 @@ object TemporalScopeBuilder { emptyMap() // if no history but entity has a scope, add an empty scope list (no history in the given time range) else if (scopeInstances.isEmpty()) - mapOf(NGSILD_SCOPE_TERM to emptyList()) + mapOf(NGSILD_SCOPE_PROPERTY to emptyList()) else if (temporalEntitiesQuery.withAggregatedValues) buildScopeAggregatedRepresentation( scopeInstances, temporalEntitiesQuery.temporalQuery.aggrMethods!! ) else if (temporalEntitiesQuery.withTemporalValues) - mapOf( - NGSILD_SCOPE_TERM to mapOf( - JSONLD_TYPE_TERM to "Property", - "values" to scopeInstances.map { - it as SimplifiedScopeInstanceResult - listOf(it.scopes, it.time) - } - ) - ) + buildScopeSimplifiedRepresentation(scopeInstances) else - mapOf( - NGSILD_SCOPE_TERM to scopeInstances.map { - it as FullScopeInstanceResult - mapOf( - JSONLD_TYPE_TERM to "Property", - JSONLD_VALUE_TERM to it.scopes, - it.timeproperty to it.time - ) - } - ) + buildScopeFullRepresentation(scopeInstances) private fun buildScopeAggregatedRepresentation( scopeHistory: List, aggrMethods: List ): Map { val attributeInstance = mutableMapOf( - JSONLD_TYPE_TERM to "Property" + JSONLD_TYPE to listOf(NGSILD_PROPERTY_TYPE.uri) ) aggrMethods.forEach { aggregate -> @@ -65,11 +54,61 @@ object TemporalScopeBuilder { .filter { aggregateResult -> aggregateResult.aggregate == aggregate } - attributeInstance[aggregate.method] = valuesForAggregate.map { aggregateResult -> - listOf(aggregateResult.value, aggregateResult.startDateTime, aggregateResult.endDateTime) - } + attributeInstance[NGSILD_PREFIX + aggregate.method] = listOf( + mapOf( + JSONLD_LIST to valuesForAggregate.map { aggregateResult -> + mapOf( + JSONLD_LIST to listOf( + mapOf(JSONLD_VALUE to aggregateResult.value), + mapOf(JSONLD_VALUE to aggregateResult.startDateTime), + mapOf(JSONLD_VALUE to aggregateResult.endDateTime) + ) + ) + } + ) + ) } - return mapOf(NGSILD_SCOPE_TERM to attributeInstance.toMap()) + return mapOf(NGSILD_SCOPE_PROPERTY to attributeInstance.toMap()) + } + + private fun buildScopeSimplifiedRepresentation( + scopeHistory: List + ): Map { + val attributeInstance = mapOf( + JSONLD_TYPE to listOf(NGSILD_PROPERTY_TYPE.uri), + NGSILD_PROPERTY_VALUES to listOf( + mapOf( + JSONLD_LIST to scopeHistory.map { scopeInstanceResult -> + scopeInstanceResult as SimplifiedScopeInstanceResult + mapOf( + JSONLD_LIST to listOf( + mapOf( + JSONLD_LIST to scopeInstanceResult.scopes.map { mapOf(JSONLD_VALUE to it) } + ), + mapOf(JSONLD_VALUE to scopeInstanceResult.time) + ) + ) + } + ) + ) + ) + + return mapOf(NGSILD_SCOPE_PROPERTY to attributeInstance) } + + private fun buildScopeFullRepresentation( + scopeHistory: List + ): Map = + mapOf( + NGSILD_SCOPE_PROPERTY to scopeHistory.map { scopeInstanceResult -> + scopeInstanceResult as FullScopeInstanceResult + mapOf( + JSONLD_TYPE to listOf(NGSILD_PROPERTY_TYPE.uri), + NGSILD_PROPERTY_VALUE to scopeInstanceResult.scopes.map { mapOf(JSONLD_VALUE to it) }, + NGSILD_PREFIX + scopeInstanceResult.timeproperty to + buildNonReifiedTemporalValue(scopeInstanceResult.time) + ) + } + ) } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt index 14ca0b4b0..ca0bd6442 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt @@ -16,7 +16,7 @@ import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PREFIX import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_HAS_OBJECT +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity import com.egm.stellio.shared.util.JsonLdUtils.getAttributeFromExpandedAttributes @@ -856,7 +856,7 @@ class TemporalEntityAttributeService( ) TemporalEntityAttribute.AttributeType.Relationship -> Triple( - getPropertyValueFromMap(attributePayload, NGSILD_RELATIONSHIP_HAS_OBJECT)!! as String, + getPropertyValueFromMap(attributePayload, NGSILD_RELATIONSHIP_OBJECT)!! as String, null, null ) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt index 8bbfa7e71..2b3b74bb8 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt @@ -5,12 +5,17 @@ import com.egm.stellio.search.scope.TemporalScopeBuilder import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SUB import com.egm.stellio.shared.util.ExpandedTerm +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_LIST import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE_TERM import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_GEOPROPERTY_TYPE +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_GEOPROPERTY_VALUES +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_JSONPROPERTY_VALUES import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PREFIX +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUES +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECTS import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedPropertyValue import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue @@ -119,14 +124,23 @@ object TemporalEntityBuilder { } val valuesKey = when (it.key.attributeType) { - TemporalEntityAttribute.AttributeType.Property -> "values" - TemporalEntityAttribute.AttributeType.Relationship -> "objects" - TemporalEntityAttribute.AttributeType.GeoProperty -> "values" + TemporalEntityAttribute.AttributeType.Property -> NGSILD_PROPERTY_VALUES + TemporalEntityAttribute.AttributeType.Relationship -> NGSILD_RELATIONSHIP_OBJECTS + TemporalEntityAttribute.AttributeType.GeoProperty -> NGSILD_GEOPROPERTY_VALUES } - attributeInstance[valuesKey] = it.value.map { attributeInstanceResult -> - attributeInstanceResult as SimplifiedAttributeInstanceResult - listOf(attributeInstanceResult.value, attributeInstanceResult.time) - } + attributeInstance[valuesKey] = listOf( + mapOf( + JSONLD_LIST to it.value.map { attributeInstanceResult -> + attributeInstanceResult as SimplifiedAttributeInstanceResult + mapOf( + JSONLD_LIST to listOf( + mapOf(JSONLD_VALUE to attributeInstanceResult.value), + mapOf(JSONLD_VALUE to attributeInstanceResult.time) + ) + ) + } + ) + ) attributeInstance.toMap() } } @@ -162,9 +176,19 @@ object TemporalEntityBuilder { val resultsForAggregate = aggregatedResultsForTEA.filter { aggregateResult -> aggregateResult.aggregate.method == aggregate.method } - attributeInstance[aggregate.method] = resultsForAggregate.map { aggregateResult -> - listOf(aggregateResult.value, aggregateResult.startDateTime, aggregateResult.endDateTime) - } + attributeInstance[NGSILD_PREFIX + aggregate.method] = listOf( + mapOf( + JSONLD_LIST to resultsForAggregate.map { aggregateResult -> + mapOf( + JSONLD_LIST to listOf( + mapOf(JSONLD_VALUE to aggregateResult.value), + mapOf(JSONLD_VALUE to aggregateResult.startDateTime), + mapOf(JSONLD_VALUE to aggregateResult.endDateTime) + ) + ) + } + ) + ) } attributeInstance.toMap() diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/model/EntityModelTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/model/EntityModelTests.kt index 96729ba09..ef98bac40 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/model/EntityModelTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/model/EntityModelTests.kt @@ -2,7 +2,8 @@ package com.egm.stellio.search.model import com.egm.stellio.search.support.EMPTY_JSON_PAYLOAD import com.egm.stellio.shared.util.* -import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test import java.time.Instant import java.time.ZoneOffset @@ -32,28 +33,7 @@ class EntityModelTests { fun `it should serialize entityPayload with SAP if present`() { val entityPayloadWithSAP = entityPayload.copy(specificAccessPolicy = AuthContextModel.SpecificAccessPolicy.AUTH_WRITE) - val serializedEntity = entityPayloadWithSAP.serializeProperties(false) + val serializedEntity = entityPayloadWithSAP.serializeProperties() assertTrue(serializedEntity.contains(AuthContextModel.AUTH_PROP_SAP)) } - - @Test - fun `it should serialize entityPayload with SAP if present and compact term if specified`() { - val entityPayloadWithSAP = - entityPayload.copy(specificAccessPolicy = AuthContextModel.SpecificAccessPolicy.AUTH_WRITE) - val serializedEntity = entityPayloadWithSAP.serializeProperties( - withCompactTerms = true, - contexts = listOf(APIC_COMPOUND_CONTEXT) - ) - val specificAccessPolicy = mapOf( - JsonLdUtils.JSONLD_TYPE_TERM to "Property", - JsonLdUtils.JSONLD_VALUE_TERM to AuthContextModel.SpecificAccessPolicy.AUTH_WRITE - ) - assertTrue(serializedEntity.contains(AuthContextModel.AUTH_TERM_SAP)) - assertEquals(specificAccessPolicy, serializedEntity[AuthContextModel.AUTH_TERM_SAP]) - - assertTrue(serializedEntity.contains(JsonLdUtils.JSONLD_ID_TERM)) - assertTrue(serializedEntity.contains(JsonLdUtils.JSONLD_TYPE_TERM)) - assertEquals("urn:ngsi-ld:beehive:01", serializedEntity[JsonLdUtils.JSONLD_ID_TERM]) - assertEquals(BEEHIVE_COMPACT_TYPE, serializedEntity[JsonLdUtils.JSONLD_TYPE_TERM]) - } } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilderTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilderTests.kt index f5717cf86..4085c9aa8 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilderTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilderTests.kt @@ -66,7 +66,7 @@ class TemporalScopeBuilderTests { aggrMethods = listOf(TemporalQuery.Aggregate.SUM, TemporalQuery.Aggregate.AVG) ) - val scopehHistory = TemporalScopeBuilder.buildScopeAttributeInstances( + val scopeHistory = TemporalScopeBuilder.buildScopeAttributeInstances( entityPayload, scopeInstances, TemporalEntitiesQuery( @@ -80,7 +80,7 @@ class TemporalScopeBuilderTests { assertJsonPayloadsAreEqual( loadSampleData("expectations/scope_aggregated_instances.json"), - JsonUtils.serializeObject(scopehHistory) + JsonUtils.serializeObject(scopeHistory) ) } @@ -104,7 +104,7 @@ class TemporalScopeBuilderTests { Instant.now().atZone(ZoneOffset.UTC).minusHours(1), ) - val scopehHistory = TemporalScopeBuilder.buildScopeAttributeInstances( + val scopeHistory = TemporalScopeBuilder.buildScopeAttributeInstances( entityPayload, scopeInstances, TemporalEntitiesQuery( @@ -118,7 +118,7 @@ class TemporalScopeBuilderTests { assertJsonPayloadsAreEqual( loadSampleData("expectations/scope_temporal_values_instances.json"), - JsonUtils.serializeObject(scopehHistory) + JsonUtils.serializeObject(scopeHistory) ) } @@ -144,7 +144,7 @@ class TemporalScopeBuilderTests { Instant.now().atZone(ZoneOffset.UTC).minusHours(1), ) - val scopehHistory = TemporalScopeBuilder.buildScopeAttributeInstances( + val scopeHistory = TemporalScopeBuilder.buildScopeAttributeInstances( entityPayload, scopeInstances, TemporalEntitiesQuery( @@ -158,7 +158,7 @@ class TemporalScopeBuilderTests { assertJsonPayloadsAreEqual( loadSampleData("expectations/scope_full_instances.json"), - JsonUtils.serializeObject(scopehHistory) + JsonUtils.serializeObject(scopeHistory) ) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/QueryServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/QueryServiceTests.kt index 1a1c3c834..84b1b71d9 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/QueryServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/QueryServiceTests.kt @@ -398,7 +398,11 @@ class QueryServiceTests { "@type": [ "https://uri.etsi.org/ngsi-ld/Property" ], - "avg": [] + "https://uri.etsi.org/ngsi-ld/avg":[ + { + "@list":[] + } + ] } ] } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/support/TestUtils.kt b/search-service/src/test/kotlin/com/egm/stellio/search/support/TestUtils.kt index 10e2c3752..c8bb3db3a 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/support/TestUtils.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/support/TestUtils.kt @@ -12,7 +12,7 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_INSTANCE_ID_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_HAS_OBJECT +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedPropertyValue import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue @@ -39,7 +39,7 @@ fun buildAttributeInstancePayload( if (attributeType == TemporalEntityAttribute.AttributeType.Property) put(NGSILD_PROPERTY_VALUE, listOf(mapOf(JSONLD_VALUE to value))) else - put(NGSILD_RELATIONSHIP_HAS_OBJECT, listOf(mapOf(JSONLD_ID to value.toString()))) + put(NGSILD_RELATIONSHIP_OBJECT, listOf(mapOf(JSONLD_ID to value.toString()))) } ) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityParameterizedSource.kt b/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityParameterizedSource.kt index 496606c42..d617e2fd3 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityParameterizedSource.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityParameterizedSource.kt @@ -552,6 +552,7 @@ class TemporalEntityParameterizedSource { beehivePropertyMultiInstancesTemporalValues, beehivePropertyMultiInstancesStringValuesTemporalValues, beehivePropertyMultiInstancesWithoutDatasetIdStringValuesTemporalValues, + beehiveRelationshipMultiInstancesTemporalValues, beehiveScopeMultiInstancesTemporalValues, beehiveScopeMultiInstances ) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt index cfb5e4bfd..f162f6320 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt @@ -23,7 +23,7 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATE_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_HAS_OBJECT +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_TIME_TYPE import com.ninjasquad.springmockk.MockkBean @@ -381,7 +381,7 @@ class EntityHandlerTests { ), "https://uri.etsi.org/ngsi-ld/default-context/rel1" to mapOf( JSONLD_TYPE to NGSILD_RELATIONSHIP_TYPE.uri, - NGSILD_RELATIONSHIP_HAS_OBJECT to mapOf( + NGSILD_RELATIONSHIP_OBJECT to mapOf( JSONLD_ID to "urn:ngsi-ld:Entity:1234" ) ) @@ -698,7 +698,7 @@ class EntityHandlerTests { "https://uri.etsi.org/ngsi-ld/default-context/managedBy" to mapOf( JSONLD_TYPE to "https://uri.etsi.org/ngsi-ld/Relationship", - NGSILD_RELATIONSHIP_HAS_OBJECT to mapOf( + NGSILD_RELATIONSHIP_OBJECT to mapOf( JSONLD_ID to "urn:ngsi-ld:Beekeeper:1230" ), NGSILD_DATASET_ID_PROPERTY to mapOf( @@ -741,7 +741,7 @@ class EntityHandlerTests { "https://uri.etsi.org/ngsi-ld/default-context/managedBy" to mapOf( JSONLD_TYPE to "https://uri.etsi.org/ngsi-ld/Relationship", - NGSILD_RELATIONSHIP_HAS_OBJECT to mapOf( + NGSILD_RELATIONSHIP_OBJECT to mapOf( JSONLD_ID to "urn:ngsi-ld:Beekeeper:1230" ), NGSILD_DATASET_ID_PROPERTY to mapOf( @@ -784,13 +784,13 @@ class EntityHandlerTests { listOf( mapOf( JSONLD_TYPE to "https://uri.etsi.org/ngsi-ld/Relationship", - NGSILD_RELATIONSHIP_HAS_OBJECT to mapOf( + NGSILD_RELATIONSHIP_OBJECT to mapOf( JSONLD_ID to "urn:ngsi-ld:Beekeeper:1229" ) ), mapOf( JSONLD_TYPE to "https://uri.etsi.org/ngsi-ld/Relationship", - NGSILD_RELATIONSHIP_HAS_OBJECT to mapOf( + NGSILD_RELATIONSHIP_OBJECT to mapOf( JSONLD_ID to "urn:ngsi-ld:Beekeeper:1230" ), NGSILD_DATASET_ID_PROPERTY to mapOf( diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_aggregated_outgoing.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_aggregated_outgoing.jsonld index c43c7446a..0c8f276ea 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_aggregated_outgoing.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_aggregated_outgoing.jsonld @@ -9,33 +9,75 @@ "@value": "$now" } ], - "https://ontology.eglobalmark.com/apic#outgoing": [{ - "@type": [ - "https://uri.etsi.org/ngsi-ld/Property" - ], - "sum": [ - [ - 12, - "2020-03-25T08:29:17.965206Z", - "2020-03-25T10:29:17.965206Z" + "https://ontology.eglobalmark.com/apic#outgoing": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" ], - [ - 14, - "2020-03-25T10:29:17.965206Z", - "2020-03-25T12:29:17.965206Z" - ] - ], - "avg": [ - [ - 2, - "2020-03-25T08:29:17.965206Z", - "2020-03-25T10:29:17.965206Z" + "https://uri.etsi.org/ngsi-ld/sum": [ + { + "@list": [ + { + "@list": [ + { + "@value": 12 + }, + { + "@value": "2020-03-25T08:29:17.965206Z" + }, + { + "@value": "2020-03-25T10:29:17.965206Z" + } + ] + }, + { + "@list": [ + { + "@value": 14 + }, + { + "@value": "2020-03-25T10:29:17.965206Z" + }, + { + "@value": "2020-03-25T12:29:17.965206Z" + } + ] + } + ] + } ], - [ - 2.5, - "2020-03-25T10:29:17.965206Z", - "2020-03-25T12:29:17.965206Z" + "https://uri.etsi.org/ngsi-ld/avg": [ + { + "@list": [ + { + "@list": [ + { + "@value": 2 + }, + { + "@value": "2020-03-25T08:29:17.965206Z" + }, + { + "@value": "2020-03-25T10:29:17.965206Z" + } + ] + }, + { + "@list": [ + { + "@value": 2.5 + }, + { + "@value": "2020-03-25T10:29:17.965206Z" + }, + { + "@value": "2020-03-25T12:29:17.965206Z" + } + ] + } + ] + } ] - ] - }] + } + ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_temporal_values.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_temporal_values.jsonld index c5db8bad0..43d0a2df8 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_temporal_values.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_string_temporal_values.jsonld @@ -13,15 +13,31 @@ "@id": "urn:ngsi-ld:Dataset:45678" } ], - "values": [ - [ - "Beehive_incoming_123", - "2020-03-25T08:29:17.965206Z" - ], - [ - "Beehive_incoming_124", - "2020-03-25T08:33:17.965206Z" - ] + "https://uri.etsi.org/ngsi-ld/hasValues": [ + { + "@list": [ + { + "@list": [ + { + "@value": "Beehive_incoming_123" + }, + { + "@value": "2020-03-25T08:29:17.965206Z" + } + ] + }, + { + "@list": [ + { + "@value": "Beehive_incoming_124" + }, + { + "@value": "2020-03-25T08:33:17.965206Z" + } + ] + } + ] + } ] } ] diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_temporal_values.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_temporal_values.jsonld index 7c8daa4c4..caad2fe99 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_temporal_values.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_temporal_values.jsonld @@ -13,15 +13,31 @@ "@id": "urn:ngsi-ld:Dataset:01234" } ], - "values": [ - [ - 550.0, - "2020-03-25T08:29:17.965206Z" - ], - [ - 650.0, - "2020-03-25T08:33:17.965206Z" - ] + "https://uri.etsi.org/ngsi-ld/hasValues": [ + { + "@list": [ + { + "@list": [ + { + "@value": 550.0 + }, + { + "@value": "2020-03-25T08:29:17.965206Z" + } + ] + }, + { + "@list": [ + { + "@value": 650.0 + }, + { + "@value": "2020-03-25T08:33:17.965206Z" + } + ] + } + ] + } ] }, { @@ -33,15 +49,31 @@ "@id": "urn:ngsi-ld:Dataset:45678" } ], - "values": [ - [ - 487.0, - "2020-03-25T08:29:17.965206Z" - ], - [ - 698.0, - "2020-03-25T08:33:17.965206Z" - ] + "https://uri.etsi.org/ngsi-ld/hasValues": [ + { + "@list": [ + { + "@list": [ + { + "@value": 487.0 + }, + { + "@value": "2020-03-25T08:29:17.965206Z" + } + ] + }, + { + "@list": [ + { + "@value": 698.0 + }, + { + "@value": "2020-03-25T08:33:17.965206Z" + } + ] + } + ] + } ] } ] diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_string_temporal_values.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_string_temporal_values.jsonld index 3052c693a..97a3674fb 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_string_temporal_values.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_string_temporal_values.jsonld @@ -8,15 +8,31 @@ "@type": [ "https://uri.etsi.org/ngsi-ld/Property" ], - "values": [ - [ - "Beehive_incoming_123", - "2020-03-25T08:29:17.965206Z" - ], - [ - "Beehive_incoming_124", - "2020-03-25T08:33:17.965206Z" - ] + "https://uri.etsi.org/ngsi-ld/hasValues": [ + { + "@list": [ + { + "@list": [ + { + "@value": "Beehive_incoming_123" + }, + { + "@value": "2020-03-25T08:29:17.965206Z" + } + ] + }, + { + "@list": [ + { + "@value": "Beehive_incoming_124" + }, + { + "@value": "2020-03-25T08:33:17.965206Z" + } + ] + } + ] + } ] } ] diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_temporal_values.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_temporal_values.jsonld index dee0dde72..3c1e0dbca 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_temporal_values.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_incoming_multi_instances_without_datasetId_temporal_values.jsonld @@ -8,15 +8,31 @@ "@type": [ "https://uri.etsi.org/ngsi-ld/Property" ], - "values": [ - [ - 550.0, - "2020-03-25T08:29:17.965206Z" - ], - [ - 650.0, - "2020-03-25T08:33:17.965206Z" - ] + "https://uri.etsi.org/ngsi-ld/hasValues": [ + { + "@list": [ + { + "@list": [ + { + "@value": 550.0 + }, + { + "@value": "2020-03-25T08:29:17.965206Z" + } + ] + }, + { + "@list": [ + { + "@value": 650.0 + }, + { + "@value": "2020-03-25T08:33:17.965206Z" + } + ] + } + ] + } ] } ] diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_relationship_multi_instances_temporal_values.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_relationship_multi_instances_temporal_values.jsonld index 126edbb3a..cb274be28 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_relationship_multi_instances_temporal_values.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_relationship_multi_instances_temporal_values.jsonld @@ -1,9 +1,44 @@ { - "id" : "urn:ngsi-ld:BeeHive:TESTC", - "type" : "BeeHive", - "incoming" : { - "type" : "Relationship", - "datasetId" : "urn:ngsi-ld:Dataset:45678", - "objects" : [ ["urn:ngsi-ld:Entity:1234","2020-03-25T08:29:17.965206Z"], ["urn:ngsi-ld:Entity:5678","2020-03-25T08:33:17.965206Z"] ] - } + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Relationship" + ], + "https://uri.etsi.org/ngsi-ld/datasetId": [ + { + "@id": "urn:ngsi-ld:Dataset:45678" + } + ], + "https://uri.etsi.org/ngsi-ld/hasObjects": [ + { + "@list": [ + { + "@list": [ + { + "@value": "urn:ngsi-ld:Entity:1234" + }, + { + "@value": "2020-03-25T08:29:17.965206Z" + } + ] + }, + { + "@list": [ + { + "@value": "urn:ngsi-ld:Entity:5678" + }, + { + "@value": "2020-03-25T08:33:17.965206Z" + } + ] + } + ] + } + ] + } + ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances.jsonld index eb7de4823..fa9d04beb 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances.jsonld @@ -3,21 +3,41 @@ "@type": [ "https://ontology.eglobalmark.com/apic#BeeHive" ], - "scope": [ + "https://uri.etsi.org/ngsi-ld/scope": [ { - "type": "Property", - "value": [ - "/A/B", - "/C/D" + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" ], - "modifiedAt": "2020-03-25T08:29:17.965206Z" + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": "/A/B" + }, + { + "@value": "/C/D" + } + ], + "https://uri.etsi.org/ngsi-ld/modifiedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:29:17.965206Z" + } + ] }, { - "type": "Property", - "value": [ - "/C/D" + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": "/C/D" + } ], - "modifiedAt": "2020-03-25T09:29:17.965206Z" + "https://uri.etsi.org/ngsi-ld/modifiedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T09:29:17.965206Z" + } + ] } ] } diff --git a/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances_temporal_values.jsonld b/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances_temporal_values.jsonld index da45f53f1..c5e79b2be 100644 --- a/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances_temporal_values.jsonld +++ b/search-service/src/test/resources/ngsild/expectations/beehive_scope_multi_instances_temporal_values.jsonld @@ -3,22 +3,46 @@ "@type": [ "https://ontology.eglobalmark.com/apic#BeeHive" ], - "scope": { - "type": "Property", - "values": [ - [ - [ - "/A/B", - "/C/D" - ], - "2020-03-25T08:29:17.965206Z" - ], - [ - [ - "/C/D" - ], - "2020-03-25T09:29:17.965206Z" - ] + "https://uri.etsi.org/ngsi-ld/scope": { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/hasValues": [ + { + "@list": [ + { + "@list": [ + { + "@list": [ + { + "@value": "/A/B" + }, + { + "@value": "/C/D" + } + ] + }, + { + "@value": "2020-03-25T08:29:17.965206Z" + } + ] + }, + { + "@list": [ + { + "@list": [ + { + "@value": "/C/D" + } + ] + }, + { + "@value": "2020-03-25T09:29:17.965206Z" + } + ] + } + ] + } ] } } diff --git a/search-service/src/test/resources/ngsild/expectations/query/two_beehives_temporal_values.json b/search-service/src/test/resources/ngsild/expectations/query/two_beehives_temporal_values.json index 3a2c3cee7..b0b4425e9 100644 --- a/search-service/src/test/resources/ngsild/expectations/query/two_beehives_temporal_values.json +++ b/search-service/src/test/resources/ngsild/expectations/query/two_beehives_temporal_values.json @@ -1,40 +1,60 @@ [ - { - "@id": "urn:ngsi-ld:BeeHive:TESTC", - "@type": [ - "https://ontology.eglobalmark.com/apic#BeeHive" - ], - "https://ontology.eglobalmark.com/apic#incoming": [ - { - "@type": [ - "https://uri.etsi.org/ngsi-ld/Property" - ], - "values": [ - [ - 20, - "2020-03-25T08:33:17.965206Z" - ] + { + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/hasValues": [ + { + "@list": [ + { + "@list": [ + { + "@value": 20 + }, + { + "@value": "2020-03-25T08:33:17.965206Z" + } + ] + } ] - } - ] - }, - { - "@id": "urn:ngsi-ld:BeeHive:TESTD", - "@type": [ - "https://ontology.eglobalmark.com/apic#BeeHive" - ], - "https://ontology.eglobalmark.com/apic#outgoing": [ - { - "@type": [ - "https://uri.etsi.org/ngsi-ld/Property" - ], - "values": [ - [ - 25, - "2020-03-25T08:33:17.965206Z" - ] + } + ] + } + ] + }, + { + "@id": "urn:ngsi-ld:BeeHive:TESTD", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#outgoing": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/hasValues": [ + { + "@list": [ + { + "@list": [ + { + "@value": 25 + }, + { + "@value": "2020-03-25T08:33:17.965206Z" + } + ] + } ] - } - ] - } + } + ] + } + ] + } ] diff --git a/search-service/src/test/resources/ngsild/expectations/query/two_entities_temporal_values_property_and_relationship.json b/search-service/src/test/resources/ngsild/expectations/query/two_entities_temporal_values_property_and_relationship.json index 4984fdd85..1a907f952 100644 --- a/search-service/src/test/resources/ngsild/expectations/query/two_entities_temporal_values_property_and_relationship.json +++ b/search-service/src/test/resources/ngsild/expectations/query/two_entities_temporal_values_property_and_relationship.json @@ -1,66 +1,106 @@ [ - { - "@id": "urn:ngsi-ld:BeeHive:TESTC", - "@type": [ - "https://ontology.eglobalmark.com/apic#BeeHive" - ], - "https://ontology.eglobalmark.com/apic#incoming": [ - { - "@type": [ - "https://uri.etsi.org/ngsi-ld/Property" - ], - "values": [ - [ - 20, - "2020-03-25T08:33:17.965206Z" - ] + { + "@id": "urn:ngsi-ld:BeeHive:TESTC", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#incoming": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/hasValues": [ + { + "@list": [ + { + "@list": [ + { + "@value": 20 + }, + { + "@value": "2020-03-25T08:33:17.965206Z" + } + ] + } ] - } - ], - "https://ontology.eglobalmark.com/egm#managedBy": [ - { - "@type": [ - "https://uri.etsi.org/ngsi-ld/Relationship" - ], - "objects": [ - [ - "urn:ngsi-ld:Beekeeper:1234", - "2020-03-25T08:33:17.965206Z" - ] + } + ] + } + ], + "https://ontology.eglobalmark.com/egm#managedBy": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Relationship" + ], + "https://uri.etsi.org/ngsi-ld/hasObjects": [ + { + "@list": [ + { + "@list": [ + { + "@value": "urn:ngsi-ld:Beekeeper:1234" + }, + { + "@value": "2020-03-25T08:33:17.965206Z" + } + ] + } ] - } - ] - }, - { - "@id": "urn:ngsi-ld:BeeHive:TESTD", - "@type": [ - "https://ontology.eglobalmark.com/apic#BeeHive" - ], - "https://ontology.eglobalmark.com/apic#outgoing": [ - { - "@type": [ - "https://uri.etsi.org/ngsi-ld/Property" - ], - "values": [ - [ - 25, - "2020-03-25T08:33:17.965206Z" - ] + } + ] + } + ] + }, + { + "@id": "urn:ngsi-ld:BeeHive:TESTD", + "@type": [ + "https://ontology.eglobalmark.com/apic#BeeHive" + ], + "https://ontology.eglobalmark.com/apic#outgoing": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/hasValues": [ + { + "@list": [ + { + "@list": [ + { + "@value": 25 + }, + { + "@value": "2020-03-25T08:33:17.965206Z" + } + ] + } ] - } - ], - "https://ontology.eglobalmark.com/egm#managedBy": [ - { - "@type": [ - "https://uri.etsi.org/ngsi-ld/Relationship" - ], - "objects": [ - [ - "urn:ngsi-ld:Beekeeper:5678", - "2020-03-25T08:33:17.965206Z" - ] + } + ] + } + ], + "https://ontology.eglobalmark.com/egm#managedBy": [ + { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Relationship" + ], + "https://uri.etsi.org/ngsi-ld/hasObjects": [ + { + "@list": [ + { + "@list": [ + { + "@value": "urn:ngsi-ld:Beekeeper:5678" + }, + { + "@value": "2020-03-25T08:33:17.965206Z" + } + ] + } ] - } - ] - } + } + ] + } + ] + } ] diff --git a/search-service/src/test/resources/ngsild/expectations/scope_aggregated_instances.json b/search-service/src/test/resources/ngsild/expectations/scope_aggregated_instances.json index 2f282f079..4001e0fc8 100644 --- a/search-service/src/test/resources/ngsild/expectations/scope_aggregated_instances.json +++ b/search-service/src/test/resources/ngsild/expectations/scope_aggregated_instances.json @@ -1,29 +1,71 @@ { - "scope": { - "type": "Property", - "sum": [ - [ - 12, - "2020-03-25T08:29:17.965206Z", - "2020-03-25T10:29:18.965206Z" - ], - [ - 14, - "2020-03-25T10:29:18.965206Z", - "2020-03-25T12:29:19.965206Z" - ] + "https://uri.etsi.org/ngsi-ld/scope": { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" ], - "avg": [ - [ - 2, - "2020-03-25T08:29:17.965206Z", - "2020-03-25T10:29:18.965206Z" - ], - [ - 2.5, - "2020-03-25T10:29:18.965206Z", - "2020-03-25T12:29:19.965206Z" - ] + "https://uri.etsi.org/ngsi-ld/sum": [ + { + "@list": [ + { + "@list": [ + { + "@value": 12 + }, + { + "@value": "2020-03-25T08:29:17.965206Z" + }, + { + "@value": "2020-03-25T10:29:18.965206Z" + } + ] + }, + { + "@list": [ + { + "@value": 14 + }, + { + "@value": "2020-03-25T10:29:18.965206Z" + }, + { + "@value": "2020-03-25T12:29:19.965206Z" + } + ] + } + ] + } + ], + "https://uri.etsi.org/ngsi-ld/avg": [ + { + "@list": [ + { + "@list": [ + { + "@value": 2 + }, + { + "@value": "2020-03-25T08:29:17.965206Z" + }, + { + "@value": "2020-03-25T10:29:18.965206Z" + } + ] + }, + { + "@list": [ + { + "@value": 2.5 + }, + { + "@value": "2020-03-25T10:29:18.965206Z" + }, + { + "@value": "2020-03-25T12:29:19.965206Z" + } + ] + } + ] + } ] } } diff --git a/search-service/src/test/resources/ngsild/expectations/scope_full_instances.json b/search-service/src/test/resources/ngsild/expectations/scope_full_instances.json index 5fa547855..c25bcfc57 100644 --- a/search-service/src/test/resources/ngsild/expectations/scope_full_instances.json +++ b/search-service/src/test/resources/ngsild/expectations/scope_full_instances.json @@ -1,20 +1,42 @@ { - "scope": [ + "https://uri.etsi.org/ngsi-ld/scope": [ { - "type": "Property", - "value": [ - "/A/B", - "/B/C" + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" ], - "observedAt": "2020-03-25T08:29:17.965206Z" + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": "/A/B" + }, + { + "@value": "/B/C" + } + ], + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:29:17.965206Z" + } + ] }, { - "type": "Property", - "value": [ - "/B/C", - "/D/E" + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/hasValue": [ + { + "@value": "/B/C" + }, + { + "@value": "/D/E" + } ], - "observedAt": "2020-03-25T08:30:17.965206Z" + "https://uri.etsi.org/ngsi-ld/observedAt": [ + { + "@type": "https://uri.etsi.org/ngsi-ld/DateTime", + "@value": "2020-03-25T08:30:17.965206Z" + } + ] } ] } diff --git a/search-service/src/test/resources/ngsild/expectations/scope_temporal_values_instances.json b/search-service/src/test/resources/ngsild/expectations/scope_temporal_values_instances.json index 11907f86a..08b333aec 100644 --- a/search-service/src/test/resources/ngsild/expectations/scope_temporal_values_instances.json +++ b/search-service/src/test/resources/ngsild/expectations/scope_temporal_values_instances.json @@ -1,21 +1,47 @@ { - "scope": { - "type": "Property", - "values": [ - [ - [ - "/A/B", - "/B/C" - ], - "2020-03-25T08:29:17.965206Z" - ], - [ - [ - "/B/C", - "/D/E" - ], - "2020-03-25T08:30:17.965206Z" - ] + "https://uri.etsi.org/ngsi-ld/scope": { + "@type": [ + "https://uri.etsi.org/ngsi-ld/Property" + ], + "https://uri.etsi.org/ngsi-ld/hasValues": [ + { + "@list": [ + { + "@list": [ + { + "@list": [ + { + "@value": "/A/B" + }, + { + "@value": "/B/C" + } + ] + }, + { + "@value": "2020-03-25T08:29:17.965206Z" + } + ] + }, + { + "@list": [ + { + "@list": [ + { + "@value": "/B/C" + }, + { + "@value": "/D/E" + } + ] + }, + { + "@value": "2020-03-25T08:30:17.965206Z" + } + ] + } + ] + } ] } } diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt index 3b441fb85..a77565d8b 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt @@ -20,7 +20,7 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_HAS_OBJECT +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_UNIT_CODE_PROPERTY @@ -447,7 +447,7 @@ val NGSILD_PROPERTIES_CORE_MEMBERS = listOf( ).plus(NGSILD_ATTRIBUTES_CORE_MEMBERS) val NGSILD_RELATIONSHIPS_CORE_MEMBERS = listOf( - NGSILD_RELATIONSHIP_HAS_OBJECT + NGSILD_RELATIONSHIP_OBJECT ).plus(NGSILD_ATTRIBUTES_CORE_MEMBERS) val NGSILD_GEOPROPERTIES_CORE_MEMBERS = listOf( diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt index bb4eaa246..6dbcb1964 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt @@ -54,7 +54,12 @@ object JsonLdUtils { const val NGSILD_GEOPROPERTY_VALUE = "https://uri.etsi.org/ngsi-ld/hasValue" const val NGSILD_RELATIONSHIP_TERM = "Relationship" val NGSILD_RELATIONSHIP_TYPE = AttributeType("https://uri.etsi.org/ngsi-ld/Relationship") - const val NGSILD_RELATIONSHIP_HAS_OBJECT = "https://uri.etsi.org/ngsi-ld/hasObject" + const val NGSILD_RELATIONSHIP_OBJECT = "https://uri.etsi.org/ngsi-ld/hasObject" + + const val NGSILD_PROPERTY_VALUES = "https://uri.etsi.org/ngsi-ld/hasValues" + const val NGSILD_GEOPROPERTY_VALUES = "https://uri.etsi.org/ngsi-ld/hasValues" + const val NGSILD_RELATIONSHIP_OBJECTS = "https://uri.etsi.org/ngsi-ld/hasObjects" + const val NGSILD_JSONPROPERTY_VALUES = "https://uri.etsi.org/ngsi-ld/jsons" const val JSONLD_ID_TERM = "id" const val JSONLD_ID = "@id" @@ -63,6 +68,7 @@ object JsonLdUtils { const val JSONLD_VALUE_TERM = "value" const val JSONLD_VALUE = "@value" const val JSONLD_OBJECT = "object" + const val JSONLD_LIST = "@list" const val JSONLD_CONTEXT = "@context" const val NGSILD_SCOPE_TERM = "scope" const val NGSILD_SCOPE_PROPERTY = "https://uri.etsi.org/ngsi-ld/$NGSILD_SCOPE_TERM" @@ -540,9 +546,9 @@ object JsonLdUtils { fun extractRelationshipObject(name: String, values: Map>): Either { return values.right() .flatMap { - if (!it.containsKey(NGSILD_RELATIONSHIP_HAS_OBJECT)) + if (!it.containsKey(NGSILD_RELATIONSHIP_OBJECT)) BadRequestDataException("Relationship $name does not have an object field").left() - else it[NGSILD_RELATIONSHIP_HAS_OBJECT]!!.right() + else it[NGSILD_RELATIONSHIP_OBJECT]!!.right() } .flatMap { if (it.isEmpty()) @@ -649,7 +655,7 @@ object JsonLdUtils { listOf( mapOf( JSONLD_TYPE to listOf(NGSILD_RELATIONSHIP_TYPE.uri), - NGSILD_RELATIONSHIP_HAS_OBJECT to listOf(mapOf(JSONLD_ID to value.toString())) + NGSILD_RELATIONSHIP_OBJECT to listOf(mapOf(JSONLD_ID to value.toString())) ) ) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/QueryUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/QueryUtils.kt index 8049082e4..655aa909e 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/QueryUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/QueryUtils.kt @@ -4,7 +4,7 @@ import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_HAS_OBJECT +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT import com.egm.stellio.shared.util.JsonUtils.serializeObject import java.util.regex.Pattern @@ -191,7 +191,7 @@ private fun transformQQueryToSqlJsonPath( value.isURI() -> """ jsonb_path_exists(#{TARGET}#, - '$."${mainAttributePath[0]}"."$NGSILD_RELATIONSHIP_HAS_OBJECT"."$JSONLD_ID" ? (@ $operator ${'$'}value)', + '$."${mainAttributePath[0]}"."$NGSILD_RELATIONSHIP_OBJECT"."$JSONLD_ID" ? (@ $operator ${'$'}value)', '{ "value": ${value.quote()} }') """.trimIndent() value.isRange() -> { diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt index 34dec47b0..30432c012 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt @@ -4,7 +4,7 @@ import com.egm.stellio.shared.model.BadRequestDataException import com.egm.stellio.shared.model.CompactedEntity import com.egm.stellio.shared.model.LdContextNotAvailableException import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_HAS_OBJECT +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT import com.egm.stellio.shared.util.JsonLdUtils.addCoreContextIfMissing import com.egm.stellio.shared.util.JsonLdUtils.compactEntity import com.egm.stellio.shared.util.JsonLdUtils.expandAttributes @@ -137,7 +137,7 @@ class JsonLdUtilsTests { @Test fun `it should return an error if a relationship has an empty object`() { val relationshipValues = mapOf( - NGSILD_RELATIONSHIP_HAS_OBJECT to emptyList() + NGSILD_RELATIONSHIP_OBJECT to emptyList() ) val result = extractRelationshipObject("isARelationship", relationshipValues) @@ -150,7 +150,7 @@ class JsonLdUtilsTests { @Test fun `it should return an error if a relationship has an invalid object type`() { val relationshipValues = mapOf( - NGSILD_RELATIONSHIP_HAS_OBJECT to listOf("invalid") + NGSILD_RELATIONSHIP_OBJECT to listOf("invalid") ) val result = extractRelationshipObject("isARelationship", relationshipValues) @@ -163,7 +163,7 @@ class JsonLdUtilsTests { @Test fun `it should return an error if a relationship has object without id`() { val relationshipValues = mapOf( - NGSILD_RELATIONSHIP_HAS_OBJECT to listOf( + NGSILD_RELATIONSHIP_OBJECT to listOf( mapOf("@value" to "urn:ngsi-ld:T:misplacedRelationshipObject") ) ) @@ -179,7 +179,7 @@ class JsonLdUtilsTests { fun `it should extract the target object of a relationship`() { val relationshipObjectId = "urn:ngsi-ld:T:1" val relationshipValues = mapOf( - NGSILD_RELATIONSHIP_HAS_OBJECT to listOf( + NGSILD_RELATIONSHIP_OBJECT to listOf( mapOf("@id" to relationshipObjectId) ) ) From 674d90ce35a66ed862319820f7119d11d095dc1d Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Tue, 26 Dec 2023 08:38:58 +0100 Subject: [PATCH 06/19] feat(common): try to extract the wrapped cause when JSON-LD processing fails --- .../kotlin/com/egm/stellio/shared/model/ApiExceptions.kt | 6 +++--- .../main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt index ef84e6c1f..e96b51108 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt @@ -21,12 +21,12 @@ data class LdContextNotAvailableException(override val message: String) : APIExc data class NonexistentTenantException(override val message: String) : APIException(message) data class NotAcceptableException(override val message: String) : APIException(message) -fun Throwable.toAPIException(fallbackMessage: String = ""): APIException = +fun Throwable.toAPIException(specificMessage: String? = null): APIException = when (this) { is APIException -> this is JsonLdError -> if (this.code == JsonLdErrorCode.LOADING_REMOTE_CONTEXT_FAILED) - LdContextNotAvailableException("Unable to load remote context (cause was: $this)") + LdContextNotAvailableException(specificMessage ?: "Unable to load remote context (cause was: $this)") else BadRequestDataException("Unexpected error while parsing payload (cause was: $this)") - else -> BadRequestDataException(this.message ?: fallbackMessage) + else -> BadRequestDataException(specificMessage ?: this.localizedMessage) } diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt index 6dbcb1964..4e0a4c5ba 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt @@ -273,7 +273,7 @@ object JsonLdUtils { return deserializeObject(outputStream.toString()) } catch (e: JsonLdError) { logger.error("Unable to expand fragment with context $contexts: ${e.message}") - throw e.toAPIException() + throw e.toAPIException(e.cause?.cause?.message) } } From 045b491410b9417d963c6351476e91aad99937e8 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Thu, 28 Dec 2023 17:39:54 +0100 Subject: [PATCH 07/19] refactor: introduce an ExpandedMembers file for manipulation of expanded members --- .../authorization/EntityAccessRights.kt | 4 + .../listener/ObservationEventListener.kt | 1 - .../stellio/search/model/AttributeInstance.kt | 2 +- .../egm/stellio/search/model/EntitiesQuery.kt | 2 +- .../egm/stellio/search/model/EntityPayload.kt | 2 +- .../search/model/TemporalEntityAttribute.kt | 2 +- .../egm/stellio/search/scope/ScopeService.kt | 2 +- .../service/AttributeInstanceService.kt | 5 +- .../search/service/AttributeService.kt | 2 +- .../search/service/EntityEventService.kt | 2 - .../search/service/EntityTypeService.kt | 2 +- .../search/util/AttributeInstanceUtils.kt | 1 - .../search/util/TemporalEntityBuilder.kt | 2 +- .../search/web/TemporalEntityHandler.kt | 34 ++++ .../EntityAccessRightsServiceTests.kt | 1 + .../stellio/search/scope/ScopeServiceTests.kt | 1 + .../service/AttributeInstanceServiceTests.kt | 3 + .../search/support/BusinessObjectsFactory.kt | 2 + .../egm/stellio/shared/model/EntityEvent.kt | 1 - .../stellio/shared/model/ExpandedMembers.kt | 73 +++++++++ .../com/egm/stellio/shared/model/GeoQuery.kt | 1 - .../egm/stellio/shared/util/JsonLdUtils.kt | 151 +++--------------- .../com/egm/stellio/shared/util/QueryUtils.kt | 1 + .../shared/model/ExpandedMembersTests.kt | 33 ++++ .../stellio/shared/util/JsonLdUtilsTests.kt | 26 --- .../listener/EntityEventListenerService.kt | 1 - .../subscription/model/NotificationParams.kt | 2 +- .../subscription/model/Subscription.kt | 1 + .../service/NotificationService.kt | 2 +- 29 files changed, 186 insertions(+), 176 deletions(-) create mode 100644 shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt create mode 100644 shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt index d2be587cf..393cee58f 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt @@ -1,5 +1,9 @@ package com.egm.stellio.search.authorization +import com.egm.stellio.shared.model.ExpandedAttributeInstances +import com.egm.stellio.shared.model.ExpandedTerm +import com.egm.stellio.shared.model.addNonReifiedProperty +import com.egm.stellio.shared.model.addSubAttribute import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_RIGHT import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SAP diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/listener/ObservationEventListener.kt b/search-service/src/main/kotlin/com/egm/stellio/search/listener/ObservationEventListener.kt index 63d691b78..0952e8a93 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/listener/ObservationEventListener.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/listener/ObservationEventListener.kt @@ -9,7 +9,6 @@ import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdTerms import com.egm.stellio.shared.util.JsonUtils.deserializeAs -import com.egm.stellio.shared.util.toExpandedAttributes import com.egm.stellio.shared.web.NGSILD_TENANT_HEADER import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/model/AttributeInstance.kt b/search-service/src/main/kotlin/com/egm/stellio/search/model/AttributeInstance.kt index 6ddd9e5d2..65ea363d8 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/model/AttributeInstance.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/model/AttributeInstance.kt @@ -1,7 +1,7 @@ package com.egm.stellio.search.model +import com.egm.stellio.shared.model.ExpandedAttributeInstance import com.egm.stellio.shared.model.WKTCoordinates -import com.egm.stellio.shared.util.ExpandedAttributeInstance import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_INSTANCE_ID_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedPropertyValue diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/model/EntitiesQuery.kt b/search-service/src/main/kotlin/com/egm/stellio/search/model/EntitiesQuery.kt index 46ff3343a..0e88024e8 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/model/EntitiesQuery.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/model/EntitiesQuery.kt @@ -1,9 +1,9 @@ package com.egm.stellio.search.model import com.egm.stellio.shared.model.EntityTypeSelection +import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.model.GeoQuery import com.egm.stellio.shared.model.PaginationQuery -import com.egm.stellio.shared.util.ExpandedTerm import java.net.URI data class EntitiesQuery( diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/model/EntityPayload.kt b/search-service/src/main/kotlin/com/egm/stellio/search/model/EntityPayload.kt index a7f583513..3a182299e 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/model/EntityPayload.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/model/EntityPayload.kt @@ -1,8 +1,8 @@ package com.egm.stellio.search.model +import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.util.AuthContextModel import com.egm.stellio.shared.util.AuthContextModel.SpecificAccessPolicy -import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/model/TemporalEntityAttribute.kt b/search-service/src/main/kotlin/com/egm/stellio/search/model/TemporalEntityAttribute.kt index aebef447e..aa14909a4 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/model/TemporalEntityAttribute.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/model/TemporalEntityAttribute.kt @@ -1,6 +1,6 @@ package com.egm.stellio.search.model -import com.egm.stellio.shared.util.ExpandedTerm +import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_GEOPROPERTY_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_TYPE diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/scope/ScopeService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/scope/ScopeService.kt index 6badab4f6..e0449c352 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/scope/ScopeService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/scope/ScopeService.kt @@ -9,10 +9,10 @@ import com.egm.stellio.search.model.AttributeInstance.TemporalProperty import com.egm.stellio.search.model.TemporalEntityAttribute.AttributeValueType import com.egm.stellio.search.util.* import com.egm.stellio.shared.model.APIException +import com.egm.stellio.shared.model.ExpandedAttributeInstances import com.egm.stellio.shared.model.NgsiLdEntity import com.egm.stellio.shared.model.OperationNotSupportedException import com.egm.stellio.shared.model.getScopes -import com.egm.stellio.shared.util.ExpandedAttributeInstances import com.egm.stellio.shared.util.INCONSISTENT_VALUES_IN_AGGREGATION_MESSAGE import com.egm.stellio.shared.util.JsonLdUtils import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/AttributeInstanceService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/AttributeInstanceService.kt index f1d5831d1..378de78ee 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/AttributeInstanceService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/AttributeInstanceService.kt @@ -8,10 +8,7 @@ import arrow.fx.coroutines.parMap import com.egm.stellio.search.model.* import com.egm.stellio.search.model.AggregatedAttributeInstanceResult.AggregateResult import com.egm.stellio.search.util.* -import com.egm.stellio.shared.model.APIException -import com.egm.stellio.shared.model.OperationNotSupportedException -import com.egm.stellio.shared.model.ResourceNotFoundException -import com.egm.stellio.shared.model.toNgsiLdAttribute +import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.* import org.springframework.r2dbc.core.DatabaseClient import org.springframework.r2dbc.core.bind diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/AttributeService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/AttributeService.kt index 95d122747..363cdf661 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/AttributeService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/AttributeService.kt @@ -13,8 +13,8 @@ import com.egm.stellio.search.util.toInt import com.egm.stellio.search.util.toList import com.egm.stellio.search.util.toUri import com.egm.stellio.shared.model.APIException +import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.model.ResourceNotFoundException -import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.compactTerm import com.egm.stellio.shared.util.JsonLdUtils.compactTerms import com.egm.stellio.shared.util.attributeNotFoundMessage diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityEventService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityEventService.kt index b66486f5a..9c707ac49 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityEventService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityEventService.kt @@ -6,8 +6,6 @@ import com.egm.stellio.search.model.UpdateOperationResult import com.egm.stellio.search.model.UpdateResult import com.egm.stellio.search.model.UpdatedDetails import com.egm.stellio.shared.model.* -import com.egm.stellio.shared.util.ExpandedAttributes -import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.getAttributeFromExpandedAttributes import com.egm.stellio.shared.util.JsonUtils.serializeObject diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityTypeService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityTypeService.kt index 5508d6d40..b8369eda1 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityTypeService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityTypeService.kt @@ -8,8 +8,8 @@ import com.egm.stellio.search.util.allToMappedList import com.egm.stellio.search.util.toInt import com.egm.stellio.search.util.toUri import com.egm.stellio.shared.model.APIException +import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.model.ResourceNotFoundException -import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.compactTerm import com.egm.stellio.shared.util.JsonLdUtils.compactTerms import com.egm.stellio.shared.util.typeNotFoundMessage diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/util/AttributeInstanceUtils.kt b/search-service/src/main/kotlin/com/egm/stellio/search/util/AttributeInstanceUtils.kt index 8de606905..0ac1e037c 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/util/AttributeInstanceUtils.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/util/AttributeInstanceUtils.kt @@ -8,7 +8,6 @@ import com.egm.stellio.search.model.AttributeMetadata import com.egm.stellio.search.model.TemporalEntityAttribute import com.egm.stellio.search.model.TemporalEntityAttribute.AttributeValueType import com.egm.stellio.shared.model.* -import com.egm.stellio.shared.util.ExpandedAttributeInstance import com.egm.stellio.shared.util.JsonLdUtils.logger import com.egm.stellio.shared.util.JsonUtils.serializeObject import java.net.URI diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt index 2b3b74bb8..1439e755c 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt @@ -3,8 +3,8 @@ package com.egm.stellio.search.util import com.egm.stellio.search.model.* import com.egm.stellio.search.scope.TemporalScopeBuilder import com.egm.stellio.shared.model.ExpandedEntity +import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SUB -import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_LIST import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt index 8740f1e1d..e928dd366 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt @@ -1,6 +1,9 @@ package com.egm.stellio.search.web +import arrow.core.Either +import arrow.core.left import arrow.core.raise.either +import arrow.core.right import com.egm.stellio.search.authorization.AuthorizationService import com.egm.stellio.search.service.* import com.egm.stellio.search.util.composeTemporalEntitiesQuery @@ -352,4 +355,35 @@ class TemporalEntityHandler( missingPathErrorResponse( "Missing entity, attribute or instance id when trying to delete an attribute instance" ) + + private fun ExpandedAttributes.checkTemporalAttributeInstance(): Either = + this.values.all { expandedInstances -> + expandedInstances.all { expandedAttributePayloadEntry -> + JsonLdUtils.getPropertyValueFromMapAsDateTime( + expandedAttributePayloadEntry, + JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY + ) != null + } + }.let { + if (it) Unit.right() + else BadRequestDataException(invalidTemporalInstanceMessage()).left() + } + + private fun ExpandedAttributes.sorted(): ExpandedAttributes = + this.mapValues { + it.value.sortedByDescending { expandedAttributePayloadEntry -> + JsonLdUtils.getPropertyValueFromMapAsDateTime( + expandedAttributePayloadEntry, + JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY + ) + } + } + + private fun ExpandedAttributes.keepFirstInstances(): ExpandedAttributes = + this.mapValues { listOf(it.value.first()) } + + private fun ExpandedAttributes.removeFirstInstances(): ExpandedAttributes = + this.mapValues { + it.value.drop(1) + } } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt index 4f4731b73..e2b04c300 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt @@ -6,6 +6,7 @@ import com.egm.stellio.search.model.EntityPayload import com.egm.stellio.search.service.EntityPayloadService import com.egm.stellio.search.support.WithTimescaleContainer import com.egm.stellio.shared.model.AccessDeniedException +import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.model.PaginationQuery import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.AuthContextModel.AUTH_TERM_NAME diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/scope/ScopeServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/scope/ScopeServiceTests.kt index f343e1d02..26231989d 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/scope/ScopeServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/scope/ScopeServiceTests.kt @@ -6,6 +6,7 @@ import com.egm.stellio.search.service.EntityPayloadService import com.egm.stellio.search.support.WithKafkaContainer import com.egm.stellio.search.support.WithTimescaleContainer import com.egm.stellio.search.util.deserializeAsMap +import com.egm.stellio.shared.model.ExpandedAttributeInstance import com.egm.stellio.shared.model.PaginationQuery import com.egm.stellio.shared.model.getScopes import com.egm.stellio.shared.util.* diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt index d3f451c5d..287569299 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt @@ -2,7 +2,10 @@ package com.egm.stellio.search.service import com.egm.stellio.search.model.* import com.egm.stellio.search.support.* +import com.egm.stellio.shared.model.ExpandedAttributes import com.egm.stellio.shared.model.ResourceNotFoundException +import com.egm.stellio.shared.model.addNonReifiedTemporalProperty +import com.egm.stellio.shared.model.getSingleEntry import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt b/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt index ca4096e49..345310b45 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt @@ -2,6 +2,8 @@ package com.egm.stellio.search.support import com.egm.stellio.search.model.* import com.egm.stellio.shared.model.PaginationQuery +import com.egm.stellio.shared.model.addNonReifiedTemporalProperty +import com.egm.stellio.shared.model.getSingleEntry import com.egm.stellio.shared.util.* import java.util.UUID import kotlin.random.Random diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/EntityEvent.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/EntityEvent.kt index a618fa22f..8ef6476b1 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/EntityEvent.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/EntityEvent.kt @@ -1,6 +1,5 @@ package com.egm.stellio.shared.model -import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.web.DEFAULT_TENANT_URI import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.annotation.JsonSubTypes diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt new file mode 100644 index 000000000..3feeaf33e --- /dev/null +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt @@ -0,0 +1,73 @@ +package com.egm.stellio.shared.model + +import com.egm.stellio.shared.util.JsonLdUtils +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue +import java.time.ZonedDateTime + +// basic alias to help identify, mainly in method calls, if the expected value is a compact or expanded one +typealias ExpandedTerm = String +typealias ExpandedAttributes = Map +typealias ExpandedAttribute = Pair +typealias ExpandedAttributeInstances = List +typealias ExpandedAttributeInstance = Map> +typealias ExpandedNonReifiedPropertyValue = List> + +fun ExpandedAttribute.toExpandedAttributes(): ExpandedAttributes = + mapOf(this.first to this.second) + +fun ExpandedAttributeInstances.addSubAttribute( + subAttributeName: ExpandedTerm, + subAttributePayload: ExpandedAttributeInstances +): ExpandedAttributeInstances { + if (this.isEmpty() || this.size > 1) + throw BadRequestDataException("Cannot add a sub-attribute into empty or multi-instance attribute: $this") + return listOf(this[0].plus(subAttributeName to subAttributePayload)) +} + +fun ExpandedAttributeInstances.addNonReifiedProperty( + subAttributeName: ExpandedTerm, + subAttributeValue: String +): ExpandedAttributeInstances { + if (this.isEmpty() || this.size > 1) + throw BadRequestDataException("Cannot add a sub-attribute into empty or multi-instance attribute: $this") + return listOf(this[0].plus(subAttributeName to JsonLdUtils.buildNonReifiedPropertyValue(subAttributeValue))) +} + +fun ExpandedAttributeInstances.addNonReifiedTemporalProperty( + subAttributeName: ExpandedTerm, + subAttributeValue: ZonedDateTime +): ExpandedAttributeInstances { + if (this.isEmpty() || this.size > 1) + throw BadRequestDataException("Cannot add a sub-attribute into empty or multi-instance attribute: $this") + return listOf(this[0].plus(subAttributeName to buildNonReifiedTemporalValue(subAttributeValue))) +} + +fun ExpandedAttributeInstances.getSingleEntry(): ExpandedAttributeInstance { + if (this.isEmpty() || this.size > 1) + throw BadRequestDataException("Expected a single entry but got none or more than one: $this") + return this[0] +} + +fun ExpandedAttributes.addCoreMembers( + entityId: String, + entityTypes: List +): Map = + this.plus(listOf(JSONLD_ID to entityId, JSONLD_TYPE to entityTypes)) + +fun ExpandedAttributeInstance.addSysAttrs( + withSysAttrs: Boolean, + createdAt: ZonedDateTime, + modifiedAt: ZonedDateTime? +): Map = + if (withSysAttrs) + this.plus(NGSILD_CREATED_AT_PROPERTY to buildNonReifiedTemporalValue(createdAt)) + .let { + if (modifiedAt != null) + it.plus(NGSILD_MODIFIED_AT_PROPERTY to buildNonReifiedTemporalValue(modifiedAt)) + else it + } + else this diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/GeoQuery.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/GeoQuery.kt index df8b5bc78..c7ab43841 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/GeoQuery.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/GeoQuery.kt @@ -1,6 +1,5 @@ package com.egm.stellio.shared.model -import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_PROPERTY data class GeoQuery( diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt index 4e0a4c5ba..0a0482e6f 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt @@ -10,14 +10,6 @@ import com.apicatalog.jsonld.JsonLdOptions import com.apicatalog.jsonld.context.cache.LruCache import com.apicatalog.jsonld.document.JsonDocument import com.egm.stellio.shared.model.* -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE_TERM -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_GEO_PROPERTIES_TERMS -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedPropertyValue -import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue -import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMapAsDateTime import com.egm.stellio.shared.util.JsonUtils.deserializeAs import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import com.egm.stellio.shared.util.JsonUtils.deserializeObject @@ -277,6 +269,28 @@ object JsonLdUtils { } } + private fun geoPropertyToWKT(jsonFragment: Map): Map { + for (geoProperty in NGSILD_GEO_PROPERTIES_TERMS) { + if (jsonFragment.containsKey(geoProperty)) { + // when creating a temporal entity, a geoproperty can be represented as a list of instances + val geoAttributes = + if (jsonFragment[geoProperty] is MutableMap<*, *>) + listOf(jsonFragment[geoProperty] as MutableMap) + else + jsonFragment[geoProperty] as List> + geoAttributes.forEach { geoAttribute -> + val geoJsonAsString = geoAttribute[JSONLD_VALUE_TERM] + val wktGeom = geoJsonToWkt(geoJsonAsString!! as Map) + .fold({ + throw BadRequestDataException(it.message) + }, { it }) + geoAttribute[JSONLD_VALUE_TERM] = wktGeom + } + } + } + return jsonFragment + } + fun extractContextFromInput(input: Map): List { return if (!input.containsKey(JSONLD_CONTEXT)) emptyList() @@ -490,16 +504,6 @@ object JsonLdUtils { .keys .elementAtOrElse(0) { _ -> term } - fun compactFragment(value: Map, contexts: List): Map = - JsonLd.compact( - JsonDocument.of(serializeObject(value).byteInputStream()), - JsonDocument.of(buildContextDocument(addCoreContextIfMissing(contexts))) - ) - .options(jsonLdOptions) - .get() - .toPrimitiveMap() - .mapValues(restoreGeoPropertyValue()) - fun filterCompactedEntityOnAttributes( input: CompactedEntity, includedAttributes: Set @@ -695,114 +699,3 @@ object JsonLdUtils { mapOf(JSONLD_ID to value) ) } - -// basic alias to help identify, mainly in method calls, if the expected value is a compact or expanded one -typealias ExpandedTerm = String -typealias ExpandedAttributes = Map -typealias ExpandedAttribute = Pair -typealias ExpandedAttributeInstances = List -typealias ExpandedAttributeInstance = Map> -typealias ExpandedNonReifiedPropertyValue = List> - -fun ExpandedAttribute.toExpandedAttributes() = - mapOf(this.first to this.second) - -fun ExpandedAttributeInstances.addSubAttribute( - subAttributeName: ExpandedTerm, - subAttributePayload: ExpandedAttributeInstances -): ExpandedAttributeInstances { - if (this.isEmpty() || this.size > 1) - throw BadRequestDataException("Cannot add a sub-attribute into empty or multi-instance attribute: $this") - return listOf(this[0].plus(subAttributeName to subAttributePayload)) -} - -fun ExpandedAttributeInstances.addNonReifiedProperty( - subAttributeName: ExpandedTerm, - subAttributeValue: String -): ExpandedAttributeInstances { - if (this.isEmpty() || this.size > 1) - throw BadRequestDataException("Cannot add a sub-attribute into empty or multi-instance attribute: $this") - return listOf(this[0].plus(subAttributeName to buildNonReifiedPropertyValue(subAttributeValue))) -} - -fun ExpandedAttributeInstances.addNonReifiedTemporalProperty( - subAttributeName: ExpandedTerm, - subAttributeValue: ZonedDateTime -): ExpandedAttributeInstances { - if (this.isEmpty() || this.size > 1) - throw BadRequestDataException("Cannot add a sub-attribute into empty or multi-instance attribute: $this") - return listOf(this[0].plus(subAttributeName to buildNonReifiedTemporalValue(subAttributeValue))) -} - -fun ExpandedAttributeInstances.getSingleEntry(): ExpandedAttributeInstance { - if (this.isEmpty() || this.size > 1) - throw BadRequestDataException("Expected a single entry but got none or more than one: $this") - return this[0] -} - -fun geoPropertyToWKT(jsonFragment: Map): Map { - for (geoProperty in NGSILD_GEO_PROPERTIES_TERMS) { - if (jsonFragment.containsKey(geoProperty)) { - // when creating a temporal entity, a geoproperty can be represented as a list of instances - val geoAttributes = - if (jsonFragment[geoProperty] is MutableMap<*, *>) - listOf(jsonFragment[geoProperty] as MutableMap) - else - jsonFragment[geoProperty] as List> - geoAttributes.forEach { geoAttribute -> - val geoJsonAsString = geoAttribute[JSONLD_VALUE_TERM] - val wktGeom = geoJsonToWkt(geoJsonAsString!! as Map) - .fold({ - throw BadRequestDataException(it.message) - }, { it }) - geoAttribute[JSONLD_VALUE_TERM] = wktGeom - } - } - } - return jsonFragment -} - -fun Map.addSysAttrs( - withSysAttrs: Boolean, - createdAt: ZonedDateTime, - modifiedAt: ZonedDateTime? -): Map = - if (withSysAttrs) - this.plus(JsonLdUtils.NGSILD_CREATED_AT_PROPERTY to buildNonReifiedTemporalValue(createdAt)) - .let { - if (modifiedAt != null) - it.plus(JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY to buildNonReifiedTemporalValue(modifiedAt)) - else it - } - else this - -fun ExpandedAttributes.checkTemporalAttributeInstance(): Either = - this.values.all { expandedInstances -> - expandedInstances.all { expandedAttributePayloadEntry -> - getPropertyValueFromMapAsDateTime(expandedAttributePayloadEntry, NGSILD_OBSERVED_AT_PROPERTY) != null - } - }.let { - if (it) Unit.right() - else BadRequestDataException(invalidTemporalInstanceMessage()).left() - } - -fun ExpandedAttributes.sorted(): ExpandedAttributes = - this.mapValues { - it.value.sortedByDescending { expandedAttributePayloadEntry -> - getPropertyValueFromMapAsDateTime(expandedAttributePayloadEntry, NGSILD_OBSERVED_AT_PROPERTY) - } - } - -fun ExpandedAttributes.keepFirstInstances(): ExpandedAttributes = - this.mapValues { listOf(it.value.first()) } - -fun ExpandedAttributes.removeFirstInstances(): ExpandedAttributes = - this.mapValues { - it.value.drop(1) - } - -fun ExpandedAttributes.addCoreMembers( - entityId: String, - entityTypes: List -): Map = - this.plus(listOf(JSONLD_ID to entityId, JSONLD_TYPE to entityTypes)) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/QueryUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/QueryUtils.kt index 655aa909e..35f1b41c8 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/QueryUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/QueryUtils.kt @@ -1,6 +1,7 @@ package com.egm.stellio.shared.util import com.egm.stellio.shared.model.ExpandedEntity +import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt new file mode 100644 index 000000000..930ff35aa --- /dev/null +++ b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt @@ -0,0 +1,33 @@ +package com.egm.stellio.shared.model + +import com.egm.stellio.shared.util.JsonLdUtils +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY +import com.egm.stellio.shared.util.ngsiLdDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class ExpandedMembersTests { + + @Test + fun `it should add createdAt information into an attribute`() { + val attrPayload = mapOf("attribute" to JsonLdUtils.buildExpandedPropertyValue(12.0)) + + val attrPayloadWithSysAttrs = attrPayload.addSysAttrs(true, ngsiLdDateTime(), null) + + assertThat(attrPayloadWithSysAttrs) + .containsKey(NGSILD_CREATED_AT_PROPERTY) + .doesNotContainKey(NGSILD_MODIFIED_AT_PROPERTY) + } + + @Test + fun `it should add createdAt and modifiedAt information into an attribute`() { + val attrPayload = mapOf("attribute" to JsonLdUtils.buildExpandedPropertyValue(12.0)) + + val attrPayloadWithSysAttrs = attrPayload.addSysAttrs(true, ngsiLdDateTime(), ngsiLdDateTime()) + + assertThat(attrPayloadWithSysAttrs) + .containsKey(NGSILD_CREATED_AT_PROPERTY) + .containsKey(NGSILD_MODIFIED_AT_PROPERTY) + } +} diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt index 30432c012..e14223f8d 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt @@ -368,30 +368,4 @@ class JsonLdUtilsTests { assertEquals(emptyList(), extractContextFromInput(input)) } - - @Test - fun `it should add createdAt information into an attribute`() { - val attrPayload = mapOf( - "type" to "Property", - "value" to 12.0 - ) - - val attrPayloadWithSysAttrs = attrPayload.addSysAttrs(true, ngsiLdDateTime(), null) - - assertTrue(attrPayloadWithSysAttrs.containsKey(JsonLdUtils.NGSILD_CREATED_AT_PROPERTY)) - assertFalse(attrPayloadWithSysAttrs.containsKey(JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY)) - } - - @Test - fun `it should add createdAt and modifiedAt information into an attribute`() { - val attrPayload = mapOf( - "type" to "Property", - "value" to 12.0 - ) - - val attrPayloadWithSysAttrs = attrPayload.addSysAttrs(true, ngsiLdDateTime(), ngsiLdDateTime()) - - assertTrue(attrPayloadWithSysAttrs.containsKey(JsonLdUtils.NGSILD_CREATED_AT_PROPERTY)) - assertTrue(attrPayloadWithSysAttrs.containsKey(JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY)) - } } diff --git a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/listener/EntityEventListenerService.kt b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/listener/EntityEventListenerService.kt index 53cc9d02d..54ceb20c5 100644 --- a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/listener/EntityEventListenerService.kt +++ b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/listener/EntityEventListenerService.kt @@ -3,7 +3,6 @@ package com.egm.stellio.subscription.listener import arrow.core.Either import arrow.core.raise.either import com.egm.stellio.shared.model.* -import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_EXPANDED_ENTITY_CORE_MEMBERS import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SYSATTRS_PROPERTIES import com.egm.stellio.shared.util.JsonUtils.deserializeAs diff --git a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/model/NotificationParams.kt b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/model/NotificationParams.kt index a7ca8e3f8..39eea3b2f 100644 --- a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/model/NotificationParams.kt +++ b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/model/NotificationParams.kt @@ -1,6 +1,6 @@ package com.egm.stellio.subscription.model -import com.egm.stellio.shared.util.ExpandedTerm +import com.egm.stellio.shared.model.ExpandedTerm import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.annotation.JsonProperty import java.time.ZonedDateTime diff --git a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/model/Subscription.kt b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/model/Subscription.kt index 31bd2e3ff..98556c9af 100644 --- a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/model/Subscription.kt +++ b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/model/Subscription.kt @@ -1,6 +1,7 @@ package com.egm.stellio.subscription.model import com.egm.stellio.shared.model.EntitySelector +import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SYSATTRS_TERMS diff --git a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/NotificationService.kt b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/NotificationService.kt index a38ed1d1a..733e95f90 100644 --- a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/NotificationService.kt +++ b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/NotificationService.kt @@ -5,8 +5,8 @@ import arrow.core.raise.either import com.egm.stellio.shared.model.APIException import com.egm.stellio.shared.model.CompactedEntity import com.egm.stellio.shared.model.ExpandedEntity +import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.model.toKeyValues -import com.egm.stellio.shared.util.ExpandedTerm import com.egm.stellio.shared.util.JsonLdUtils.compactEntity import com.egm.stellio.shared.util.JsonLdUtils.filterJsonLdEntityOnAttributes import com.egm.stellio.shared.util.JsonUtils.serializeObject From aeae04975c6f105ba836231158cfe023f6390613 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Thu, 28 Dec 2023 17:40:30 +0100 Subject: [PATCH 08/19] refactor: clean up all the expand / compact processing utilities --- config/detekt/detekt.yml | 8 +- search-service/config/detekt/baseline.xml | 1 - .../authorization/AuthorizationService.kt | 6 +- .../DisabledAuthorizationService.kt | 6 +- .../EnabledAuthorizationService.kt | 20 +- .../authorization/EntityAccessRights.kt | 17 +- .../egm/stellio/search/authorization/User.kt | 4 +- .../egm/stellio/search/model/EntitiesQuery.kt | 2 +- .../search/service/EntityEventService.kt | 4 +- .../search/service/EntityPayloadService.kt | 2 +- .../stellio/search/service/QueryService.kt | 8 +- .../service/TemporalEntityAttributeService.kt | 28 +- .../stellio/search/util/EntitiesQueryUtils.kt | 32 +- .../stellio/search/web/AttributeHandler.kt | 17 +- .../search/web/EntityAccessControlHandler.kt | 64 ++-- .../egm/stellio/search/web/EntityHandler.kt | 42 ++- .../search/web/EntityOperationHandler.kt | 29 +- .../stellio/search/web/EntityTypeHandler.kt | 16 +- .../search/web/TemporalEntityHandler.kt | 53 ++- .../web/TemporalEntityOperationsHandler.kt | 13 +- .../db/migration/V0_29__JsonLd_migration.kt | 21 +- .../AuthorizationServiceTests.kt | 12 +- .../EnabledAuthorizationServiceTests.kt | 14 +- .../EntityAccessRightsServiceTests.kt | 2 +- .../listener/ObservationEventListenerTests.kt | 8 +- .../stellio/search/model/EntityModelTests.kt | 2 +- .../stellio/search/scope/ScopeServiceTests.kt | 14 +- .../search/scope/TemporalScopeBuilderTests.kt | 2 +- .../service/AttributeInstanceServiceTests.kt | 5 +- .../search/service/AttributeServiceTests.kt | 16 +- .../service/EntityPayloadServiceTests.kt | 31 +- .../search/service/EntityQueryServiceTests.kt | 44 +-- .../search/service/EntityTypeServiceTests.kt | 12 +- .../search/service/QueryServiceTests.kt | 28 +- .../TemporalEntityAttributeServiceTests.kt | 52 +-- .../search/support/BusinessObjectsFactory.kt | 8 +- .../util/AttributeInstanceUtilsTests.kt | 24 +- .../search/util/EntitiesQueryUtilsTests.kt | 32 +- .../TemporalEntitiesParameterizedSource.kt | 12 +- .../search/util/TemporalEntityBuilderTests.kt | 14 +- .../search/web/AnonymousUserHandlerTests.kt | 7 +- .../search/web/AttributeHandlerTests.kt | 8 +- .../web/EntityAccessControlHandlerTests.kt | 37 ++- .../stellio/search/web/EntityHandlerTests.kt | 95 +++--- .../search/web/EntityTypeHandlerTests.kt | 6 +- .../search/web/TemporalEntityHandlerTests.kt | 54 ++- .../TemporalEntityOperationsHandlerTests.kt | 8 +- .../migration/V0_29_JsonLd_migrationTests.kt | 4 +- .../src/test/resources/logback-test.xml | 1 + .../temporal_instance_fragment.jsonld | 12 +- shared/config/detekt/baseline.xml | 6 +- .../stellio/shared/model/CompactedEntity.kt | 25 +- .../stellio/shared/model/ExpandedEntity.kt | 35 +- .../stellio/shared/model/ExpandedMembers.kt | 132 +++++++- .../egm/stellio/shared/model/NgsiLdEntity.kt | 32 +- .../egm/stellio/shared/util/ApiResponses.kt | 21 +- .../com/egm/stellio/shared/util/ApiUtils.kt | 83 +++-- .../com/egm/stellio/shared/util/AuthUtils.kt | 7 +- .../egm/stellio/shared/util/GeoQueryUtils.kt | 5 - .../egm/stellio/shared/util/JsonLdUtils.kt | 313 +++--------------- .../shared/model/ExpandedEntityTests.kt | 5 +- .../shared/model/ExpandedMembersTests.kt | 159 ++++++++- .../stellio/shared/model/NgsiLdEntityTests.kt | 59 ++-- .../egm/stellio/shared/util/ApiUtilsTests.kt | 77 ++++- .../stellio/shared/util/GeoQueryUtilsTests.kt | 16 +- .../stellio/shared/util/JsonLdUtilsTests.kt | 300 +---------------- .../egm/stellio/shared/util/JsonUtilsTests.kt | 8 +- .../egm/stellio/shared/util/MockkedHandler.kt | 3 +- .../stellio/shared/util/JsonLdContextUtils.kt | 14 +- .../stellio/shared/util/NgsiLdTestUtils.kt | 6 +- .../com/egm/stellio/shared/util/TestUtils.kt | 9 +- .../subscription/model/Notification.kt | 2 +- .../subscription/model/Subscription.kt | 4 +- .../service/NotificationService.kt | 39 +-- .../subscription/web/SubscriptionHandler.kt | 12 +- .../job/TimeIntervalNotificationJobTest.kt | 11 +- .../subscription/model/SubscriptionTest.kt | 24 +- .../service/NotificationServiceTests.kt | 12 +- .../service/SubscriptionServiceTests.kt | 42 +-- .../subscription/support/FixtureUtils.kt | 6 +- .../web/SubscriptionHandlerTests.kt | 8 +- .../src/test/resources/logback-test.xml | 1 + 82 files changed, 1147 insertions(+), 1286 deletions(-) diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index 4d7881032..d94210013 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -168,10 +168,10 @@ complexity: TooManyFunctions: active: true excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] - thresholdInFiles: 20 - thresholdInClasses: 20 - thresholdInInterfaces: 20 - thresholdInObjects: 20 + thresholdInFiles: 30 + thresholdInClasses: 30 + thresholdInInterfaces: 30 + thresholdInObjects: 30 thresholdInEnums: 11 ignoreDeprecated: false ignorePrivate: false diff --git a/search-service/config/detekt/baseline.xml b/search-service/config/detekt/baseline.xml index 263c11be1..118a5dc3a 100644 --- a/search-service/config/detekt/baseline.xml +++ b/search-service/config/detekt/baseline.xml @@ -29,6 +29,5 @@ ReturnCount:EntitiesQueryUtils.kt$fun buildTemporalQuery( params: MultiValueMap<String, String>, inQueryEntities: Boolean = false, withAggregatedValues: Boolean = false ): Either<APIException, TemporalQuery> SwallowedException:EntitiesQueryUtils.kt$e: IllegalArgumentException TooManyFunctions:EntityPayloadService.kt$EntityPayloadService - TooManyFunctions:TemporalEntityAttributeService.kt$TemporalEntityAttributeService diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/AuthorizationService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/AuthorizationService.kt index 96d982d69..9ea94122a 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/AuthorizationService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/AuthorizationService.kt @@ -23,20 +23,20 @@ interface AuthorizationService { suspend fun getAuthorizedEntities( entitiesQuery: EntitiesQuery, - contextLink: String, + contexts: List, sub: Option ): Either>> suspend fun getGroupsMemberships( offset: Int, limit: Int, - contextLink: String, + contexts: List, sub: Option ): Either>> suspend fun getUsers( offset: Int, limit: Int, - contextLink: String, + contexts: List, ): Either>> } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/DisabledAuthorizationService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/DisabledAuthorizationService.kt index bfbaf3d84..36928017e 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/DisabledAuthorizationService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/DisabledAuthorizationService.kt @@ -41,20 +41,20 @@ class DisabledAuthorizationService : AuthorizationService { override suspend fun getAuthorizedEntities( entitiesQuery: EntitiesQuery, - contextLink: String, + contexts: List, sub: Option ): Either>> = Pair(-1, emptyList()).right() override suspend fun getGroupsMemberships( offset: Int, limit: Int, - contextLink: String, + contexts: List, sub: Option ): Either>> = Pair(-1, emptyList()).right() override suspend fun getUsers( offset: Int, limit: Int, - contextLink: String, + contexts: List, ): Either>> = Pair(-1, emptyList()).right() } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationService.kt index b89f24101..b0b910814 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationService.kt @@ -95,7 +95,7 @@ class EnabledAuthorizationService( override suspend fun getAuthorizedEntities( entitiesQuery: EntitiesQuery, - contextLink: String, + contexts: List, sub: Option ): Either>> = either { val accessRights = entitiesQuery.attrs.mapNotNull { AccessRight.forExpandedAttributeName(it).getOrNull() } @@ -127,8 +127,8 @@ class EnabledAuthorizationService( ) } else entityAccessControl } - .map { it.serializeProperties(contextLink) } - .map { ExpandedEntity(it, listOf(contextLink)) } + .map { it.serializeProperties(contexts) } + .map { ExpandedEntity(it, contexts) } val count = entityAccessRightsService.getSubjectAccessRightsCount( sub, @@ -143,7 +143,7 @@ class EnabledAuthorizationService( override suspend fun getGroupsMemberships( offset: Int, limit: Int, - contextLink: String, + contexts: List, sub: Option ): Either>> = either { val groups = @@ -162,10 +162,7 @@ class EnabledAuthorizationService( } val jsonLdEntities = groups.second.map { - ExpandedEntity( - it.serializeProperties(), - listOf(contextLink) - ) + ExpandedEntity(it.serializeProperties(), contexts) } Pair(groups.first, jsonLdEntities) @@ -174,16 +171,13 @@ class EnabledAuthorizationService( override suspend fun getUsers( offset: Int, limit: Int, - contextLink: String + contexts: List, ): Either>> = either { val users = subjectReferentialService.getUsers(offset, limit) val usersCount = subjectReferentialService.getUsersCount().bind() val jsonLdEntities = users.map { - ExpandedEntity( - it.serializeProperties(contextLink), - listOf(contextLink) - ) + ExpandedEntity(it.serializeProperties(contexts), contexts) } Pair(usersCount, jsonLdEntities) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt index 393cee58f..7d33ccb70 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt @@ -4,7 +4,8 @@ import com.egm.stellio.shared.model.ExpandedAttributeInstances import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.model.addNonReifiedProperty import com.egm.stellio.shared.model.addSubAttribute -import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.AccessRight +import com.egm.stellio.shared.util.AuthContextModel import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_RIGHT import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SAP import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SUBJECT_INFO @@ -18,6 +19,8 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyMapValue import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedRelationshipValue +import com.egm.stellio.shared.util.extractSub +import com.egm.stellio.shared.util.toUri import java.net.URI data class EntityAccessRights( @@ -36,16 +39,16 @@ data class EntityAccessRights( ) { val datasetId: URI = (DATASET_ID_PREFIX + uri.extractSub()).toUri() - suspend fun serializeProperties(contextLink: String): ExpandedAttributeInstances = + suspend fun serializeProperties(contexts: List): ExpandedAttributeInstances = buildExpandedRelationshipValue(uri) .addNonReifiedProperty(NGSILD_DATASET_ID_PROPERTY, datasetId.toString()) .addSubAttribute( AUTH_PROP_SUBJECT_INFO, - buildExpandedPropertyMapValue(subjectInfo, listOf(contextLink)) + buildExpandedPropertyMapValue(subjectInfo, contexts) ) } - suspend fun serializeProperties(contextLink: String): Map { + suspend fun serializeProperties(contexts: List): Map { val resultEntity = mutableMapOf() resultEntity[JSONLD_ID] = id.toString() @@ -58,17 +61,17 @@ data class EntityAccessRights( rCanAdminUsers?.run { resultEntity[AUTH_REL_CAN_ADMIN] = this.map { - it.serializeProperties(contextLink) + it.serializeProperties(contexts) }.flatten() } rCanWriteUsers?.run { resultEntity[AUTH_REL_CAN_WRITE] = this.map { - it.serializeProperties(contextLink) + it.serializeProperties(contexts) }.flatten() } rCanReadUsers?.run { resultEntity[AUTH_REL_CAN_READ] = this.map { - it.serializeProperties(contextLink) + it.serializeProperties(contexts) }.flatten() } return resultEntity diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/User.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/User.kt index c000d1ac5..8999a36fd 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/User.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/User.kt @@ -23,7 +23,7 @@ data class User( val familyName: String? = null, val subjectInfo: Map ) { - suspend fun serializeProperties(contextLink: String): Map { + suspend fun serializeProperties(contexts: List): Map { val resultEntity = mutableMapOf() resultEntity[JSONLD_ID] = USER_ENTITY_PREFIX + id resultEntity[JSONLD_TYPE] = listOf(type) @@ -43,7 +43,7 @@ data class User( }.run { if (this.isNotEmpty()) resultEntity[AUTH_PROP_SUBJECT_INFO] = - buildExpandedPropertyMapValue(this, listOf(contextLink)) + buildExpandedPropertyMapValue(this, contexts) } return resultEntity diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/model/EntitiesQuery.kt b/search-service/src/main/kotlin/com/egm/stellio/search/model/EntitiesQuery.kt index 0e88024e8..1b650bf47 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/model/EntitiesQuery.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/model/EntitiesQuery.kt @@ -15,5 +15,5 @@ data class EntitiesQuery( val paginationQuery: PaginationQuery, val attrs: Set = emptySet(), val geoQuery: GeoQuery? = null, - val context: String + val contexts: List ) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityEventService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityEventService.kt index 9c707ac49..81755d408 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityEventService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityEventService.kt @@ -7,7 +7,6 @@ import com.egm.stellio.search.model.UpdateResult import com.egm.stellio.search.model.UpdatedDetails import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE -import com.egm.stellio.shared.util.JsonLdUtils.getAttributeFromExpandedAttributes import com.egm.stellio.shared.util.JsonUtils.serializeObject import com.egm.stellio.shared.util.getTenantFromContext import kotlinx.coroutines.CoroutineScope @@ -253,8 +252,7 @@ class EntityEventService( when (attributeName) { JSONLD_TYPE -> Pair(JSONLD_TYPE, serializeObject(jsonLdAttributes[JSONLD_TYPE]!!)) else -> { - val extractedPayload = getAttributeFromExpandedAttributes( - jsonLdAttributes as ExpandedAttributes, + val extractedPayload = (jsonLdAttributes as ExpandedAttributes).getAttributeFromExpandedAttributes( attributeName, datasetId )!! diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityPayloadService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityPayloadService.kt index 6c1aedab4..abb2eda6a 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityPayloadService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityPayloadService.kt @@ -307,7 +307,7 @@ class EntityPayloadService( accessRightFilter ).let { if (entitiesQuery.q != null) - it.wrapToAndClause(buildQQuery(entitiesQuery.q, listOf(entitiesQuery.context))) + it.wrapToAndClause(buildQQuery(entitiesQuery.q, entitiesQuery.contexts)) else it }.let { if (entitiesQuery.scopeQ != null) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/QueryService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/QueryService.kt index 960a77dcd..16f04f396 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/QueryService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/QueryService.kt @@ -48,7 +48,7 @@ class QueryService( val entitiesPayloads = entityPayloadService.retrieve(entitiesIds) - .map { toJsonLdEntity(it, listOf(entitiesQuery.context)) } + .map { toJsonLdEntity(it, entitiesQuery.contexts) } Pair(entitiesPayloads, count).right().bind() } @@ -56,7 +56,7 @@ class QueryService( suspend fun queryTemporalEntity( entityId: URI, temporalEntitiesQuery: TemporalEntitiesQuery, - contextLink: String + contexts: List ): Either = either { val attrs = temporalEntitiesQuery.entitiesQuery.attrs val temporalEntityAttributes = temporalEntityAttributeService.getForEntity(entityId, attrs).let { @@ -84,7 +84,7 @@ class QueryService( TemporalEntityBuilder.buildTemporalEntity( EntityTemporalResult(entityPayload, scopeHistory, temporalEntityAttributesWithInstances), temporalEntitiesQuery, - listOf(contextLink) + contexts ) } @@ -176,7 +176,7 @@ class QueryService( TemporalEntityBuilder.buildTemporalEntities( attributeInstancesPerEntityAndAttribute, temporalEntitiesQuery, - listOf(temporalEntitiesQuery.entitiesQuery.context) + temporalEntitiesQuery.entitiesQuery.contexts ), count ) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt index ca0bd6442..05303e082 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt @@ -19,9 +19,6 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity -import com.egm.stellio.shared.util.JsonLdUtils.getAttributeFromExpandedAttributes -import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMap -import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMapAsDateTime import com.egm.stellio.shared.util.JsonUtils.serializeObject import com.savvasdalkitsis.jsonmerger.JsonMerger import io.r2dbc.postgresql.codec.Json @@ -149,8 +146,7 @@ class TemporalEntityAttributeService( } .forEach { val (expandedAttributeName, attributeMetadata) = it - val attributePayload = getAttributeFromExpandedAttributes( - expandedEntity.getAttributes(), + val attributePayload = expandedEntity.getAttributes().getAttributeFromExpandedAttributes( expandedAttributeName, attributeMetadata.datasetId )!! @@ -535,8 +531,7 @@ class TemporalEntityAttributeService( getForEntityAndAttribute(entityUri, ngsiLdAttribute.name, ngsiLdAttributeInstance.datasetId) .fold({ null }, { it }) val attributeMetadata = ngsiLdAttributeInstance.toTemporalAttributeMetadata().bind() - val attributePayload = getAttributeFromExpandedAttributes( - expandedAttributes, + val attributePayload = expandedAttributes.getAttributeFromExpandedAttributes( ngsiLdAttribute.name, ngsiLdAttributeInstance.datasetId )!! @@ -601,8 +596,7 @@ class TemporalEntityAttributeService( .fold({ null }, { it }) if (currentTea != null) { val attributeMetadata = ngsiLdAttributeInstance.toTemporalAttributeMetadata().bind() - val attributePayload = getAttributeFromExpandedAttributes( - expandedAttributes, + val attributePayload = expandedAttributes.getAttributeFromExpandedAttributes( ngsiLdAttribute.name, ngsiLdAttributeInstance.datasetId )!! @@ -711,8 +705,7 @@ class TemporalEntityAttributeService( getForEntityAndAttribute(entityUri, ngsiLdAttribute.name, ngsiLdAttributeInstance.datasetId) .fold({ null }, { it }) val attributeMetadata = ngsiLdAttributeInstance.toTemporalAttributeMetadata().bind() - val attributePayload = getAttributeFromExpandedAttributes( - expandedAttributes, + val attributePayload = expandedAttributes.getAttributeFromExpandedAttributes( ngsiLdAttribute.name, ngsiLdAttributeInstance.datasetId )!! @@ -757,8 +750,7 @@ class TemporalEntityAttributeService( getForEntityAndAttribute(entityUri, ngsiLdAttribute.name, ngsiLdAttributeInstance.datasetId) .fold({ null }, { it }) val attributeMetadata = ngsiLdAttributeInstance.toTemporalAttributeMetadata().bind() - val attributePayload = getAttributeFromExpandedAttributes( - expandedAttributes, + val attributePayload = expandedAttributes.getAttributeFromExpandedAttributes( ngsiLdAttribute.name, ngsiLdAttributeInstance.datasetId )!! @@ -850,13 +842,13 @@ class TemporalEntityAttributeService( when (tea.attributeType) { TemporalEntityAttribute.AttributeType.Property -> Triple( - valueToStringOrNull(getPropertyValueFromMap(attributePayload, NGSILD_PROPERTY_VALUE)!!), - valueToDoubleOrNull(getPropertyValueFromMap(attributePayload, NGSILD_PROPERTY_VALUE)!!), + valueToStringOrNull(attributePayload.getMemberValue(NGSILD_PROPERTY_VALUE)!!), + valueToDoubleOrNull(attributePayload.getMemberValue(NGSILD_PROPERTY_VALUE)!!), null ) TemporalEntityAttribute.AttributeType.Relationship -> Triple( - getPropertyValueFromMap(attributePayload, NGSILD_RELATIONSHIP_OBJECT)!! as String, + attributePayload.getMemberValue(NGSILD_RELATIONSHIP_OBJECT)!! as String, null, null ) @@ -864,7 +856,7 @@ class TemporalEntityAttributeService( Triple( null, null, - WKTCoordinates(getPropertyValueFromMap(attributePayload, NGSILD_PROPERTY_VALUE)!! as String) + WKTCoordinates(attributePayload.getMemberValue(NGSILD_PROPERTY_VALUE)!! as String) ) } @@ -893,7 +885,7 @@ class TemporalEntityAttributeService( val timeAndProperty = if (expandedAttributeInstance.containsKey(NGSILD_OBSERVED_AT_PROPERTY)) Pair( - getPropertyValueFromMapAsDateTime(expandedAttributeInstance, NGSILD_OBSERVED_AT_PROPERTY)!!, + expandedAttributeInstance.getMemberValueAsDateTime(NGSILD_OBSERVED_AT_PROPERTY)!!, AttributeInstance.TemporalProperty.OBSERVED_AT ) else diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/util/EntitiesQueryUtils.kt b/search-service/src/main/kotlin/com/egm/stellio/search/util/EntitiesQueryUtils.kt index b0d2d10e3..f4d86e7a7 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/util/EntitiesQueryUtils.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/util/EntitiesQueryUtils.kt @@ -15,10 +15,10 @@ import java.util.Optional fun composeEntitiesQuery( defaultPagination: ApplicationProperties.Pagination, requestParams: MultiValueMap, - contextLink: String + contexts: List ): Either = either { val ids = requestParams.getFirst(QUERY_PARAM_ID)?.split(",").orEmpty().toListOfUri().toSet() - val typeSelection = expandTypeSelection(requestParams.getFirst(QUERY_PARAM_TYPE), contextLink) + val typeSelection = expandTypeSelection(requestParams.getFirst(QUERY_PARAM_TYPE), contexts) val idPattern = validateIdPattern(requestParams.getFirst(QUERY_PARAM_ID_PATTERN)).bind() /** @@ -27,14 +27,14 @@ fun composeEntitiesQuery( */ val q = requestParams.getFirst(QUERY_PARAM_Q)?.decode() val scopeQ = requestParams.getFirst(QUERY_PARAM_SCOPEQ) - val attrs = parseAndExpandRequestParameter(requestParams.getFirst(QUERY_PARAM_ATTRS), contextLink) + val attrs = parseAndExpandRequestParameter(requestParams.getFirst(QUERY_PARAM_ATTRS), contexts) val paginationQuery = parsePaginationParameters( requestParams, defaultPagination.limitDefault, defaultPagination.limitMax ).bind() - val geoQuery = parseGeoQueryParameters(requestParams.toSingleValueMap(), contextLink).bind() + val geoQuery = parseGeoQueryParameters(requestParams.toSingleValueMap(), contexts).bind() EntitiesQuery( ids = ids, @@ -45,7 +45,7 @@ fun composeEntitiesQuery( paginationQuery = paginationQuery, attrs = attrs, geoQuery = geoQuery, - context = contextLink + contexts = contexts ) } @@ -67,22 +67,22 @@ fun composeEntitiesQueryFromPostRequest( defaultPagination: ApplicationProperties.Pagination, requestBody: String, requestParams: MultiValueMap, - contextLink: String + contexts: List ): Either = either { val query = Query(requestBody).bind() - composeEntitiesQueryFromPostRequest(defaultPagination, query, requestParams, contextLink).bind() + composeEntitiesQueryFromPostRequest(defaultPagination, query, requestParams, contexts).bind() } fun composeEntitiesQueryFromPostRequest( defaultPagination: ApplicationProperties.Pagination, query: Query, requestParams: MultiValueMap, - contextLink: String + contexts: List ): Either = either { val entitySelector = query.entities?.get(0) - val typeSelection = expandTypeSelection(entitySelector?.typeSelection, contextLink) + val typeSelection = expandTypeSelection(entitySelector?.typeSelection, contexts) val idPattern = validateIdPattern(entitySelector?.idPattern).bind() - val attrs = parseAndExpandRequestParameter(query.attrs?.joinToString(","), contextLink) + val attrs = parseAndExpandRequestParameter(query.attrs?.joinToString(","), contexts) val geoQuery = if (query.geoQ != null) { val geoQueryElements = mapOf( "geometry" to query.geoQ.geometry, @@ -90,7 +90,7 @@ fun composeEntitiesQueryFromPostRequest( "georel" to query.geoQ.georel, "geoproperty" to query.geoQ.geoproperty ) - parseGeoQueryParameters(geoQueryElements, contextLink).bind() + parseGeoQueryParameters(geoQueryElements, contexts).bind() } else null val paginationQuery = parsePaginationParameters( @@ -108,20 +108,20 @@ fun composeEntitiesQueryFromPostRequest( paginationQuery = paginationQuery, attrs = attrs, geoQuery = geoQuery, - context = contextLink + contexts = contexts ) } fun composeTemporalEntitiesQuery( defaultPagination: ApplicationProperties.Pagination, requestParams: MultiValueMap, - contextLink: String, + contexts: List, inQueryEntities: Boolean = false ): Either = either { val entitiesQuery = composeEntitiesQuery( defaultPagination, requestParams, - contextLink + contexts ).bind() if (inQueryEntities) @@ -154,14 +154,14 @@ fun composeTemporalEntitiesQueryFromPostRequest( defaultPagination: ApplicationProperties.Pagination, requestBody: String, requestParams: MultiValueMap, - contextLink: String + contexts: List ): Either = either { val query = Query(requestBody).bind() val entitiesQuery = composeEntitiesQueryFromPostRequest( defaultPagination, query, requestParams, - contextLink + contexts ).bind() .validateMinimalQueryEntitiesParameters().bind() diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/AttributeHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/AttributeHandler.kt index 59b125b51..c4d70b75c 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/AttributeHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/AttributeHandler.kt @@ -3,6 +3,7 @@ package com.egm.stellio.search.web import arrow.core.raise.either import com.egm.stellio.search.service.AttributeService import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdTerm import org.springframework.http.HttpHeaders import org.springframework.http.MediaType import org.springframework.http.ResponseEntity @@ -22,16 +23,16 @@ class AttributeHandler( @RequestHeader httpHeaders: HttpHeaders, @RequestParam details: Optional ): ResponseEntity<*> = either { - val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() val detailedRepresentation = details.orElse(false) val availableAttribute: Any = if (detailedRepresentation) - attributeService.getAttributeDetails(listOf(contextLink)) + attributeService.getAttributeDetails(contexts) else - attributeService.getAttributeList(listOf(contextLink)) + attributeService.getAttributeList(contexts) - prepareGetSuccessResponse(mediaType, contextLink).body(JsonUtils.serializeObject(availableAttribute)) + prepareGetSuccessResponseHeaders(mediaType, contexts).body(JsonUtils.serializeObject(availableAttribute)) }.fold( { it.toErrorResponse() }, { it } @@ -45,14 +46,14 @@ class AttributeHandler( @RequestHeader httpHeaders: HttpHeaders, @PathVariable attrId: String ): ResponseEntity<*> = either { - val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() - val expandedAttribute = JsonLdUtils.expandJsonLdTerm(attrId.decode(), contextLink) + val expandedAttribute = expandJsonLdTerm(attrId.decode(), contexts) val attributeTypeInfo = - attributeService.getAttributeTypeInfoByAttribute(expandedAttribute, listOf(contextLink)).bind() + attributeService.getAttributeTypeInfoByAttribute(expandedAttribute, contexts).bind() - prepareGetSuccessResponse(mediaType, contextLink).body(JsonUtils.serializeObject(attributeTypeInfo)) + prepareGetSuccessResponseHeaders(mediaType, contexts).body(JsonUtils.serializeObject(attributeTypeInfo)) }.fold( { it.toErrorResponse() }, { it } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityAccessControlHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityAccessControlHandler.kt index 22973ec26..daf8751f9 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityAccessControlHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityAccessControlHandler.kt @@ -13,9 +13,9 @@ import com.egm.stellio.shared.util.AuthContextModel.ALL_IAM_RIGHTS import com.egm.stellio.shared.util.AuthContextModel.ALL_IAM_RIGHTS_TERMS import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SAP import com.egm.stellio.shared.util.AuthContextModel.AUTH_TERM_SAP +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute import com.egm.stellio.shared.util.JsonLdUtils.expandAttributes -import com.egm.stellio.shared.util.JsonLdUtils.removeContextFromInput import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import com.egm.stellio.shared.web.BaseHandler import kotlinx.coroutines.reactive.awaitFirst @@ -45,13 +45,13 @@ class EntityAccessControlHandler( ): ResponseEntity<*> = either { val sub = getSubFromSecurityContext() - val contextLink = getAuthzContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getAuthzContextFromLinkHeaderOrDefault(httpHeaders).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() val entitiesQuery = composeEntitiesQuery( applicationProperties.pagination, params, - contextLink + contexts ).bind() if (!entitiesQuery.attrs.all { ALL_IAM_RIGHTS.contains(it) }) @@ -59,31 +59,27 @@ class EntityAccessControlHandler( "The attrs parameter only accepts as a value one or more of $ALL_IAM_RIGHTS_TERMS" ).left().bind>() - val countAndAuthorizedEntities = authorizationService.getAuthorizedEntities( + val (count, entities) = authorizationService.getAuthorizedEntities( entitiesQuery, - contextLink, + contexts, sub ).bind() - if (countAndAuthorizedEntities.first == -1) { + if (count == -1) { return@either ResponseEntity.status(HttpStatus.NO_CONTENT).build() } - val compactedEntities = JsonLdUtils.compactEntities( - countAndAuthorizedEntities.second, - contextLink, - mediaType - ) + val compactedEntities = JsonLdUtils.compactEntities(entities, contexts) val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) buildQueryResponse( compactedEntities.toFinalRepresentation(ngsiLdDataRepresentation), - countAndAuthorizedEntities.first, + count, "/ngsi-ld/v1/entityAccessControl/entities", entitiesQuery.paginationQuery, params, mediaType, - contextLink + contexts ) }.fold( { it.toErrorResponse() }, @@ -97,41 +93,37 @@ class EntityAccessControlHandler( ): ResponseEntity<*> = either { val sub = getSubFromSecurityContext() - val contextLink = getAuthzContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getAuthzContextFromLinkHeaderOrDefault(httpHeaders).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() val entitiesQuery = composeEntitiesQuery( applicationProperties.pagination, params, - contextLink + contexts ).bind() - val countAndGroupEntities = + val (count, entities) = authorizationService.getGroupsMemberships( entitiesQuery.paginationQuery.offset, entitiesQuery.paginationQuery.limit, - contextLink, + contexts, sub ).bind() - if (countAndGroupEntities.first == -1) { + if (count == -1) { return@either ResponseEntity.status(HttpStatus.NO_CONTENT).build() } - val compactedEntities = JsonLdUtils.compactEntities( - countAndGroupEntities.second, - contextLink, - mediaType - ) + val compactedEntities = JsonLdUtils.compactEntities(entities, contexts) val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) buildQueryResponse( compactedEntities.toFinalRepresentation(ngsiLdDataRepresentation), - countAndGroupEntities.first, + count, "/ngsi-ld/v1/entityAccessControl/groups", entitiesQuery.paginationQuery, params, mediaType, - contextLink + contexts ) }.fold( { it.toErrorResponse() }, @@ -147,40 +139,36 @@ class EntityAccessControlHandler( authorizationService.userIsAdmin(sub).bind() - val contextLink = getAuthzContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getAuthzContextFromLinkHeaderOrDefault(httpHeaders).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() val entitiesQuery = composeEntitiesQuery( applicationProperties.pagination, params, - contextLink + contexts ).bind() - val countAndUserEntities = + val (count, entities) = authorizationService.getUsers( entitiesQuery.paginationQuery.offset, entitiesQuery.paginationQuery.limit, - contextLink + contexts ).bind() - if (countAndUserEntities.first == -1) { + if (count == -1) { return@either ResponseEntity.status(HttpStatus.NO_CONTENT).build() } - val compactedEntities = JsonLdUtils.compactEntities( - countAndUserEntities.second, - contextLink, - mediaType - ) + val compactedEntities = JsonLdUtils.compactEntities(entities, contexts) val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) buildQueryResponse( compactedEntities.toFinalRepresentation(ngsiLdDataRepresentation), - countAndUserEntities.first, + count, "/ngsi-ld/v1/entityAccessControl/users", entitiesQuery.paginationQuery, params, mediaType, - contextLink + contexts ) }.fold( { it.toErrorResponse() }, @@ -294,7 +282,7 @@ class EntityAccessControlHandler( val body = requestBody.awaitFirst().deserializeAsMap() val contexts = checkAndGetContext(httpHeaders, body).bind().replaceDefaultContextToAuthzContext() - val expandedAttribute = expandAttribute(AUTH_TERM_SAP, removeContextFromInput(body), contexts) + val expandedAttribute = expandAttribute(AUTH_TERM_SAP, body.minus(JSONLD_CONTEXT), contexts) if (expandedAttribute.first != AUTH_PROP_SAP) BadRequestDataException("${expandedAttribute.first} is not authorized property name") .left().bind>() diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityHandler.kt index b02590e3c..4eadd56e1 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityHandler.kt @@ -13,10 +13,12 @@ import com.egm.stellio.search.util.validateMinimalQueryEntitiesParameters import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.JsonLdUtils.compactEntities +import com.egm.stellio.shared.util.JsonLdUtils.compactEntity import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute import com.egm.stellio.shared.util.JsonLdUtils.expandAttributes import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity -import com.egm.stellio.shared.util.JsonLdUtils.removeContextFromInput +import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdTerm import com.egm.stellio.shared.util.JsonUtils.serializeObject import com.egm.stellio.shared.web.BaseHandler import org.springframework.http.HttpHeaders @@ -188,34 +190,30 @@ class EntityHandler( val mediaType = getApplicableMediaType(httpHeaders).bind() val sub = getSubFromSecurityContext() - val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() val entitiesQuery = composeEntitiesQuery( applicationProperties.pagination, params, - contextLink + contexts ).bind() .validateMinimalQueryEntitiesParameters().bind() val accessRightFilter = authorizationService.computeAccessRightFilter(sub) - val countAndEntities = queryService.queryEntities(entitiesQuery, accessRightFilter).bind() + val (entities, count) = queryService.queryEntities(entitiesQuery, accessRightFilter).bind() - val filteredEntities = JsonLdUtils.filterJsonLdEntitiesOnAttributes(countAndEntities.first, entitiesQuery.attrs) + val filteredEntities = entities.filterOnAttributes(entitiesQuery.attrs) - val compactedEntities = JsonLdUtils.compactEntities( - filteredEntities, - contextLink, - mediaType - ) + val compactedEntities = compactEntities(filteredEntities, contexts) val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) buildQueryResponse( compactedEntities.toFinalRepresentation(ngsiLdDataRepresentation), - countAndEntities.second, + count, "/ngsi-ld/v1/entities", entitiesQuery.paginationQuery, params, mediaType, - contextLink + contexts ) }.fold( { it.toErrorResponse() }, @@ -234,29 +232,29 @@ class EntityHandler( val mediaType = getApplicableMediaType(httpHeaders).bind() val sub = getSubFromSecurityContext() - val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() val queryParams = composeEntitiesQuery( applicationProperties.pagination, params, - contextLink + contexts ).bind() entityPayloadService.checkEntityExistence(entityId).bind() authorizationService.userCanReadEntity(entityId, sub).bind() - val jsonLdEntity = queryService.queryEntity(entityId, listOf(contextLink)).bind() + val jsonLdEntity = queryService.queryEntity(entityId, contexts).bind() jsonLdEntity.checkContainsAnyOf(queryParams.attrs).bind() val filteredExpandedEntity = ExpandedEntity( - JsonLdUtils.filterJsonLdEntityOnAttributes(jsonLdEntity, queryParams.attrs), + jsonLdEntity.filterOnAttributes(queryParams.attrs), jsonLdEntity.contexts ) - val compactedEntity = JsonLdUtils.compactEntity(filteredExpandedEntity, contextLink, mediaType).toMutableMap() + val compactedEntity = compactEntity(filteredExpandedEntity, contexts) val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) - prepareGetSuccessResponse(mediaType, contextLink) + prepareGetSuccessResponseHeaders(mediaType, contexts) .body(serializeObject(compactedEntity.toFinalRepresentation(ngsiLdDataRepresentation))) }.fold( { it.toErrorResponse() }, @@ -411,7 +409,7 @@ class EntityHandler( // We expect an NGSI-LD Attribute Fragment which should be a JSON-LD Object (see 5.4) val (body, contexts) = extractPayloadAndContexts(requestBody, httpHeaders).bind() - val expandedAttribute = expandAttribute(attrId, removeContextFromInput(body), contexts) + val expandedAttribute = expandAttribute(attrId, body, contexts) entityPayloadService.partialUpdateAttribute( entityId, @@ -458,8 +456,8 @@ class EntityHandler( val deleteAll = params.getFirst("deleteAll")?.toBoolean() ?: false val datasetId = params.getFirst("datasetId")?.toUri() - val contexts = listOf(getContextFromLinkHeaderOrDefault(httpHeaders).bind()) - val expandedAttrId = JsonLdUtils.expandJsonLdTerm(attrId, contexts) + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() + val expandedAttrId = expandJsonLdTerm(attrId, contexts) authorizationService.userCanUpdateEntity(entityId, sub).bind() @@ -504,7 +502,7 @@ class EntityHandler( entityPayloadService.checkEntityExistence(entityId).bind() authorizationService.userCanUpdateEntity(entityId, sub).bind() - val expandedAttribute = expandAttribute(attrId, removeContextFromInput(body), contexts) + val expandedAttribute = expandAttribute(attrId, body, contexts) entityPayloadService.replaceAttribute(entityId, expandedAttribute, sub.getOrNull()).bind() .let { diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityOperationHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityOperationHandler.kt index 06647c2c9..9b9bcb911 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityOperationHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityOperationHandler.kt @@ -12,10 +12,11 @@ import com.egm.stellio.search.util.validateMinimalQueryEntitiesParameters import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID_TERM import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT +import com.egm.stellio.shared.util.JsonLdUtils.compactEntities import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntityF -import com.egm.stellio.shared.util.JsonLdUtils.filterJsonLdEntitiesOnAttributes import com.egm.stellio.shared.util.JsonUtils.deserializeAsList import kotlinx.coroutines.reactive.awaitFirst import org.springframework.http.HttpHeaders @@ -53,7 +54,7 @@ class EntityOperationHandler( .checkNamesAreNgsiLdSupported().bind() .checkContentIsNgsiLdSupported().bind() checkBatchRequestBody(body).bind() - checkContext(httpHeaders, body).bind() + checkContentType(httpHeaders, body).bind() val context = getContextFromLinkHeader(httpHeaders.getOrEmpty(HttpHeaders.LINK)).bind() val (parsedEntities, unparsableEntities) = expandAndPrepareBatchOfEntities(body, context, httpHeaders.contentType).bind() @@ -93,7 +94,7 @@ class EntityOperationHandler( .checkNamesAreNgsiLdSupported().bind() .checkContentIsNgsiLdSupported().bind() checkBatchRequestBody(body).bind() - checkContext(httpHeaders, body).bind() + checkContentType(httpHeaders, body).bind() val context = getContextFromLinkHeader(httpHeaders.getOrEmpty(HttpHeaders.LINK)).bind() val (parsedEntities, unparsableEntities) = @@ -158,7 +159,7 @@ class EntityOperationHandler( .checkNamesAreNgsiLdSupported().bind() .checkContentIsNgsiLdSupported().bind() checkBatchRequestBody(body).bind() - checkContext(httpHeaders, body).bind() + checkContentType(httpHeaders, body).bind() val context = getContextFromLinkHeader(httpHeaders.getOrEmpty(HttpHeaders.LINK)).bind() val disallowOverwrite = options.map { it == QUERY_PARAM_OPTIONS_NOOVERWRITE_VALUE }.orElse(false) @@ -258,37 +259,33 @@ class EntityOperationHandler( @RequestParam params: MultiValueMap ): ResponseEntity<*> = either { val sub = getSubFromSecurityContext() - val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() val entitiesQuery = composeEntitiesQueryFromPostRequest( applicationProperties.pagination, requestBody.awaitFirst(), params, - contextLink + contexts ).bind() .validateMinimalQueryEntitiesParameters().bind() val accessRightFilter = authorizationService.computeAccessRightFilter(sub) - val countAndEntities = queryService.queryEntities(entitiesQuery, accessRightFilter).bind() + val (entities, count) = queryService.queryEntities(entitiesQuery, accessRightFilter).bind() - val filteredEntities = filterJsonLdEntitiesOnAttributes(countAndEntities.first, entitiesQuery.attrs) + val filteredEntities = entities.filterOnAttributes(entitiesQuery.attrs) - val compactedEntities = JsonLdUtils.compactEntities( - filteredEntities, - contextLink, - mediaType - ) + val compactedEntities = compactEntities(filteredEntities, contexts) val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) buildQueryResponse( compactedEntities.toFinalRepresentation(ngsiLdDataRepresentation), - countAndEntities.second, + count, "/ngsi-ld/v1/entities", entitiesQuery.paginationQuery, LinkedMultiValueMap(), mediaType, - contextLink + contexts ) }.fold( { it.toErrorResponse() }, @@ -308,7 +305,7 @@ class EntityOperationHandler( payload.map { val jsonLdExpansionResult = if (contentType == JSON_LD_MEDIA_TYPE) - expandJsonLdEntityF(it) + expandJsonLdEntityF(it.minus(JSONLD_CONTEXT), it.extractContexts()) else expandJsonLdEntityF(it, listOf(context ?: NGSILD_CORE_CONTEXT)) jsonLdExpansionResult diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityTypeHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityTypeHandler.kt index a120d9e3b..25640601d 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityTypeHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityTypeHandler.kt @@ -24,16 +24,16 @@ class EntityTypeHandler( @RequestHeader httpHeaders: HttpHeaders, @RequestParam details: Optional ): ResponseEntity<*> = either { - val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() val detailedRepresentation = details.orElse(false) val availableEntityTypes: Any = if (detailedRepresentation) - entityTypeService.getEntityTypes(listOf(contextLink)) + entityTypeService.getEntityTypes(contexts) else - entityTypeService.getEntityTypeList(listOf(contextLink)) + entityTypeService.getEntityTypeList(contexts) - prepareGetSuccessResponse(mediaType, contextLink) + prepareGetSuccessResponseHeaders(mediaType, contexts) .body(JsonUtils.serializeObject(availableEntityTypes)) }.fold( { it.toErrorResponse() }, @@ -48,13 +48,13 @@ class EntityTypeHandler( @RequestHeader httpHeaders: HttpHeaders, @PathVariable type: String ): ResponseEntity<*> = either { - val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() - val expandedType = expandJsonLdTerm(type.decode(), contextLink) + val expandedType = expandJsonLdTerm(type.decode(), contexts) - val entityTypeInfo = entityTypeService.getEntityTypeInfoByType(expandedType, listOf(contextLink)).bind() + val entityTypeInfo = entityTypeService.getEntityTypeInfoByType(expandedType, contexts).bind() - prepareGetSuccessResponse(mediaType, contextLink).body(JsonUtils.serializeObject(entityTypeInfo)) + prepareGetSuccessResponseHeaders(mediaType, contexts).body(JsonUtils.serializeObject(entityTypeInfo)) }.fold( { it.toErrorResponse() }, { it } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt index e928dd366..81223adf7 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityHandler.kt @@ -10,13 +10,15 @@ import com.egm.stellio.search.util.composeTemporalEntitiesQuery import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.compactEntities +import com.egm.stellio.shared.util.JsonLdUtils.compactEntity import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute import com.egm.stellio.shared.util.JsonLdUtils.expandAttributes import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity -import com.egm.stellio.shared.util.JsonUtils.deserializeAsList +import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdTerm import com.egm.stellio.shared.util.JsonUtils.serializeObject import com.egm.stellio.shared.web.BaseHandler -import kotlinx.coroutines.reactive.awaitFirst import org.springframework.http.HttpHeaders import org.springframework.http.HttpStatus import org.springframework.http.MediaType @@ -138,11 +140,11 @@ class TemporalEntityHandler( @RequestParam params: MultiValueMap ): ResponseEntity<*> = either { val sub = getSubFromSecurityContext() - val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() val temporalEntitiesQuery = - composeTemporalEntitiesQuery(applicationProperties.pagination, params, contextLink, true).bind() + composeTemporalEntitiesQuery(applicationProperties.pagination, params, contexts, true).bind() val accessRightFilter = authorizationService.computeAccessRightFilter(sub) @@ -151,11 +153,7 @@ class TemporalEntityHandler( accessRightFilter ).bind() - val compactedEntities = JsonLdUtils.compactEntities( - temporalEntities, - contextLink, - mediaType - ) + val compactedEntities = compactEntities(temporalEntities, contexts) val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) buildQueryResponse( @@ -165,7 +163,7 @@ class TemporalEntityHandler( temporalEntitiesQuery.entitiesQuery.paginationQuery, params, mediaType, - contextLink + contexts ) }.fold( { it.toErrorResponse() }, @@ -185,24 +183,24 @@ class TemporalEntityHandler( entityPayloadService.checkEntityExistence(entityId).bind() - val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() authorizationService.userCanReadEntity(entityId, sub).bind() val temporalEntitiesQuery = - composeTemporalEntitiesQuery(applicationProperties.pagination, params, contextLink).bind() + composeTemporalEntitiesQuery(applicationProperties.pagination, params, contexts).bind() val temporalEntity = queryService.queryTemporalEntity( entityId, temporalEntitiesQuery, - contextLink + contexts ).bind() - val compactedEntity = JsonLdUtils.compactEntity(temporalEntity, contextLink, mediaType).toMutableMap() + val compactedEntity = compactEntity(temporalEntity, contexts) val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) - prepareGetSuccessResponse(mediaType, contextLink) + prepareGetSuccessResponseHeaders(mediaType, contexts) .body(serializeObject(compactedEntity.toFinalRepresentation(ngsiLdDataRepresentation))) }.fold( { it.toErrorResponse() }, @@ -225,17 +223,14 @@ class TemporalEntityHandler( @RequestBody requestBody: Mono ): ResponseEntity<*> = either { val sub = getSubFromSecurityContext() - val body = requestBody.awaitFirst().deserializeAsList().first() - .checkNamesAreNgsiLdSupported().bind() - .checkContentIsNgsiLdSupported().bind() - val contexts = checkAndGetContext(httpHeaders, body).bind() + val (body, contexts) = extractPayloadAndContexts(requestBody, httpHeaders).bind() val instanceUri = instanceId.toUri() attrId.checkNameIsNgsiLdSupported().bind() entityPayloadService.checkEntityExistence(entityId).bind() authorizationService.userCanUpdateEntity(entityId, sub).bind() - val expandedAttribute = expandAttribute(attrId, JsonLdUtils.removeContextFromInput(body), contexts) + val expandedAttribute = expandAttribute(attrId, body, contexts) expandedAttribute.toExpandedAttributes().checkTemporalAttributeInstance().bind() attributeInstanceService.modifyAttributeInstance( @@ -294,9 +289,9 @@ class TemporalEntityHandler( val deleteAll = params.getFirst("deleteAll")?.toBoolean() ?: false val datasetId = params.getFirst("datasetId")?.toUri() - val contexts = listOf(getContextFromLinkHeaderOrDefault(httpHeaders).bind()) + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() attrId.checkNameIsNgsiLdSupported().bind() - val expandedAttrId = JsonLdUtils.expandJsonLdTerm(attrId, contexts) + val expandedAttrId = expandJsonLdTerm(attrId, contexts) temporalEntityAttributeService.checkEntityAndAttributeExistence( entityId, @@ -334,9 +329,9 @@ class TemporalEntityHandler( @PathVariable instanceId: URI ): ResponseEntity<*> = either { val sub = getSubFromSecurityContext() - val contexts = listOf(getContextFromLinkHeaderOrDefault(httpHeaders).bind()) + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() attrId.checkNameIsNgsiLdSupported().bind() - val expandedAttrId = JsonLdUtils.expandJsonLdTerm(attrId, contexts) + val expandedAttrId = expandJsonLdTerm(attrId, contexts) entityPayloadService.checkEntityExistence(entityId).bind() @@ -359,10 +354,7 @@ class TemporalEntityHandler( private fun ExpandedAttributes.checkTemporalAttributeInstance(): Either = this.values.all { expandedInstances -> expandedInstances.all { expandedAttributePayloadEntry -> - JsonLdUtils.getPropertyValueFromMapAsDateTime( - expandedAttributePayloadEntry, - JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY - ) != null + expandedAttributePayloadEntry.getMemberValueAsDateTime(NGSILD_OBSERVED_AT_PROPERTY) != null } }.let { if (it) Unit.right() @@ -372,10 +364,7 @@ class TemporalEntityHandler( private fun ExpandedAttributes.sorted(): ExpandedAttributes = this.mapValues { it.value.sortedByDescending { expandedAttributePayloadEntry -> - JsonLdUtils.getPropertyValueFromMapAsDateTime( - expandedAttributePayloadEntry, - JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY - ) + expandedAttributePayloadEntry.getMemberValueAsDateTime(NGSILD_OBSERVED_AT_PROPERTY) } } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityOperationsHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityOperationsHandler.kt index 7844afe9e..a3675e2e1 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityOperationsHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/TemporalEntityOperationsHandler.kt @@ -7,6 +7,7 @@ import com.egm.stellio.search.util.composeTemporalEntitiesQueryFromPostRequest import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.toFinalRepresentation import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.JsonLdUtils.compactEntities import kotlinx.coroutines.reactive.awaitFirst import org.springframework.http.HttpHeaders import org.springframework.http.MediaType @@ -33,7 +34,7 @@ class TemporalEntityOperationsHandler( @RequestParam params: MultiValueMap ): ResponseEntity<*> = either { val sub = getSubFromSecurityContext() - val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() val temporalEntitiesQuery = @@ -41,7 +42,7 @@ class TemporalEntityOperationsHandler( applicationProperties.pagination, requestBody.awaitFirst(), params, - contextLink + contexts ).bind() val accessRightFilter = authorizationService.computeAccessRightFilter(sub) @@ -51,11 +52,7 @@ class TemporalEntityOperationsHandler( accessRightFilter ).bind() - val compactedEntities = JsonLdUtils.compactEntities( - temporalEntities, - contextLink, - mediaType - ) + val compactedEntities = compactEntities(temporalEntities, contexts) val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) @@ -66,7 +63,7 @@ class TemporalEntityOperationsHandler( temporalEntitiesQuery.entitiesQuery.paginationQuery, params, mediaType, - contextLink + contexts ) }.fold( { it.toErrorResponse() }, diff --git a/search-service/src/main/kotlin/db/migration/V0_29__JsonLd_migration.kt b/search-service/src/main/kotlin/db/migration/V0_29__JsonLd_migration.kt index af872e100..bd1f1d7dc 100644 --- a/search-service/src/main/kotlin/db/migration/V0_29__JsonLd_migration.kt +++ b/search-service/src/main/kotlin/db/migration/V0_29__JsonLd_migration.kt @@ -6,7 +6,7 @@ import com.egm.stellio.search.model.TemporalEntityAttribute import com.egm.stellio.search.util.guessPropertyValueType import com.egm.stellio.search.util.toTemporalAttributeMetadata import com.egm.stellio.shared.model.* -import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.AuthContextModel import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SAP import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_EXPANDED_ENTITY_CORE_MEMBERS import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY @@ -14,12 +14,10 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE import com.egm.stellio.shared.util.JsonLdUtils.expandDeserializedPayload -import com.egm.stellio.shared.util.JsonLdUtils.extractContextFromInput -import com.egm.stellio.shared.util.JsonLdUtils.getAttributeFromExpandedAttributes -import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMapAsDateTime -import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMapAsString import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import com.egm.stellio.shared.util.JsonUtils.serializeObject +import com.egm.stellio.shared.util.extractContexts +import com.egm.stellio.shared.util.toUri import kotlinx.coroutines.runBlocking import org.flywaydb.core.api.migration.BaseJavaMigration import org.flywaydb.core.api.migration.Context @@ -75,7 +73,7 @@ class V0_29__JsonLd_migration : BaseJavaMigration() { }.forEach { (entityId, payload) -> logger.debug("Migrating entity {}", entityId) val deserializedPayload = payload.deserializeAsMap() - val contexts = extractContextFromInput(deserializedPayload) + val contexts = deserializedPayload.extractContexts() .map { if (contextsToTransform.containsKey(it)) { contextsToTransform[it]!! @@ -94,12 +92,11 @@ class V0_29__JsonLd_migration : BaseJavaMigration() { // extract specific access policy (if any) from the payload to be able to store it in entity_payload // then remove it from the expanded payload val specificAccessPolicy = - getAttributeFromExpandedAttributes( - originalExpandedEntity as ExpandedAttributes, + (originalExpandedEntity as ExpandedAttributes).getAttributeFromExpandedAttributes( AUTH_PROP_SAP, null )?.let { - getPropertyValueFromMapAsString(it, NGSILD_PROPERTY_VALUE) + it.getMemberValueAsString(NGSILD_PROPERTY_VALUE) }?.let { AuthContextModel.SpecificAccessPolicy.valueOf(it) } @@ -113,8 +110,7 @@ class V0_29__JsonLd_migration : BaseJavaMigration() { // as a property of the entity node, so we give them the creation date of the entity val entityCreationDate = try { - getPropertyValueFromMapAsDateTime( - expandedEntity as Map>, + (expandedEntity as Map>).getMemberValueAsDateTime( NGSILD_CREATED_AT_PROPERTY ) ?: defaultZonedDateTime } catch (e: DateTimeParseException) { @@ -149,8 +145,7 @@ class V0_29__JsonLd_migration : BaseJavaMigration() { val attributeName = ngsiLdAttribute.name ngsiLdAttribute.getAttributeInstances().forEach { ngsiLdAttributeInstance -> val datasetId = ngsiLdAttributeInstance.datasetId - val attributePayload = getAttributeFromExpandedAttributes( - jsonLdEntity.getAttributes(), + val attributePayload = jsonLdEntity.getAttributes().getAttributeFromExpandedAttributes( attributeName, datasetId )!! diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/AuthorizationServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/AuthorizationServiceTests.kt index 71bf18013..d99ac0758 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/AuthorizationServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/AuthorizationServiceTests.kt @@ -3,8 +3,8 @@ package com.egm.stellio.search.authorization import arrow.core.None import com.egm.stellio.search.model.EntitiesQuery import com.egm.stellio.shared.model.PaginationQuery -import com.egm.stellio.shared.util.AUTHZ_TEST_COMPOUND_CONTEXT -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT +import com.egm.stellio.shared.util.AUTHZ_TEST_COMPOUND_CONTEXTS +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXTS import com.egm.stellio.shared.util.shouldSucceedWith import com.egm.stellio.shared.util.toUri import io.mockk.spyk @@ -32,9 +32,9 @@ class AuthorizationServiceTests { authorizationService.getAuthorizedEntities( EntitiesQuery( paginationQuery = PaginationQuery(limit = 0, offset = 0), - context = NGSILD_CORE_CONTEXT + contexts = NGSILD_CORE_CONTEXTS ), - NGSILD_CORE_CONTEXT, + NGSILD_CORE_CONTEXTS, None ).shouldSucceedWith { assertEquals(-1, it.first) @@ -47,7 +47,7 @@ class AuthorizationServiceTests { authorizationService.getGroupsMemberships( 0, 0, - AUTHZ_TEST_COMPOUND_CONTEXT, + AUTHZ_TEST_COMPOUND_CONTEXTS, None ).shouldSucceedWith { assertEquals(-1, it.first) @@ -60,7 +60,7 @@ class AuthorizationServiceTests { authorizationService.getUsers( 0, 0, - AUTHZ_TEST_COMPOUND_CONTEXT + AUTHZ_TEST_COMPOUND_CONTEXTS ).shouldSucceedWith { assertEquals(-1, it.first) assertEquals(0, it.second.size) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationServiceTests.kt index 2a466805d..c4d459e86 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationServiceTests.kt @@ -250,7 +250,7 @@ class EnabledAuthorizationServiceTests { ) coEvery { subjectReferentialService.getCountAllGroups() } returns Either.Right(2) - enabledAuthorizationService.getGroupsMemberships(0, 2, AUTHZ_TEST_COMPOUND_CONTEXT, Some(subjectUuid)) + enabledAuthorizationService.getGroupsMemberships(0, 2, AUTHZ_TEST_COMPOUND_CONTEXTS, Some(subjectUuid)) .shouldSucceedWith { assertEquals(2, it.first) it.second.forEach { jsonLdEntity -> @@ -275,7 +275,7 @@ class EnabledAuthorizationServiceTests { ) coEvery { subjectReferentialService.getCountGroups(any()) } returns Either.Right(1) - enabledAuthorizationService.getGroupsMemberships(0, 2, AUTHZ_TEST_COMPOUND_CONTEXT, Some(subjectUuid)) + enabledAuthorizationService.getGroupsMemberships(0, 2, AUTHZ_TEST_COMPOUND_CONTEXTS, Some(subjectUuid)) .shouldSucceedWith { assertEquals(1, it.first) assertEquals(1, it.second[0].types.size) @@ -309,7 +309,7 @@ class EnabledAuthorizationServiceTests { ) coEvery { subjectReferentialService.getUsersCount() } returns Either.Right(2) - enabledAuthorizationService.getUsers(0, 2, AUTHZ_TEST_COMPOUND_CONTEXT) + enabledAuthorizationService.getUsers(0, 2, AUTHZ_TEST_COMPOUND_CONTEXTS) .shouldSucceedWith { assertEquals(2, it.first) it.second.forEach { jsonLdEntity -> @@ -343,9 +343,9 @@ class EnabledAuthorizationServiceTests { EntitiesQuery( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 10, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), - contextLink = APIC_COMPOUND_CONTEXT, + contexts = APIC_COMPOUND_CONTEXTS, sub = Some(subjectUuid) ).shouldSucceedWith { assertEquals(1, it.first) @@ -399,9 +399,9 @@ class EnabledAuthorizationServiceTests { EntitiesQuery( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 10, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), - contextLink = APIC_COMPOUND_CONTEXT, + contexts = APIC_COMPOUND_CONTEXTS, sub = Some(subjectUuid) ).shouldSucceedWith { assertEquals(1, it.first) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt index e2b04c300..b8aea8ba4 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt @@ -544,7 +544,7 @@ class EntityAccessRightsServiceTests : WithTimescaleContainer { ) { val rawEntity = if (specificAccessPolicy != null) - loadMinimalEntityWithSap(entityId, types, specificAccessPolicy, setOf(AUTHZ_TEST_COMPOUND_CONTEXT)) + loadMinimalEntityWithSap(entityId, types, specificAccessPolicy, AUTHZ_TEST_COMPOUND_CONTEXTS) else loadMinimalEntity(entityId, types) rawEntity.sampleDataToNgsiLdEntity().map { entityPayloadService.createEntityPayload( diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/listener/ObservationEventListenerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/listener/ObservationEventListenerTests.kt index 96db6d1b7..de13fb806 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/listener/ObservationEventListenerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/listener/ObservationEventListenerTests.kt @@ -49,7 +49,7 @@ class ObservationEventListenerTests { coVerify { entityPayloadService.createEntity( any(), - listOf(APIC_COMPOUND_CONTEXT), + APIC_COMPOUND_CONTEXTS, eq("0123456789-1234-5678-987654321") ) } @@ -59,7 +59,7 @@ class ObservationEventListenerTests { eq("0123456789-1234-5678-987654321"), eq(expectedEntityId), eq(listOf(BEEHIVE_TYPE)), - eq(listOf(APIC_COMPOUND_CONTEXT)) + eq(APIC_COMPOUND_CONTEXTS) ) } } @@ -106,7 +106,7 @@ class ObservationEventListenerTests { it.updated[0].updateOperationResult == UpdateOperationResult.UPDATED }, eq(false), - eq(listOf(APIC_COMPOUND_CONTEXT)) + eq(APIC_COMPOUND_CONTEXTS) ) } } @@ -173,7 +173,7 @@ class ObservationEventListenerTests { it.updated[0].datasetId == expectedTemperatureDatasetId }, eq(true), - eq(listOf(APIC_COMPOUND_CONTEXT)) + eq(APIC_COMPOUND_CONTEXTS) ) } } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/model/EntityModelTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/model/EntityModelTests.kt index ef98bac40..7ecf93b3f 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/model/EntityModelTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/model/EntityModelTests.kt @@ -18,7 +18,7 @@ class EntityModelTests { createdAt = now, modifiedAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = DEFAULT_CONTEXTS + contexts = NGSILD_TEST_CORE_CONTEXTS ) @Test diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/scope/ScopeServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/scope/ScopeServiceTests.kt index 26231989d..119e6f445 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/scope/ScopeServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/scope/ScopeServiceTests.kt @@ -98,7 +98,7 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { "scope": [${inputScopes.joinToString(",") { "\"$it\"" } }] } """.trimIndent(), - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) scopeService.update( @@ -137,7 +137,7 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { TemporalEntitiesQuery( EntitiesQuery( paginationQuery = PaginationQuery(limit = 100, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), TemporalQuery(timeproperty = TemporalProperty.MODIFIED_AT), withTemporalValues = false, @@ -163,7 +163,7 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { TemporalEntitiesQuery( EntitiesQuery( paginationQuery = PaginationQuery(limit = 100, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), TemporalQuery( timeproperty = TemporalProperty.MODIFIED_AT, @@ -193,7 +193,7 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { TemporalEntitiesQuery( EntitiesQuery( paginationQuery = PaginationQuery(limit = 100, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), TemporalQuery( timeproperty = TemporalProperty.MODIFIED_AT, @@ -227,7 +227,7 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { TemporalEntitiesQuery( EntitiesQuery( paginationQuery = PaginationQuery(limit = 100, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), TemporalQuery( timeproperty = TemporalProperty.MODIFIED_AT, @@ -262,7 +262,7 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { TemporalEntitiesQuery( EntitiesQuery( paginationQuery = PaginationQuery(limit = 100, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), TemporalQuery( timeproperty = TemporalProperty.MODIFIED_AT, @@ -303,7 +303,7 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { TemporalEntitiesQuery( EntitiesQuery( paginationQuery = PaginationQuery(limit = 100, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), TemporalQuery(), withTemporalValues = false, diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilderTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilderTests.kt index 4085c9aa8..c5467fd66 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilderTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilderTests.kt @@ -168,6 +168,6 @@ class TemporalScopeBuilderTests { types = listOf(BEEHIVE_TYPE), createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(APIC_COMPOUND_CONTEXT) + contexts = APIC_COMPOUND_CONTEXTS ) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt index 287569299..ef46b42c5 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt @@ -15,7 +15,6 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue -import com.egm.stellio.shared.util.JsonUtils.deserializeAsList import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import io.mockk.spyk import io.mockk.verify @@ -548,10 +547,10 @@ class AttributeInstanceServiceTests : WithTimescaleContainer, WithKafkaContainer val instanceTemporalFragment = loadSampleData("fragments/temporal_instance_fragment.jsonld") - val attributeInstancePayload = mapOf(INCOMING_COMPACT_PROPERTY to instanceTemporalFragment.deserializeAsList()) + val attributeInstancePayload = mapOf(INCOMING_COMPACT_PROPERTY to instanceTemporalFragment.deserializeAsMap()) val jsonLdAttribute = JsonLdUtils.expandJsonLdFragment( attributeInstancePayload, - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) as ExpandedAttributes val temporalEntitiesQuery = gimmeTemporalEntitiesQuery( diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeServiceTests.kt index 75860f489..703e83ddd 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeServiceTests.kt @@ -94,7 +94,7 @@ class AttributeServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return an AttributeList`() = runTest { - val attributeNames = attributeService.getAttributeList(listOf(APIC_COMPOUND_CONTEXT)) + val attributeNames = attributeService.getAttributeList(APIC_COMPOUND_CONTEXTS) assertTrue( attributeNames.attributeList == listOf( INCOMING_COMPACT_PROPERTY, @@ -109,13 +109,13 @@ class AttributeServiceTests : WithTimescaleContainer, WithKafkaContainer { fun `it should return an empty list of attributes if no attributes was found`() = runTest { clearPreviousTemporalEntityAttributesAndObservations() - val attributeNames = attributeService.getAttributeList(listOf(APIC_COMPOUND_CONTEXT)) + val attributeNames = attributeService.getAttributeList(APIC_COMPOUND_CONTEXTS) assert(attributeNames.attributeList.isEmpty()) } @Test fun `it should return a list of AttributeDetails`() = runTest { - val attributeDetails = attributeService.getAttributeDetails(listOf(APIC_COMPOUND_CONTEXT)) + val attributeDetails = attributeService.getAttributeDetails(APIC_COMPOUND_CONTEXTS) assertEquals(4, attributeDetails.size) assertTrue( attributeDetails.containsAll( @@ -149,14 +149,14 @@ class AttributeServiceTests : WithTimescaleContainer, WithKafkaContainer { fun `it should return an empty list of AttributeDetails if no attribute was found`() = runTest { clearPreviousTemporalEntityAttributesAndObservations() - val attributeDetails = attributeService.getAttributeDetails(listOf(APIC_COMPOUND_CONTEXT)) + val attributeDetails = attributeService.getAttributeDetails(APIC_COMPOUND_CONTEXTS) assertTrue(attributeDetails.isEmpty()) } @Test fun `it should return an attribute Information by specific attribute`() = runTest { val attributeTypeInfo = - attributeService.getAttributeTypeInfoByAttribute(INCOMING_PROPERTY, listOf(APIC_COMPOUND_CONTEXT)) + attributeService.getAttributeTypeInfoByAttribute(INCOMING_PROPERTY, APIC_COMPOUND_CONTEXTS) attributeTypeInfo.shouldSucceedWith { AttributeTypeInfo( @@ -172,7 +172,7 @@ class AttributeServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should error when type doesn't exist`() = runTest { val attributeTypeInfo = - attributeService.getAttributeTypeInfoByAttribute(TEMPERATURE_PROPERTY, listOf(APIC_COMPOUND_CONTEXT)) + attributeService.getAttributeTypeInfoByAttribute(TEMPERATURE_PROPERTY, APIC_COMPOUND_CONTEXTS) attributeTypeInfo.shouldFail { assertEquals(ResourceNotFoundException(attributeNotFoundMessage(TEMPERATURE_PROPERTY)), it) @@ -233,13 +233,13 @@ class AttributeServiceTests : WithTimescaleContainer, WithKafkaContainer { private fun newEntityPayload( id: String, types: List, - context: String = APIC_COMPOUND_CONTEXT + contexts: List = APIC_COMPOUND_CONTEXTS ): EntityPayload = EntityPayload( entityId = toUri(id), types = types, createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(context) + contexts = contexts ) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityPayloadServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityPayloadServiceTests.kt index fedfcbb76..c17575fdc 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityPayloadServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityPayloadServiceTests.kt @@ -2,7 +2,10 @@ package com.egm.stellio.search.service import arrow.core.right import com.egm.stellio.search.model.* -import com.egm.stellio.search.support.* +import com.egm.stellio.search.support.EMPTY_PAYLOAD +import com.egm.stellio.search.support.WithKafkaContainer +import com.egm.stellio.search.support.WithTimescaleContainer +import com.egm.stellio.search.support.buildSapAttribute import com.egm.stellio.search.util.deserializeAsMap import com.egm.stellio.shared.model.AlreadyExistsException import com.egm.stellio.shared.model.ResourceNotFoundException @@ -79,7 +82,7 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should create an entity payload from string with specificAccessPolicy`() = runTest { - loadMinimalEntityWithSap(entity01Uri, setOf(BEEHIVE_TYPE), AUTH_READ, setOf(AUTHZ_TEST_COMPOUND_CONTEXT)) + loadMinimalEntityWithSap(entity01Uri, setOf(BEEHIVE_TYPE), AUTH_READ, AUTHZ_TEST_COMPOUND_CONTEXTS) .sampleDataToNgsiLdEntity() .map { entityPayloadService.createEntityPayload( @@ -88,7 +91,7 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { now ) } - loadMinimalEntityWithSap(entity02Uri, setOf(BEEHIVE_TYPE), AUTH_WRITE, setOf(AUTHZ_TEST_COMPOUND_CONTEXT)) + loadMinimalEntityWithSap(entity02Uri, setOf(BEEHIVE_TYPE), AUTH_WRITE, AUTHZ_TEST_COMPOUND_CONTEXTS) .sampleDataToNgsiLdEntity() .map { entityPayloadService.createEntityPayload( @@ -147,13 +150,13 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { entityPayloadService.createEntity( rawEntity, - listOf(APIC_COMPOUND_CONTEXT), + APIC_COMPOUND_CONTEXTS, "0123456789-1234-5678-987654321" ).shouldSucceed() entityPayloadService.retrieve(beehiveTestCId) .shouldSucceedWith { - assertEquals(listOf(APIC_COMPOUND_CONTEXT), it.contexts) + assertEquals(APIC_COMPOUND_CONTEXTS, it.contexts) } coVerify { @@ -205,7 +208,7 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { entityPayloadService.createEntity( createEntityPayload, - listOf(APIC_COMPOUND_CONTEXT), + APIC_COMPOUND_CONTEXTS, "0123456789-1234-5678-987654321" ).shouldSucceed() @@ -265,13 +268,13 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { entityPayloadService.createEntity( createEntityPayload, - listOf(APIC_COMPOUND_CONTEXT), + APIC_COMPOUND_CONTEXTS, "0123456789-1234-5678-987654321" ).shouldSucceed() val expandedAttributes = expandAttributes( loadSampleData("fragments/beehive_merge_entity_multiple_types.jsonld"), - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) entityPayloadService.mergeEntity( @@ -309,13 +312,13 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { entityPayloadService.createEntity( createEntityPayload, - listOf(APIC_COMPOUND_CONTEXT), + APIC_COMPOUND_CONTEXTS, "0123456789-1234-5678-987654321" ).shouldSucceed() val expandedAttributes = expandAttributes( loadSampleData("fragments/beehive_merge_entity_multiple_types_and_scopes.jsonld"), - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) entityPayloadService.mergeEntity( @@ -352,7 +355,7 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { entityPayloadService.createEntity( createEntityPayload, - listOf(APIC_COMPOUND_CONTEXT), + APIC_COMPOUND_CONTEXTS, "0123456789-1234-5678-987654321" ).shouldSucceed() @@ -398,7 +401,7 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { val expandedAttribute = expandAttribute( loadSampleData("fragments/beehive_new_incoming_property.json"), - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) entityPayloadService.replaceAttribute(beehiveTestCId, expandedAttribute, "0123456789-1234-5678-987654321") @@ -436,7 +439,7 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should retrieve an entity payload with specificAccesPolicy`() = runTest { - loadMinimalEntityWithSap(entity01Uri, setOf(BEEHIVE_TYPE), AUTH_READ, setOf(AUTHZ_TEST_COMPOUND_CONTEXT)) + loadMinimalEntityWithSap(entity01Uri, setOf(BEEHIVE_TYPE), AUTH_READ, AUTHZ_TEST_COMPOUND_CONTEXTS) .sampleDataToNgsiLdEntity() .map { entityPayloadService.createEntityPayload( @@ -707,7 +710,7 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should remove a specific access policy from a entity payload`() = runTest { - loadMinimalEntityWithSap(entity01Uri, setOf(BEEHIVE_TYPE), AUTH_READ, setOf(AUTHZ_TEST_COMPOUND_CONTEXT)) + loadMinimalEntityWithSap(entity01Uri, setOf(BEEHIVE_TYPE), AUTH_READ, AUTHZ_TEST_COMPOUND_CONTEXTS) .sampleDataToNgsiLdEntity() .map { entityPayloadService.createEntityPayload( diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityQueryServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityQueryServiceTests.kt index beee42708..3a145c4a4 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityQueryServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityQueryServiceTests.kt @@ -59,11 +59,11 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { coEvery { attributeInstanceService.create(any()) } returns Unit.right() runBlocking { - entityPayloadService.createEntity(firstRawEntity, listOf(APIC_COMPOUND_CONTEXT)) - entityPayloadService.createEntity(secondRawEntity, listOf(APIC_COMPOUND_CONTEXT)) - entityPayloadService.createEntity(thirdRawEntity, listOf(APIC_COMPOUND_CONTEXT)) - entityPayloadService.createEntity(fourthRawEntity, listOf(APIC_COMPOUND_CONTEXT)) - entityPayloadService.createEntity(fifthRawEntity, listOf(APIC_COMPOUND_CONTEXT)) + entityPayloadService.createEntity(firstRawEntity, APIC_COMPOUND_CONTEXTS) + entityPayloadService.createEntity(secondRawEntity, APIC_COMPOUND_CONTEXTS) + entityPayloadService.createEntity(thirdRawEntity, APIC_COMPOUND_CONTEXTS) + entityPayloadService.createEntity(fourthRawEntity, APIC_COMPOUND_CONTEXTS) + entityPayloadService.createEntity(fifthRawEntity, APIC_COMPOUND_CONTEXTS) } } @@ -100,7 +100,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { EntitiesQuery( typeSelection = types, paginationQuery = PaginationQuery(limit = 30, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { null } @@ -129,7 +129,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { typeSelection = BEEHIVE_TYPE, scopeQ = scopeQ, paginationQuery = PaginationQuery(limit = 30, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { null } @@ -146,7 +146,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { ids = setOf(entity02Uri), typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 2, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { null } @@ -162,7 +162,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { ids = setOf(entity02Uri, entity05Uri), typeSelection = "$APIARY_TYPE|$BEEHIVE_TYPE", paginationQuery = PaginationQuery(limit = 2, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { null } @@ -178,7 +178,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 2, offset = 0), attrs = setOf(NGSILD_NAME_PROPERTY), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { null } @@ -194,7 +194,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { ids = setOf(entity02Uri), typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 1, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { null } @@ -209,7 +209,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { EntitiesQuery( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 1, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { null } @@ -224,7 +224,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { typeSelection = BEEHIVE_TYPE, idPattern = ".*urn:ngsi-ld:BeeHive:01.*", paginationQuery = PaginationQuery(limit = 1, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { null } @@ -282,7 +282,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { EntitiesQuery( q = q, paginationQuery = PaginationQuery(limit = 2, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { null } @@ -323,7 +323,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { coordinates ).getOrNull()!! ), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { null } @@ -337,7 +337,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { EntitiesQuery( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 30, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { """ @@ -362,7 +362,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { EntitiesQuery( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 30, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { """ @@ -389,7 +389,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { EntitiesQuery( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 30, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { """ @@ -413,7 +413,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { EntitiesQuery( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 30, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { null }.shouldSucceedWith { assertEquals(2, it) } } @@ -425,7 +425,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { ids = setOf(entity02Uri, entity01Uri), typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 30, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { "entity_payload.entity_id IN ('urn:ngsi-ld:BeeHive:01')" } .shouldSucceedWith { assertEquals(1, it) } @@ -439,7 +439,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { ids = setOf(entity02Uri, entity01Uri), typeSelection = "https://ontology.eglobalmark.com/apic#UnknownType", paginationQuery = PaginationQuery(limit = 2, offset = 10), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { null } @@ -454,7 +454,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 2, offset = 10), attrs = setOf("unknownAttribute"), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) { null } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityTypeServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityTypeServiceTests.kt index b5551d30d..fea6cb905 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityTypeServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityTypeServiceTests.kt @@ -94,7 +94,7 @@ class EntityTypeServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return an EntityTypeList`() = runTest { - val entityTypes = entityTypeService.getEntityTypeList(listOf(APIC_COMPOUND_CONTEXT)) + val entityTypes = entityTypeService.getEntityTypeList(APIC_COMPOUND_CONTEXTS) assertTrue( entityTypes.typeList == listOf(APIARY_COMPACT_TYPE, BEEHIVE_COMPACT_TYPE, SENSOR_COMPACT_TYPE) @@ -111,7 +111,7 @@ class EntityTypeServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a list of EntityType`() = runTest { - val entityTypes = entityTypeService.getEntityTypes(listOf(APIC_COMPOUND_CONTEXT)) + val entityTypes = entityTypeService.getEntityTypes(APIC_COMPOUND_CONTEXTS) assertTrue(entityTypes.size == 3) assertTrue( @@ -153,7 +153,7 @@ class EntityTypeServiceTests : WithTimescaleContainer, WithKafkaContainer { fun `it should return an EntityTypeInfo for a specific type`() = runTest { val entityTypeInfo = entityTypeService.getEntityTypeInfoByType( BEEHIVE_TYPE, - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) entityTypeInfo.shouldSucceedWith { @@ -180,7 +180,7 @@ class EntityTypeServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should error when type doesn't exist`() = runTest { val entityTypeInfo = - entityTypeService.getEntityTypeInfoByType(TEMPERATURE_PROPERTY, listOf(APIC_COMPOUND_CONTEXT)) + entityTypeService.getEntityTypeInfoByType(TEMPERATURE_PROPERTY, APIC_COMPOUND_CONTEXTS) entityTypeInfo.shouldFail { assertEquals(ResourceNotFoundException(typeNotFoundMessage(TEMPERATURE_PROPERTY)), it) @@ -241,13 +241,13 @@ class EntityTypeServiceTests : WithTimescaleContainer, WithKafkaContainer { private fun newEntityPayload( id: String, types: List, - context: String = APIC_COMPOUND_CONTEXT + contexts: List = APIC_COMPOUND_CONTEXTS ): EntityPayload = EntityPayload( entityId = toUri(id), types = types, createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(context) + contexts = contexts ) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/QueryServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/QueryServiceTests.kt index 84b1b71d9..05eb66203 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/QueryServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/QueryServiceTests.kt @@ -56,7 +56,7 @@ class QueryServiceTests { fun `it should return a JSON-LD entity when querying by id`() = runTest { coEvery { entityPayloadService.retrieve(any()) } returns gimmeEntityPayload().right() - queryService.queryEntity(entityUri, listOf(APIC_COMPOUND_CONTEXT)) + queryService.queryEntity(entityUri, APIC_COMPOUND_CONTEXTS) .shouldSucceedWith { assertEquals(entityUri.toString(), it.id) assertEquals(listOf(BEEHIVE_TYPE), it.types) @@ -68,7 +68,7 @@ class QueryServiceTests { fun `it should return an API exception if no entity exists with the given id`() = runTest { coEvery { entityPayloadService.retrieve(any()) } returns ResourceNotFoundException("").left() - queryService.queryEntity(entityUri, listOf(APIC_COMPOUND_CONTEXT)) + queryService.queryEntity(entityUri, APIC_COMPOUND_CONTEXTS) .shouldFail { assertTrue(it is ResourceNotFoundException) } @@ -115,13 +115,13 @@ class QueryServiceTests { entitiesQuery = EntitiesQuery( paginationQuery = PaginationQuery(limit = 0, offset = 50), attrs = setOf(INCOMING_PROPERTY, OUTGOING_PROPERTY), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), withTemporalValues = false, withAudit = false, withAggregatedValues = false ), - APIC_COMPOUND_CONTEXT + APIC_COMPOUND_CONTEXTS ).fold({ assertInstanceOf(ResourceNotFoundException::class.java, it) assertEquals( @@ -167,13 +167,13 @@ class QueryServiceTests { ), entitiesQuery = EntitiesQuery( paginationQuery = PaginationQuery(limit = 0, offset = 50), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), withTemporalValues = false, withAudit = false, withAggregatedValues = false ), - APIC_COMPOUND_CONTEXT + APIC_COMPOUND_CONTEXTS ) coVerify { @@ -199,7 +199,7 @@ class QueryServiceTests { temporalQuery = TemporalQuery(), entitiesQuery = EntitiesQuery( paginationQuery = PaginationQuery(limit = 0, offset = 50), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), withTemporalValues = false, withAudit = false, @@ -222,7 +222,7 @@ class QueryServiceTests { ), entitiesQuery = EntitiesQuery( paginationQuery = PaginationQuery(limit = 0, offset = 50), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), withTemporalValues = false, withAudit = false, @@ -250,7 +250,7 @@ class QueryServiceTests { temporalQuery = TemporalQuery(), entitiesQuery = EntitiesQuery( paginationQuery = PaginationQuery(limit = 0, offset = 50), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), withTemporalValues = false, withAudit = false, @@ -296,7 +296,7 @@ class QueryServiceTests { EntitiesQuery( typeSelection = "$BEEHIVE_TYPE,$APIARY_TYPE", paginationQuery = PaginationQuery(limit = 2, offset = 2), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), TemporalQuery( timerel = TemporalQuery.Timerel.BEFORE, @@ -314,7 +314,7 @@ class QueryServiceTests { EntitiesQuery( typeSelection = "$BEEHIVE_TYPE,$APIARY_TYPE", paginationQuery = PaginationQuery(limit = 2, offset = 2), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) ) attributeInstanceService.search( @@ -330,7 +330,7 @@ class QueryServiceTests { EntitiesQuery( typeSelection = "$BEEHIVE_TYPE,$APIARY_TYPE", paginationQuery = PaginationQuery(limit = 2, offset = 2), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), any() ) @@ -364,7 +364,7 @@ class QueryServiceTests { EntitiesQuery( typeSelection = "$BEEHIVE_TYPE,$APIARY_TYPE", paginationQuery = PaginationQuery(limit = 2, offset = 2), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), TemporalQuery( timerel = TemporalQuery.Timerel.BEFORE, @@ -418,7 +418,7 @@ class QueryServiceTests { entityId = entityUri, types = listOf(BEEHIVE_TYPE), createdAt = now, - contexts = listOf(APIC_COMPOUND_CONTEXT), + contexts = APIC_COMPOUND_CONTEXTS, payload = Json.of(loadSampleData("beehive_expanded.jsonld")) ) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeServiceTests.kt index c46bb84cc..b65534660 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeServiceTests.kt @@ -56,7 +56,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon entityId = beehiveTestCId, types = listOf(BEEHIVE_TYPE), createdAt = Instant.now().atZone(UTC), - contexts = listOf(APIC_COMPOUND_CONTEXT), + contexts = APIC_COMPOUND_CONTEXTS, payload = EMPTY_JSON_PAYLOAD ) ).block() @@ -66,7 +66,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon entityId = beehiveTestDId, types = listOf(BEEHIVE_TYPE), createdAt = Instant.now().atZone(UTC), - contexts = listOf(APIC_COMPOUND_CONTEXT), + contexts = APIC_COMPOUND_CONTEXTS, payload = EMPTY_JSON_PAYLOAD ) ).block() @@ -93,7 +93,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) val temporalEntityAttributes = temporalEntityAttributeService.getForEntity( @@ -118,7 +118,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon temporalEntityAttributeService.createEntityTemporalReferences( rawEntity, - listOf(APIC_COMPOUND_CONTEXT), + APIC_COMPOUND_CONTEXTS, "0123456789-1234-5678-987654321" ).shouldSucceed() @@ -170,7 +170,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon temporalEntityAttributeService.createEntityTemporalReferences( rawEntity, - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ).shouldSucceed() val teas = temporalEntityAttributeService.getForEntity(beehiveTestCId, emptySet()) @@ -226,7 +226,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon assertThrows("it should have thrown a RuntimeException") { temporalEntityAttributeService.createEntityTemporalReferences( rawEntity, - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ).shouldSucceed() } @@ -240,7 +240,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) .shouldSucceed() val temporalEntityAttribute = temporalEntityAttributeService.getForEntityAndAttribute( @@ -250,7 +250,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon val createdAt = ngsiLdDateTime() val newProperty = loadSampleData("fragments/beehive_new_incoming_property.json") - val expandedAttribute = expandAttribute(newProperty, listOf(APIC_COMPOUND_CONTEXT)) + val expandedAttribute = expandAttribute(newProperty, APIC_COMPOUND_CONTEXTS) val newNgsiLdProperty = expandedAttribute.toNgsiLdAttribute().shouldSucceedAndResult() temporalEntityAttributeService.replaceAttribute( temporalEntityAttribute, @@ -288,7 +288,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) .shouldSucceed() val temporalEntityAttribute = temporalEntityAttributeService.getForEntityAndAttribute( @@ -298,7 +298,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon val mergedAt = ngsiLdDateTime() val propertyToMerge = loadSampleData("fragments/beehive_mergeAttribute.json") - val expandedAttribute = expandAttribute(propertyToMerge, listOf(APIC_COMPOUND_CONTEXT)) + val expandedAttribute = expandAttribute(propertyToMerge, APIC_COMPOUND_CONTEXTS) temporalEntityAttributeService.mergeAttribute( temporalEntityAttribute, INCOMING_PROPERTY, @@ -331,7 +331,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon } } """.trimIndent(), - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) temporalEntityAttributeService.getForEntityAndAttribute( @@ -352,12 +352,12 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) .shouldSucceed() val createdAt = ngsiLdDateTime() val attributesToMerge = loadSampleData("fragments/beehive_mergeAttributes.json") - val expandedAttributes = JsonLdUtils.expandAttributes(attributesToMerge, listOf(APIC_COMPOUND_CONTEXT)) + val expandedAttributes = JsonLdUtils.expandAttributes(attributesToMerge, APIC_COMPOUND_CONTEXTS) val ngsiLdAttributes = expandedAttributes.toMap().toNgsiLdAttributes().shouldSucceedAndResult() temporalEntityAttributeService.mergeEntityAttributes( beehiveTestCId, @@ -417,13 +417,13 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) .shouldSucceed() val createdAt = ngsiLdDateTime() val observedAt = ZonedDateTime.parse("2019-12-04T12:00:00.00Z") val propertyToMerge = loadSampleData("fragments/beehive_mergeAttribute_without_observedAt.json") - val expandedAttributes = JsonLdUtils.expandAttributes(propertyToMerge, listOf(APIC_COMPOUND_CONTEXT)) + val expandedAttributes = JsonLdUtils.expandAttributes(propertyToMerge, APIC_COMPOUND_CONTEXTS) val ngsiLdAttributes = expandedAttributes.toMap().toNgsiLdAttributes().shouldSucceedAndResult() temporalEntityAttributeService.mergeEntityAttributes( beehiveTestCId, @@ -456,12 +456,12 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) .shouldSucceed() val replacedAt = ngsiLdDateTime() val propertyToReplace = loadSampleData("fragments/beehive_new_incoming_property.json") - val expandedAttribute = expandAttribute(propertyToReplace, listOf(APIC_COMPOUND_CONTEXT)) + val expandedAttribute = expandAttribute(propertyToReplace, APIC_COMPOUND_CONTEXTS) val ngsiLdAttribute = expandedAttribute.toNgsiLdAttribute().shouldSucceedAndResult() temporalEntityAttributeService.replaceEntityAttribute( @@ -490,12 +490,12 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) .shouldSucceed() val replacedAt = ngsiLdDateTime() val propertyToReplace = loadSampleData("fragments/beehive_new_unknown_property.json") - val expandedAttribute = expandAttribute(propertyToReplace, listOf(APIC_COMPOUND_CONTEXT)) + val expandedAttribute = expandAttribute(propertyToReplace, APIC_COMPOUND_CONTEXTS) val ngsiLdAttribute = expandedAttribute.toNgsiLdAttribute().shouldSucceedAndResult() temporalEntityAttributeService.replaceEntityAttribute( @@ -518,7 +518,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) temporalEntityAttributeService.getForEntityAndAttribute( beehiveTestCId, @@ -532,7 +532,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) temporalEntityAttributeService.getForEntityAndAttribute( beehiveTestCId, @@ -547,7 +547,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) temporalEntityAttributeService.getForEntityAndAttribute( beehiveTestCId, @@ -565,7 +565,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() coEvery { attributeInstanceService.deleteInstancesOfAttribute(any(), any(), any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) temporalEntityAttributeService.deleteTemporalAttribute( beehiveTestDId, @@ -588,7 +588,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() coEvery { attributeInstanceService.deleteAllInstancesOfAttribute(any(), any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) temporalEntityAttributeService.deleteTemporalAttribute( beehiveTestCId, @@ -611,7 +611,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) temporalEntityAttributeService.checkEntityAndAttributeExistence(beehiveTestCId, INCOMING_PROPERTY) .shouldSucceed() @@ -623,7 +623,7 @@ class TemporalEntityAttributeServiceTests : WithTimescaleContainer, WithKafkaCon coEvery { attributeInstanceService.create(any()) } returns Unit.right() - temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, listOf(APIC_COMPOUND_CONTEXT)) + temporalEntityAttributeService.createEntityTemporalReferences(rawEntity, APIC_COMPOUND_CONTEXTS) val result = temporalEntityAttributeService.checkEntityAndAttributeExistence(beehiveTestCId, "speed") diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt b/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt index 345310b45..9c4cc2090 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt @@ -4,7 +4,9 @@ import com.egm.stellio.search.model.* import com.egm.stellio.shared.model.PaginationQuery import com.egm.stellio.shared.model.addNonReifiedTemporalProperty import com.egm.stellio.shared.model.getSingleEntry -import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.APIC_COMPOUND_CONTEXTS +import com.egm.stellio.shared.util.JsonLdUtils +import com.egm.stellio.shared.util.ngsiLdDateTime import java.util.UUID import kotlin.random.Random @@ -43,7 +45,7 @@ fun gimmeTemporalEntitiesQuery( TemporalEntitiesQuery( entitiesQuery = EntitiesQuery( paginationQuery = PaginationQuery(limit = 50, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), temporalQuery = temporalQuery, withTemporalValues = withTemporalValues, @@ -54,5 +56,5 @@ fun gimmeTemporalEntitiesQuery( fun buildDefaultQueryParams(): EntitiesQuery = EntitiesQuery( paginationQuery = PaginationQuery(limit = 50, offset = 0), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/util/AttributeInstanceUtilsTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/util/AttributeInstanceUtilsTests.kt index c03031768..96cf56594 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/util/AttributeInstanceUtilsTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/util/AttributeInstanceUtilsTests.kt @@ -1,8 +1,8 @@ package com.egm.stellio.search.util import com.egm.stellio.search.model.TemporalEntityAttribute -import com.egm.stellio.shared.util.DEFAULT_CONTEXTS import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute +import com.egm.stellio.shared.util.NGSILD_TEST_CORE_CONTEXTS import com.egm.stellio.shared.util.ngsiLdDateTime import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -19,7 +19,7 @@ class AttributeInstanceUtilsTests { val expandedStringProperty = expandAttribute( "property", mapOf("type" to "Property", "value" to "A string"), - DEFAULT_CONTEXTS + NGSILD_TEST_CORE_CONTEXTS ) assertEquals( TemporalEntityAttribute.AttributeValueType.STRING, @@ -32,7 +32,7 @@ class AttributeInstanceUtilsTests { val expandedBooleanProperty = expandAttribute( "property", mapOf("type" to "Property", "value" to 20.0), - DEFAULT_CONTEXTS + NGSILD_TEST_CORE_CONTEXTS ) assertEquals( TemporalEntityAttribute.AttributeValueType.NUMBER, @@ -45,7 +45,7 @@ class AttributeInstanceUtilsTests { val expandedBooleanProperty = expandAttribute( "property", mapOf("type" to "Property", "value" to 20), - DEFAULT_CONTEXTS + NGSILD_TEST_CORE_CONTEXTS ) assertEquals( TemporalEntityAttribute.AttributeValueType.NUMBER, @@ -58,7 +58,7 @@ class AttributeInstanceUtilsTests { val expandedBooleanProperty = expandAttribute( "property", mapOf("type" to "Property", "value" to true), - DEFAULT_CONTEXTS + NGSILD_TEST_CORE_CONTEXTS ) assertEquals( TemporalEntityAttribute.AttributeValueType.BOOLEAN, @@ -71,7 +71,7 @@ class AttributeInstanceUtilsTests { val expandedListProperty = expandAttribute( "property", mapOf("type" to "Property", "value" to mapOf("key1" to "value1", "key2" to "value3")), - DEFAULT_CONTEXTS + NGSILD_TEST_CORE_CONTEXTS ) assertEquals( TemporalEntityAttribute.AttributeValueType.OBJECT, @@ -84,7 +84,7 @@ class AttributeInstanceUtilsTests { val expandedListProperty = expandAttribute( "property", mapOf("type" to "Property", "value" to listOf("A", "B")), - DEFAULT_CONTEXTS + NGSILD_TEST_CORE_CONTEXTS ) assertEquals( TemporalEntityAttribute.AttributeValueType.ARRAY, @@ -97,7 +97,7 @@ class AttributeInstanceUtilsTests { val expandedTimeProperty = expandAttribute( "property", mapOf("type" to "Property", "value" to LocalTime.now()), - DEFAULT_CONTEXTS + NGSILD_TEST_CORE_CONTEXTS ) assertEquals( TemporalEntityAttribute.AttributeValueType.TIME, @@ -110,7 +110,7 @@ class AttributeInstanceUtilsTests { val expandedTimeProperty = expandAttribute( "property", mapOf("type" to "Property", "value" to mapOf("@type" to "DateTime", "@value" to ngsiLdDateTime())), - DEFAULT_CONTEXTS + NGSILD_TEST_CORE_CONTEXTS ) assertEquals( TemporalEntityAttribute.AttributeValueType.DATETIME, @@ -123,7 +123,7 @@ class AttributeInstanceUtilsTests { val expandedTimeProperty = expandAttribute( "property", mapOf("type" to "Property", "value" to "urn:ngsi-ld:uri"), - DEFAULT_CONTEXTS + NGSILD_TEST_CORE_CONTEXTS ) assertEquals( TemporalEntityAttribute.AttributeValueType.URI, @@ -139,7 +139,7 @@ class AttributeInstanceUtilsTests { "type" to "GeoProperty", "value" to mapOf("type" to "Point", "coordinates" to listOf(0, 0)) ), - DEFAULT_CONTEXTS + NGSILD_TEST_CORE_CONTEXTS ) assertEquals( TemporalEntityAttribute.AttributeValueType.GEOMETRY, @@ -152,7 +152,7 @@ class AttributeInstanceUtilsTests { val expandedGeoRelationship = expandAttribute( "relationship", mapOf("type" to "Relationship", "value" to URI("urn:ngsi-ld")), - DEFAULT_CONTEXTS + NGSILD_TEST_CORE_CONTEXTS ) assertEquals( TemporalEntityAttribute.AttributeValueType.URI, diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/util/EntitiesQueryUtilsTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/util/EntitiesQueryUtilsTests.kt index 9efd1f0b1..49698071e 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/util/EntitiesQueryUtilsTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/util/EntitiesQueryUtilsTests.kt @@ -27,7 +27,7 @@ class EntitiesQueryUtilsTests { val entitiesQuery = composeEntitiesQuery( ApplicationProperties.Pagination(1, 20), requestParams, - APIC_COMPOUND_CONTEXT + APIC_COMPOUND_CONTEXTS ).shouldSucceedAndResult() assertEquals("$BEEHIVE_TYPE,$APIARY_TYPE", entitiesQuery.typeSelection) @@ -50,7 +50,7 @@ class EntitiesQueryUtilsTests { val entitiesQuery = composeEntitiesQuery( ApplicationProperties.Pagination(30, 100), requestParams, - NGSILD_TEST_CORE_CONTEXT + NGSILD_TEST_CORE_CONTEXTS ).shouldSucceedAndResult() assertEquals("speed>50;foodName==dietary fibres", entitiesQuery.q) @@ -62,7 +62,7 @@ class EntitiesQueryUtilsTests { val entitiesQuery = composeEntitiesQuery( ApplicationProperties.Pagination(30, 100), requestParams, - NGSILD_TEST_CORE_CONTEXT + NGSILD_TEST_CORE_CONTEXTS ).shouldSucceedAndResult() assertEquals(null, entitiesQuery.typeSelection) @@ -122,7 +122,7 @@ class EntitiesQueryUtilsTests { ApplicationProperties.Pagination(30, 100), query, LinkedMultiValueMap(), - APIC_COMPOUND_CONTEXT + APIC_COMPOUND_CONTEXTS ).shouldSucceedWith { assertEquals(setOf("urn:ngsi-ld:BeeHive:TESTC".toUri()), it.ids) assertEquals("urn:ngsi-ld:BeeHive:*", it.idPattern) @@ -154,7 +154,7 @@ class EntitiesQueryUtilsTests { ApplicationProperties.Pagination(30, 100), query, LinkedMultiValueMap(), - APIC_COMPOUND_CONTEXT + APIC_COMPOUND_CONTEXTS ).shouldSucceedWith { assertEquals(BEEHIVE_TYPE, it.typeSelection) assertEquals(setOf("${NGSILD_DEFAULT_VOCAB}attr1"), it.attrs) @@ -175,7 +175,7 @@ class EntitiesQueryUtilsTests { ApplicationProperties.Pagination(30, 100), query, LinkedMultiValueMap(), - APIC_COMPOUND_CONTEXT + APIC_COMPOUND_CONTEXTS ).shouldFailWith { it is BadRequestDataException && it.message == "The type parameter should be equals to 'Query'" @@ -195,7 +195,7 @@ class EntitiesQueryUtilsTests { ApplicationProperties.Pagination(30, 100), query, LinkedMultiValueMap(), - APIC_COMPOUND_CONTEXT + APIC_COMPOUND_CONTEXTS ).shouldFailWith { it is BadRequestDataException && it.message.startsWith("The supplied query could not be parsed") @@ -215,7 +215,7 @@ class EntitiesQueryUtilsTests { ApplicationProperties.Pagination(30, 100), query, LinkedMultiValueMap(), - APIC_COMPOUND_CONTEXT + APIC_COMPOUND_CONTEXTS ).shouldFailWith { it is BadRequestDataException && it.message.startsWith("The supplied query could not be parsed") @@ -232,7 +232,7 @@ class EntitiesQueryUtilsTests { composeTemporalEntitiesQuery( pagination, queryParams, - APIC_COMPOUND_CONTEXT, + APIC_COMPOUND_CONTEXTS, true ).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) @@ -252,7 +252,7 @@ class EntitiesQueryUtilsTests { composeTemporalEntitiesQuery( pagination, queryParams, - APIC_COMPOUND_CONTEXT + APIC_COMPOUND_CONTEXTS ).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals("'timerel' and 'time' must be used in conjunction", it.message) @@ -271,7 +271,7 @@ class EntitiesQueryUtilsTests { composeTemporalEntitiesQuery( pagination, queryParams, - APIC_COMPOUND_CONTEXT, + APIC_COMPOUND_CONTEXTS, true ).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) @@ -288,7 +288,7 @@ class EntitiesQueryUtilsTests { every { pagination.limitMax } returns 100 val temporalEntitiesQuery = - composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXT).shouldSucceedAndResult() + composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXTS).shouldSucceedAndResult() assertEquals( setOf("urn:ngsi-ld:BeeHive:TESTC".toUri(), "urn:ngsi-ld:BeeHive:TESTB".toUri()), @@ -321,7 +321,7 @@ class EntitiesQueryUtilsTests { every { pagination.limitMax } returns 100 val temporalEntitiesQuery = - composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXT).shouldSucceedAndResult() + composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXTS).shouldSucceedAndResult() assertTrue(temporalEntitiesQuery.withAudit) } @@ -353,7 +353,7 @@ class EntitiesQueryUtilsTests { queryParams.add("attrs", "outgoing") val temporalQuery = - composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXT).shouldSucceedAndResult() + composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXTS).shouldSucceedAndResult() assertEquals(1, temporalQuery.entitiesQuery.attrs.size) assertTrue(temporalQuery.entitiesQuery.attrs.contains(OUTGOING_PROPERTY)) @@ -371,7 +371,7 @@ class EntitiesQueryUtilsTests { queryParams.add("attrs", "incoming,outgoing") val temporalQuery = - composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXT).shouldSucceedAndResult() + composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXTS).shouldSucceedAndResult() assertEquals(2, temporalQuery.entitiesQuery.attrs.size) assertIterableEquals(setOf(INCOMING_PROPERTY, OUTGOING_PROPERTY), temporalQuery.entitiesQuery.attrs) @@ -388,7 +388,7 @@ class EntitiesQueryUtilsTests { queryParams.add("timeAt", "2019-10-17T07:31:39Z") val temporalQuery = - composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXT).shouldSucceedAndResult() + composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXTS).shouldSucceedAndResult() assertTrue(temporalQuery.entitiesQuery.attrs.isEmpty()) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntitiesParameterizedSource.kt b/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntitiesParameterizedSource.kt index c48202a83..cb709ed23 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntitiesParameterizedSource.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntitiesParameterizedSource.kt @@ -25,7 +25,7 @@ class TemporalEntitiesParameterizedSource { types = listOf(BEEHIVE_TYPE), createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(APIC_COMPOUND_CONTEXT) + contexts = APIC_COMPOUND_CONTEXTS ), emptyList(), mapOf( @@ -50,7 +50,7 @@ class TemporalEntitiesParameterizedSource { types = listOf(BEEHIVE_TYPE), createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(APIC_COMPOUND_CONTEXT) + contexts = APIC_COMPOUND_CONTEXTS ), emptyList(), mapOf( @@ -79,7 +79,7 @@ class TemporalEntitiesParameterizedSource { types = listOf(BEEHIVE_TYPE), createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(APIC_COMPOUND_CONTEXT) + contexts = APIC_COMPOUND_CONTEXTS ), emptyList(), mapOf( @@ -111,7 +111,7 @@ class TemporalEntitiesParameterizedSource { types = listOf(BEEHIVE_TYPE), createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(APIC_COMPOUND_CONTEXT) + contexts = APIC_COMPOUND_CONTEXTS ), emptyList(), mapOf( @@ -147,7 +147,7 @@ class TemporalEntitiesParameterizedSource { types = listOf(BEEHIVE_TYPE), createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(APIC_COMPOUND_CONTEXT) + contexts = APIC_COMPOUND_CONTEXTS ), emptyList(), mapOf( @@ -186,7 +186,7 @@ class TemporalEntitiesParameterizedSource { types = listOf(BEEHIVE_TYPE), createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(APIC_COMPOUND_CONTEXT) + contexts = APIC_COMPOUND_CONTEXTS ), emptyList(), mapOf( diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityBuilderTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityBuilderTests.kt index d94ac2a14..8c7651b4e 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityBuilderTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/util/TemporalEntityBuilderTests.kt @@ -38,7 +38,7 @@ class TemporalEntityBuilderTests { types = listOf(BEEHIVE_TYPE), createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(APIC_COMPOUND_CONTEXT) + contexts = APIC_COMPOUND_CONTEXTS ) val temporalEntity = TemporalEntityBuilder.buildTemporalEntity( EntityTemporalResult(entityPayload, emptyList(), attributeAndResultsMap), @@ -49,7 +49,7 @@ class TemporalEntityBuilderTests { withAudit = false, withAggregatedValues = false ), - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) assertJsonPayloadsAreEqual( loadSampleData("expectations/beehive_empty_outgoing.jsonld"), @@ -72,7 +72,7 @@ class TemporalEntityBuilderTests { types = listOf(BEEHIVE_TYPE), createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(APIC_COMPOUND_CONTEXT) + contexts = APIC_COMPOUND_CONTEXTS ) val temporalEntity = TemporalEntityBuilder.buildTemporalEntity( @@ -84,7 +84,7 @@ class TemporalEntityBuilderTests { withAudit, false ), - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) assertJsonPayloadsAreEqual( expectation, @@ -110,7 +110,7 @@ class TemporalEntityBuilderTests { withAudit, false ), - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) assertJsonPayloadsAreEqual( expectation, @@ -178,7 +178,7 @@ class TemporalEntityBuilderTests { types = listOf(BEEHIVE_TYPE), createdAt = now, payload = EMPTY_JSON_PAYLOAD, - contexts = listOf(APIC_COMPOUND_CONTEXT) + contexts = APIC_COMPOUND_CONTEXTS ) val temporalEntity = TemporalEntityBuilder.buildTemporalEntity( @@ -190,7 +190,7 @@ class TemporalEntityBuilderTests { withAudit = false, withAggregatedValues = true ), - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) assertJsonPayloadsAreEqual( diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/AnonymousUserHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/AnonymousUserHandlerTests.kt index 82eed369e..12df2bd12 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/AnonymousUserHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/AnonymousUserHandlerTests.kt @@ -8,8 +8,7 @@ import com.egm.stellio.search.service.EntityPayloadService import com.egm.stellio.search.service.QueryService import com.egm.stellio.search.service.TemporalEntityAttributeService import com.egm.stellio.shared.config.ApplicationProperties -import com.egm.stellio.shared.util.AQUAC_COMPOUND_CONTEXT -import com.egm.stellio.shared.util.buildContextLinkHeader +import com.egm.stellio.shared.util.AQUAC_HEADER_LINK import com.ninjasquad.springmockk.MockkBean import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired @@ -28,8 +27,6 @@ import org.springframework.test.web.reactive.server.WebTestClient @Import(WebSecurityTestConfig::class) class AnonymousUserHandlerTests { - private val aquacHeaderLink = buildContextLinkHeader(AQUAC_COMPOUND_CONTEXT) - @Autowired private lateinit var webClient: WebTestClient @@ -54,7 +51,7 @@ class AnonymousUserHandlerTests { webClient .get() .uri("/ngsi-ld/v1/entities/urn:ngsi-ld:Sensor:0022CCC") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .exchange() .expectStatus().isUnauthorized } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/AttributeHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/AttributeHandlerTests.kt index 5e56e10fc..c687c4dea 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/AttributeHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/AttributeHandlerTests.kt @@ -42,8 +42,6 @@ class AttributeHandlerTests { @MockkBean private lateinit var attributeService: AttributeService - private val apicHeaderLink = buildContextLinkHeader(APIC_COMPOUND_CONTEXT) - private val expectedAttributeDetails = """ [ @@ -204,7 +202,7 @@ class AttributeHandlerTests { @Test fun `get attribute type information should correctly serialize an AttributeTypeInfo`() { - coEvery { attributeService.getAttributeTypeInfoByAttribute(any(), listOf(APIC_COMPOUND_CONTEXT)) } returns + coEvery { attributeService.getAttributeTypeInfoByAttribute(any(), APIC_COMPOUND_CONTEXTS) } returns AttributeTypeInfo( id = TEMPERATURE_PROPERTY.toUri(), type = "Attribute", @@ -216,14 +214,14 @@ class AttributeHandlerTests { webClient.get() .uri("/ngsi-ld/v1/attributes/temperature") - .header(HttpHeaders.LINK, apicHeaderLink) + .header(HttpHeaders.LINK, APIC_HEADER_LINK) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .exchange() .expectStatus().isOk .expectBody().json(expectedAttributeTypeInfo) coVerify { - attributeService.getAttributeTypeInfoByAttribute(TEMPERATURE_PROPERTY, listOf(APIC_COMPOUND_CONTEXT)) + attributeService.getAttributeTypeInfoByAttribute(TEMPERATURE_PROPERTY, APIC_COMPOUND_CONTEXTS) } } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt index 138cf91d6..633414c3b 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt @@ -27,7 +27,6 @@ import com.egm.stellio.shared.util.AuthContextModel.GROUP_TYPE import com.egm.stellio.shared.util.AuthContextModel.SpecificAccessPolicy.AUTH_READ import com.egm.stellio.shared.util.AuthContextModel.USER_COMPACT_TYPE import com.egm.stellio.shared.util.AuthContextModel.USER_TYPE -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue import com.ninjasquad.springmockk.MockkBean @@ -57,8 +56,6 @@ import java.time.Duration @Import(WebSecurityTestConfig::class) class EntityAccessControlHandlerTests { - private val authzHeaderLink = buildContextLinkHeader(AUTHZ_TEST_CONTEXT) - @Autowired private lateinit var webClient: WebTestClient @@ -323,7 +320,7 @@ class EntityAccessControlHandlerTests { webClient.delete() .uri("/ngsi-ld/v1/entityAccessControl/$otherUserSub/attrs/$entityUri1") - .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHZ_TEST_CONTEXT)) + .header(HttpHeaders.LINK, AUTHZ_HEADER_LINK) .exchange() .expectStatus().isNoContent @@ -385,7 +382,7 @@ class EntityAccessControlHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entityAccessControl/$entityUri1/attrs/specificAccessPolicy") - .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHZ_TEST_CONTEXT)) + .header(HttpHeaders.LINK, AUTHZ_HEADER_LINK) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue(requestPayload) .exchange() @@ -490,7 +487,7 @@ class EntityAccessControlHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entityAccessControl/$entityUri1/attrs/specificAccessPolicy") - .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHZ_TEST_CONTEXT)) + .header(HttpHeaders.LINK, AUTHZ_HEADER_LINK) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue(requestPayload) .exchange() @@ -513,7 +510,7 @@ class EntityAccessControlHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entityAccessControl/$entityUri1/attrs/specificAccessPolicy") - .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHZ_TEST_CONTEXT)) + .header(HttpHeaders.LINK, AUTHZ_HEADER_LINK) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue(requestPayload) .exchange() @@ -528,7 +525,7 @@ class EntityAccessControlHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entityAccessControl/$entityUri1/attrs/specificAccessPolicy") - .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHZ_TEST_CONTEXT)) + .header(HttpHeaders.LINK, AUTHZ_HEADER_LINK) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue("{}") .exchange() @@ -542,7 +539,7 @@ class EntityAccessControlHandlerTests { webClient.delete() .uri("/ngsi-ld/v1/entityAccessControl/$entityUri1/attrs/specificAccessPolicy") - .header(HttpHeaders.LINK, buildContextLinkHeader(AUTHZ_TEST_CONTEXT)) + .header(HttpHeaders.LINK, AUTHZ_HEADER_LINK) .exchange() .expectStatus().isNoContent @@ -618,7 +615,7 @@ class EntityAccessControlHandlerTests { "id": "urn:ngsi-ld:Beehive:TESTC", "type": "$BEEHIVE_TYPE", "$AUTH_TERM_RIGHT": {"type":"Property", "value": "rCanRead"}, - "@context": ["$AUTHORIZATION_COMPOUND_CONTEXT"] + "@context": "$AUTHORIZATION_COMPOUND_CONTEXT" }, { "id": "urn:ngsi-ld:Beehive:TESTD", @@ -634,7 +631,7 @@ class EntityAccessControlHandlerTests { "value": {"$AUTH_TERM_KIND": "User", "$AUTH_TERM_USERNAME": "stellio-user"} } }, - "@context": ["$AUTHORIZATION_COMPOUND_CONTEXT"] + "@context": "$AUTHORIZATION_COMPOUND_CONTEXT" }] """.trimMargin() ) @@ -714,7 +711,7 @@ class EntityAccessControlHandlerTests { "id": "urn:ngsi-ld:group:1", "type": "$GROUP_COMPACT_TYPE", "name" : {"type":"Property", "value": "egm"}, - "@context": ["$AUTHORIZATION_COMPOUND_CONTEXT"] + "@context": "$AUTHORIZATION_COMPOUND_CONTEXT" } ] """.trimMargin() @@ -737,14 +734,15 @@ class EntityAccessControlHandlerTests { NGSILD_NAME_PROPERTY to buildExpandedPropertyValue("egm"), AuthContextModel.AUTH_REL_IS_MEMBER_OF to buildExpandedPropertyValue("true") ), - listOf(AUTHZ_TEST_CONTEXT) + listOf(AUTHZ_TEST_COMPOUND_CONTEXT) ) ) ).right() webClient.get() .uri("/ngsi-ld/v1/entityAccessControl/groups?count=true") - .header(HttpHeaders.LINK, authzHeaderLink) + .header(HttpHeaders.LINK, AUTHZ_HEADER_LINK) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .exchange() .expectStatus().isOk .expectHeader().valueEquals(RESULTS_COUNT_HEADER, "1") @@ -756,7 +754,10 @@ class EntityAccessControlHandlerTests { "type": "Group", "name": {"type":"Property", "value": "egm"}, "isMemberOf": {"type":"Property", "value": "true"}, - "@context": ["$AUTHZ_TEST_CONTEXT", "$NGSILD_CORE_CONTEXT"] + "@context": [ + "$AUTHZ_TEST_CONTEXT", + "$AUTHORIZATION_COMPOUND_CONTEXT" + ] } ] """.trimMargin() @@ -836,7 +837,7 @@ class EntityAccessControlHandlerTests { "givenName", "familyName", mapOf("profile" to "stellio-user", "username" to "username") - ).serializeProperties(AUTHZ_TEST_COMPOUND_CONTEXT), + ).serializeProperties(AUTHZ_TEST_COMPOUND_CONTEXTS), listOf(NGSILD_TEST_CORE_CONTEXT) ) ) @@ -858,7 +859,7 @@ class EntityAccessControlHandlerTests { "$AUTH_TERM_GIVEN_NAME" : { "type":"Property", "value": "givenName" }, "$AUTH_TERM_FAMILY_NAME" : { "type":"Property", "value": "familyName" }, "$AUTH_TERM_SUBJECT_INFO": { "type":"Property","value":{ "profile": "stellio-user" } }, - "@context": ["$AUTHORIZATION_COMPOUND_CONTEXT"] + "@context": "$AUTHORIZATION_COMPOUND_CONTEXT" } ] """.trimMargin() @@ -871,7 +872,7 @@ class EntityAccessControlHandlerTests { entityAccessRights: EntityAccessRights, context: String = NGSILD_TEST_CORE_CONTEXT ): ExpandedEntity { - val earSerialized = entityAccessRights.serializeProperties(AUTHZ_TEST_COMPOUND_CONTEXT) + val earSerialized = entityAccessRights.serializeProperties(AUTHZ_TEST_COMPOUND_CONTEXTS) return ExpandedEntity(earSerialized, listOf(context)) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt index f162f6320..55f430519 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt @@ -16,6 +16,7 @@ import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXTS import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATE_TIME_TYPE @@ -55,8 +56,6 @@ import java.time.* @Import(WebSecurityTestConfig::class) class EntityHandlerTests { - private val aquacHeaderLink = buildContextLinkHeader(AQUAC_COMPOUND_CONTEXT) - @Autowired private lateinit var webClient: WebTestClient @@ -187,7 +186,7 @@ class EntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entities") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .bodyValue(jsonLdFile) .exchange() .expectStatus().isBadRequest @@ -204,7 +203,7 @@ class EntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entities") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .bodyValue(entityWithoutId) .exchange() .expectStatus().isBadRequest @@ -221,7 +220,7 @@ class EntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entities") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .bodyValue(entityWithoutType) .exchange() .expectStatus().isBadRequest @@ -325,7 +324,7 @@ class EntityHandlerTests { """ { "createdAt": "2015-10-18T11:20:30.000001Z", - "@context": ["$NGSILD_CORE_CONTEXT"] + "@context": "$NGSILD_CORE_CONTEXT" } """.trimIndent() ) @@ -402,7 +401,7 @@ class EntityHandlerTests { "type": "Beehive", "prop1": "some value", "rel1": "urn:ngsi-ld:Entity:1234", - "@context": ["$NGSILD_CORE_CONTEXT"] + "@context": "$NGSILD_CORE_CONTEXT" } """.trimIndent() ) @@ -457,7 +456,7 @@ class EntityHandlerTests { .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .exchange() .expectStatus().isOk - .expectBody().json("""{"@context":["$NGSILD_CORE_CONTEXT"]}""") + .expectBody().json("""{"@context":"$NGSILD_CORE_CONTEXT"}""") .jsonPath("$.createdAt").doesNotExist() .jsonPath("$.modifiedAt").doesNotExist() } @@ -513,7 +512,7 @@ class EntityHandlerTests { "createdAt":"2015-10-18T11:20:30.000001Z", "modifiedAt":"2015-10-18T12:20:30.000001Z" }, - "@context": ["$NGSILD_CORE_CONTEXT"] + "@context": "$NGSILD_CORE_CONTEXT" } """.trimIndent() ) @@ -553,7 +552,7 @@ class EntityHandlerTests { "@value":"2015-10-18" } }, - "@context": ["$NGSILD_CORE_CONTEXT"] + "@context": "$NGSILD_CORE_CONTEXT" } """.trimIndent() ) @@ -593,7 +592,7 @@ class EntityHandlerTests { "@value":"11:20:30" } }, - "@context": ["$NGSILD_CORE_CONTEXT"] + "@context": "$NGSILD_CORE_CONTEXT" } """.trimIndent() ) @@ -630,7 +629,7 @@ class EntityHandlerTests { "id":"urn:ngsi-ld:Beehive:4567", "type":"Beehive", "name":{"type":"Property","datasetId":"urn:ngsi-ld:Property:french-name","value":"ruche"}, - "@context": ["$NGSILD_CORE_CONTEXT"] + "@context": "$NGSILD_CORE_CONTEXT" } """.trimIndent() ) @@ -683,7 +682,7 @@ class EntityHandlerTests { "type":"Property","datasetId":"urn:ngsi-ld:Property:french-name","value":"ruche" } ], - "@context": ["$NGSILD_CORE_CONTEXT"] + "@context": "$NGSILD_CORE_CONTEXT" } """.trimIndent() ) @@ -726,7 +725,7 @@ class EntityHandlerTests { "datasetId":"urn:ngsi-ld:Dataset:managedBy:0215", "object":"urn:ngsi-ld:Beekeeper:1230" }, - "@context": ["$NGSILD_CORE_CONTEXT"] + "@context": "$NGSILD_CORE_CONTEXT" } """.trimIndent() ) @@ -825,7 +824,7 @@ class EntityHandlerTests { "object":"urn:ngsi-ld:Beekeeper:1230" } ], - "@context": ["$NGSILD_CORE_CONTEXT"] + "@context": "$NGSILD_CORE_CONTEXT" } """.trimIndent() ) @@ -859,7 +858,7 @@ class EntityHandlerTests { webClient.get() .uri("/ngsi-ld/v1/entities/urn:ngsi-ld:BeeHive:TEST") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .exchange() .expectStatus().isForbidden .expectBody().json( @@ -899,7 +898,7 @@ class EntityHandlerTests { { "id": "$beehiveId", "type": "Beehive", - "@context": ["$NGSILD_CORE_CONTEXT"] + "@context": "$NGSILD_CORE_CONTEXT" } ] """.trimMargin() @@ -915,7 +914,7 @@ class EntityHandlerTests { EntitiesQuery( typeSelection = "https://uri.etsi.org/ngsi-ld/default-context/Beehive", paginationQuery = PaginationQuery(offset = 0, limit = 30), - context = NGSILD_CORE_CONTEXT + contexts = NGSILD_CORE_CONTEXTS ), any() ) @@ -949,7 +948,7 @@ class EntityHandlerTests { "id": "$beehiveId", "type": "Beehive", "createdAt":"2015-10-18T11:20:30.000001Z", - "@context": ["$NGSILD_CORE_CONTEXT"] + "@context": "$NGSILD_CORE_CONTEXT" } ] """.trimMargin() @@ -988,7 +987,7 @@ class EntityHandlerTests { { "id": "urn:ngsi-ld:Beehive:TESTC", "type": "Beehive", - "@context": ["$NGSILD_CORE_CONTEXT"] + "@context": "$NGSILD_CORE_CONTEXT" } ] """.trimMargin() @@ -1050,7 +1049,7 @@ class EntityHandlerTests { ids = setOf(beehiveId), typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(offset = 0, limit = 30), - context = APIC_COMPOUND_CONTEXT + contexts = APIC_COMPOUND_CONTEXTS ), any() ) @@ -1061,7 +1060,7 @@ class EntityHandlerTests { "@id" to beehiveId.toString(), "@type" to listOf("Beehive") ), - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) ), 1 @@ -1079,7 +1078,7 @@ class EntityHandlerTests { { "id": "$beehiveId", "type": "Beehive", - "@context": ["$APIC_COMPOUND_CONTEXT"] + "@context": "$APIC_COMPOUND_CONTEXT" } ] """.trimMargin() @@ -1301,7 +1300,7 @@ class EntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entities/$entityId/attrs") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1351,7 +1350,7 @@ class EntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entities/$entityId/attrs") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1402,7 +1401,7 @@ class EntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entities/$entityId/attrs") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1449,7 +1448,7 @@ class EntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entities/$entityId/attrs") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1489,7 +1488,7 @@ class EntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entities/$entityId/attrs") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .bodyValue(jsonLdFile) .exchange() .expectStatus().isNotFound @@ -1530,7 +1529,7 @@ class EntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entities/$entityId/attrs") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(invalidPayload) .exchange() @@ -1559,7 +1558,7 @@ class EntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/entities/$entityId/attrs") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1605,7 +1604,7 @@ class EntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/entities/$entityId/attrs/$attrId") - .header("Link", aquacHeaderLink) + .header("Link", AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1640,7 +1639,7 @@ class EntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/entities/$entityId/attrs/$attrId") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1670,7 +1669,7 @@ class EntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/entities/$entityId/attrs/$attrId") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1695,7 +1694,7 @@ class EntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/entities/$entityId/attrs/$attrId") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1750,7 +1749,7 @@ class EntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/entities/$entityId") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1804,7 +1803,7 @@ class EntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/entities/$entityId?observedAt=2019-12-04T12:00:00.00Z") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1842,7 +1841,7 @@ class EntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/entities/$entityId?observedAt=notDateTime") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1894,7 +1893,7 @@ class EntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/entities/$entityId") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1916,7 +1915,7 @@ class EntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/entities/") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -1957,7 +1956,7 @@ class EntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/entities/$entityId/attrs") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -2003,7 +2002,7 @@ class EntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/entities/$entityId/attrs") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -2030,7 +2029,7 @@ class EntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/entities/$entityId/attrs") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -2113,7 +2112,7 @@ class EntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/entities/$entityId/attrs") - .header(HttpHeaders.LINK, aquacHeaderLink) + .header(HttpHeaders.LINK, AQUAC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .bodyValue(jsonLdFile) .exchange() @@ -2136,7 +2135,7 @@ class EntityHandlerTests { coEvery { entityPayloadService.checkEntityExistence(beehiveId) } returns Unit.right() coEvery { entityPayloadService.retrieve(any()) } returns entity.right() every { entity.types } returns listOf(BEEHIVE_TYPE) - every { entity.contexts } returns listOf(APIC_COMPOUND_CONTEXT) + every { entity.contexts } returns APIC_COMPOUND_CONTEXTS coEvery { authorizationService.userCanAdminEntity(beehiveId, sub) } returns Unit.right() coEvery { entityPayloadService.deleteEntity(any()) } returns Unit.right() coEvery { authorizationService.removeRightsOnEntity(any()) } returns Unit.right() @@ -2159,7 +2158,7 @@ class EntityHandlerTests { entityEventService.publishEntityDeleteEvent( eq("60AAEBA3-C0C7-42B6-8CB0-0D30857F210E"), eq(entity), - eq(listOf(APIC_COMPOUND_CONTEXT)) + eq(APIC_COMPOUND_CONTEXTS) ) } } @@ -2277,7 +2276,7 @@ class EntityHandlerTests { eq(TEMPERATURE_PROPERTY), isNull(), eq(false), - eq(listOf(APIC_COMPOUND_CONTEXT)) + eq(APIC_COMPOUND_CONTEXTS) ) } } @@ -2312,7 +2311,7 @@ class EntityHandlerTests { eq(TEMPERATURE_PROPERTY), isNull(), eq(true), - eq(listOf(APIC_COMPOUND_CONTEXT)) + eq(APIC_COMPOUND_CONTEXTS) ) } } @@ -2347,7 +2346,7 @@ class EntityHandlerTests { eq(TEMPERATURE_PROPERTY), eq(datasetId.toUri()), eq(false), - eq(listOf(APIC_COMPOUND_CONTEXT)) + eq(APIC_COMPOUND_CONTEXTS) ) } } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityTypeHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityTypeHandlerTests.kt index 2847bae64..67e26edda 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityTypeHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityTypeHandlerTests.kt @@ -40,8 +40,6 @@ class EntityTypeHandlerTests { @MockkBean private lateinit var entityTypeService: EntityTypeService - private val apicHeaderLink = buildContextLinkHeader(APIC_COMPOUND_CONTEXT) - private val deadFishesType = "https://ontology.eglobalmark.com/aquac#DeadFishes" private val sensorType = "https://ontology.eglobalmark.com/egm#Sensor" @@ -261,7 +259,7 @@ class EntityTypeHandlerTests { webClient.get() .uri("/ngsi-ld/v1/types/BeeHive") - .header(HttpHeaders.LINK, apicHeaderLink) + .header(HttpHeaders.LINK, APIC_HEADER_LINK) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .exchange() .expectStatus().isOk @@ -270,7 +268,7 @@ class EntityTypeHandlerTests { coVerify { entityTypeService.getEntityTypeInfoByType( "https://ontology.eglobalmark.com/apic#BeeHive", - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) } } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt index d5224438b..6f63fd71d 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt @@ -49,8 +49,6 @@ import java.util.UUID @Import(WebSecurityTestConfig::class) class TemporalEntityHandlerTests { - private lateinit var apicHeaderLink: String - @Autowired private lateinit var webClient: WebTestClient @@ -75,8 +73,6 @@ class TemporalEntityHandlerTests { @BeforeAll fun configureWebClientDefaults() { - apicHeaderLink = buildContextLinkHeader(APIC_COMPOUND_CONTEXT) - webClient = webClient.mutate() .apply(mockJwt().jwt { it.subject(MOCK_USER_SUB) }) .apply(csrf()) @@ -105,7 +101,7 @@ class TemporalEntityHandlerTests { val data = loadSampleData("/temporal/beehive_create_temporal_entity_first_instance.jsonld").deserializeAsMap() - val jsonLdEntity = JsonLdUtils.expandJsonLdEntity(data, listOf(APIC_COMPOUND_CONTEXT)) + val jsonLdEntity = JsonLdUtils.expandJsonLdEntity(data, APIC_COMPOUND_CONTEXTS) val expectedInstancesFilePath = "/temporal/beehive_create_temporal_entity_without_first_instance_expanded.jsonld" val jsonInstances = @@ -178,7 +174,7 @@ class TemporalEntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs") - .header("Link", buildContextLinkHeader(APIC_COMPOUND_CONTEXT)) + .header("Link", APIC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(entityTemporalFragment)) .exchange() @@ -205,7 +201,7 @@ class TemporalEntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs") - .header("Link", buildContextLinkHeader(APIC_COMPOUND_CONTEXT)) + .header("Link", APIC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(entityTemporalFragment)) .exchange() @@ -232,7 +228,7 @@ class TemporalEntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs") - .header("Link", buildContextLinkHeader(APIC_COMPOUND_CONTEXT)) + .header("Link", APIC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(entityTemporalFragment)) .exchange() @@ -259,7 +255,7 @@ class TemporalEntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs") - .header("Link", buildContextLinkHeader(APIC_COMPOUND_CONTEXT)) + .header("Link", APIC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(entityTemporalFragment)) .exchange() @@ -282,7 +278,7 @@ class TemporalEntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs") - .header("Link", buildContextLinkHeader(APIC_COMPOUND_CONTEXT)) + .header("Link", APIC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue("{ \"id\": \"bad\" }")) .exchange() @@ -311,7 +307,7 @@ class TemporalEntityHandlerTests { webClient.post() .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs") - .header("Link", buildContextLinkHeader(APIC_COMPOUND_CONTEXT)) + .header("Link", APIC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(entityTemporalFragment)) .exchange() @@ -569,7 +565,7 @@ class TemporalEntityHandlerTests { "/ngsi-ld/v1/temporal/entities/$entityUri?" + "timerel=between&timeAt=2019-10-17T07:31:39Z&endTimeAt=2019-10-18T07:31:39Z" ) - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isOk @@ -584,7 +580,7 @@ class TemporalEntityHandlerTests { !temporalEntitiesQuery.withTemporalValues && !temporalEntitiesQuery.withAudit }, - eq(APIC_COMPOUND_CONTEXT) + eq(APIC_COMPOUND_CONTEXTS) ) } confirmVerified(queryService) @@ -604,7 +600,7 @@ class TemporalEntityHandlerTests { "/ngsi-ld/v1/temporal/entities/$entityUri?" + "timerel=between&timeAt=2019-10-17T07:31:39Z&endTimeAt=2019-10-18T07:31:39Z" ) - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isOk @@ -625,7 +621,7 @@ class TemporalEntityHandlerTests { "/ngsi-ld/v1/temporal/entities/$entityUri?" + "timerel=between&timeAt=2019-10-17T07:31:39Z&endTimeAt=2019-10-18T07:31:39Z" ) - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isOk @@ -645,7 +641,7 @@ class TemporalEntityHandlerTests { "/ngsi-ld/v1/temporal/entities/$entityUri?" + "timerel=between&timeAt=2019-10-17T07:31:39Z&endTimeAt=2019-10-18T07:31:39Z" ) - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isOk .expectBody().jsonPath("$").isMap @@ -667,7 +663,7 @@ class TemporalEntityHandlerTests { "/ngsi-ld/v1/temporal/entities/$entityUri?" + "timerel=between&timeAt=2019-10-17T07:31:39Z&endTimeAt=2019-10-18T07:31:39Z" ) - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .header("Accept", MediaType.APPLICATION_JSON.toString()) .exchange() .expectStatus().isOk @@ -691,7 +687,7 @@ class TemporalEntityHandlerTests { "/ngsi-ld/v1/temporal/entities/$entityUri?" + "timerel=between&timeAt=2019-10-17T07:31:39Z&endTimeAt=2019-10-18T07:31:39Z&options=temporalValues" ) - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isOk .expectBody().jsonPath("$").isMap @@ -782,7 +778,7 @@ class TemporalEntityHandlerTests { "/ngsi-ld/v1/temporal/entities?" + "timerel=between&timeAt=2019-10-17T07:31:39Z&endTimeAt=2019-10-18T07:31:39Z&type=BeeHive" ) - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isOk .expectBody().json("[]") @@ -819,7 +815,7 @@ class TemporalEntityHandlerTests { "timerel=between&timeAt=2019-10-17T07:31:39Z&endTimeAt=2019-10-18T07:31:39Z&" + "type=BeeHive" ) - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isOk .expectBody() @@ -846,7 +842,7 @@ class TemporalEntityHandlerTests { "type=BeeHive" ) .header("Accept", MediaType.APPLICATION_JSON.toString()) - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isOk .expectHeader().exists("Link") @@ -1069,7 +1065,7 @@ class TemporalEntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs/$TEMPERATURE_COMPACT_PROPERTY/$attributeInstanceId") - .header("Link", buildContextLinkHeader(APIC_COMPOUND_CONTEXT)) + .header("Link", APIC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(instanceTemporalFragment)) .exchange() @@ -1100,7 +1096,7 @@ class TemporalEntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs/$TEMPERATURE_COMPACT_PROPERTY/$attributeInstanceId") - .header("Link", buildContextLinkHeader(APIC_COMPOUND_CONTEXT)) + .header("Link", APIC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(instanceTemporalFragment)) .exchange() @@ -1130,7 +1126,7 @@ class TemporalEntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs/$TEMPERATURE_COMPACT_PROPERTY/$attributeInstanceId") - .header("Link", buildContextLinkHeader(APIC_COMPOUND_CONTEXT)) + .header("Link", APIC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(instanceTemporalFragment)) .exchange() @@ -1163,7 +1159,7 @@ class TemporalEntityHandlerTests { webClient.patch() .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs/$TEMPERATURE_COMPACT_PROPERTY/$attributeInstanceId") - .header("Link", buildContextLinkHeader(APIC_COMPOUND_CONTEXT)) + .header("Link", APIC_HEADER_LINK) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(instanceTemporalFragment)) .exchange() @@ -1541,7 +1537,7 @@ class TemporalEntityHandlerTests { webClient .method(HttpMethod.DELETE) .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs/$temporalEntityAttributeName/$attributeInstanceId") - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isNoContent .expectBody().isEmpty @@ -1564,7 +1560,7 @@ class TemporalEntityHandlerTests { webClient .method(HttpMethod.DELETE) .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs/$temporalEntityAttributeName/$attributeInstanceId") - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isNotFound .expectBody().json( @@ -1601,7 +1597,7 @@ class TemporalEntityHandlerTests { webClient .method(HttpMethod.DELETE) .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs/$temporalEntityAttributeName/$attributeInstanceId") - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isNotFound .expectBody().json( @@ -1639,7 +1635,7 @@ class TemporalEntityHandlerTests { webClient .method(HttpMethod.DELETE) .uri("/ngsi-ld/v1/temporal/entities/$entityUri/attrs/$temporalEntityAttributeName/$attributeInstanceId") - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isForbidden .expectBody().json( diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityOperationsHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityOperationsHandlerTests.kt index d853c43e3..9b297bd01 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityOperationsHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityOperationsHandlerTests.kt @@ -30,8 +30,6 @@ import java.time.ZonedDateTime @Import(WebSecurityTestConfig::class) class TemporalEntityOperationsHandlerTests { - private lateinit var apicHeaderLink: String - @Autowired private lateinit var webClient: WebTestClient @@ -43,8 +41,6 @@ class TemporalEntityOperationsHandlerTests { @BeforeAll fun configureWebClientDefaults() { - apicHeaderLink = buildContextLinkHeader(APIC_COMPOUND_CONTEXT) - webClient = webClient.mutate() .apply(mockJwt().jwt { it.subject(MOCK_USER_SUB) }) .apply(csrf()) @@ -84,7 +80,7 @@ class TemporalEntityOperationsHandlerTests { webClient.post() .uri("/ngsi-ld/v1/temporal/entityOperations/query?options=temporalValues") .bodyValue(query) - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isOk @@ -133,7 +129,7 @@ class TemporalEntityOperationsHandlerTests { webClient.post() .uri("/ngsi-ld/v1/temporal/entityOperations/query?options=temporalValues&count=true") .bodyValue(query) - .header("Link", apicHeaderLink) + .header("Link", APIC_HEADER_LINK) .exchange() .expectStatus().isOk .expectHeader().valueEquals(RESULTS_COUNT_HEADER, "2") diff --git a/search-service/src/test/kotlin/db/migration/V0_29_JsonLd_migrationTests.kt b/search-service/src/test/kotlin/db/migration/V0_29_JsonLd_migrationTests.kt index 645011f5e..8266a912e 100644 --- a/search-service/src/test/kotlin/db/migration/V0_29_JsonLd_migrationTests.kt +++ b/search-service/src/test/kotlin/db/migration/V0_29_JsonLd_migrationTests.kt @@ -1,6 +1,6 @@ package db.migration -import com.egm.stellio.shared.util.APIC_COMPOUND_CONTEXT +import com.egm.stellio.shared.util.APIC_COMPOUND_CONTEXTS import com.egm.stellio.shared.util.JsonLdUtils import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import com.egm.stellio.shared.util.loadSampleData @@ -12,7 +12,7 @@ import org.springframework.test.context.ActiveProfiles @ActiveProfiles("test") class V0_29_JsonLd_migrationTests { - private val contexts = listOf(APIC_COMPOUND_CONTEXT) + private val contexts = APIC_COMPOUND_CONTEXTS @Test fun `it should remove instances when attribute has more than one instance with the same datasetId`() = runTest { diff --git a/search-service/src/test/resources/logback-test.xml b/search-service/src/test/resources/logback-test.xml index 6f4662426..81c32e60b 100644 --- a/search-service/src/test/resources/logback-test.xml +++ b/search-service/src/test/resources/logback-test.xml @@ -19,6 +19,7 @@ + diff --git a/search-service/src/test/resources/ngsild/fragments/temporal_instance_fragment.jsonld b/search-service/src/test/resources/ngsild/fragments/temporal_instance_fragment.jsonld index 3ab3fe316..d9628f0cb 100644 --- a/search-service/src/test/resources/ngsild/fragments/temporal_instance_fragment.jsonld +++ b/search-service/src/test/resources/ngsild/fragments/temporal_instance_fragment.jsonld @@ -1,7 +1,5 @@ -[ - { - "type": "Property", - "value": 10, - "observedAt": "2023-03-13T12:33:06Z" - } -] \ No newline at end of file +{ + "type": "Property", + "value": 10, + "observedAt": "2023-03-13T12:33:06Z" +} diff --git a/shared/config/detekt/baseline.xml b/shared/config/detekt/baseline.xml index 07383bca3..407fa1a07 100644 --- a/shared/config/detekt/baseline.xml +++ b/shared/config/detekt/baseline.xml @@ -5,15 +5,13 @@ CyclomaticComplexMethod:ExceptionHandler.kt$ExceptionHandler$@ExceptionHandler fun transformErrorResponse(throwable: Throwable): ResponseEntity<ProblemDetail> LongMethod:ExpandedEntityTests.kt$ExpandedEntityTests$@Test fun `it should return simplified GeoJSON entities`() LongMethod:QueryUtils.kt$private fun transformQQueryToSqlJsonPath( mainAttributePath: List<ExpandedTerm>, trailingAttributePath: List<ExpandedTerm>, operator: String, value: String ) - LongParameterList:ApiResponses.kt$( body: String, count: Int, resourceUrl: String, paginationQuery: PaginationQuery, requestParams: MultiValueMap<String, String>, mediaType: MediaType, contextLink: String ) - LongParameterList:ApiResponses.kt$( entities: Any, count: Int, resourceUrl: String, paginationQuery: PaginationQuery, requestParams: MultiValueMap<String, String>, mediaType: MediaType, contextLink: String ) + LongParameterList:ApiResponses.kt$( body: String, count: Int, resourceUrl: String, paginationQuery: PaginationQuery, requestParams: MultiValueMap<String, String>, mediaType: MediaType, contexts: List<String> ) + LongParameterList:ApiResponses.kt$( entities: Any, count: Int, resourceUrl: String, paginationQuery: PaginationQuery, requestParams: MultiValueMap<String, String>, mediaType: MediaType, contexts: List<String> ) LongParameterList:NgsiLdEntity.kt$NgsiLdEntity$( val id: URI, val types: List<ExpandedTerm>, val scopes: List<String>?, val relationships: List<NgsiLdRelationship>, val properties: List<NgsiLdProperty>, val geoProperties: List<NgsiLdGeoProperty>, val contexts: List<String> ) LongParameterList:NgsiLdEntity.kt$NgsiLdGeoPropertyInstance$( val coordinates: WKTCoordinates, createdAt: ZonedDateTime?, modifiedAt: ZonedDateTime?, observedAt: ZonedDateTime?, datasetId: URI?, properties: List<NgsiLdProperty>, relationships: List<NgsiLdRelationship> ) LongParameterList:NgsiLdEntity.kt$NgsiLdPropertyInstance$( val value: Any, val unitCode: String?, createdAt: ZonedDateTime?, modifiedAt: ZonedDateTime?, observedAt: ZonedDateTime?, datasetId: URI?, properties: List<NgsiLdProperty>, relationships: List<NgsiLdRelationship> ) LongParameterList:NgsiLdEntity.kt$NgsiLdRelationshipInstance$( val objectId: URI, createdAt: ZonedDateTime?, modifiedAt: ZonedDateTime?, observedAt: ZonedDateTime?, datasetId: URI?, properties: List<NgsiLdProperty>, relationships: List<NgsiLdRelationship> ) - NestedBlockDepth:JsonLdUtils.kt$JsonLdUtils$fun getPropertyValueFromMap(value: ExpandedAttributeInstance, propertyKey: String): Any? SpreadOperator:EntityEvent.kt$EntityEvent$( *[ JsonSubTypes.Type(value = EntityCreateEvent::class), JsonSubTypes.Type(value = EntityReplaceEvent::class), JsonSubTypes.Type(value = EntityDeleteEvent::class), JsonSubTypes.Type(value = AttributeAppendEvent::class), JsonSubTypes.Type(value = AttributeReplaceEvent::class), JsonSubTypes.Type(value = AttributeUpdateEvent::class), JsonSubTypes.Type(value = AttributeDeleteEvent::class), JsonSubTypes.Type(value = AttributeDeleteAllInstancesEvent::class) ] ) SwallowedException:JsonLdUtils.kt$JsonLdUtils$e: JsonLdError - TooManyFunctions:JsonLdUtils.kt$JsonLdUtils diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt index 2f2448df5..b742116ab 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt @@ -1,6 +1,7 @@ package com.egm.stellio.shared.model import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID_TERM import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_OBJECT import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE_TERM @@ -74,9 +75,14 @@ fun CompactedEntity.withoutSysAttrs(sysAttrToKeep: String?): Map { } } +/** + * Create the final representation of the entity, taking into account the options parameter and the Accept header. + * + * As a GeoJSON representation may have a null value for a key, returns a Map instead of CompactedEntity. + */ fun CompactedEntity.toFinalRepresentation( ngsiLdDataRepresentation: NgsiLdDataRepresentation -): Any = +): Map = this.let { if (!ngsiLdDataRepresentation.includeSysAttrs) it.withoutSysAttrs(ngsiLdDataRepresentation.timeproperty) else it @@ -84,12 +90,21 @@ fun CompactedEntity.toFinalRepresentation( if (ngsiLdDataRepresentation.attributeRepresentation == AttributeRepresentation.SIMPLIFIED) it.toKeyValues() else it }.let { - if (ngsiLdDataRepresentation.entityRepresentation == EntityRepresentation.GEO_JSON) - // geometryProperty is not null when GeoJSON representation is asked (defaults to location) - it.toGeoJson(ngsiLdDataRepresentation.geometryProperty!!) - else it + when (ngsiLdDataRepresentation.entityRepresentation) { + EntityRepresentation.GEO_JSON -> + // geometryProperty is not null when GeoJSON representation is asked (defaults to location) + it.toGeoJson(ngsiLdDataRepresentation.geometryProperty!!) + EntityRepresentation.JSON -> it.minus(JSONLD_CONTEXT) + EntityRepresentation.JSON_LD -> it + } } +/** + * Create the final representation of a list of entities, taking into account the options parameter + * and the Accept header. + * + * For a GeoJSON representation, the result is a map containing a list of GeoJson objects. + */ fun List.toFinalRepresentation( ngsiLdDataRepresentation: NgsiLdDataRepresentation ): Any = diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedEntity.kt index 00e6ab96f..07fcd8bee 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedEntity.kt @@ -3,12 +3,13 @@ package com.egm.stellio.shared.model import arrow.core.Either import arrow.core.left import arrow.core.right -import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.JsonLdUtils +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_EXPANDED_ENTITY_CORE_MEMBERS import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.castAttributeValue +import com.egm.stellio.shared.util.entityOrAttrsNotFoundMessage import java.time.ZonedDateTime data class ExpandedEntity( @@ -24,7 +25,7 @@ data class ExpandedEntity( else ResourceNotFoundException(entityOrAttrsNotFoundMessage(id, expandedAttributes)).left() fun getAttributes(): ExpandedAttributes = - members.filter { !JsonLdUtils.JSONLD_EXPANDED_ENTITY_CORE_MEMBERS.contains(it.key) } + members.filter { !JSONLD_EXPANDED_ENTITY_CORE_MEMBERS.contains(it.key) } .mapValues { castAttributeValue(it.value) } fun getScopes(): List? = @@ -36,7 +37,7 @@ data class ExpandedEntity( fun populateCreationTimeDate(createdAt: ZonedDateTime): ExpandedEntity = ExpandedEntity( members = members.mapValues { - if (JsonLdUtils.JSONLD_EXPANDED_ENTITY_CORE_MEMBERS.contains(it.key)) + if (JSONLD_EXPANDED_ENTITY_CORE_MEMBERS.contains(it.key)) it.value else castAttributeValue(it.value).map { expandedAttributeInstance -> expandedAttributeInstance.addDateTimeProperty( @@ -55,7 +56,7 @@ data class ExpandedEntity( fun populateReplacementTimeDates(createdAt: ZonedDateTime, replacedAt: ZonedDateTime): ExpandedEntity = ExpandedEntity( members = members.mapValues { - if (JsonLdUtils.JSONLD_EXPANDED_ENTITY_CORE_MEMBERS.contains(it.key)) + if (JSONLD_EXPANDED_ENTITY_CORE_MEMBERS.contains(it.key)) it.value else castAttributeValue(it.value).map { expandedAttributeInstance -> expandedAttributeInstance.addDateTimeProperty( @@ -83,4 +84,28 @@ data class ExpandedEntity( if (dateTime != null) this.plus(propertyKey to JsonLdUtils.buildNonReifiedTemporalValue(dateTime)) else this + + fun filterOnAttributes(includedAttributes: Set): Map { + val inputToMap = { i: ExpandedEntity -> i.members } + return filterEntityOnAttributes(this, inputToMap, includedAttributes) + } + + private fun filterEntityOnAttributes( + input: T, + inputToMap: (T) -> Map, + includedAttributes: Set + ): Map { + return if (includedAttributes.isEmpty()) { + inputToMap(input) + } else { + val includedKeys = JSONLD_EXPANDED_ENTITY_CORE_MEMBERS.plus(includedAttributes) + inputToMap(input).filterKeys { includedKeys.contains(it) } + } + } } + +fun List.filterOnAttributes(includedAttributes: Set): List = + this.filter { it.containsAnyOf(includedAttributes) } + .map { + ExpandedEntity(it.filterOnAttributes(includedAttributes), it.contexts) + } diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt index 3feeaf33e..fa1e048a0 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt @@ -1,12 +1,27 @@ package com.egm.stellio.shared.model +import arrow.core.Either +import arrow.core.flatMap +import arrow.core.left +import arrow.core.right import com.egm.stellio.shared.util.JsonLdUtils import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATE_TIME_TYPE +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATE_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_TIME_TYPE import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue +import com.egm.stellio.shared.util.toUri +import java.net.URI +import java.time.LocalDate +import java.time.LocalTime import java.time.ZonedDateTime +import kotlin.reflect.full.safeCast // basic alias to help identify, mainly in method calls, if the expected value is a compact or expanded one typealias ExpandedTerm = String @@ -16,6 +31,25 @@ typealias ExpandedAttributeInstances = List typealias ExpandedAttributeInstance = Map> typealias ExpandedNonReifiedPropertyValue = List> +fun ExpandedAttributes.addCoreMembers( + entityId: String, + entityTypes: List +): Map = + this.plus(listOf(JSONLD_ID to entityId, JSONLD_TYPE to entityTypes)) + +fun ExpandedAttributes.getAttributeFromExpandedAttributes( + expandedAttributeName: ExpandedTerm, + datasetId: URI? +): ExpandedAttributeInstance? = + this[expandedAttributeName]?.let { expandedAttributeInstances -> + expandedAttributeInstances.find { expandedAttributeInstance -> + if (datasetId == null) + !expandedAttributeInstance.containsKey(NGSILD_DATASET_ID_PROPERTY) + else + expandedAttributeInstance.getMemberValue(NGSILD_DATASET_ID_PROPERTY) == datasetId.toString() + } + } + fun ExpandedAttribute.toExpandedAttributes(): ExpandedAttributes = mapOf(this.first to this.second) @@ -52,12 +86,6 @@ fun ExpandedAttributeInstances.getSingleEntry(): ExpandedAttributeInstance { return this[0] } -fun ExpandedAttributes.addCoreMembers( - entityId: String, - entityTypes: List -): Map = - this.plus(listOf(JSONLD_ID to entityId, JSONLD_TYPE to entityTypes)) - fun ExpandedAttributeInstance.addSysAttrs( withSysAttrs: Boolean, createdAt: ZonedDateTime, @@ -71,3 +99,95 @@ fun ExpandedAttributeInstance.addSysAttrs( else it } else this + +/** + * Extract the actual value (@value) of a member from an expanded property. + * + * Called on a similar structure: + * { + * https://uri.etsi.org/ngsi-ld/hasValue=[{ + * @type=[https://uri.etsi.org/ngsi-ld/Property], + * @value=250 + * }], + * https://uri.etsi.org/ngsi-ld/unitCode=[{ + * @value=kg + * }], + * https://uri.etsi.org/ngsi-ld/observedAt=[{ + * @value=2019-12-18T10:45:44.248755Z + * }] + * } + * + * @return the actual value, e.g. "kg" if provided #memberName is https://uri.etsi.org/ngsi-ld/unitCode + */ +fun ExpandedAttributeInstance.getMemberValue(memberName: ExpandedTerm): Any? { + if (this[memberName] == null) + return null + + val intermediateList = this[memberName] as List> + return if (intermediateList.size == 1) { + val firstListEntry = intermediateList[0] + val finalValueType = firstListEntry[JSONLD_TYPE] + when { + finalValueType != null -> { + val finalValue = String::class.safeCast(firstListEntry[JSONLD_VALUE]) + when (finalValueType) { + NGSILD_DATE_TIME_TYPE -> ZonedDateTime.parse(finalValue) + NGSILD_DATE_TYPE -> LocalDate.parse(finalValue) + NGSILD_TIME_TYPE -> LocalTime.parse(finalValue) + else -> firstListEntry[JSONLD_VALUE] + } + } + + firstListEntry[JSONLD_VALUE] != null -> + firstListEntry[JSONLD_VALUE] + + firstListEntry[JSONLD_ID] != null -> { + // Used to get the value of datasetId property, + // since it is mapped to "@id" key rather than "@value" + firstListEntry[JSONLD_ID] + } + + else -> { + // it is a map / JSON object, keep it as is + // {https://uri.etsi.org/ngsi-ld/default-context/key=[{@value=value}], ...} + firstListEntry + } + } + } else { + intermediateList.map { + it[JSONLD_VALUE] + } + } +} + +fun ExpandedAttributeInstance.getMemberValueAsDateTime(memberName: ExpandedTerm): ZonedDateTime? = + ZonedDateTime::class.safeCast(this.getMemberValue(memberName)) + +fun ExpandedAttributeInstance.getMemberValueAsString(memberName: ExpandedTerm): String? = + String::class.safeCast(this.getMemberValue(memberName)) + +fun ExpandedAttributeInstance.extractRelationshipObject(name: String): Either = + this.right() + .flatMap { + if (!it.containsKey(NGSILD_RELATIONSHIP_OBJECT)) + BadRequestDataException("Relationship $name does not have an object field").left() + else it[NGSILD_RELATIONSHIP_OBJECT]!!.right() + } + .flatMap { + if (it.isEmpty()) + BadRequestDataException("Relationship $name is empty").left() + else it[0].right() + } + .flatMap { + if (it !is Map<*, *>) + BadRequestDataException("Relationship $name has an invalid object type: ${it.javaClass}").left() + else it[JSONLD_ID].right() + } + .flatMap { + if (it !is String) + BadRequestDataException("Relationship $name has an invalid or no object id: $it").left() + else it.toUri().right() + } + +fun castAttributeValue(value: Any): ExpandedAttributeInstances = + value as List>> diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt index a77565d8b..95510b628 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt @@ -24,10 +24,6 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_UNIT_CODE_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.extractRelationshipObject -import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMap -import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMapAsDateTime -import com.egm.stellio.shared.util.JsonLdUtils.getPropertyValueFromMapAsString import java.net.URI import java.time.LocalDate import java.time.LocalTime @@ -179,15 +175,15 @@ class NgsiLdPropertyInstance private constructor( name: String, values: ExpandedAttributeInstance ): Either = either { - val value = getPropertyValueFromMap(values, NGSILD_PROPERTY_VALUE) + val value = values.getMemberValue(NGSILD_PROPERTY_VALUE) ensureNotNull(value) { BadRequestDataException("Property $name has an instance without a value") } - val unitCode = getPropertyValueFromMapAsString(values, NGSILD_UNIT_CODE_PROPERTY) - val createdAt = getPropertyValueFromMapAsDateTime(values, NGSILD_CREATED_AT_PROPERTY) - val modifiedAt = getPropertyValueFromMapAsDateTime(values, NGSILD_MODIFIED_AT_PROPERTY) - val observedAt = getPropertyValueFromMapAsDateTime(values, NGSILD_OBSERVED_AT_PROPERTY) + val unitCode = values.getMemberValueAsString(NGSILD_UNIT_CODE_PROPERTY) + val createdAt = values.getMemberValueAsDateTime(NGSILD_CREATED_AT_PROPERTY) + val modifiedAt = values.getMemberValueAsDateTime(NGSILD_MODIFIED_AT_PROPERTY) + val observedAt = values.getMemberValueAsDateTime(NGSILD_OBSERVED_AT_PROPERTY) val datasetId = values.getDatasetId() val attributes = getNonCoreAttributes(values, NGSILD_PROPERTIES_CORE_MEMBERS) @@ -227,10 +223,10 @@ class NgsiLdRelationshipInstance private constructor( name: String, values: ExpandedAttributeInstance ): Either = either { - val objectId = extractRelationshipObject(name, values).bind() - val createdAt = getPropertyValueFromMapAsDateTime(values, NGSILD_CREATED_AT_PROPERTY) - val modifiedAt = getPropertyValueFromMapAsDateTime(values, NGSILD_MODIFIED_AT_PROPERTY) - val observedAt = getPropertyValueFromMapAsDateTime(values, NGSILD_OBSERVED_AT_PROPERTY) + val objectId = values.extractRelationshipObject(name).bind() + val createdAt = values.getMemberValueAsDateTime(NGSILD_CREATED_AT_PROPERTY) + val modifiedAt = values.getMemberValueAsDateTime(NGSILD_MODIFIED_AT_PROPERTY) + val observedAt = values.getMemberValueAsDateTime(NGSILD_OBSERVED_AT_PROPERTY) val datasetId = values.getDatasetId() val attributes = getNonCoreAttributes(values, NGSILD_RELATIONSHIPS_CORE_MEMBERS) @@ -269,9 +265,9 @@ class NgsiLdGeoPropertyInstance( name: String, values: ExpandedAttributeInstance ): Either = either { - val createdAt = getPropertyValueFromMapAsDateTime(values, NGSILD_CREATED_AT_PROPERTY) - val modifiedAt = getPropertyValueFromMapAsDateTime(values, NGSILD_MODIFIED_AT_PROPERTY) - val observedAt = getPropertyValueFromMapAsDateTime(values, NGSILD_OBSERVED_AT_PROPERTY) + val createdAt = values.getMemberValueAsDateTime(NGSILD_CREATED_AT_PROPERTY) + val modifiedAt = values.getMemberValueAsDateTime(NGSILD_MODIFIED_AT_PROPERTY) + val observedAt = values.getMemberValueAsDateTime(NGSILD_OBSERVED_AT_PROPERTY) val datasetId = values.getDatasetId() val wktValue = (values[NGSILD_GEOPROPERTY_VALUE]!![0] as Map)[JSONLD_VALUE] as String @@ -315,7 +311,7 @@ private suspend inline fun getAttributesOfType( ): Either> = either { attributes .mapValues { - JsonLdUtils.castAttributeValue(it.value) + castAttributeValue(it.value) }.filter { // only check the first entry, multi-attribute consistency is later checked by each attribute isAttributeOfType(it.value[0], type) @@ -395,7 +391,7 @@ fun ExpandedAttributeInstance.getDatasetId(): URI? = (this[NGSILD_DATASET_ID_PROPERTY]?.get(0) as? Map)?.get(JSONLD_ID)?.toUri() fun ExpandedAttributeInstance.getScopes(): List? = - when (val rawScopes = getPropertyValueFromMap(this, NGSILD_SCOPE_PROPERTY)) { + when (val rawScopes = this.getMemberValue(NGSILD_SCOPE_PROPERTY)) { is String -> listOf(rawScopes) is List<*> -> rawScopes as List else -> null diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiResponses.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiResponses.kt index b2ef5c67f..224dead2c 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiResponses.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiResponses.kt @@ -106,7 +106,7 @@ fun buildQueryResponse( paginationQuery: PaginationQuery, requestParams: MultiValueMap, mediaType: MediaType, - contextLink: String + contexts: List ): ResponseEntity = buildQueryResponse( serializeObject(entities), @@ -115,7 +115,7 @@ fun buildQueryResponse( paginationQuery, requestParams, mediaType, - contextLink + contexts ) fun buildQueryResponse( @@ -125,7 +125,7 @@ fun buildQueryResponse( paginationQuery: PaginationQuery, requestParams: MultiValueMap, mediaType: MediaType, - contextLink: String + contexts: List ): ResponseEntity { val prevAndNextLinks = PagingUtils.getPagingLinks( resourceUrl, @@ -136,31 +136,30 @@ fun buildQueryResponse( ) val responseHeaders = if (prevAndNextLinks.first != null && prevAndNextLinks.second != null) - prepareGetSuccessResponse(mediaType, contextLink) + prepareGetSuccessResponseHeaders(mediaType, contexts) .header(HttpHeaders.LINK, prevAndNextLinks.first) .header(HttpHeaders.LINK, prevAndNextLinks.second) else if (prevAndNextLinks.first != null) - prepareGetSuccessResponse(mediaType, contextLink) + prepareGetSuccessResponseHeaders(mediaType, contexts) .header(HttpHeaders.LINK, prevAndNextLinks.first) else if (prevAndNextLinks.second != null) - prepareGetSuccessResponse(mediaType, contextLink) + prepareGetSuccessResponseHeaders(mediaType, contexts) .header(HttpHeaders.LINK, prevAndNextLinks.second) else - prepareGetSuccessResponse(mediaType, contextLink) + prepareGetSuccessResponseHeaders(mediaType, contexts) return if (paginationQuery.count) responseHeaders.header(RESULTS_COUNT_HEADER, count.toString()).body(body) else responseHeaders.body(body) } -fun prepareGetSuccessResponse(mediaType: MediaType, contextLink: String): ResponseEntity.BodyBuilder { - return ResponseEntity.status(HttpStatus.OK) +fun prepareGetSuccessResponseHeaders(mediaType: MediaType, contexts: List): ResponseEntity.BodyBuilder = + ResponseEntity.status(HttpStatus.OK) .apply { if (mediaType == JSON_LD_MEDIA_TYPE) { this.header(HttpHeaders.CONTENT_TYPE, JSON_LD_CONTENT_TYPE) } else { - this.header(HttpHeaders.LINK, buildContextLinkHeader(contextLink)) + this.header(HttpHeaders.LINK, buildContextLinkHeader(contexts.first())) this.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) } } -} diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt index 0bf415ccf..e994080c9 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt @@ -8,8 +8,9 @@ import arrow.core.right import arrow.fx.coroutines.parMap import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_CONTEXT +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_TERM -import com.egm.stellio.shared.util.JsonLdUtils.extractContextFromInput import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import kotlinx.coroutines.reactive.awaitFirst import org.springframework.http.HttpHeaders @@ -51,12 +52,16 @@ val linkHeaderRegex: Regex = """<(.*)>;rel="http://www.w3.org/ns/json-ld#context";type="application/ld\+json"""".toRegex() /** - * As per 6.3.5, extract @context from Link header. In the absence of such Link header, it returns the default - * JSON-LD @context. + * As per 6.3.5, If the request verb is GET or DELETE, then the associated JSON-LD "@context" shall be obtained from a + * Link header as mandated by JSON-LD, section 6.2.extract @context from Link header. + * In the absence of such Link header, it returns the default JSON-LD @context. */ -fun getContextFromLinkHeaderOrDefault(httpHeaders: HttpHeaders): Either = +fun getContextFromLinkHeaderOrDefault(httpHeaders: HttpHeaders): Either> = getContextFromLinkHeader(httpHeaders.getOrEmpty(HttpHeaders.LINK)) - .map { it ?: JsonLdUtils.NGSILD_CORE_CONTEXT } + .map { + if (it != null) addCoreContextIfMissing(listOf(it)) + else listOf(NGSILD_CORE_CONTEXT) + } fun getContextFromLinkHeader(linkHeader: List): Either = if (linkHeader.isNotEmpty()) @@ -75,32 +80,31 @@ fun checkAndGetContext( httpHeaders: HttpHeaders, body: Map ): Either> = either { - checkContext(httpHeaders, body).bind() + checkContentType(httpHeaders, body).bind() if (httpHeaders.contentType == MediaType.APPLICATION_JSON || httpHeaders.contentType == MediaType.valueOf(JSON_MERGE_PATCH_CONTENT_TYPE) ) { - val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind() - listOf(contextLink) + getContextFromLinkHeaderOrDefault(httpHeaders).bind() } else { - val contexts = extractContextFromInput(body) + val contexts = body.extractContexts() // kind of duplicate what is checked in checkContext but a bit more sure ensure(contexts.isNotEmpty()) { BadRequestDataException( "Request payload must contain @context term for a request having an application/ld+json content type" ) } - contexts + addCoreContextIfMissing(contexts) } } -suspend fun checkContext(httpHeaders: HttpHeaders, body: List>): Either = +suspend fun checkContentType(httpHeaders: HttpHeaders, body: List>): Either = either { body.parMap { - checkContext(httpHeaders, it).bind() + checkContentType(httpHeaders, it).bind() } }.map { Unit.right() } -fun checkContext(httpHeaders: HttpHeaders, body: Map): Either { +fun checkContentType(httpHeaders: HttpHeaders, body: Map): Either { if (httpHeaders.contentType == MediaType.APPLICATION_JSON || httpHeaders.contentType == MediaType.valueOf(JSON_MERGE_PATCH_CONTENT_TYPE) ) { @@ -123,6 +127,10 @@ fun checkContext(httpHeaders: HttpHeaders, body: Map): Either, httpHeaders: HttpHeaders @@ -132,7 +140,40 @@ suspend fun extractPayloadAndContexts( .checkContentIsNgsiLdSupported().bind() val contexts = checkAndGetContext(httpHeaders, body).bind() - Pair(body, contexts) + Pair(body.minus(JSONLD_CONTEXT), contexts) +} + +fun Map.extractContexts(): List = + if (!this.containsKey(JSONLD_CONTEXT)) + emptyList() + else if (this[JSONLD_CONTEXT] is List<*>) + this[JSONLD_CONTEXT] as List + else if (this[JSONLD_CONTEXT] is String) + listOf(this[JSONLD_CONTEXT] as String) + else + emptyList() + +private val coreContextRegex = ".*ngsi-ld-core-context-v\\d+.\\d+.jsonld$".toRegex() + +internal fun addCoreContextIfMissing(contexts: List): List = + when { + contexts.isEmpty() -> listOf(NGSILD_CORE_CONTEXT) + // to ensure that core @context, if present, comes last + contexts.any { it.matches(coreContextRegex) } -> { + val coreContext = contexts.find { it.matches(coreContextRegex) }!! + contexts.filter { !it.matches(coreContextRegex) }.plus(coreContext) + } + // to check if the core @context is included / embedded in one of the link + canExpandJsonLdKeyFromCore(contexts) -> contexts + else -> contexts.plus(NGSILD_CORE_CONTEXT) + } + +/** + * Utility but basic method to find if given contexts can resolve a known term from the core context. + */ +private fun canExpandJsonLdKeyFromCore(contexts: List): Boolean { + val expandedType = JsonLdUtils.expandJsonLdTerm("datasetId", contexts) + return expandedType == NGSILD_DATASET_ID_PROPERTY } enum class OptionsParamValue(val value: String) { @@ -153,9 +194,6 @@ fun parseRequestParameter(requestParam: String?): Set = .orEmpty() .toSet() -fun expandTypeSelection(entityTypeSelection: EntityTypeSelection?, contextLink: String): EntityTypeSelection? = - expandTypeSelection(entityTypeSelection, listOf(contextLink)) - fun expandTypeSelection(entityTypeSelection: EntityTypeSelection?, contexts: List): EntityTypeSelection? = entityTypeSelection?.replace(typeSelectionRegex) { JsonLdUtils.expandJsonLdTerm(it.value.trim(), contexts) @@ -166,10 +204,10 @@ fun compactTypeSelection(entityTypeSelection: EntityTypeSelection, contexts: Lis JsonLdUtils.compactTerm(it.value.trim(), contexts) } -fun parseAndExpandRequestParameter(requestParam: String?, contextLink: String): Set = +fun parseAndExpandRequestParameter(requestParam: String?, contexts: List): Set = parseRequestParameter(requestParam) .map { - JsonLdUtils.expandJsonLdTerm(it.trim(), contextLink) + JsonLdUtils.expandJsonLdTerm(it.trim(), contexts) }.toSet() fun parseRepresentations( @@ -247,6 +285,13 @@ fun List.getApplicable(): Either { mediaType.right() } +fun acceptToMediaType(accept: String): MediaType = + when (accept) { + JSON_LD_CONTENT_TYPE -> JSON_LD_MEDIA_TYPE + GEO_JSON_CONTENT_TYPE -> GEO_JSON_MEDIA_TYPE + else -> MediaType.APPLICATION_JSON + } + fun String.parseTimeParameter(errorMsg: String): Either = try { ZonedDateTime.parse(this).right() diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/AuthUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/AuthUtils.kt index 2e5c9232f..5bf2863c0 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/AuthUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/AuthUtils.kt @@ -152,9 +152,12 @@ enum class AccessRight(val attributeName: String) { } } -fun getAuthzContextFromLinkHeaderOrDefault(httpHeaders: HttpHeaders): Either = +fun getAuthzContextFromLinkHeaderOrDefault(httpHeaders: HttpHeaders): Either> = getContextFromLinkHeader(httpHeaders.getOrEmpty(HttpHeaders.LINK)) - .map { it ?: AUTHORIZATION_COMPOUND_CONTEXT } + .map { + if (it != null) listOf(it).plus(AUTHORIZATION_COMPOUND_CONTEXT) + else listOf(AUTHORIZATION_COMPOUND_CONTEXT) + } fun List.replaceDefaultContextToAuthzContext() = if (this.size == 1 && this[0] == NGSILD_CORE_CONTEXT) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/GeoQueryUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/GeoQueryUtils.kt index a82b3996f..183ff2fd7 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/GeoQueryUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/GeoQueryUtils.kt @@ -35,11 +35,6 @@ const val GEOREL_NEAR_MAXDISTANCE_MODIFIER = "maxDistance" private val georelNearRegex = "^near;(?:minDistance|maxDistance)==\\d+$".toRegex() -fun parseGeoQueryParameters( - requestParams: Map, - contextLink: String -): Either = parseGeoQueryParameters(requestParams, listOf(contextLink)) - fun parseGeoQueryParameters( requestParams: Map, contexts: List diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt index 0a0482e6f..56aa337d7 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt @@ -1,7 +1,6 @@ package com.egm.stellio.shared.util import arrow.core.Either -import arrow.core.flatMap import arrow.core.left import arrow.core.right import com.apicatalog.jsonld.JsonLd @@ -11,21 +10,16 @@ import com.apicatalog.jsonld.context.cache.LruCache import com.apicatalog.jsonld.document.JsonDocument import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.JsonUtils.deserializeAs +import com.egm.stellio.shared.util.JsonUtils.deserializeAsList import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import com.egm.stellio.shared.util.JsonUtils.deserializeObject import com.egm.stellio.shared.util.JsonUtils.serializeObject -import jakarta.json.Json -import jakarta.json.JsonObject -import jakarta.json.JsonStructure +import jakarta.json.* import org.slf4j.Logger import org.slf4j.LoggerFactory -import org.springframework.http.MediaType import java.io.ByteArrayOutputStream import java.net.URI -import java.time.LocalDate -import java.time.LocalTime import java.time.ZonedDateTime -import kotlin.reflect.full.safeCast @JvmInline value class AttributeType(val uri: String) @@ -34,6 +28,7 @@ object JsonLdUtils { const val NGSILD_CORE_CONTEXT = "https://easy-global-market.github.io/ngsild-api-data-models/" + "shared-jsonld-contexts/ngsi-ld-core-context-v1.8.jsonld" + val NGSILD_CORE_CONTEXTS = listOf(NGSILD_CORE_CONTEXT) const val NGSILD_PREFIX = "https://uri.etsi.org/ngsi-ld/" const val NGSILD_DEFAULT_VOCAB = "https://uri.etsi.org/ngsi-ld/default-context/" @@ -53,6 +48,7 @@ object JsonLdUtils { const val NGSILD_RELATIONSHIP_OBJECTS = "https://uri.etsi.org/ngsi-ld/hasObjects" const val NGSILD_JSONPROPERTY_VALUES = "https://uri.etsi.org/ngsi-ld/jsons" + const val JSONLD_GRAPH = "@graph" const val JSONLD_ID_TERM = "id" const val JSONLD_ID = "@id" const val JSONLD_TYPE_TERM = "type" @@ -106,8 +102,6 @@ object JsonLdUtils { val logger: Logger = LoggerFactory.getLogger(javaClass) - private const val DEFAULT_CORE_CONTEXT_PATH = NGSILD_CORE_CONTEXT - private const val CONTEXT_CACHE_CAPACITY = 128 private const val DOCUMENT_CACHE_CAPACITY = 256 @@ -122,20 +116,6 @@ object JsonLdUtils { return contextsArray.build() } - private fun addCoreContext(contexts: List): List = - contexts.plus(DEFAULT_CORE_CONTEXT_PATH) - - internal fun addCoreContextIfMissing(contexts: List): List = - when { - contexts.isEmpty() -> listOf(NGSILD_CORE_CONTEXT) - // to ensure core @context comes last - contexts.contains(NGSILD_CORE_CONTEXT) -> - contexts.filter { it != NGSILD_CORE_CONTEXT }.plus(NGSILD_CORE_CONTEXT) - // to check if the core @context is included / embedded in one of the link - canExpandJsonLdKeyFromCore(contexts) -> contexts - else -> contexts.plus(NGSILD_CORE_CONTEXT) - } - suspend fun expandDeserializedPayload( deserializedPayload: Map, contexts: List @@ -155,20 +135,12 @@ object JsonLdUtils { else it.toAPIException().left() }) - suspend fun expandJsonLdEntityF(input: Map): Either = - expandJsonLdEntityF(input, extractContextFromInput(input)) - suspend fun expandJsonLdEntity(input: Map, contexts: List): ExpandedEntity = ExpandedEntity(doJsonLdExpansion(input, contexts), contexts) suspend fun expandJsonLdEntity(input: String, contexts: List): ExpandedEntity = expandJsonLdEntity(input.deserializeAsMap(), contexts) - suspend fun expandJsonLdEntity(input: String): ExpandedEntity { - val jsonInput = input.deserializeAsMap() - return expandJsonLdEntity(jsonInput, extractContextFromInput(jsonInput)) - } - fun expandJsonLdTerms(terms: List, contexts: List): List = terms.map { expandJsonLdTerm(it, contexts) @@ -184,7 +156,7 @@ object JsonLdUtils { serializeObject( mapOf( term to mapOf(), - JSONLD_CONTEXT to addCoreContext(contexts) + JSONLD_CONTEXT to contexts ) ).byteInputStream() ) @@ -238,19 +210,17 @@ object JsonLdUtils { fragment: Map, contexts: List ): ExpandedAttributes = - expandJsonLdFragment(fragment, contexts) as ExpandedAttributes + doJsonLdExpansion(fragment, contexts) as ExpandedAttributes private suspend fun doJsonLdExpansion(fragment: Map, contexts: List): Map { // transform the GeoJSON value of geo properties into WKT format before JSON-LD expansion // since JSON-LD expansion breaks the data (e.g., flattening the lists of lists) val parsedFragment = geoPropertyToWKT(fragment) - val usedContext = addCoreContext(contexts) - try { val expandedFragment = JsonLd.expand( JsonDocument.of( - serializeObject(parsedFragment.plus(JSONLD_CONTEXT to usedContext)).byteInputStream() + serializeObject(parsedFragment.plus(JSONLD_CONTEXT to contexts)).byteInputStream() ) ) .options(jsonLdOptions) @@ -291,125 +261,6 @@ object JsonLdUtils { return jsonFragment } - fun extractContextFromInput(input: Map): List { - return if (!input.containsKey(JSONLD_CONTEXT)) - emptyList() - else if (input[JSONLD_CONTEXT] is List<*>) - input[JSONLD_CONTEXT] as List - else if (input[JSONLD_CONTEXT] is String) - listOf(input[JSONLD_CONTEXT] as String) - else - emptyList() - } - - fun removeContextFromInput(input: Map): Map = - input.minus(JSONLD_CONTEXT) - - fun castAttributeValue(value: Any): List>> = - value as List>> - - /** - * Extract the actual value (@value) of a property from the properties map of an expanded property. - * - * @param value a map similar to: - * { - * https://uri.etsi.org/ngsi-ld/hasValue=[{ - * @type=[https://uri.etsi.org/ngsi-ld/Property], - * @value=250 - * }], - * https://uri.etsi.org/ngsi-ld/unitCode=[{ - * @value=kg - * }], - * https://uri.etsi.org/ngsi-ld/observedAt=[{ - * @value=2019-12-18T10:45:44.248755Z - * }] - * } - * - * @return the actual value, e.g. "kg" if provided #propertyKey is https://uri.etsi.org/ngsi-ld/unitCode - */ - fun getPropertyValueFromMap(value: ExpandedAttributeInstance, propertyKey: String): Any? = - if (value[propertyKey] != null) { - val intermediateList = value[propertyKey] as List> - if (intermediateList.size == 1) { - val firstListEntry = intermediateList[0] - val finalValueType = firstListEntry[JSONLD_TYPE] - when { - finalValueType != null -> { - val finalValue = String::class.safeCast(firstListEntry[JSONLD_VALUE]) - when (finalValueType) { - NGSILD_DATE_TIME_TYPE -> ZonedDateTime.parse(finalValue) - NGSILD_DATE_TYPE -> LocalDate.parse(finalValue) - NGSILD_TIME_TYPE -> LocalTime.parse(finalValue) - else -> firstListEntry[JSONLD_VALUE] - } - } - - firstListEntry[JSONLD_VALUE] != null -> - firstListEntry[JSONLD_VALUE] - - firstListEntry[JSONLD_ID] != null -> { - // Used to get the value of datasetId property, - // since it is mapped to "@id" key rather than "@value" - firstListEntry[JSONLD_ID] - } - - else -> { - // it is a map / JSON object, keep it as is - // {https://uri.etsi.org/ngsi-ld/default-context/key=[{@value=value}], ...} - firstListEntry - } - } - } else { - intermediateList.map { - it[JSONLD_VALUE] - } - } - } else - null - - fun getPropertyValueFromMapAsDateTime(values: Map>, propertyKey: String): ZonedDateTime? { - val observedAt = ZonedDateTime::class.safeCast(getPropertyValueFromMap(values, propertyKey)) - return observedAt?.run { - ZonedDateTime.parse(this.toString()) - } - } - - fun getPropertyValueFromMapAsString(values: Map>, propertyKey: String): String? = - String::class.safeCast(getPropertyValueFromMap(values, propertyKey)) - - fun getAttributeFromExpandedAttributes( - expandedAttributes: ExpandedAttributes, - expandedAttributeName: ExpandedTerm, - datasetId: URI? - ): ExpandedAttributeInstance? = - expandedAttributes[expandedAttributeName]?.let { expandedAttributeInstances -> - expandedAttributeInstances.find { expandedAttributeInstance -> - if (datasetId == null) - !expandedAttributeInstance.containsKey(NGSILD_DATASET_ID_PROPERTY) - else - getPropertyValueFromMap( - expandedAttributeInstance, - NGSILD_DATASET_ID_PROPERTY - ) == datasetId.toString() - } - } - - /** - * Utility but basic method to find if given contexts can resolve a known term from the core context. - */ - private fun canExpandJsonLdKeyFromCore(contexts: List): Boolean { - val jsonDocument = JsonDocument.of( - serializeObject( - mapOf("datasetId" to mapOf(), JSONLD_CONTEXT to contexts) - ).byteInputStream() - ) - val expandedType = JsonLd.expand(jsonDocument) - .options(jsonLdOptions) - .get() - return expandedType.isNotEmpty() && - (expandedType[0] as? Map<*, *>)?.containsKey(NGSILD_DATASET_ID_PROPERTY) ?: false - } - private fun restoreGeoPropertyValue(): (Map.Entry) -> Any = { if (NGSILD_GEO_PROPERTIES_TERMS.contains(it.key)) { when (it.value) { @@ -434,40 +285,16 @@ object JsonLdUtils { fun compactEntity( expandedEntity: ExpandedEntity, - context: String? = null, - mediaType: MediaType = JSON_LD_MEDIA_TYPE + contexts: List ): CompactedEntity = - compactEntity(expandedEntity, context?.let { listOf(context) } ?: emptyList(), mediaType) - - fun compactEntity( - expandedEntity: ExpandedEntity, - contexts: List, - mediaType: MediaType = JSON_LD_MEDIA_TYPE - ): CompactedEntity { - val allContexts = addCoreContextIfMissing(contexts) - - return if (mediaType == MediaType.APPLICATION_JSON) - JsonLd.compact( - JsonDocument.of(serializeObject(expandedEntity.members).byteInputStream()), - JsonDocument.of(buildContextDocument(allContexts)) - ) - .options(jsonLdOptions) - .get() - .toPrimitiveMap() - .minus(JSONLD_CONTEXT) - .mapValues(restoreGeoPropertyValue()) - else - JsonLd.compact( - JsonDocument.of(serializeObject(expandedEntity.members).byteInputStream()), - JsonDocument.of(buildContextDocument(allContexts)) - ) - .options(jsonLdOptions) - .get() - .toPrimitiveMap() - .minus(JSONLD_CONTEXT) - .plus(JSONLD_CONTEXT to allContexts) - .mapValues(restoreGeoPropertyValue()) - } + JsonLd.compact( + JsonDocument.of(serializeObject(expandedEntity.members).byteInputStream()), + JsonDocument.of(buildContextDocument(contexts)) + ) + .options(jsonLdOptions) + .get() + .toPrimitiveMap() + .mapValues(restoreGeoPropertyValue()) private fun JsonObject.toPrimitiveMap(): Map { val outputStream = ByteArrayOutputStream() @@ -478,12 +305,41 @@ object JsonLdUtils { fun compactEntities( entities: List, - context: String, - mediaType: MediaType - ): List = - entities.map { - compactEntity(it, context, mediaType) + contexts: List + ): List { + // do not try to compact an empty list, it will fail + if (entities.isEmpty()) return emptyList() + + val jsonObject = JsonLd.compact( + JsonDocument.of(serializeObject(entities.map { it.members }).byteInputStream()), + JsonDocument.of(buildContextDocument(contexts)) + ) + .options(jsonLdOptions) + .get() + + return if (entities.size == 1) + listOf(jsonObject.toPrimitiveMap().mapValues(restoreGeoPropertyValue())) + else { + // extract the context from the root of the object to inject it back in the compacted entities later + val context: Any = when (jsonObject[JSONLD_CONTEXT]) { + is JsonArray -> (jsonObject[JSONLD_CONTEXT] as JsonArray).map { it.toString() } + else -> (jsonObject[JSONLD_CONTEXT] as JsonString).string + } + // extract compacted entities from the @graph key + (jsonObject[JSONLD_GRAPH] as JsonArray).toPrimitiveListOfObjects() + .map { + it.mapValues(restoreGeoPropertyValue()) + .plus(JSONLD_CONTEXT to context) + } } + } + + private fun JsonArray.toPrimitiveListOfObjects(): List> { + val outputStream = ByteArrayOutputStream() + val jsonWriter = Json.createWriter(outputStream) + jsonWriter.write(this) + return outputStream.toString().deserializeAsList() + } fun compactTerms(terms: List, contexts: List): List = terms.map { @@ -496,7 +352,7 @@ object JsonLdUtils { fun compactTerm(term: String, contexts: List): String = JsonLd.compact( JsonDocument.of(serializeObject(mapOf(term to emptyMap())).byteInputStream()), - JsonDocument.of(buildContextDocument(addCoreContextIfMissing(contexts))) + JsonDocument.of(buildContextDocument(contexts)) ) .options(jsonLdOptions) .get() @@ -504,73 +360,6 @@ object JsonLdUtils { .keys .elementAtOrElse(0) { _ -> term } - fun filterCompactedEntityOnAttributes( - input: CompactedEntity, - includedAttributes: Set - ): CompactedEntity { - val identity: (CompactedEntity) -> CompactedEntity = { it } - return filterEntityOnAttributes(input, identity, includedAttributes, false) - } - - fun filterJsonLdEntitiesOnAttributes( - jsonLdEntities: List, - includedAttributes: Set - ): List = - jsonLdEntities.filter { it.containsAnyOf(includedAttributes) } - .map { - ExpandedEntity(filterJsonLdEntityOnAttributes(it, includedAttributes), it.contexts) - } - - fun filterJsonLdEntityOnAttributes( - input: ExpandedEntity, - includedAttributes: Set - ): Map { - val inputToMap = { i: ExpandedEntity -> i.members } - return filterEntityOnAttributes(input, inputToMap, includedAttributes, true) - } - - private fun filterEntityOnAttributes( - input: T, - inputToMap: (T) -> Map, - includedAttributes: Set, - isExpandedForm: Boolean - ): Map { - return if (includedAttributes.isEmpty()) { - inputToMap(input) - } else { - val mandatoryFields = if (isExpandedForm) - JSONLD_EXPANDED_ENTITY_CORE_MEMBERS - else - JSONLD_COMPACTED_ENTITY_CORE_MEMBERS - val includedKeys = mandatoryFields.plus(includedAttributes) - inputToMap(input).filterKeys { includedKeys.contains(it) } - } - } - - fun extractRelationshipObject(name: String, values: Map>): Either { - return values.right() - .flatMap { - if (!it.containsKey(NGSILD_RELATIONSHIP_OBJECT)) - BadRequestDataException("Relationship $name does not have an object field").left() - else it[NGSILD_RELATIONSHIP_OBJECT]!!.right() - } - .flatMap { - if (it.isEmpty()) - BadRequestDataException("Relationship $name is empty").left() - else it[0].right() - } - .flatMap { - if (it !is Map<*, *>) - BadRequestDataException("Relationship $name has an invalid object type: ${it.javaClass}").left() - else it[JSONLD_ID].right() - } - .flatMap { - if (it !is String) - BadRequestDataException("Relationship $name has an invalid or no object id: $it").left() - else it.toUri().right() - } - } - /** * Build the expanded payload of a property. * diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt index b3c1b4b8a..a779ea398 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt @@ -5,7 +5,6 @@ import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_TERM import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat @@ -122,7 +121,7 @@ class ExpandedEntityTests { fun `it should find an expanded attribute contained in the entity`() { val expandedEntity = ExpandedEntity( mapOf(INCOMING_PROPERTY to "", OUTGOING_PROPERTY to ""), - DEFAULT_CONTEXTS + NGSILD_TEST_CORE_CONTEXTS ) val checkResult = expandedEntity.checkContainsAnyOf(setOf(TEMPERATURE_PROPERTY, INCOMING_PROPERTY)) @@ -136,7 +135,7 @@ class ExpandedEntityTests { fun `it should not find an expanded attribute contained in the entity`() { val expandedEntity = ExpandedEntity( mapOf(INCOMING_PROPERTY to "", OUTGOING_PROPERTY to "", JSONLD_ID to "urn:ngsi-ld:Entity:01"), - DEFAULT_CONTEXTS + NGSILD_TEST_CORE_CONTEXTS ) val checkResult = expandedEntity.checkContainsAnyOf(setOf(TEMPERATURE_PROPERTY, NGSILD_NAME_PROPERTY)) diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt index 930ff35aa..e7e724746 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt @@ -1,17 +1,24 @@ package com.egm.stellio.shared.model import com.egm.stellio.shared.util.JsonLdUtils +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT +import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue +import com.egm.stellio.shared.util.NGSILD_TEST_CORE_CONTEXTS import com.egm.stellio.shared.util.ngsiLdDateTime +import com.egm.stellio.shared.util.toUri +import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test class ExpandedMembersTests { @Test fun `it should add createdAt information into an attribute`() { - val attrPayload = mapOf("attribute" to JsonLdUtils.buildExpandedPropertyValue(12.0)) + val attrPayload = mapOf("attribute" to buildExpandedPropertyValue(12.0)) val attrPayloadWithSysAttrs = attrPayload.addSysAttrs(true, ngsiLdDateTime(), null) @@ -22,7 +29,7 @@ class ExpandedMembersTests { @Test fun `it should add createdAt and modifiedAt information into an attribute`() { - val attrPayload = mapOf("attribute" to JsonLdUtils.buildExpandedPropertyValue(12.0)) + val attrPayload = mapOf("attribute" to buildExpandedPropertyValue(12.0)) val attrPayloadWithSysAttrs = attrPayload.addSysAttrs(true, ngsiLdDateTime(), ngsiLdDateTime()) @@ -30,4 +37,152 @@ class ExpandedMembersTests { .containsKey(NGSILD_CREATED_AT_PROPERTY) .containsKey(NGSILD_MODIFIED_AT_PROPERTY) } + + @Test + fun `it should not find an unknown attribute instance in a list of attributes`() = runTest { + val entityFragment = + """ + { + "brandName": { + "value": "a new value" + } + } + """.trimIndent() + + val expandedAttributes = JsonLdUtils.expandAttributes(entityFragment, NGSILD_TEST_CORE_CONTEXTS) + assertNull(expandedAttributes.getAttributeFromExpandedAttributes("unknownAttribute", null)) + } + + @Test + fun `it should find an attribute instance from a list of attributes without multi-attributes`() = runTest { + val entityFragment = + """ + { + "brandName": { + "value": "a new value", + "observedAt": "2021-03-16T00:00:00.000Z" + }, + "name": { + "value": 12 + } + } + """.trimIndent() + + val expandedAttributes = JsonLdUtils.expandAttributes(entityFragment, NGSILD_TEST_CORE_CONTEXTS) + val expandedBrandName = JsonLdUtils.expandJsonLdTerm("brandName", NGSILD_TEST_CORE_CONTEXTS) + + assertNotNull(expandedAttributes.getAttributeFromExpandedAttributes(expandedBrandName, null)) + assertNull( + expandedAttributes.getAttributeFromExpandedAttributes(expandedBrandName, "urn:datasetId".toUri()) + ) + } + + @Test + fun `it should find an attribute instance from a list of attributes with multi-attributes`() = runTest { + val entityFragment = + """ + { + "brandName": [{ + "value": "a new value", + "observedAt": "2021-03-16T00:00:00.000Z" + }, + { + "value": "a new value", + "observedAt": "2021-03-16T00:00:00.000Z", + "datasetId": "urn:datasetId:1" + }], + "name": { + "value": 12, + "datasetId": "urn:datasetId:1" + } + } + """.trimIndent() + + val expandedAttributes = JsonLdUtils.expandAttributes(entityFragment, NGSILD_TEST_CORE_CONTEXTS) + val expandedBrandName = JsonLdUtils.expandJsonLdTerm("brandName", NGSILD_TEST_CORE_CONTEXTS) + val expandedName = JsonLdUtils.expandJsonLdTerm("name", NGSILD_TEST_CORE_CONTEXTS) + + assertNotNull(expandedAttributes.getAttributeFromExpandedAttributes(expandedBrandName, null)) + assertNotNull( + expandedAttributes.getAttributeFromExpandedAttributes(expandedBrandName, "urn:datasetId:1".toUri()) + ) + assertNull( + expandedAttributes.getAttributeFromExpandedAttributes(expandedBrandName, "urn:datasetId:2".toUri()) + ) + assertNotNull( + expandedAttributes.getAttributeFromExpandedAttributes(expandedName, "urn:datasetId:1".toUri()) + ) + assertNull(expandedAttributes.getAttributeFromExpandedAttributes(expandedName, null)) + } + + @Test + fun `it should return an error if a relationship has no object field`() { + val relationshipValues = buildExpandedPropertyValue("something")[0] + + val result = relationshipValues.extractRelationshipObject("isARelationship") + assertTrue(result.isLeft()) + result.mapLeft { + assertEquals("Relationship isARelationship does not have an object field", it.message) + } + } + + @Test + fun `it should return an error if a relationship has an empty object`() { + val relationshipValues = mapOf( + NGSILD_RELATIONSHIP_OBJECT to emptyList() + ) + + val result = relationshipValues.extractRelationshipObject("isARelationship") + assertTrue(result.isLeft()) + result.mapLeft { + assertEquals("Relationship isARelationship is empty", it.message) + } + } + + @Test + fun `it should return an error if a relationship has an invalid object type`() { + val relationshipValues = mapOf( + NGSILD_RELATIONSHIP_OBJECT to listOf("invalid") + ) + + val result = relationshipValues.extractRelationshipObject("isARelationship") + assertTrue(result.isLeft()) + result.mapLeft { + assertEquals( + "Relationship isARelationship has an invalid object type: class java.lang.String", + it.message + ) + } + } + + @Test + fun `it should return an error if a relationship has object without id`() { + val relationshipValues = mapOf( + NGSILD_RELATIONSHIP_OBJECT to listOf( + mapOf("@value" to "urn:ngsi-ld:T:misplacedRelationshipObject") + ) + ) + + val result = relationshipValues.extractRelationshipObject("isARelationship") + assertTrue(result.isLeft()) + result.mapLeft { + assertEquals("Relationship isARelationship has an invalid or no object id: null", it.message) + } + } + + @Test + fun `it should extract the target object of a relationship`() { + val relationshipObjectId = "urn:ngsi-ld:T:1" + val relationshipValues = mapOf( + NGSILD_RELATIONSHIP_OBJECT to listOf( + mapOf(JSONLD_ID to relationshipObjectId) + ) + ) + + val result = relationshipValues.extractRelationshipObject("isARelationship") + assertTrue(result.isRight()) + result.map { + assertEquals(relationshipObjectId.toUri(), it) + } + } } diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/model/NgsiLdEntityTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/model/NgsiLdEntityTests.kt index a93847f36..f418c672f 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/model/NgsiLdEntityTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/model/NgsiLdEntityTests.kt @@ -1,11 +1,11 @@ package com.egm.stellio.shared.model -import com.egm.stellio.shared.util.DEFAULT_CONTEXTS import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DEFAULT_VOCAB import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.expandAttributes import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity +import com.egm.stellio.shared.util.NGSILD_TEST_CORE_CONTEXTS import com.egm.stellio.shared.util.shouldFail import com.egm.stellio.shared.util.shouldSucceedAndResult import com.egm.stellio.shared.util.toUri @@ -26,7 +26,7 @@ class NgsiLdEntityTests { } """.trimIndent() - val ngsiLdEntity = expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS) + val ngsiLdEntity = expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS) assertEquals("urn:ngsi-ld:Device:01234", ngsiLdEntity.id) assertEquals(listOf("https://uri.etsi.org/ngsi-ld/default-context/Device"), ngsiLdEntity.types) @@ -41,7 +41,7 @@ class NgsiLdEntityTests { } """.trimIndent() - expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldFail { + expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals("The provided NGSI-LD entity does not contain an id property", it.message) } @@ -60,7 +60,7 @@ class NgsiLdEntityTests { } """.trimIndent() - expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldFail { + expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals("The provided NGSI-LD entity does not contain a type property", it.message) } @@ -80,7 +80,7 @@ class NgsiLdEntityTests { } """.trimIndent() - expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldFail { + expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( "Entity has attribute(s) with an unknown type: [${NGSILD_DEFAULT_VOCAB}deviceState]", @@ -103,7 +103,8 @@ class NgsiLdEntityTests { } """.trimIndent() - val ngsiLdEntity = expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldSucceedAndResult() + val ngsiLdEntity = expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity() + .shouldSucceedAndResult() assertEquals(1, ngsiLdEntity.properties.size) val ngsiLdProperty = ngsiLdEntity.properties[0] @@ -132,7 +133,8 @@ class NgsiLdEntityTests { } """.trimIndent() - val ngsiLdEntity = expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldSucceedAndResult() + val ngsiLdEntity = expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity() + .shouldSucceedAndResult() assertEquals(1, ngsiLdEntity.properties.size) val ngsiLdProperty = ngsiLdEntity.properties[0] @@ -172,7 +174,8 @@ class NgsiLdEntityTests { } """.trimIndent() - val ngsiLdEntity = expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldSucceedAndResult() + val ngsiLdEntity = expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity() + .shouldSucceedAndResult() val ngsiLdPropertyInstance = ngsiLdEntity.properties[0].instances[0] assertEquals("Open", ngsiLdPropertyInstance.value) @@ -197,7 +200,8 @@ class NgsiLdEntityTests { } """.trimIndent() - val ngsiLdEntity = expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldSucceedAndResult() + val ngsiLdEntity = expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity() + .shouldSucceedAndResult() val ngsiLdPropertyInstance = ngsiLdEntity.properties[0].instances[0] assertEquals(ZonedDateTime.parse("2022-01-19T00:00:00Z"), ngsiLdPropertyInstance.createdAt) @@ -217,7 +221,7 @@ class NgsiLdEntityTests { } """.trimIndent() - expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldFail { + expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( "Property ${NGSILD_DEFAULT_VOCAB}deviceState has an instance without a value", @@ -246,7 +250,8 @@ class NgsiLdEntityTests { } """.trimIndent() - val ngsiLdEntity = expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldSucceedAndResult() + val ngsiLdEntity = expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity() + .shouldSucceedAndResult() assertEquals(1, ngsiLdEntity.properties.size) val ngsiLdProperty = ngsiLdEntity.properties[0] @@ -274,7 +279,7 @@ class NgsiLdEntityTests { } """.trimIndent() - expandAttributes(rawProperty, DEFAULT_CONTEXTS).toNgsiLdAttributes().shouldFail { + expandAttributes(rawProperty, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdAttributes().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( "Attribute ${NGSILD_DEFAULT_VOCAB}deviceState instances must have the same type", @@ -312,7 +317,7 @@ class NgsiLdEntityTests { } """.trimIndent() - expandAttributes(rawProperty, DEFAULT_CONTEXTS).toNgsiLdAttributes().shouldFail { + expandAttributes(rawProperty, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdAttributes().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( "Attribute ${NGSILD_DEFAULT_VOCAB}deviceState " + @@ -345,7 +350,7 @@ class NgsiLdEntityTests { } """.trimIndent() - expandAttributes(rawProperty, DEFAULT_CONTEXTS).toNgsiLdAttributes().shouldFail { + expandAttributes(rawProperty, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdAttributes().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( "Attribute ${NGSILD_DEFAULT_VOCAB}deviceState can't have more than one default instance", @@ -370,7 +375,7 @@ class NgsiLdEntityTests { """.trimIndent() val ngsiLdAttributes = - expandAttributes(rawProperty, DEFAULT_CONTEXTS).toNgsiLdAttributes().shouldSucceedAndResult() + expandAttributes(rawProperty, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdAttributes().shouldSucceedAndResult() assertEquals(1, ngsiLdAttributes.size) val ngsiLdAttribute = ngsiLdAttributes[0] @@ -394,7 +399,8 @@ class NgsiLdEntityTests { } """.trimIndent() - val ngsiLdEntity = expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldSucceedAndResult() + val ngsiLdEntity = expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity() + .shouldSucceedAndResult() assertEquals(1, ngsiLdEntity.relationships.size) val ngsiLdRelationship = ngsiLdEntity.relationships[0] @@ -422,7 +428,8 @@ class NgsiLdEntityTests { } """.trimIndent() - val ngsiLdEntity = expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldSucceedAndResult() + val ngsiLdEntity = expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity() + .shouldSucceedAndResult() val ngsiLdRelationshipInstance = ngsiLdEntity.relationships[0].instances[0] assertEquals("urn:ngsi-ld:DeviceModel:09876".toUri(), ngsiLdRelationshipInstance.objectId) @@ -452,7 +459,8 @@ class NgsiLdEntityTests { } """.trimIndent() - val ngsiLdEntity = expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldSucceedAndResult() + val ngsiLdEntity = expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity() + .shouldSucceedAndResult() assertEquals(1, ngsiLdEntity.relationships.size) val ngsiLdRelationship = ngsiLdEntity.relationships[0] @@ -478,7 +486,7 @@ class NgsiLdEntityTests { """.trimIndent() - expandAttributes(rawRelationship, DEFAULT_CONTEXTS).toNgsiLdAttributes().shouldFail { + expandAttributes(rawRelationship, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdAttributes().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( "Attribute ${NGSILD_DEFAULT_VOCAB}refDeviceModel can't have more " + @@ -508,7 +516,7 @@ class NgsiLdEntityTests { } """.trimIndent() - expandAttributes(rawRelationship, DEFAULT_CONTEXTS).toNgsiLdAttributes().shouldFail { + expandAttributes(rawRelationship, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdAttributes().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( "Attribute ${NGSILD_DEFAULT_VOCAB}refDeviceModel " + @@ -542,7 +550,7 @@ class NgsiLdEntityTests { } """.trimIndent() - expandAttributes(rawRelationship, DEFAULT_CONTEXTS).toNgsiLdAttributes().shouldFail { + expandAttributes(rawRelationship, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdAttributes().shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( "Attribute ${NGSILD_DEFAULT_VOCAB}refDeviceModel instances must have the same type", @@ -574,7 +582,8 @@ class NgsiLdEntityTests { } """.trimIndent() - val ngsiLdEntity = expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldSucceedAndResult() + val ngsiLdEntity = expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity() + .shouldSucceedAndResult() val location = ngsiLdEntity.geoProperties.find { it.name == NGSILD_LOCATION_PROPERTY } assertNotNull(location) @@ -618,7 +627,8 @@ class NgsiLdEntityTests { } """.trimIndent() - val ngsiLdEntity = expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldSucceedAndResult() + val ngsiLdEntity = expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity() + .shouldSucceedAndResult() val location = ngsiLdEntity.geoProperties.find { it.name == NGSILD_LOCATION_PROPERTY } assertNotNull(location) @@ -656,7 +666,8 @@ class NgsiLdEntityTests { } """.trimIndent() - val ngsiLdEntity = expandJsonLdEntity(rawEntity, DEFAULT_CONTEXTS).toNgsiLdEntity().shouldSucceedAndResult() + val ngsiLdEntity = expandJsonLdEntity(rawEntity, NGSILD_TEST_CORE_CONTEXTS).toNgsiLdEntity() + .shouldSucceedAndResult() val location = ngsiLdEntity.geoProperties.find { it.name == NGSILD_LOCATION_PROPERTY } assertNotNull(location) diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/ApiUtilsTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/ApiUtilsTests.kt index 8e763ed9f..5c6479422 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/ApiUtilsTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/ApiUtilsTests.kt @@ -47,17 +47,17 @@ class ApiUtilsTests { @Test fun `it should return an empty list if no attrs param is provided`() { - assertTrue(parseAndExpandRequestParameter(null, "").isEmpty()) + assertTrue(parseAndExpandRequestParameter(null, emptyList()).isEmpty()) } @Test fun `it should return an singleton list if there is one provided attrs param`() { - assertEquals(1, parseAndExpandRequestParameter("attr1", NGSILD_TEST_CORE_CONTEXT).size) + assertEquals(1, parseAndExpandRequestParameter("attr1", NGSILD_TEST_CORE_CONTEXTS).size) } @Test fun `it should return a list with two elements if there are two provided attrs param`() { - assertEquals(2, parseAndExpandRequestParameter("attr1, attr2", NGSILD_TEST_CORE_CONTEXT).size) + assertEquals(2, parseAndExpandRequestParameter("attr1, attr2", NGSILD_TEST_CORE_CONTEXTS).size) } @Test @@ -82,7 +82,7 @@ class ApiUtilsTests { @Test fun `it should extract a @context from a valid Link header`() = runTest { - getContextFromLinkHeader(listOf(buildContextLinkHeader(APIC_COMPOUND_CONTEXT))).shouldSucceedWith { + getContextFromLinkHeader(listOf(APIC_HEADER_LINK)).shouldSucceedWith { assertNotNull(it) assertEquals(APIC_COMPOUND_CONTEXT, it) } @@ -97,7 +97,7 @@ class ApiUtilsTests { @Test fun `it should return a BadRequestData error if @context provided in Link header is invalid`() = runTest { - getContextFromLinkHeader(listOf(APIC_COMPOUND_CONTEXT)).shouldFail { + getContextFromLinkHeader(APIC_COMPOUND_CONTEXTS).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( "Badly formed Link header: $APIC_COMPOUND_CONTEXT", @@ -110,7 +110,7 @@ class ApiUtilsTests { fun `it should return the default @context if no Link header was provided and default is asked`() = runTest { val httpHeaders = HttpHeaders() getContextFromLinkHeaderOrDefault(httpHeaders).shouldSucceedWith { - assertEquals(NGSILD_CORE_CONTEXT, it) + assertEquals(listOf(NGSILD_CORE_CONTEXT), it) } } @@ -122,12 +122,12 @@ class ApiUtilsTests { val jsonLdInput = mapOf( "id" to "urn:ngsi-ld:Building:farm001", "type" to "Building", - "@context" to "https://fiware.github.io/data-models/context.jsonld" + "@context" to NGSILD_TEST_CORE_CONTEXT ) checkAndGetContext(httpHeaders, jsonLdInput).shouldSucceedWith { assertEquals(1, it.size) - assertEquals("https://fiware.github.io/data-models/context.jsonld", it[0]) + assertEquals(NGSILD_TEST_CORE_CONTEXT, it[0]) } } @@ -177,11 +177,70 @@ class ApiUtilsTests { } } + @Test + fun `it should find a JSON-LD @context in an input map`() { + val input = mapOf( + "id" to "urn:ngsi-ld:Entity:1", + "@context" to "https://some.context" + ) + + assertEquals(listOf("https://some.context"), input.extractContexts()) + } + + @Test + fun `it should find a list of JSON-LD @contexts in an input map`() { + val input = mapOf( + "id" to "urn:ngsi-ld:Entity:1", + "@context" to listOf("https://some.context", "https://some.context.2") + ) + + assertEquals(listOf("https://some.context", "https://some.context.2"), input.extractContexts()) + } + + @Test + fun `it should return an empty list if no JSON-LD @context was found an input map`() { + val input = mapOf( + "id" to "urn:ngsi-ld:Entity:1" + ) + + assertEquals(emptyList(), input.extractContexts()) + } + + @Test + fun `it should return the core context if the list of contexts is empty`() { + val contexts = addCoreContextIfMissing(emptyList()) + assertEquals(1, contexts.size) + assertEquals(listOf(NGSILD_CORE_CONTEXT), contexts) + } + + @Test + fun `it should move the core context at last position if it is not last in the list of contexts`() { + val contexts = addCoreContextIfMissing(listOf(NGSILD_CORE_CONTEXT).plus(APIC_COMPOUND_CONTEXTS)) + assertEquals(2, contexts.size) + assertEquals(APIC_COMPOUND_CONTEXTS.plus(NGSILD_CORE_CONTEXT), contexts) + } + + @Test + fun `it should add the core context at last position if it is not in the list of contexts`() { + val contexts = addCoreContextIfMissing(listOf(APIC_CONTEXT)) + assertEquals(2, contexts.size) + assertEquals(listOf(APIC_CONTEXT, NGSILD_CORE_CONTEXT), contexts) + } + + @Test + fun `it should not add the core context if it resolvable from the provided contexts`() { + val contexts = addCoreContextIfMissing( + listOf("https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.4.jsonld") + ) + assertEquals(1, contexts.size) + assertEquals(listOf("https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.4.jsonld"), contexts) + } + @Test fun `it should parse and expand entity type selection query`() { val query = "(TypeA|TypeB);(TypeC,TypeD)" val defaultExpand = "https://uri.etsi.org/ngsi-ld/default-context/" - val expandedQuery = expandTypeSelection(query, NGSILD_TEST_CORE_CONTEXT) + val expandedQuery = expandTypeSelection(query, NGSILD_TEST_CORE_CONTEXTS) val expectedExpandTypeSelection = "(${defaultExpand}TypeA|${defaultExpand}TypeB);(${defaultExpand}TypeC,${defaultExpand}TypeD)" assertEquals(expectedExpandTypeSelection, expandedQuery) diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt index 14d7ee6dd..5f84144b6 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt @@ -18,7 +18,7 @@ class GeoQueryUtilsTests { fun `it should parse geo query parameters`() = runTest { val requestParams = gimmeFullParamsMap() val geoQueryParams = - parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXT).shouldSucceedAndResult() + parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXTS).shouldSucceedAndResult() val geoQuery = GeoQuery( georel = "near;maxDistance==1500", @@ -36,7 +36,7 @@ class GeoQueryUtilsTests { georel = "near%3BmaxDistance%3D%3D1500" ).plus("coordinates" to "[57.5522%2C%20-20.3484]") val geoQueryParams = - parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXT).shouldSucceedAndResult() + parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXTS).shouldSucceedAndResult() val geoQuery = GeoQuery( georel = "near;maxDistance==1500", @@ -53,7 +53,7 @@ class GeoQueryUtilsTests { val requestParams = gimmeFullParamsMap("operationSpace") val geoQueryParams = - parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXT).shouldSucceedAndResult() + parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXTS).shouldSucceedAndResult() val geoQuery = GeoQuery( georel = "near;maxDistance==1500", @@ -68,7 +68,7 @@ class GeoQueryUtilsTests { @Test fun `it should fail to create a geoquery if georel has an invalid near clause`() = runTest { val requestParams = gimmeFullParamsMap(georel = "near;distance<100") - parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXT).shouldFail { + parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXTS).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals("Invalid expression for 'near' georel: near;distance<100", it.message) } @@ -77,7 +77,7 @@ class GeoQueryUtilsTests { @Test fun `it should fail to create a geoquery if georel is not recognized`() = runTest { val requestParams = gimmeFullParamsMap(georel = "unrecognized") - parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXT).shouldFail { + parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXTS).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals("Invalid 'georel' parameter provided: unrecognized", it.message) } @@ -86,7 +86,7 @@ class GeoQueryUtilsTests { @Test fun `it should fail to create a geoquery if geometry is not recognized`() = runTest { val requestParams = gimmeFullParamsMap(geometry = "Unrecognized") - parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXT).shouldFail { + parseGeoQueryParameters(requestParams, NGSILD_TEST_CORE_CONTEXTS).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals("Unrecognized is not a recognized value for 'geometry' parameter", it.message) } @@ -98,7 +98,7 @@ class GeoQueryUtilsTests { "geometry" to "Point", "coordinates" to "[57.5522,%20-20.3484]" ) - parseGeoQueryParameters(geoQueryParameters, NGSILD_TEST_CORE_CONTEXT).shouldFail { + parseGeoQueryParameters(geoQueryParameters, NGSILD_TEST_CORE_CONTEXTS).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( "Missing at least one geo parameter between 'geometry', 'georel' and 'coordinates'", @@ -114,7 +114,7 @@ class GeoQueryUtilsTests { "geometry" to "Polygon", "coordinates" to "[57.5522,%20-20.3484]" ) - parseGeoQueryParameters(geoQueryParameters, NGSILD_TEST_CORE_CONTEXT).shouldFail { + parseGeoQueryParameters(geoQueryParameters, NGSILD_TEST_CORE_CONTEXTS).shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEqualsIgnoringNoise( """ diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt index e14223f8d..4d1af65f6 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt @@ -1,81 +1,17 @@ package com.egm.stellio.shared.util import com.egm.stellio.shared.model.BadRequestDataException -import com.egm.stellio.shared.model.CompactedEntity import com.egm.stellio.shared.model.LdContextNotAvailableException -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CORE_CONTEXT -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT -import com.egm.stellio.shared.util.JsonLdUtils.addCoreContextIfMissing import com.egm.stellio.shared.util.JsonLdUtils.compactEntity -import com.egm.stellio.shared.util.JsonLdUtils.expandAttributes import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdFragment -import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdTerm -import com.egm.stellio.shared.util.JsonLdUtils.extractContextFromInput -import com.egm.stellio.shared.util.JsonLdUtils.extractRelationshipObject -import com.egm.stellio.shared.util.JsonLdUtils.getAttributeFromExpandedAttributes import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows -import org.springframework.http.MediaType class JsonLdUtilsTests { - private val normalizedJson = - """ - { - "id": "urn:ngsi-ld:Vehicle:A4567", - "type": "Vehicle", - "brandName": { - "type": "Property", - "value": "Mercedes" - }, - "isParked": { - "type": "Relationship", - "object": "urn:ngsi-ld:OffStreetParking:Downtown1", - "observedAt": "2017-07-29T12:00:04Z", - "providedBy": { - "type": "Relationship", - "object": "urn:ngsi-ld:Person:Bob" - } - }, - "location": { - "type": "GeoProperty", - "value": { - "type": "Point", - "coordinates": [ - 24.30623, - 60.07966 - ] - } - }, - "@context": [ - "https://example.org/ngsi-ld/latest/commonTerms.jsonld", - "https://example.org/ngsi-ld/latest/vehicle.jsonld", - "https://example.org/ngsi-ld/latest/parking.jsonld", - "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld" - ] - } - """.trimIndent() - - @Test - fun `it should filter a JSON-LD Map on the attributes specified as well as the mandatory attributes`() { - val normalizedMap = mapper.readValue(normalizedJson, Map::class.java) - - val resultMap = JsonLdUtils.filterCompactedEntityOnAttributes( - normalizedMap as CompactedEntity, - setOf("brandName", "location") - ) - - assertTrue(resultMap.containsKey("id")) - assertTrue(resultMap.containsKey("type")) - assertTrue(resultMap.containsKey("@context")) - assertTrue(resultMap.containsKey("brandName")) - assertTrue(resultMap.containsKey("location")) - assertFalse(resultMap.containsKey("isParked")) - } - @Test fun `it should throw a LdContextNotAvailable exception if the provided JSON-LD context is not available`() = runTest { @@ -121,124 +57,8 @@ class JsonLdUtilsTests { ) } - @Test - fun `it should return an error if a relationship has no object field`() { - val relationshipValues = mapOf( - "value" to listOf("something") - ) - - val result = extractRelationshipObject("isARelationship", relationshipValues) - assertTrue(result.isLeft()) - result.mapLeft { - assertEquals("Relationship isARelationship does not have an object field", it.message) - } - } - - @Test - fun `it should return an error if a relationship has an empty object`() { - val relationshipValues = mapOf( - NGSILD_RELATIONSHIP_OBJECT to emptyList() - ) - - val result = extractRelationshipObject("isARelationship", relationshipValues) - assertTrue(result.isLeft()) - result.mapLeft { - assertEquals("Relationship isARelationship is empty", it.message) - } - } - - @Test - fun `it should return an error if a relationship has an invalid object type`() { - val relationshipValues = mapOf( - NGSILD_RELATIONSHIP_OBJECT to listOf("invalid") - ) - - val result = extractRelationshipObject("isARelationship", relationshipValues) - assertTrue(result.isLeft()) - result.mapLeft { - assertEquals("Relationship isARelationship has an invalid object type: class java.lang.String", it.message) - } - } - - @Test - fun `it should return an error if a relationship has object without id`() { - val relationshipValues = mapOf( - NGSILD_RELATIONSHIP_OBJECT to listOf( - mapOf("@value" to "urn:ngsi-ld:T:misplacedRelationshipObject") - ) - ) - - val result = extractRelationshipObject("isARelationship", relationshipValues) - assertTrue(result.isLeft()) - result.mapLeft { - assertEquals("Relationship isARelationship has an invalid or no object id: null", it.message) - } - } - - @Test - fun `it should extract the target object of a relationship`() { - val relationshipObjectId = "urn:ngsi-ld:T:1" - val relationshipValues = mapOf( - NGSILD_RELATIONSHIP_OBJECT to listOf( - mapOf("@id" to relationshipObjectId) - ) - ) - - val result = extractRelationshipObject("isARelationship", relationshipValues) - assertTrue(result.isRight()) - result.map { - assertEquals(relationshipObjectId.toUri(), it) - } - } - - @Test - fun `it should return the core context if the list of contexts is empty`() { - val contexts = addCoreContextIfMissing(emptyList()) - assertEquals(1, contexts.size) - assertEquals(listOf(NGSILD_CORE_CONTEXT), contexts) - } - - @Test - fun `it should move the core context at last position if it is not last in the list of contexts`() { - val contexts = addCoreContextIfMissing(listOf(NGSILD_CORE_CONTEXT, APIC_COMPOUND_CONTEXT)) - assertEquals(2, contexts.size) - assertEquals(listOf(APIC_COMPOUND_CONTEXT, NGSILD_CORE_CONTEXT), contexts) - } - - @Test - fun `it should add the core context at last position if it is not in the list of contexts`() { - val contexts = addCoreContextIfMissing(listOf(NGSILD_EGM_CONTEXT)) - assertEquals(2, contexts.size) - assertEquals(listOf(NGSILD_EGM_CONTEXT, NGSILD_CORE_CONTEXT), contexts) - } - - @Test - fun `it should not add the core context if it resolvable from the provided contexts`() { - val contexts = addCoreContextIfMissing( - listOf("https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.4.jsonld") - ) - assertEquals(1, contexts.size) - assertEquals(listOf("https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.4.jsonld"), contexts) - } - @Test fun `it should compact and return a JSON entity`() = runTest { - val entity = - """ - { - "id": "urn:ngsi-ld:Device:01234", - "type": "Device" - } - """.trimIndent() - - val jsonLdEntity = JsonLdUtils.expandJsonLdEntity(entity, DEFAULT_CONTEXTS) - val compactedEntity = compactEntity(jsonLdEntity, DEFAULT_CONTEXTS, MediaType.APPLICATION_JSON) - - assertJsonPayloadsAreEqual(entity, mapper.writeValueAsString(compactedEntity)) - } - - @Test - fun `it should compact and return a JSON-LD entity`() = runTest { val entity = """ { @@ -249,123 +69,15 @@ class JsonLdUtilsTests { val expectedEntity = """ { - "id":"urn:ngsi-ld:Device:01234", - "type":"Device", - "@context":[ - "$NGSILD_TEST_CORE_CONTEXT" - ] + "id": "urn:ngsi-ld:Device:01234", + "type": "Device", + "@context": "$NGSILD_TEST_CORE_CONTEXT" } """.trimIndent() - val jsonLdEntity = JsonLdUtils.expandJsonLdEntity(entity, DEFAULT_CONTEXTS) - val compactedEntity = compactEntity(jsonLdEntity, DEFAULT_CONTEXTS) + val jsonLdEntity = JsonLdUtils.expandJsonLdEntity(entity, NGSILD_TEST_CORE_CONTEXTS) + val compactedEntity = compactEntity(jsonLdEntity, NGSILD_TEST_CORE_CONTEXTS) assertJsonPayloadsAreEqual(expectedEntity, mapper.writeValueAsString(compactedEntity)) } - - @Test - fun `it should not find an unknown attribute instance in a list of attributes`() = runTest { - val entityFragment = - """ - { - "brandName": { - "value": "a new value" - } - } - """.trimIndent() - - val expandedAttributes = expandAttributes(entityFragment, DEFAULT_CONTEXTS) - assertNull(getAttributeFromExpandedAttributes(expandedAttributes, "unknownAttribute", null)) - } - - @Test - fun `it should find an attribute instance from a list of attributes without multi-attributes`() = runTest { - val entityFragment = - """ - { - "brandName": { - "value": "a new value", - "observedAt": "2021-03-16T00:00:00.000Z" - }, - "name": { - "value": 12 - } - } - """.trimIndent() - - val expandedAttributes = expandAttributes(entityFragment, DEFAULT_CONTEXTS) - val expandedBrandName = expandJsonLdTerm("brandName", DEFAULT_CONTEXTS) - - assertNotNull(getAttributeFromExpandedAttributes(expandedAttributes, expandedBrandName, null)) - assertNull( - getAttributeFromExpandedAttributes(expandedAttributes, expandedBrandName, "urn:datasetId".toUri()) - ) - } - - @Test - fun `it should find an attribute instance from a list of attributes with multi-attributes`() = runTest { - val entityFragment = - """ - { - "brandName": [{ - "value": "a new value", - "observedAt": "2021-03-16T00:00:00.000Z" - }, - { - "value": "a new value", - "observedAt": "2021-03-16T00:00:00.000Z", - "datasetId": "urn:datasetId:1" - }], - "name": { - "value": 12, - "datasetId": "urn:datasetId:1" - } - } - """.trimIndent() - - val expandedAttributes = expandAttributes(entityFragment, DEFAULT_CONTEXTS) - val expandedBrandName = expandJsonLdTerm("brandName", DEFAULT_CONTEXTS) - val expandedName = expandJsonLdTerm("name", DEFAULT_CONTEXTS) - - assertNotNull(getAttributeFromExpandedAttributes(expandedAttributes, expandedBrandName, null)) - assertNotNull( - getAttributeFromExpandedAttributes(expandedAttributes, expandedBrandName, "urn:datasetId:1".toUri()) - ) - assertNull( - getAttributeFromExpandedAttributes(expandedAttributes, expandedBrandName, "urn:datasetId:2".toUri()) - ) - assertNotNull( - getAttributeFromExpandedAttributes(expandedAttributes, expandedName, "urn:datasetId:1".toUri()) - ) - assertNull(getAttributeFromExpandedAttributes(expandedAttributes, expandedName, null)) - } - - @Test - fun `it should find a JSON-LD @context in an input map`() { - val input = mapOf( - "id" to "urn:ngsi-ld:Entity:1", - "@context" to "https://some.context" - ) - - assertEquals(listOf("https://some.context"), extractContextFromInput(input)) - } - - @Test - fun `it should find a list of JSON-LD @contexts in an input map`() { - val input = mapOf( - "id" to "urn:ngsi-ld:Entity:1", - "@context" to listOf("https://some.context", "https://some.context.2") - ) - - assertEquals(listOf("https://some.context", "https://some.context.2"), extractContextFromInput(input)) - } - - @Test - fun `it should return an empty list if no JSON-LD @context was found an input map`() { - val input = mapOf( - "id" to "urn:ngsi-ld:Entity:1" - ) - - assertEquals(emptyList(), extractContextFromInput(input)) - } } diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonUtilsTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonUtilsTests.kt index ae61a4fc0..ff57553be 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonUtilsTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonUtilsTests.kt @@ -121,8 +121,8 @@ class JsonUtilsTests { DEFAULT_TENANT_URI, entityId, listOf(BEEHIVE_TYPE), - serializeObject(expandJsonLdFragment(entityPayload, listOf(APIC_COMPOUND_CONTEXT))), - listOf(APIC_COMPOUND_CONTEXT) + serializeObject(expandJsonLdFragment(entityPayload, APIC_COMPOUND_CONTEXTS)), + APIC_COMPOUND_CONTEXTS ) ) assertJsonPayloadsAreEqual(loadSampleData("events/entity/entityCreateEvent.json"), event) @@ -136,8 +136,8 @@ class JsonUtilsTests { DEFAULT_TENANT_URI, entityId, listOf(BEEHIVE_TYPE), - serializeObject(expandJsonLdFragment(entityPayload, listOf(APIC_COMPOUND_CONTEXT))), - listOf(APIC_COMPOUND_CONTEXT) + serializeObject(expandJsonLdFragment(entityPayload, APIC_COMPOUND_CONTEXTS)), + APIC_COMPOUND_CONTEXTS ) ) assertJsonPayloadsAreEqual(loadSampleData("events/entity/entityDeleteEvent.json"), event) diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/MockkedHandler.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/MockkedHandler.kt index 2ce12c3f5..4cf9d92fc 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/MockkedHandler.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/MockkedHandler.kt @@ -1,7 +1,6 @@ package com.egm.stellio.shared.util import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdFragment -import com.egm.stellio.shared.util.JsonLdUtils.extractContextFromInput import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import kotlinx.coroutines.reactive.awaitFirst import org.springframework.http.HttpStatus @@ -21,7 +20,7 @@ class MockkedHandler : customExceptionHandler() { @PostMapping("/validate-json-ld-fragment") suspend fun validateJsonLdFragment(@RequestBody body: Mono): ResponseEntity<*> { val payload = body.awaitFirst().deserializeAsMap() - expandJsonLdFragment(payload, extractContextFromInput(payload)) + expandJsonLdFragment(payload, payload.extractContexts()) return ResponseEntity.status(HttpStatus.CREATED).build() } diff --git a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/JsonLdContextUtils.kt b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/JsonLdContextUtils.kt index bd17e87e4..4e81b3c63 100644 --- a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/JsonLdContextUtils.kt +++ b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/JsonLdContextUtils.kt @@ -2,14 +2,20 @@ package com.egm.stellio.shared.util const val EGM_TEST_BASE_CONTEXT_URL = "http://localhost:8093/jsonld-contexts" const val NGSILD_TEST_CORE_CONTEXT = "$EGM_TEST_BASE_CONTEXT_URL/ngsi-ld-core-context-v1.8.jsonld" -val DEFAULT_CONTEXTS = listOf(NGSILD_TEST_CORE_CONTEXT) -const val NGSILD_EGM_CONTEXT = "$EGM_TEST_BASE_CONTEXT_URL/egm.jsonld" +val NGSILD_TEST_CORE_CONTEXTS = listOf(NGSILD_TEST_CORE_CONTEXT) + const val AQUAC_COMPOUND_CONTEXT = "$EGM_TEST_BASE_CONTEXT_URL/aquac-compound.jsonld" +val AQUAC_HEADER_LINK = buildContextLinkHeader(AQUAC_COMPOUND_CONTEXT) + +const val APIC_CONTEXT = "$EGM_TEST_BASE_CONTEXT_URL/apic.jsonld" const val APIC_COMPOUND_CONTEXT = "$EGM_TEST_BASE_CONTEXT_URL/apic-compound.jsonld" +val APIC_COMPOUND_CONTEXTS = listOf(APIC_COMPOUND_CONTEXT) +val APIC_HEADER_LINK = buildContextLinkHeader(APIC_COMPOUND_CONTEXT) + const val AUTHZ_TEST_CONTEXT = "$EGM_TEST_BASE_CONTEXT_URL/authorization.jsonld" const val AUTHZ_TEST_COMPOUND_CONTEXT = "$EGM_TEST_BASE_CONTEXT_URL/authorization-compound.jsonld" - -val APIC_HEADER_LINK = buildContextLinkHeader(APIC_COMPOUND_CONTEXT) +val AUTHZ_TEST_COMPOUND_CONTEXTS = listOf(AUTHZ_TEST_COMPOUND_CONTEXT) +val AUTHZ_HEADER_LINK = buildContextLinkHeader(AUTHZ_TEST_CONTEXT) const val SENSOR_COMPACT_TYPE = "Sensor" const val SENSOR_TYPE = "https://ontology.eglobalmark.com/egm#$SENSOR_COMPACT_TYPE" diff --git a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/NgsiLdTestUtils.kt b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/NgsiLdTestUtils.kt index e4d8d8160..b3f4da647 100644 --- a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/NgsiLdTestUtils.kt +++ b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/NgsiLdTestUtils.kt @@ -25,20 +25,20 @@ suspend fun gimmeSimpleEntityWithGeoProperty( } """.trimIndent() - return JsonLdUtils.expandJsonLdEntity(entityWithLocation, DEFAULT_CONTEXTS) + return JsonLdUtils.expandJsonLdEntity(entityWithLocation, NGSILD_TEST_CORE_CONTEXTS) } suspend fun gimmeSimpleEntityWithAttributes( id: String, type: String, - contexts: List = listOf(APIC_COMPOUND_CONTEXT) + contexts: List = APIC_COMPOUND_CONTEXTS ): ExpandedEntity = gimmeSimpleEntityWithAttributes(id, listOf(type), contexts) suspend fun gimmeSimpleEntityWithAttributes( id: String, types: List, - contexts: List = listOf(APIC_COMPOUND_CONTEXT) + contexts: List = APIC_COMPOUND_CONTEXTS ): ExpandedEntity { val entity = mapOf( "id" to id, diff --git a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt index 862f9bf73..2588406f5 100644 --- a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt +++ b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt @@ -5,7 +5,9 @@ import arrow.core.Some import arrow.core.left import arrow.core.right import com.egm.stellio.shared.model.* +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_CONTEXT import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity +import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import org.springframework.core.io.ClassPathResource import java.net.URI @@ -36,7 +38,7 @@ fun loadMinimalEntityWithSap( entityId: URI, entityTypes: Set, specificAccessPolicy: AuthContextModel.SpecificAccessPolicy, - contexts: Set = setOf(NGSILD_TEST_CORE_CONTEXT) + contexts: List = NGSILD_TEST_CORE_CONTEXTS ): String = """ { @@ -58,6 +60,11 @@ suspend fun String.sampleDataToNgsiLdEntity(): Either> + val data: List> ) diff --git a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/model/Subscription.kt b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/model/Subscription.kt index 98556c9af..04ce928d9 100644 --- a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/model/Subscription.kt +++ b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/model/Subscription.kt @@ -177,12 +177,12 @@ fun Map.toFinalRepresentation( } fun List.serialize( - context: String, + contexts: List, mediaType: MediaType = JSON_LD_MEDIA_TYPE, includeSysAttrs: Boolean = false ): String = this.map { - convertToMap(it.compact(context)) + convertToMap(it.compact(contexts)) .toFinalRepresentation(mediaType, includeSysAttrs) }.let { serializeObject(it) diff --git a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/NotificationService.kt b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/NotificationService.kt index 733e95f90..3c52ec35a 100644 --- a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/NotificationService.kt +++ b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/service/NotificationService.kt @@ -2,14 +2,10 @@ package com.egm.stellio.subscription.service import arrow.core.Either import arrow.core.raise.either -import com.egm.stellio.shared.model.APIException -import com.egm.stellio.shared.model.CompactedEntity -import com.egm.stellio.shared.model.ExpandedEntity -import com.egm.stellio.shared.model.ExpandedTerm -import com.egm.stellio.shared.model.toKeyValues +import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.JsonLdUtils.compactEntity -import com.egm.stellio.shared.util.JsonLdUtils.filterJsonLdEntityOnAttributes import com.egm.stellio.shared.util.JsonUtils.serializeObject +import com.egm.stellio.shared.util.acceptToMediaType import com.egm.stellio.shared.util.getTenantFromContext import com.egm.stellio.shared.web.DEFAULT_TENANT_URI import com.egm.stellio.shared.web.NGSILD_TENANT_HEADER @@ -39,12 +35,19 @@ class NotificationService( ): Either>> = either { subscriptionService.getMatchingSubscriptions(expandedEntity, updatedAttributes, notificationTrigger).bind() .map { - val filteredEntity = - filterJsonLdEntityOnAttributes(expandedEntity, it.notification.attributes?.toSet().orEmpty()) + val filteredEntity = expandedEntity.filterOnAttributes(it.notification.attributes?.toSet().orEmpty()) + val entityRepresentation = + EntityRepresentation.forMediaType(acceptToMediaType(it.notification.endpoint.accept.accept)) + val attributeRepresentation = + if (it.notification.format == NotificationParams.FormatType.KEY_VALUES) + AttributeRepresentation.SIMPLIFIED + else AttributeRepresentation.NORMALIZED + val compactedEntity = compactEntity( ExpandedEntity(filteredEntity, it.contexts), - it.contexts, - MediaType.valueOf(it.notification.endpoint.accept.accept) + it.contexts + ).toFinalRepresentation( + NgsiLdDataRepresentation(entityRepresentation, attributeRepresentation, true) ) callSubscriber(it, compactedEntity) } @@ -52,13 +55,13 @@ class NotificationService( suspend fun callSubscriber( subscription: Subscription, - entity: CompactedEntity + entity: Map ): Triple { val mediaType = MediaType.valueOf(subscription.notification.endpoint.accept.accept) val tenantUri = getTenantFromContext() val notification = Notification( subscriptionId = subscription.id, - data = buildNotificationData(entity, subscription) + data = listOf(entity) ) val uri = subscription.notification.endpoint.uri.toString() logger.info("Notification is about to be sent to $uri for subscription ${subscription.id}") @@ -91,16 +94,4 @@ class NotificationService( subscriptionService.updateSubscriptionNotification(result.first, result.second, result.third) return result } - - private fun buildNotificationData( - compactedEntity: CompactedEntity, - subscription: Subscription - ): List> { - val processedEntity = if (subscription.notification.format == NotificationParams.FormatType.KEY_VALUES) - compactedEntity.toKeyValues() - else - compactedEntity - - return listOf(processedEntity) - } } diff --git a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/web/SubscriptionHandler.kt b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/web/SubscriptionHandler.kt index c5f09d59d..1e3354854 100644 --- a/subscription-service/src/main/kotlin/com/egm/stellio/subscription/web/SubscriptionHandler.kt +++ b/subscription-service/src/main/kotlin/com/egm/stellio/subscription/web/SubscriptionHandler.kt @@ -67,7 +67,7 @@ class SubscriptionHandler( @RequestHeader httpHeaders: HttpHeaders, @RequestParam params: MultiValueMap ): ResponseEntity<*> = either { - val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() val sub = getSubFromSecurityContext() @@ -79,7 +79,7 @@ class SubscriptionHandler( applicationProperties.pagination.limitMax ).bind() val subscriptions = subscriptionService.getSubscriptions(paginationQuery.limit, paginationQuery.offset, sub) - .serialize(contextLink, mediaType, includeSysAttrs) + .serialize(contexts, mediaType, includeSysAttrs) val subscriptionsCount = subscriptionService.getSubscriptionsCount(sub).bind() buildQueryResponse( @@ -89,7 +89,7 @@ class SubscriptionHandler( paginationQuery, params, mediaType, - contextLink + contexts ) }.fold( { it.toErrorResponse() }, @@ -106,7 +106,7 @@ class SubscriptionHandler( @RequestParam options: Optional ): ResponseEntity<*> = either { val includeSysAttrs = options.filter { it.contains(QUERY_PARAM_OPTIONS_SYSATTRS_VALUE) }.isPresent - val contextLink = getContextFromLinkHeaderOrDefault(httpHeaders).bind() + val contexts = getContextFromLinkHeaderOrDefault(httpHeaders).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() checkSubscriptionExists(subscriptionId).bind() @@ -115,8 +115,8 @@ class SubscriptionHandler( checkIsAllowed(subscriptionId, sub).bind() val subscription = subscriptionService.getById(subscriptionId) - prepareGetSuccessResponse(mediaType, contextLink) - .body(subscription.serialize(contextLink, mediaType, includeSysAttrs)) + prepareGetSuccessResponseHeaders(mediaType, contexts) + .body(subscription.serialize(contexts, mediaType, includeSysAttrs)) }.fold( { it.toErrorResponse() }, { it } diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/job/TimeIntervalNotificationJobTest.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/job/TimeIntervalNotificationJobTest.kt index c23bc9d24..e0abee223 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/job/TimeIntervalNotificationJobTest.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/job/TimeIntervalNotificationJobTest.kt @@ -3,8 +3,11 @@ package com.egm.stellio.subscription.job import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.config.ApplicationProperties.TenantConfiguration import com.egm.stellio.shared.model.EntitySelector -import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.APIC_HEADER_LINK import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap +import com.egm.stellio.shared.util.NGSILD_TEST_CORE_CONTEXT +import com.egm.stellio.shared.util.loadSampleData +import com.egm.stellio.shared.util.toUri import com.egm.stellio.shared.web.DEFAULT_TENANT_URI import com.egm.stellio.subscription.config.WebClientConfig import com.egm.stellio.subscription.model.Notification @@ -117,7 +120,7 @@ class TimeIntervalNotificationJobTest { val compactedEntities = timeIntervalNotificationJob.getEntities( DEFAULT_TENANT_URI, query, - buildContextLinkHeader(APIC_COMPOUND_CONTEXT) + APIC_HEADER_LINK ) assertEquals(1, compactedEntities.size) assertEquals("urn:ngsi-ld:BeeHive:TESTC", compactedEntities[0]["id"]) @@ -142,7 +145,7 @@ class TimeIntervalNotificationJobTest { val compactedEntities = timeIntervalNotificationJob.getEntities( DEFAULT_TENANT_URI, "?type=BeeHive", - buildContextLinkHeader(APIC_COMPOUND_CONTEXT) + APIC_HEADER_LINK ) assertEquals(2, compactedEntities.size) assertEquals("urn:ngsi-ld:BeeHive:TESTC", compactedEntities[0]["id"]) @@ -191,7 +194,7 @@ class TimeIntervalNotificationJobTest { val compactedEntities = timeIntervalNotificationJob.getEntitiesToNotify( DEFAULT_TENANT_URI, subscription, - buildContextLinkHeader(APIC_COMPOUND_CONTEXT) + APIC_HEADER_LINK ) assertEquals(2, compactedEntities.size) assertTrue( diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/model/SubscriptionTest.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/model/SubscriptionTest.kt index 1cef02955..0590568ec 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/model/SubscriptionTest.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/model/SubscriptionTest.kt @@ -46,12 +46,12 @@ class SubscriptionTest { receiverInfo = endpointReceiverInfo ) ), - contexts = listOf(APIC_COMPOUND_CONTEXT) + contexts = APIC_COMPOUND_CONTEXTS ) @Test fun `it should expand a subscription`() { - val subscription = subscription.copy().expand(listOf(APIC_COMPOUND_CONTEXT)) + val subscription = subscription.copy().expand(APIC_COMPOUND_CONTEXTS) assertThat(subscription) .extracting("geoQ.geoproperty", "watchedAttributes", "notification.attributes") @@ -75,7 +75,7 @@ class SubscriptionTest { typeSelection = "($BEEHIVE_COMPACT_TYPE,$APIARY_COMPACT_TYPE);$BEEKEEPER_COMPACT_TYPE" ) ) - ).expand(listOf(APIC_COMPOUND_CONTEXT)) + ).expand(APIC_COMPOUND_CONTEXTS) assertThat(subscription.entities) .allMatch { it.typeSelection == "($BEEHIVE_TYPE,$APIARY_TYPE);$BEEKEEPER_TYPE" } @@ -84,9 +84,9 @@ class SubscriptionTest { @Test fun `it should compact a subscription`() { - val subscription = subscription.copy().expand(listOf(APIC_COMPOUND_CONTEXT)) + val subscription = subscription.copy().expand(APIC_COMPOUND_CONTEXTS) - val compactedSubscription = subscription.compact(APIC_COMPOUND_CONTEXT) + val compactedSubscription = subscription.compact(APIC_COMPOUND_CONTEXTS) assertThat(compactedSubscription) .extracting("geoQ.geoproperty", "watchedAttributes", "notification.attributes") @@ -102,7 +102,7 @@ class SubscriptionTest { @Test fun `it should serialize a subscription as JSON and add the status attribute`() { - val subscription = subscription.copy().expand(listOf(APIC_COMPOUND_CONTEXT)) + val subscription = subscription.copy().expand(APIC_COMPOUND_CONTEXTS) val serializedSub = subscription.serialize(NGSILD_TEST_CORE_CONTEXT, includeSysAttrs = false) @@ -114,7 +114,7 @@ class SubscriptionTest { @Test fun `it should serialize a subscription as JSON without createdAt and modifiedAt if not specified`() { - val subscription = subscription.copy().expand(listOf(APIC_COMPOUND_CONTEXT)) + val subscription = subscription.copy().expand(APIC_COMPOUND_CONTEXTS) val serializedSub = subscription.serialize(NGSILD_TEST_CORE_CONTEXT, includeSysAttrs = false) @@ -126,7 +126,7 @@ class SubscriptionTest { @Test fun `it should serialize a subscription as JSON with createdAt and modifiedAt if specified`() { - val subscription = subscription.copy().expand(listOf(APIC_COMPOUND_CONTEXT)) + val subscription = subscription.copy().expand(APIC_COMPOUND_CONTEXTS) val serializedSub = subscription.serialize(NGSILD_TEST_CORE_CONTEXT, includeSysAttrs = true) @@ -137,7 +137,7 @@ class SubscriptionTest { @Test fun `it should serialize a subscription with a context if JSON-LD media type is asked`() { - val subscription = subscription.copy().expand(listOf(APIC_COMPOUND_CONTEXT)) + val subscription = subscription.copy().expand(APIC_COMPOUND_CONTEXTS) val serializedSub = subscription.serialize(NGSILD_TEST_CORE_CONTEXT, mediaType = JSON_LD_MEDIA_TYPE) @@ -148,7 +148,7 @@ class SubscriptionTest { @Test fun `it should serialize a subscription without context if JSON media type is asked`() { - val subscription = subscription.copy().expand(listOf(APIC_COMPOUND_CONTEXT)) + val subscription = subscription.copy().expand(APIC_COMPOUND_CONTEXTS) val serializedSub = subscription.serialize(NGSILD_TEST_CORE_CONTEXT, mediaType = MediaType.APPLICATION_JSON) @@ -163,7 +163,7 @@ class SubscriptionTest { val otherSubscription = subscription.copy(id = "urn:ngsi-ld:Subscription:02".toUri()) val serializedSubs = - listOf(subscription, otherSubscription).serialize(NGSILD_TEST_CORE_CONTEXT, includeSysAttrs = true) + listOf(subscription, otherSubscription).serialize(NGSILD_TEST_CORE_CONTEXTS, includeSysAttrs = true) val deserializedSubs = deserializeListOfObjects(serializedSubs) @@ -181,7 +181,7 @@ class SubscriptionTest { val otherSubscription = subscription.copy(id = "urn:ngsi-ld:Subscription:02".toUri()) val serializedSubs = listOf(subscription, otherSubscription) - .serialize(NGSILD_TEST_CORE_CONTEXT, mediaType = MediaType.APPLICATION_JSON) + .serialize(NGSILD_TEST_CORE_CONTEXTS, mediaType = MediaType.APPLICATION_JSON) val deserializedSubs = deserializeListOfObjects(serializedSubs) diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt index 79e3b2c04..f47bc9ccd 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt @@ -7,7 +7,6 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_TERM import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_TERM -import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import com.egm.stellio.shared.web.NGSILD_TENANT_HEADER import com.egm.stellio.subscription.model.Endpoint @@ -68,9 +67,7 @@ class NotificationServiceTests { ] } }, - "@context":[ - "$APIC_COMPOUND_CONTEXT" - ] + "@context":[ "$APIC_COMPOUND_CONTEXT" ] } """.trimIndent() @@ -118,7 +115,7 @@ class NotificationServiceTests { FormatType.NORMALIZED, listOf(NGSILD_NAME_PROPERTY, NGSILD_LOCATION_PROPERTY) ), - contexts = listOf(APIC_COMPOUND_CONTEXT) + contexts = APIC_COMPOUND_CONTEXTS ) val jsonLdEntity = expandJsonLdEntity(rawEntity) @@ -188,10 +185,7 @@ class NotificationServiceTests { assertEquals(1, notificationResult.second.data.size) assertTrue(notificationResult.second.data[0].containsKey(NGSILD_NAME_PROPERTY)) assertTrue(notificationResult.second.data[0].containsKey(MANAGED_BY_RELATIONSHIP)) - assertEquals( - listOf(NGSILD_TEST_CORE_CONTEXT), - notificationResult.second.data[0][JsonLdUtils.JSONLD_CONTEXT] - ) + assertEquals(NGSILD_TEST_CORE_CONTEXT, notificationResult.second.data[0][JsonLdUtils.JSONLD_CONTEXT]) assertTrue(notificationResult.third) } } diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt index 476abfa1a..cf385bedb 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt @@ -681,7 +681,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) ) - subscriptionService.update(subscription.id, parsedInput, listOf(APIC_COMPOUND_CONTEXT)) + subscriptionService.update(subscription.id, parsedInput, APIC_COMPOUND_CONTEXTS) val updatedSubscription = subscriptionService.getById(subscription.id) assertThat(updatedSubscription) @@ -715,7 +715,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) ) - subscriptionService.updateNotification(subscription.id, parsedInput, listOf(APIC_COMPOUND_CONTEXT)) + subscriptionService.updateNotification(subscription.id, parsedInput, APIC_COMPOUND_CONTEXTS) val updatedSubscription = subscriptionService.getById(subscription.id) assertThat(updatedSubscription) @@ -746,7 +746,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) ) - subscriptionService.updateEntities(subscription.id, parsedInput, listOf(APIC_COMPOUND_CONTEXT)) + subscriptionService.updateEntities(subscription.id, parsedInput, APIC_COMPOUND_CONTEXTS) val updatedSubscription = subscriptionService.getById(subscription.id) assertThat(updatedSubscription) @@ -783,7 +783,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { subscriptionService.update( subscription.id, mapOf("type" to NGSILD_SUBSCRIPTION_TERM, "isActive" to true), - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ).shouldSucceed() val updatedSubscription = subscriptionService.getById(subscription.id) @@ -805,7 +805,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { subscriptionService.update( subscription.id, mapOf("type" to NGSILD_SUBSCRIPTION_TERM, "isActive" to false), - listOf(APIC_COMPOUND_CONTEXT) + APIC_COMPOUND_CONTEXTS ) val updatedSubscription = subscriptionService.getById(subscription.id) @@ -829,7 +829,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { "watchedAttributes" to arrayListOf(INCOMING_COMPACT_PROPERTY, TEMPERATURE_COMPACT_PROPERTY) ) - subscriptionService.update(subscription.id, parsedInput, listOf(APIC_COMPOUND_CONTEXT)).shouldSucceed() + subscriptionService.update(subscription.id, parsedInput, APIC_COMPOUND_CONTEXTS).shouldSucceed() val updatedSubscription = subscriptionService.getById(subscription.id) @@ -858,7 +858,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { "type" to NGSILD_SUBSCRIPTION_TERM, "notificationTrigger" to notificationTriggers ) - subscriptionService.update(subscription.id, parsedInput, listOf(APIC_COMPOUND_CONTEXT)) + subscriptionService.update(subscription.id, parsedInput, APIC_COMPOUND_CONTEXTS) val updatedSubscription = subscriptionService.getById(subscription.id) assertThat(updatedSubscription) @@ -875,7 +875,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { val parsedInput = mapOf("type" to NGSILD_SUBSCRIPTION_TERM, "unknownAttribute" to "unknownValue") - subscriptionService.update(subscription.id, parsedInput, listOf(APIC_COMPOUND_CONTEXT)) + subscriptionService.update(subscription.id, parsedInput, APIC_COMPOUND_CONTEXTS) .shouldFailWith { it is BadRequestDataException && it.message == "Subscription urn:ngsi-ld:Subscription:1 has invalid attribute: unknownAttribute" @@ -889,7 +889,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { val parsedInput = mapOf("type" to NGSILD_SUBSCRIPTION_TERM, "throttling" to "someValue") - subscriptionService.update(subscription.id, parsedInput, listOf(APIC_COMPOUND_CONTEXT)) + subscriptionService.update(subscription.id, parsedInput, APIC_COMPOUND_CONTEXTS) .shouldFailWith { it is NotImplementedException && it.message == "Subscription urn:ngsi-ld:Subscription:1 has unsupported attribute: throttling" @@ -929,7 +929,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should not return a subscription if q query is invalid`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) + val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -944,7 +944,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a subscription if entity matches q query`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) + val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -959,7 +959,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should not return a subscription if entity doesn't match q query`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) + val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -974,7 +974,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a subscription if entity matches a complex q query`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) + val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -989,7 +989,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a subscription if entity matches a complex q query with AND logical operator`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) + val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1004,7 +1004,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a subscription if entity matches a complex q query with OR logical operator`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) + val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1019,7 +1019,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a subscription if entity matched a q query with a boolean value`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) + val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1034,7 +1034,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should return a subscription if entity matches a scope query`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) + val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1049,7 +1049,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should not return a subscription if entity does not match a scope query`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) + val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1081,7 +1081,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { coordinates: String, expectedSize: Int ) = runTest { - val jsonldEntity = expandJsonLdEntity(entity, listOf(APIC_COMPOUND_CONTEXT)) + val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(INCOMING_COMPACT_PROPERTY), @@ -1175,14 +1175,14 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { subscriptionService.getContextsForSubscription(subscription.id) .shouldSucceedWith { - assertEquals(listOf(APIC_COMPOUND_CONTEXT), it) + assertEquals(APIC_COMPOUND_CONTEXTS, it) } } @Test fun `it should return a link to contexts endpoint if subscription has more than one context`() = runTest { val subscription = loadAndDeserializeSubscription("subscription_minimal_entities.json").copy( - contexts = listOf(APIC_COMPOUND_CONTEXT, NGSILD_TEST_CORE_CONTEXT) + contexts = APIC_COMPOUND_CONTEXTS.plus(NGSILD_TEST_CORE_CONTEXT) ) val contextLink = subscriptionService.getContextsLink(subscription) diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/support/FixtureUtils.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/support/FixtureUtils.kt index cb66c37b3..ffcdd3f71 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/support/FixtureUtils.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/support/FixtureUtils.kt @@ -9,15 +9,15 @@ import com.egm.stellio.subscription.utils.ParsingUtils import java.time.Instant import java.time.ZoneOffset -fun loadAndDeserializeSubscription(filename: String, context: String = APIC_COMPOUND_CONTEXT): Subscription { +fun loadAndDeserializeSubscription(filename: String, contexts: List = APIC_COMPOUND_CONTEXTS): Subscription { val subscriptionPayload = loadSampleData(filename) - return ParsingUtils.parseSubscription(subscriptionPayload.deserializeAsMap(), listOf(context)) + return ParsingUtils.parseSubscription(subscriptionPayload.deserializeAsMap(), contexts) .shouldSucceedAndResult() } fun gimmeSubscriptionFromMembers( additionalMembers: Map, - contexts: List = listOf(APIC_COMPOUND_CONTEXT) + contexts: List = APIC_COMPOUND_CONTEXTS ): Subscription { val payload = mapOf( "id" to "urn:ngsi-ld:Subscription:01".toUri(), diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/web/SubscriptionHandlerTests.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/web/SubscriptionHandlerTests.kt index d82ca7adf..01be1ed33 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/web/SubscriptionHandlerTests.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/web/SubscriptionHandlerTests.kt @@ -150,7 +150,7 @@ class SubscriptionHandlerTests { @Test fun `get subscription context should return a list of contexts`() = runTest { - val subscription = gimmeRawSubscription().copy(contexts = listOf(APIC_COMPOUND_CONTEXT)) + val subscription = gimmeRawSubscription().copy(contexts = APIC_COMPOUND_CONTEXTS) coEvery { subscriptionService.exists(any()) } returns true.right() coEvery { subscriptionService.isCreatorOf(any(), any()) } returns true.right() coEvery { subscriptionService.getContextsForSubscription(any()) } returns subscription.contexts.right() @@ -499,7 +499,7 @@ class SubscriptionHandlerTests { coVerify { subscriptionService.exists(eq(subscriptionId)) } coVerify { subscriptionService.isCreatorOf(subscriptionId, sub) } - coVerify { subscriptionService.update(eq(subscriptionId), parsedSubscription, listOf(APIC_COMPOUND_CONTEXT)) } + coVerify { subscriptionService.update(eq(subscriptionId), parsedSubscription, APIC_COMPOUND_CONTEXTS) } confirmVerified(subscriptionService) } @@ -531,7 +531,7 @@ class SubscriptionHandlerTests { coVerify { subscriptionService.exists(eq(subscriptionId)) } coVerify { subscriptionService.isCreatorOf(subscriptionId, sub) } - coVerify { subscriptionService.update(eq(subscriptionId), parsedSubscription, listOf(APIC_COMPOUND_CONTEXT)) } + coVerify { subscriptionService.update(eq(subscriptionId), parsedSubscription, APIC_COMPOUND_CONTEXTS) } confirmVerified(subscriptionService) } @@ -660,7 +660,7 @@ class SubscriptionHandlerTests { fun `delete subscription should return a 500 if subscription could not be deleted`() = runTest { coEvery { subscriptionService.exists(any()) } returns true.right() coEvery { subscriptionService.isCreatorOf(any(), any()) } returns true.right() - coEvery { subscriptionService.getContextsForSubscription(any()) } returns listOf(APIC_COMPOUND_CONTEXT).right() + coEvery { subscriptionService.getContextsForSubscription(any()) } returns APIC_COMPOUND_CONTEXTS.right() coEvery { subscriptionService.delete(any()) } throws RuntimeException("Unexpected server error") webClient.delete() diff --git a/subscription-service/src/test/resources/logback-test.xml b/subscription-service/src/test/resources/logback-test.xml index 10055c983..5169d8573 100644 --- a/subscription-service/src/test/resources/logback-test.xml +++ b/subscription-service/src/test/resources/logback-test.xml @@ -19,6 +19,7 @@ + From c861f54aa540c73fc50c109182cd5ab482f316d5 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Sun, 31 Dec 2023 09:56:34 +0100 Subject: [PATCH 09/19] fixup: unused import --- .../kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt index 1439e755c..91ec45bd7 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt @@ -12,7 +12,6 @@ import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE_TERM import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_GEOPROPERTY_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_GEOPROPERTY_VALUES -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_JSONPROPERTY_VALUES import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PREFIX import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUES import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECTS From a69de714f99606f2eb385bb48f14ac7b8e9186b8 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Sun, 31 Dec 2023 17:16:33 +0100 Subject: [PATCH 10/19] more tests for JsonLdUtils / refactor geoJsonToWkt processing --- .../com/egm/stellio/shared/util/GeoUtils.kt | 3 + .../egm/stellio/shared/util/JsonLdUtils.kt | 53 ++--- .../stellio/shared/util/JsonLdUtilsTests.kt | 222 +++++++++++++++++- 3 files changed, 246 insertions(+), 32 deletions(-) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/GeoUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/GeoUtils.kt index fa917c702..2d656ebc1 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/GeoUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/GeoUtils.kt @@ -45,6 +45,9 @@ fun geoJsonToWkt(geoJsonSerializedPayload: String): Either BadRequestDataException("Invalid geometry definition: $geoJsonSerializedPayload ($it)").left() }) +fun throwingGeoJsonToWkt(geoJsonPayload: Map): String = + geoJsonToWkt(geoJsonPayload).fold({ throw it }, { it }) + fun wktToGeoJson(wkt: String): Map { val geometry = WKTReader().read(wkt) val geoJsonWriter = GeoJsonWriter() diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt index 56aa337d7..24f59151e 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt @@ -48,7 +48,7 @@ object JsonLdUtils { const val NGSILD_RELATIONSHIP_OBJECTS = "https://uri.etsi.org/ngsi-ld/hasObjects" const val NGSILD_JSONPROPERTY_VALUES = "https://uri.etsi.org/ngsi-ld/jsons" - const val JSONLD_GRAPH = "@graph" + private const val JSONLD_GRAPH = "@graph" const val JSONLD_ID_TERM = "id" const val JSONLD_ID = "@id" const val JSONLD_TYPE_TERM = "type" @@ -215,14 +215,12 @@ object JsonLdUtils { private suspend fun doJsonLdExpansion(fragment: Map, contexts: List): Map { // transform the GeoJSON value of geo properties into WKT format before JSON-LD expansion // since JSON-LD expansion breaks the data (e.g., flattening the lists of lists) - val parsedFragment = geoPropertyToWKT(fragment) + val preparedFragment = fragment + .mapValues(transformGeoPropertyToWKT()) + .plus(JSONLD_CONTEXT to contexts) try { - val expandedFragment = JsonLd.expand( - JsonDocument.of( - serializeObject(parsedFragment.plus(JSONLD_CONTEXT to contexts)).byteInputStream() - ) - ) + val expandedFragment = JsonLd.expand(JsonDocument.of(serializeObject(preparedFragment).byteInputStream())) .options(jsonLdOptions) .get() @@ -239,29 +237,26 @@ object JsonLdUtils { } } - private fun geoPropertyToWKT(jsonFragment: Map): Map { - for (geoProperty in NGSILD_GEO_PROPERTIES_TERMS) { - if (jsonFragment.containsKey(geoProperty)) { - // when creating a temporal entity, a geoproperty can be represented as a list of instances - val geoAttributes = - if (jsonFragment[geoProperty] is MutableMap<*, *>) - listOf(jsonFragment[geoProperty] as MutableMap) - else - jsonFragment[geoProperty] as List> - geoAttributes.forEach { geoAttribute -> - val geoJsonAsString = geoAttribute[JSONLD_VALUE_TERM] - val wktGeom = geoJsonToWkt(geoJsonAsString!! as Map) - .fold({ - throw BadRequestDataException(it.message) - }, { it }) - geoAttribute[JSONLD_VALUE_TERM] = wktGeom + private fun transformGeoPropertyToWKT(): (Map.Entry) -> Any = { + if (NGSILD_GEO_PROPERTIES_TERMS.contains(it.key)) { + when (it.value) { + is Map<*, *> -> { + val geoProperty = it.value as MutableMap + val wktGeometry = throwingGeoJsonToWkt(geoProperty[JSONLD_VALUE_TERM]!! as Map) + geoProperty.plus(JSONLD_VALUE_TERM to wktGeometry) } + is List<*> -> { + (it.value as List>).map { geoProperty -> + val wktGeometry = throwingGeoJsonToWkt(geoProperty[JSONLD_VALUE_TERM] as Map) + geoProperty.plus(JSONLD_VALUE_TERM to wktGeometry) + } + } + else -> it.value } - } - return jsonFragment + } else it.value } - private fun restoreGeoPropertyValue(): (Map.Entry) -> Any = { + private fun restoreGeoPropertyFromWKT(): (Map.Entry) -> Any = { if (NGSILD_GEO_PROPERTIES_TERMS.contains(it.key)) { when (it.value) { is Map<*, *> -> { @@ -294,7 +289,7 @@ object JsonLdUtils { .options(jsonLdOptions) .get() .toPrimitiveMap() - .mapValues(restoreGeoPropertyValue()) + .mapValues(restoreGeoPropertyFromWKT()) private fun JsonObject.toPrimitiveMap(): Map { val outputStream = ByteArrayOutputStream() @@ -318,7 +313,7 @@ object JsonLdUtils { .get() return if (entities.size == 1) - listOf(jsonObject.toPrimitiveMap().mapValues(restoreGeoPropertyValue())) + listOf(jsonObject.toPrimitiveMap().mapValues(restoreGeoPropertyFromWKT())) else { // extract the context from the root of the object to inject it back in the compacted entities later val context: Any = when (jsonObject[JSONLD_CONTEXT]) { @@ -328,7 +323,7 @@ object JsonLdUtils { // extract compacted entities from the @graph key (jsonObject[JSONLD_GRAPH] as JsonArray).toPrimitiveListOfObjects() .map { - it.mapValues(restoreGeoPropertyValue()) + it.mapValues(restoreGeoPropertyFromWKT()) .plus(JSONLD_CONTEXT to context) } } diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt index 4d1af65f6..edc9a0d48 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/JsonLdUtilsTests.kt @@ -2,11 +2,26 @@ package com.egm.stellio.shared.util import com.egm.stellio.shared.model.BadRequestDataException import com.egm.stellio.shared.model.LdContextNotAvailableException +import com.egm.stellio.shared.model.getAttributeFromExpandedAttributes +import com.egm.stellio.shared.model.getMemberValueAsString +import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_CONTEXT +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DEFAULT_VOCAB +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVATION_SPACE_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE +import com.egm.stellio.shared.util.JsonLdUtils.compactEntities import com.egm.stellio.shared.util.JsonLdUtils.compactEntity +import com.egm.stellio.shared.util.JsonLdUtils.compactTerm +import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute +import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity +import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntityF import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdFragment import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap +import com.egm.stellio.shared.util.JsonUtils.serializeObject import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows @@ -58,7 +73,7 @@ class JsonLdUtilsTests { } @Test - fun `it should compact and return a JSON entity`() = runTest { + fun `it should compact and return an entity`() = runTest { val entity = """ { @@ -75,9 +90,210 @@ class JsonLdUtilsTests { } """.trimIndent() - val jsonLdEntity = JsonLdUtils.expandJsonLdEntity(entity, NGSILD_TEST_CORE_CONTEXTS) - val compactedEntity = compactEntity(jsonLdEntity, NGSILD_TEST_CORE_CONTEXTS) + val expandedEntity = expandJsonLdEntity(entity, NGSILD_TEST_CORE_CONTEXTS) + val compactedEntity = compactEntity(expandedEntity, NGSILD_TEST_CORE_CONTEXTS) assertJsonPayloadsAreEqual(expectedEntity, mapper.writeValueAsString(compactedEntity)) } + + @Test + fun `it should compact and return a list of one entity`() = runTest { + val entity = + """ + { + "id": "urn:ngsi-ld:Device:01234", + "type": "Device" + } + """.trimIndent() + val expectedEntity = + """ + [{ + "id": "urn:ngsi-ld:Device:01234", + "type": "Device", + "@context": "$NGSILD_TEST_CORE_CONTEXT" + }] + """.trimIndent() + + val expandedEntity = expandJsonLdEntity(entity, NGSILD_TEST_CORE_CONTEXTS) + val compactedEntities = compactEntities(listOf(expandedEntity), NGSILD_TEST_CORE_CONTEXTS) + + assertJsonPayloadsAreEqual(expectedEntity, mapper.writeValueAsString(compactedEntities)) + } + + @Test + fun `it should compact and return a list of entities`() = runTest { + val entity = + """ + { + "id": "urn:ngsi-ld:Device:01234", + "type": "Device" + } + """.trimIndent() + val expectedEntity = + """ + [{ + "id": "urn:ngsi-ld:Device:01234", + "type": "Device", + "@context": "$NGSILD_TEST_CORE_CONTEXT" + },{ + "id": "urn:ngsi-ld:Device:01234", + "type": "Device", + "@context": "$NGSILD_TEST_CORE_CONTEXT" + }] + """.trimIndent() + + val expandedEntity = expandJsonLdEntity(entity, NGSILD_TEST_CORE_CONTEXTS) + val compactedEntities = compactEntities(listOf(expandedEntity, expandedEntity), NGSILD_TEST_CORE_CONTEXTS) + + assertJsonPayloadsAreEqual(expectedEntity, mapper.writeValueAsString(compactedEntities)) + } + + @Test + fun `it should expand an attribute from a fragment`() = runTest { + val fragment = + """ + { + "attribute": { + "type": "Property", + "value": "something" + } + } + """.trimIndent() + + val expandedAttribute = expandAttribute(fragment, NGSILD_TEST_CORE_CONTEXTS) + assertEquals(NGSILD_DEFAULT_VOCAB + "attribute", expandedAttribute.first) + assertThat(expandedAttribute.second).hasSize(1) + } + + @Test + fun `it should expand an attribute from a name and a string payload`() = runTest { + val payload = + """ + { + "type": "Property", + "value": "something" + } + """.trimIndent() + + val expandedAttribute = expandAttribute("attribute", payload, NGSILD_TEST_CORE_CONTEXTS) + assertEquals(NGSILD_DEFAULT_VOCAB + "attribute", expandedAttribute.first) + assertThat(expandedAttribute.second).hasSize(1) + } + + @Test + fun `it should expand an attribute from a name and a map payload`() = runTest { + val payload = mapOf( + "type" to "Property", + "value" to "something" + ) + + val expandedAttribute = expandAttribute("attribute", payload, NGSILD_TEST_CORE_CONTEXTS) + assertEquals(NGSILD_DEFAULT_VOCAB + "attribute", expandedAttribute.first) + assertThat(expandedAttribute.second).hasSize(1) + } + + @Test + fun `it should correctly transform geoproperties`() = runTest { + val payload = + """ + { + "id": "urn:ngsi-ld:Device:01234", + "type": "Device", + "location": { + "type": "GeoProperty", + "value": { + "type": "Point", + "coordinates": [ 100.12, 0.23 ] + } + }, + "observationSpace": { + "type": "GeoProperty", + "value": { + "type": "Polygon", + "coordinates": [[ + [100.12, 0.23], + [101.12, 0.23], + [101.12, 1.23], + [100.12, 1.23], + [100.12, 0.23] + ]] + } + } + } + """.trimIndent() + + val expandedEntity = expandJsonLdEntityF(payload.deserializeAsMap(), NGSILD_TEST_CORE_CONTEXTS) + .shouldSucceedAndResult() + + val location = expandedEntity.getAttributes().getAttributeFromExpandedAttributes(NGSILD_LOCATION_PROPERTY, null) + assertNotNull(location) + assertEquals( + "POINT (100.12 0.23)", + location!!.getMemberValueAsString(NGSILD_PROPERTY_VALUE) + ) + + val observationSpace = expandedEntity.getAttributes() + .getAttributeFromExpandedAttributes(NGSILD_OBSERVATION_SPACE_PROPERTY, null) + assertNotNull(observationSpace) + assertEquals( + "POLYGON ((100.12 0.23, 101.12 0.23, 101.12 1.23, 100.12 1.23, 100.12 0.23))", + observationSpace!!.getMemberValueAsString(NGSILD_PROPERTY_VALUE) + ) + } + + @Test + fun `it should correctly transform and restore geoproperties`() = runTest { + val payload = + """ + { + "id": "urn:ngsi-ld:Device:01234", + "type": "Device", + "location": { + "type": "GeoProperty", + "value": { + "type": "Point", + "coordinates": [ 100.12, 0.23 ] + } + }, + "observationSpace": { + "type": "GeoProperty", + "value": { + "type": "Polygon", + "coordinates": [[ + [100.12, 0.23], + [101.12, 0.23], + [101.12, 1.23], + [100.12, 1.23], + [100.12, 0.23] + ]] + } + } + } + """.trimIndent() + + val deserializedPayload = payload.deserializeAsMap() + val expandedEntity = expandJsonLdEntityF(deserializedPayload, NGSILD_TEST_CORE_CONTEXTS) + .shouldSucceedAndResult() + val compactedEntity = compactEntity(expandedEntity, NGSILD_TEST_CORE_CONTEXTS) + assertJsonPayloadsAreEqual( + serializeObject(deserializedPayload.plus(JSONLD_CONTEXT to NGSILD_TEST_CORE_CONTEXT)), + serializeObject(compactedEntity) + ) + } + + @Test + fun `it should correctly compact a term if it is in the provided contexts`() = runTest { + assertEquals( + INCOMING_COMPACT_PROPERTY, + compactTerm(INCOMING_PROPERTY, APIC_COMPOUND_CONTEXTS) + ) + } + + @Test + fun `it should return the input term if it was not able to compact it`() = runTest { + assertEquals( + INCOMING_PROPERTY, + compactTerm(INCOMING_PROPERTY, NGSILD_TEST_CORE_CONTEXTS) + ) + } } From e18b440cd01eb761c28c663e5c5f4da61a7ed3ed Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Sun, 31 Dec 2023 17:32:44 +0100 Subject: [PATCH 11/19] refactor: move some last expanded members functions --- .../stellio/shared/model/ExpandedMembers.kt | 34 ++++++++++++++++-- .../egm/stellio/shared/model/NgsiLdEntity.kt | 35 ++----------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt index fa1e048a0..285c6c137 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt @@ -4,7 +4,7 @@ import arrow.core.Either import arrow.core.flatMap import arrow.core.left import arrow.core.right -import com.egm.stellio.shared.util.JsonLdUtils +import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE @@ -13,10 +13,11 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATE_TIME_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATE_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT +import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_TIME_TYPE import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue -import com.egm.stellio.shared.util.toUri import java.net.URI import java.time.LocalDate import java.time.LocalTime @@ -189,5 +190,34 @@ fun ExpandedAttributeInstance.extractRelationshipObject(name: String): Either)?.get(JSONLD_ID)?.toUri() + +fun ExpandedAttributeInstance.getScopes(): List? = + when (val rawScopes = this.getMemberValue(NGSILD_SCOPE_PROPERTY)) { + is String -> listOf(rawScopes) + is List<*> -> rawScopes as List + else -> null + } + +fun ExpandedAttributeInstance.getPropertyValue(): Any { + val hasValueEntry = this[NGSILD_PROPERTY_VALUE]!! + + return if (hasValueEntry.size == 1 && (hasValueEntry[0] as Map).containsKey(JSONLD_VALUE)) { + val rawValue = (hasValueEntry[0] as Map)[JSONLD_VALUE]!! + if (rawValue is String) { + when { + rawValue.isURI() -> rawValue.toUri() + rawValue.isTime() -> LocalTime.parse(rawValue) + rawValue.isDate() -> LocalDate.parse(rawValue) + rawValue.isDateTime() -> ZonedDateTime.parse(rawValue) + else -> rawValue + } + } else rawValue + } else if (hasValueEntry.size == 1) + hasValueEntry[0] as Map + else hasValueEntry.map { (it as Map)[JSONLD_VALUE]!! } +} + fun castAttributeValue(value: Any): ExpandedAttributeInstances = value as List>> diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt index 95510b628..4a9408134 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt @@ -8,7 +8,7 @@ import arrow.core.raise.ensure import arrow.core.raise.ensureNotNull import arrow.core.right import arrow.fx.coroutines.parMap -import com.egm.stellio.shared.util.* +import com.egm.stellio.shared.util.AttributeType import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE @@ -24,9 +24,9 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_UNIT_CODE_PROPERTY +import com.egm.stellio.shared.util.ngsiLdDateTime +import com.egm.stellio.shared.util.toUri import java.net.URI -import java.time.LocalDate -import java.time.LocalTime import java.time.ZonedDateTime class NgsiLdEntity private constructor( @@ -387,35 +387,6 @@ suspend fun ExpandedAttributeInstances.toNgsiLdAttribute( suspend fun ExpandedEntity.toNgsiLdEntity(): Either = NgsiLdEntity.create(this.members, this.contexts) -fun ExpandedAttributeInstance.getDatasetId(): URI? = - (this[NGSILD_DATASET_ID_PROPERTY]?.get(0) as? Map)?.get(JSONLD_ID)?.toUri() - -fun ExpandedAttributeInstance.getScopes(): List? = - when (val rawScopes = this.getMemberValue(NGSILD_SCOPE_PROPERTY)) { - is String -> listOf(rawScopes) - is List<*> -> rawScopes as List - else -> null - } - -fun ExpandedAttributeInstance.getPropertyValue(): Any { - val hasValueEntry = this[NGSILD_PROPERTY_VALUE]!! - - return if (hasValueEntry.size == 1 && (hasValueEntry[0] as Map).containsKey(JSONLD_VALUE)) { - val rawValue = (hasValueEntry[0] as Map)[JSONLD_VALUE]!! - if (rawValue is String) { - when { - rawValue.isURI() -> rawValue.toUri() - rawValue.isTime() -> LocalTime.parse(rawValue) - rawValue.isDate() -> LocalDate.parse(rawValue) - rawValue.isDateTime() -> ZonedDateTime.parse(rawValue) - else -> rawValue - } - } else rawValue - } else if (hasValueEntry.size == 1) - hasValueEntry[0] as Map - else hasValueEntry.map { (it as Map)[JSONLD_VALUE]!! } -} - fun List.flatOnInstances(): List> = this.flatMap { ngsiLdAttribute -> ngsiLdAttribute.getAttributeInstances().map { Pair(ngsiLdAttribute, it) } From c7073e09acc4bb5198aabbd0c06beeeb2ba0a530 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Sun, 31 Dec 2023 18:45:35 +0100 Subject: [PATCH 12/19] refactoring in tests utils and expanded members --- .../service/TemporalEntityAttributeService.kt | 7 ++- .../search/util/AttributeInstanceUtils.kt | 3 +- .../util/AttributeInstanceUtilsTests.kt | 15 +----- .../stellio/shared/model/ExpandedMembers.kt | 29 +++-------- .../egm/stellio/shared/model/NgsiLdEntity.kt | 2 +- .../shared/model/ExpandedMembersTests.kt | 31 +++++------- .../stellio/shared/util/GeoQueryUtilsTests.kt | 27 ++++++++++ .../stellio/shared/util/NgsiLdTestUtils.kt | 49 ------------------- .../com/egm/stellio/shared/util/TestUtils.kt | 20 ++++++++ .../service/SubscriptionServiceTests.kt | 30 ++++++------ 10 files changed, 86 insertions(+), 127 deletions(-) delete mode 100644 shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/NgsiLdTestUtils.kt diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt index 05303e082..dfe512a7d 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt @@ -15,7 +15,6 @@ import com.egm.stellio.shared.util.AttributeType import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PREFIX -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity @@ -842,8 +841,8 @@ class TemporalEntityAttributeService( when (tea.attributeType) { TemporalEntityAttribute.AttributeType.Property -> Triple( - valueToStringOrNull(attributePayload.getMemberValue(NGSILD_PROPERTY_VALUE)!!), - valueToDoubleOrNull(attributePayload.getMemberValue(NGSILD_PROPERTY_VALUE)!!), + valueToStringOrNull(attributePayload.getPropertyValue()!!), + valueToDoubleOrNull(attributePayload.getPropertyValue()!!), null ) TemporalEntityAttribute.AttributeType.Relationship -> @@ -856,7 +855,7 @@ class TemporalEntityAttributeService( Triple( null, null, - WKTCoordinates(attributePayload.getMemberValue(NGSILD_PROPERTY_VALUE)!! as String) + WKTCoordinates(attributePayload.getPropertyValue()!! as String) ) } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/util/AttributeInstanceUtils.kt b/search-service/src/main/kotlin/com/egm/stellio/search/util/AttributeInstanceUtils.kt index 0ac1e037c..775fe91ee 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/util/AttributeInstanceUtils.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/util/AttributeInstanceUtils.kt @@ -83,7 +83,7 @@ fun guessAttributeValueType( ): AttributeValueType = when (attributeType) { TemporalEntityAttribute.AttributeType.Property -> - guessPropertyValueType(expandedAttributeInstance.getPropertyValue()).first + guessPropertyValueType(expandedAttributeInstance.getPropertyValue()!!).first TemporalEntityAttribute.AttributeType.Relationship -> AttributeValueType.URI TemporalEntityAttribute.AttributeType.GeoProperty -> AttributeValueType.GEOMETRY } @@ -106,6 +106,5 @@ fun guessPropertyValueType( is LocalDate -> Pair(AttributeValueType.DATE, Triple(value.toString(), null, null)) is ZonedDateTime -> Pair(AttributeValueType.DATETIME, Triple(value.toString(), null, null)) is LocalTime -> Pair(AttributeValueType.TIME, Triple(value.toString(), null, null)) - is URI -> Pair(AttributeValueType.URI, Triple(value.toString(), null, null)) else -> Pair(AttributeValueType.STRING, Triple(value.toString(), null, null)) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/util/AttributeInstanceUtilsTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/util/AttributeInstanceUtilsTests.kt index 96cf56594..a44cb9e32 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/util/AttributeInstanceUtilsTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/util/AttributeInstanceUtilsTests.kt @@ -96,7 +96,7 @@ class AttributeInstanceUtilsTests { fun `it should guess the value type of a time property`() = runTest { val expandedTimeProperty = expandAttribute( "property", - mapOf("type" to "Property", "value" to LocalTime.now()), + mapOf("type" to "Property", "value" to mapOf("@type" to "Time", "@value" to LocalTime.now())), NGSILD_TEST_CORE_CONTEXTS ) assertEquals( @@ -118,19 +118,6 @@ class AttributeInstanceUtilsTests { ) } - @Test - fun `it should guess the value type of an URI property`() = runTest { - val expandedTimeProperty = expandAttribute( - "property", - mapOf("type" to "Property", "value" to "urn:ngsi-ld:uri"), - NGSILD_TEST_CORE_CONTEXTS - ) - assertEquals( - TemporalEntityAttribute.AttributeValueType.URI, - guessAttributeValueType(TemporalEntityAttribute.AttributeType.Property, expandedTimeProperty.second[0]) - ) - } - @Test fun `it should guess the value type of a geo-property`() = runTest { val expandedGeoProperty = expandAttribute( diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt index 285c6c137..24c92bd3c 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt @@ -4,7 +4,6 @@ import arrow.core.Either import arrow.core.flatMap import arrow.core.left import arrow.core.right -import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE @@ -17,7 +16,9 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_TIME_TYPE +import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedPropertyValue import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue +import com.egm.stellio.shared.util.toUri import java.net.URI import java.time.LocalDate import java.time.LocalTime @@ -47,7 +48,7 @@ fun ExpandedAttributes.getAttributeFromExpandedAttributes( if (datasetId == null) !expandedAttributeInstance.containsKey(NGSILD_DATASET_ID_PROPERTY) else - expandedAttributeInstance.getMemberValue(NGSILD_DATASET_ID_PROPERTY) == datasetId.toString() + expandedAttributeInstance.getDatasetId() == datasetId } } @@ -69,7 +70,7 @@ fun ExpandedAttributeInstances.addNonReifiedProperty( ): ExpandedAttributeInstances { if (this.isEmpty() || this.size > 1) throw BadRequestDataException("Cannot add a sub-attribute into empty or multi-instance attribute: $this") - return listOf(this[0].plus(subAttributeName to JsonLdUtils.buildNonReifiedPropertyValue(subAttributeValue))) + return listOf(this[0].plus(subAttributeName to buildNonReifiedPropertyValue(subAttributeValue))) } fun ExpandedAttributeInstances.addNonReifiedTemporalProperty( @@ -161,6 +162,9 @@ fun ExpandedAttributeInstance.getMemberValue(memberName: ExpandedTerm): Any? { } } +fun ExpandedAttributeInstance.getPropertyValue(): Any? = + getMemberValue(NGSILD_PROPERTY_VALUE) + fun ExpandedAttributeInstance.getMemberValueAsDateTime(memberName: ExpandedTerm): ZonedDateTime? = ZonedDateTime::class.safeCast(this.getMemberValue(memberName)) @@ -200,24 +204,5 @@ fun ExpandedAttributeInstance.getScopes(): List? = else -> null } -fun ExpandedAttributeInstance.getPropertyValue(): Any { - val hasValueEntry = this[NGSILD_PROPERTY_VALUE]!! - - return if (hasValueEntry.size == 1 && (hasValueEntry[0] as Map).containsKey(JSONLD_VALUE)) { - val rawValue = (hasValueEntry[0] as Map)[JSONLD_VALUE]!! - if (rawValue is String) { - when { - rawValue.isURI() -> rawValue.toUri() - rawValue.isTime() -> LocalTime.parse(rawValue) - rawValue.isDate() -> LocalDate.parse(rawValue) - rawValue.isDateTime() -> ZonedDateTime.parse(rawValue) - else -> rawValue - } - } else rawValue - } else if (hasValueEntry.size == 1) - hasValueEntry[0] as Map - else hasValueEntry.map { (it as Map)[JSONLD_VALUE]!! } -} - fun castAttributeValue(value: Any): ExpandedAttributeInstances = value as List>> diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt index 4a9408134..0012a24ad 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt @@ -175,7 +175,7 @@ class NgsiLdPropertyInstance private constructor( name: String, values: ExpandedAttributeInstance ): Either = either { - val value = values.getMemberValue(NGSILD_PROPERTY_VALUE) + val value = values.getPropertyValue() ensureNotNull(value) { BadRequestDataException("Property $name has an instance without a value") } diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt index e7e724746..8d784a2ef 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt @@ -1,14 +1,11 @@ package com.egm.stellio.shared.model -import com.egm.stellio.shared.util.JsonLdUtils -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID +import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECT import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue -import com.egm.stellio.shared.util.NGSILD_TEST_CORE_CONTEXTS -import com.egm.stellio.shared.util.ngsiLdDateTime -import com.egm.stellio.shared.util.toUri +import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedRelationshipValue import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.* @@ -163,26 +160,20 @@ class ExpandedMembersTests { ) ) - val result = relationshipValues.extractRelationshipObject("isARelationship") - assertTrue(result.isLeft()) - result.mapLeft { - assertEquals("Relationship isARelationship has an invalid or no object id: null", it.message) - } + relationshipValues.extractRelationshipObject("isARelationship") + .shouldFail { + assertEquals("Relationship isARelationship has an invalid or no object id: null", it.message) + } } @Test fun `it should extract the target object of a relationship`() { val relationshipObjectId = "urn:ngsi-ld:T:1" - val relationshipValues = mapOf( - NGSILD_RELATIONSHIP_OBJECT to listOf( - mapOf(JSONLD_ID to relationshipObjectId) - ) - ) + val relationshipValues = buildExpandedRelationshipValue(relationshipObjectId.toUri()) - val result = relationshipValues.extractRelationshipObject("isARelationship") - assertTrue(result.isRight()) - result.map { - assertEquals(relationshipObjectId.toUri(), it) - } + relationshipValues[0].extractRelationshipObject("isARelationship") + .shouldSucceedWith { + assertEquals(relationshipObjectId.toUri(), it) + } } } diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt index 5f84144b6..e7fe7754b 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt @@ -1,6 +1,7 @@ package com.egm.stellio.shared.util import com.egm.stellio.shared.model.BadRequestDataException +import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.model.GeoQuery import com.egm.stellio.shared.model.GeoQuery.GeometryType import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_PROPERTY @@ -210,4 +211,30 @@ class GeoQueryUtilsTests { "coordinates" to "[57.5522,%20-20.3484]", "geoproperty" to geoproperty ) + + private suspend fun gimmeSimpleEntityWithGeoProperty( + propertyKey: String, + longitude: Double, + latitude: Double + ): ExpandedEntity { + val entityWithLocation = + """ + { + "id": "urn:ngsi-ld:Entity:01", + "type": "Entity", + "$propertyKey": { + "type": "GeoProperty", + "value": { + "type": "Point", + "coordinates": [ + $longitude, + $latitude + ] + } + } + } + """.trimIndent() + + return JsonLdUtils.expandJsonLdEntity(entityWithLocation, NGSILD_TEST_CORE_CONTEXTS) + } } diff --git a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/NgsiLdTestUtils.kt b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/NgsiLdTestUtils.kt deleted file mode 100644 index b3f4da647..000000000 --- a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/NgsiLdTestUtils.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.egm.stellio.shared.util - -import com.egm.stellio.shared.model.ExpandedEntity - -suspend fun gimmeSimpleEntityWithGeoProperty( - propertyKey: String, - longitude: Double, - latitude: Double -): ExpandedEntity { - val entityWithLocation = - """ - { - "id": "urn:ngsi-ld:Entity:01", - "type": "Entity", - "$propertyKey": { - "type": "GeoProperty", - "value": { - "type": "Point", - "coordinates": [ - $longitude, - $latitude - ] - } - } - } - """.trimIndent() - - return JsonLdUtils.expandJsonLdEntity(entityWithLocation, NGSILD_TEST_CORE_CONTEXTS) -} - -suspend fun gimmeSimpleEntityWithAttributes( - id: String, - type: String, - contexts: List = APIC_COMPOUND_CONTEXTS -): ExpandedEntity = - gimmeSimpleEntityWithAttributes(id, listOf(type), contexts) - -suspend fun gimmeSimpleEntityWithAttributes( - id: String, - types: List, - contexts: List = APIC_COMPOUND_CONTEXTS -): ExpandedEntity { - val entity = mapOf( - "id" to id, - "type" to types - ) - - return JsonLdUtils.expandJsonLdEntity(entity, contexts) -} diff --git a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt index 2588406f5..0431917ce 100644 --- a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt +++ b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt @@ -52,6 +52,26 @@ fun loadMinimalEntityWithSap( } """.trimIndent() +suspend fun loadAndExpandMinimalEntity( + id: String, + type: String, + contexts: List = APIC_COMPOUND_CONTEXTS +): ExpandedEntity = + loadAndExpandMinimalEntity(id, listOf(type), contexts) + +suspend fun loadAndExpandMinimalEntity( + id: String, + types: List, + contexts: List = APIC_COMPOUND_CONTEXTS +): ExpandedEntity { + val entity = mapOf( + "id" to id, + "type" to types + ) + + return expandJsonLdEntity(entity, contexts) +} + suspend fun String.sampleDataToNgsiLdEntity(): Either> { val jsonLdEntity = expandJsonLdEntity(this) return when (val ngsiLdEntity = jsonLdEntity.toNgsiLdEntity()) { diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt index cf385bedb..49003c65b 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt @@ -388,7 +388,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beekeeper:12345678", BEEKEEPER_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:12345678", BEEKEEPER_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, emptySet(), @@ -409,7 +409,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beekeeper:3456789", BEEKEEPER_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:3456789", BEEKEEPER_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, emptySet(), @@ -430,7 +430,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, emptySet(), @@ -451,7 +451,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, emptySet(), @@ -472,7 +472,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, emptySet(), @@ -489,7 +489,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, setOf(TEMPERATURE_PROPERTY), @@ -510,7 +510,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beekeeper:01", SENSOR_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", SENSOR_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, emptySet(), @@ -532,7 +532,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, emptySet(), @@ -551,7 +551,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, setOf(INCOMING_PROPERTY), @@ -570,7 +570,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, setOf(TEMPERATURE_PROPERTY), @@ -590,7 +590,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, setOf(TEMPERATURE_PROPERTY), @@ -610,7 +610,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, setOf(TEMPERATURE_PROPERTY), @@ -630,7 +630,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, setOf(TEMPERATURE_PROPERTY), @@ -651,7 +651,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( jsonLdEntity, setOf(TEMPERATURE_PROPERTY), @@ -919,7 +919,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = gimmeSimpleEntityWithAttributes("urn:ngsi-ld:Beehive:1234567890", types.split(",")) + val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", types.split(",")) subscriptionService.getMatchingSubscriptions( jsonLdEntity, emptySet(), From ad217d21ac07a85792254031125e1cebe0388864 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Mon, 1 Jan 2024 12:04:33 +0100 Subject: [PATCH 13/19] refactor: misc cleanup --- build.gradle.kts | 1 - .../listener/ObservationEventListener.kt | 11 +- .../search/model/TemporalEntityAttribute.kt | 2 +- .../search/service/EntityPayloadService.kt | 12 --- .../service/TemporalEntityAttributeService.kt | 6 +- .../search/util/TemporalEntityBuilder.kt | 4 +- .../search/web/EntityAccessControlHandler.kt | 7 +- .../egm/stellio/search/web/EntityHandler.kt | 20 ++-- .../EnabledAuthorizationServiceTests.kt | 6 +- .../listener/ObservationEventListenerTests.kt | 5 +- .../service/EntityPayloadServiceTests.kt | 41 +++---- .../search/service/EntityQueryServiceTests.kt | 9 +- .../egm/stellio/search/support/TestUtils.kt | 2 +- .../stellio/search/web/EntityHandlerTests.kt | 18 ++-- .../search/web/TemporalEntityHandlerTests.kt | 4 +- ...ingService.json => breedingService.jsonld} | 0 .../entity_with_all_attributes_1.jsonld | 2 +- .../entity_with_all_attributes_2.jsonld | 2 +- .../stellio/shared/model/CompactedEntity.kt | 15 ++- .../stellio/shared/model/ExpandedEntity.kt | 5 +- .../egm/stellio/shared/util/JsonLdUtils.kt | 14 +-- .../shared/model/ExpandedEntityTests.kt | 6 +- .../stellio/shared/util/GeoQueryUtilsTests.kt | 12 +-- .../support/JsonLdContextServerExtension.kt | 2 +- .../com/egm/stellio/shared/util/TestUtils.kt | 11 +- subscription-service/build.gradle.kts | 1 + .../service/NotificationServiceTests.kt | 32 +++--- .../service/SubscriptionServiceTests.kt | 100 +++++++++--------- 28 files changed, 174 insertions(+), 176 deletions(-) rename search-service/src/test/resources/ngsild/aquac/{BreedingService.json => breedingService.jsonld} (100%) diff --git a/build.gradle.kts b/build.gradle.kts index 0273717ce..2fdfdbe43 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -84,7 +84,6 @@ subprojects { testImplementation("io.projectreactor:reactor-test") testImplementation("org.springframework.security:spring-security-test") testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test") - testImplementation("org.wiremock:wiremock-standalone:3.3.1") } tasks.withType { diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/listener/ObservationEventListener.kt b/search-service/src/main/kotlin/com/egm/stellio/search/listener/ObservationEventListener.kt index 0952e8a93..799881dbb 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/listener/ObservationEventListener.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/listener/ObservationEventListener.kt @@ -7,6 +7,7 @@ import com.egm.stellio.search.service.EntityEventService import com.egm.stellio.search.service.EntityPayloadService import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute +import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdEntity import com.egm.stellio.shared.util.JsonLdUtils.expandJsonLdTerms import com.egm.stellio.shared.util.JsonUtils.deserializeAs import com.egm.stellio.shared.web.NGSILD_TENANT_HEADER @@ -63,10 +64,16 @@ class ObservationEventListener( tenantUri: URI, observationEvent: EntityCreateEvent ): Either = either { + val expandedEntity = expandJsonLdEntity( + observationEvent.operationPayload, + observationEvent.contexts + ) + val ngsiLdEntity = expandedEntity.toNgsiLdEntity().bind() + mono { entityPayloadService.createEntity( - observationEvent.operationPayload, - observationEvent.contexts, + ngsiLdEntity, + expandedEntity, observationEvent.sub ).map { entityEventService.publishEntityCreateEvent( diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/model/TemporalEntityAttribute.kt b/search-service/src/main/kotlin/com/egm/stellio/search/model/TemporalEntityAttribute.kt index aa14909a4..189aec73b 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/model/TemporalEntityAttribute.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/model/TemporalEntityAttribute.kt @@ -40,7 +40,7 @@ data class TemporalEntityAttribute( Relationship, GeoProperty; - fun toNgsiLdExpanded(): String = + fun toExpandedName(): String = when (this) { Property -> NGSILD_PROPERTY_TYPE.uri Relationship -> NGSILD_RELATIONSHIP_TYPE.uri diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityPayloadService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityPayloadService.kt index abb2eda6a..a9b3e1cda 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityPayloadService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/EntityPayloadService.kt @@ -34,18 +34,6 @@ class EntityPayloadService( ) { private val logger = LoggerFactory.getLogger(javaClass) - @Transactional - suspend fun createEntity( - payload: String, - contexts: List, - sub: String? = null - ): Either = either { - val jsonLdEntity = JsonLdUtils.expandJsonLdEntity(payload, contexts) - val ngsiLdEntity = jsonLdEntity.toNgsiLdEntity().bind() - - createEntity(ngsiLdEntity, jsonLdEntity, sub).bind() - } - @Transactional suspend fun createEntity( ngsiLdEntity: NgsiLdEntity, diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt index dfe512a7d..2e3559ea9 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/TemporalEntityAttributeService.kt @@ -121,11 +121,11 @@ class TemporalEntityAttributeService( sub: String? = null ): Either = either { val createdAt = ZonedDateTime.now(ZoneOffset.UTC) - val jsonLdEntity = expandJsonLdEntity(payload, contexts) - val ngsiLdEntity = jsonLdEntity.toNgsiLdEntity().bind() + val expandedEntity = expandJsonLdEntity(payload, contexts) + val ngsiLdEntity = expandedEntity.toNgsiLdEntity().bind() ngsiLdEntity.prepareTemporalAttributes() .map { - createEntityTemporalReferences(ngsiLdEntity, jsonLdEntity, it, createdAt, sub).bind() + createEntityTemporalReferences(ngsiLdEntity, expandedEntity, it, createdAt, sub).bind() }.bind() } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt index 91ec45bd7..60aee47bc 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt @@ -116,7 +116,7 @@ object TemporalEntityBuilder { ): Map { return attributeAndResultsMap.mapValues { val attributeInstance = mutableMapOf( - JSONLD_TYPE to listOf(it.key.attributeType.toNgsiLdExpanded()) + JSONLD_TYPE to listOf(it.key.attributeType.toExpandedName()) ) it.key.datasetId?.let { datasetId -> attributeInstance[NGSILD_DATASET_ID_PROPERTY] = buildNonReifiedPropertyValue(datasetId.toString()) @@ -158,7 +158,7 @@ object TemporalEntityBuilder { ): Map { return attributeAndResultsMap.mapValues { val attributeInstance = mutableMapOf( - JSONLD_TYPE to listOf(it.key.attributeType.toNgsiLdExpanded()) + JSONLD_TYPE to listOf(it.key.attributeType.toExpandedName()) ) it.key.datasetId?.let { datasetId -> attributeInstance[NGSILD_DATASET_ID_PROPERTY] = buildNonReifiedPropertyValue(datasetId.toString()) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityAccessControlHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityAccessControlHandler.kt index daf8751f9..cc5c3b431 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityAccessControlHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityAccessControlHandler.kt @@ -14,6 +14,7 @@ import com.egm.stellio.shared.util.AuthContextModel.ALL_IAM_RIGHTS_TERMS import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SAP import com.egm.stellio.shared.util.AuthContextModel.AUTH_TERM_SAP import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_CONTEXT +import com.egm.stellio.shared.util.JsonLdUtils.compactEntities import com.egm.stellio.shared.util.JsonLdUtils.expandAttribute import com.egm.stellio.shared.util.JsonLdUtils.expandAttributes import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap @@ -69,7 +70,7 @@ class EntityAccessControlHandler( return@either ResponseEntity.status(HttpStatus.NO_CONTENT).build() } - val compactedEntities = JsonLdUtils.compactEntities(entities, contexts) + val compactedEntities = compactEntities(entities, contexts) val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) buildQueryResponse( @@ -113,7 +114,7 @@ class EntityAccessControlHandler( return@either ResponseEntity.status(HttpStatus.NO_CONTENT).build() } - val compactedEntities = JsonLdUtils.compactEntities(entities, contexts) + val compactedEntities = compactEntities(entities, contexts) val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) buildQueryResponse( @@ -158,7 +159,7 @@ class EntityAccessControlHandler( return@either ResponseEntity.status(HttpStatus.NO_CONTENT).build() } - val compactedEntities = JsonLdUtils.compactEntities(entities, contexts) + val compactedEntities = compactEntities(entities, contexts) val ngsiLdDataRepresentation = parseRepresentations(params, mediaType) buildQueryResponse( diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityHandler.kt index 4eadd56e1..161a45669 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/web/EntityHandler.kt @@ -51,15 +51,15 @@ class EntityHandler( ): ResponseEntity<*> = either { val sub = getSubFromSecurityContext() val (body, contexts) = extractPayloadAndContexts(requestBody, httpHeaders).bind() - val jsonLdEntity = expandJsonLdEntity(body, contexts) - val ngsiLdEntity = jsonLdEntity.toNgsiLdEntity().bind() + val expandedEntity = expandJsonLdEntity(body, contexts) + val ngsiLdEntity = expandedEntity.toNgsiLdEntity().bind() authorizationService.userCanCreateEntities(sub).bind() entityPayloadService.checkEntityExistence(ngsiLdEntity.id, true).bind() entityPayloadService.createEntity( ngsiLdEntity, - jsonLdEntity, + expandedEntity, sub.getOrNull() ).bind() authorizationService.createAdminRight(ngsiLdEntity.id, sub).bind() @@ -145,8 +145,8 @@ class EntityHandler( val sub = getSubFromSecurityContext() val (body, contexts) = extractPayloadAndContexts(requestBody, httpHeaders).bind() - val jsonLdEntity = expandJsonLdEntity(body, contexts) - val ngsiLdEntity = jsonLdEntity.toNgsiLdEntity().bind() + val expandedEntity = expandJsonLdEntity(body, contexts) + val ngsiLdEntity = expandedEntity.toNgsiLdEntity().bind() entityPayloadService.checkEntityExistence(entityId).bind() authorizationService.userCanUpdateEntity(entityId, sub).bind() @@ -158,7 +158,7 @@ class EntityHandler( entityPayloadService.replaceEntity( entityId, ngsiLdEntity, - jsonLdEntity, + expandedEntity, sub.getOrNull() ).bind() @@ -243,13 +243,13 @@ class EntityHandler( authorizationService.userCanReadEntity(entityId, sub).bind() - val jsonLdEntity = queryService.queryEntity(entityId, contexts).bind() + val expandedEntity = queryService.queryEntity(entityId, contexts).bind() - jsonLdEntity.checkContainsAnyOf(queryParams.attrs).bind() + expandedEntity.checkContainsAnyOf(queryParams.attrs).bind() val filteredExpandedEntity = ExpandedEntity( - jsonLdEntity.filterOnAttributes(queryParams.attrs), - jsonLdEntity.contexts + expandedEntity.filterOnAttributes(queryParams.attrs), + expandedEntity.contexts ) val compactedEntity = compactEntity(filteredExpandedEntity, contexts) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationServiceTests.kt index c4d459e86..88596bef4 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EnabledAuthorizationServiceTests.kt @@ -407,9 +407,9 @@ class EnabledAuthorizationServiceTests { assertEquals(1, it.first) assertEquals(2, it.second.size) - val jsonLdEntityWithOtherRights = it.second.find { it.id == entityId01.toString() }!! - assertEquals(4, jsonLdEntityWithOtherRights.members.size) - assertTrue(jsonLdEntityWithOtherRights.members.containsKey(AUTH_REL_CAN_WRITE)) + val expandedEntityWithOtherRights = it.second.find { it.id == entityId01.toString() }!! + assertEquals(4, expandedEntityWithOtherRights.members.size) + assertTrue(expandedEntityWithOtherRights.members.containsKey(AUTH_REL_CAN_WRITE)) } coVerify { diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/listener/ObservationEventListenerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/listener/ObservationEventListenerTests.kt index de13fb806..e7d289095 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/listener/ObservationEventListenerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/listener/ObservationEventListenerTests.kt @@ -8,6 +8,7 @@ import com.egm.stellio.search.model.UpdatedDetails import com.egm.stellio.search.service.EntityEventService import com.egm.stellio.search.service.EntityPayloadService import com.egm.stellio.shared.model.ExpandedEntity +import com.egm.stellio.shared.model.NgsiLdEntity import com.egm.stellio.shared.util.* import com.ninjasquad.springmockk.MockkBean import io.mockk.* @@ -40,7 +41,7 @@ class ObservationEventListenerTests { val observationEvent = loadSampleData("events/entity/entityCreateEvent.json") coEvery { - entityPayloadService.createEntity(any(), any(), any()) + entityPayloadService.createEntity(any(), any(), any()) } returns Unit.right() coEvery { entityEventService.publishEntityCreateEvent(any(), any(), any(), any()) } returns Job() @@ -48,8 +49,8 @@ class ObservationEventListenerTests { coVerify { entityPayloadService.createEntity( + any(), any(), - APIC_COMPOUND_CONTEXTS, eq("0123456789-1234-5678-987654321") ) } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityPayloadServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityPayloadServiceTests.kt index c17575fdc..b8b2a055e 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityPayloadServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityPayloadServiceTests.kt @@ -146,11 +146,12 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { temporalEntityAttributeService.createEntityTemporalReferences(any(), any(), any(), any(), any()) } returns Unit.right() - val rawEntity = loadSampleData("beehive_minimal.jsonld") + val (expandedEntity, ngsiLdEntity) = + loadAndPrepareSampleData("beehive_minimal.jsonld").shouldSucceedAndResult() entityPayloadService.createEntity( - rawEntity, - APIC_COMPOUND_CONTEXTS, + ngsiLdEntity, + expandedEntity, "0123456789-1234-5678-987654321" ).shouldSucceed() @@ -204,11 +205,12 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { temporalEntityAttributeService.getForEntity(any(), any()) } returns emptyList() - val createEntityPayload = loadSampleData("beehive_minimal.jsonld") + val (expandedEntity, ngsiLdEntity) = + loadAndPrepareSampleData("beehive_minimal.jsonld").shouldSucceedAndResult() entityPayloadService.createEntity( - createEntityPayload, - APIC_COMPOUND_CONTEXTS, + ngsiLdEntity, + expandedEntity, "0123456789-1234-5678-987654321" ).shouldSucceed() @@ -264,11 +266,12 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { temporalEntityAttributeService.getForEntity(any(), any()) } returns emptyList() - val createEntityPayload = loadSampleData("beehive_minimal.jsonld") + val (expandedEntity, ngsiLdEntity) = + loadAndPrepareSampleData("beehive_minimal.jsonld").shouldSucceedAndResult() entityPayloadService.createEntity( - createEntityPayload, - APIC_COMPOUND_CONTEXTS, + ngsiLdEntity, + expandedEntity, "0123456789-1234-5678-987654321" ).shouldSucceed() @@ -308,11 +311,12 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { temporalEntityAttributeService.getForEntity(any(), any()) } returns emptyList() - val createEntityPayload = loadSampleData("beehive_minimal.jsonld") + val (expandedEntity, ngsiLdEntity) = + loadAndPrepareSampleData("beehive_minimal.jsonld").shouldSucceedAndResult() entityPayloadService.createEntity( - createEntityPayload, - APIC_COMPOUND_CONTEXTS, + ngsiLdEntity, + expandedEntity, "0123456789-1234-5678-987654321" ).shouldSucceed() @@ -351,20 +355,21 @@ class EntityPayloadServiceTests : WithTimescaleContainer, WithKafkaContainer { } returns Unit.right() coEvery { temporalEntityAttributeService.deleteTemporalAttributesOfEntity(any()) } returns Unit.right() - val createEntityPayload = loadSampleData("beehive_minimal.jsonld") + val (expandedEntity, ngsiLdEntity) = + loadAndPrepareSampleData("beehive_minimal.jsonld").shouldSucceedAndResult() entityPayloadService.createEntity( - createEntityPayload, - APIC_COMPOUND_CONTEXTS, + ngsiLdEntity, + expandedEntity, "0123456789-1234-5678-987654321" ).shouldSucceed() - val (jsonLdEntity, ngsiLdEntity) = loadSampleData().sampleDataToNgsiLdEntity().shouldSucceedAndResult() + val (newExpandedEntity, newNgsiLdEntity) = loadSampleData().sampleDataToNgsiLdEntity().shouldSucceedAndResult() entityPayloadService.replaceEntity( beehiveURI, - ngsiLdEntity, - jsonLdEntity, + newNgsiLdEntity, + newExpandedEntity, "0123456789-1234-5678-987654321" ).shouldSucceed() diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityQueryServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityQueryServiceTests.kt index 3a145c4a4..b2cc67694 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityQueryServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityQueryServiceTests.kt @@ -59,11 +59,10 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer { coEvery { attributeInstanceService.create(any()) } returns Unit.right() runBlocking { - entityPayloadService.createEntity(firstRawEntity, APIC_COMPOUND_CONTEXTS) - entityPayloadService.createEntity(secondRawEntity, APIC_COMPOUND_CONTEXTS) - entityPayloadService.createEntity(thirdRawEntity, APIC_COMPOUND_CONTEXTS) - entityPayloadService.createEntity(fourthRawEntity, APIC_COMPOUND_CONTEXTS) - entityPayloadService.createEntity(fifthRawEntity, APIC_COMPOUND_CONTEXTS) + listOf(firstRawEntity, secondRawEntity, thirdRawEntity, fourthRawEntity, fifthRawEntity).forEach { + val (expandedEntity, ngsiLdEntity) = it.sampleDataToNgsiLdEntity().shouldSucceedAndResult() + entityPayloadService.createEntity(ngsiLdEntity, expandedEntity) + } } } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/support/TestUtils.kt b/search-service/src/test/kotlin/com/egm/stellio/search/support/TestUtils.kt index c8bb3db3a..518b59801 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/support/TestUtils.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/support/TestUtils.kt @@ -30,7 +30,7 @@ fun buildAttributeInstancePayload( attributeType: TemporalEntityAttribute.AttributeType = TemporalEntityAttribute.AttributeType.Property ): String = serializeObject( mutableMapOf( - JSONLD_TYPE to listOf(attributeType.toNgsiLdExpanded()), + JSONLD_TYPE to listOf(attributeType.toExpandedName()), NGSILD_OBSERVED_AT_PROPERTY to buildNonReifiedTemporalValue(observedAt), NGSILD_INSTANCE_ID_PROPERTY to buildNonReifiedPropertyValue(instanceId.toString()) ).apply { diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt index 55f430519..989ef4144 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt @@ -91,7 +91,7 @@ class EntityHandlerTests { @Test fun `create entity should return a 201 if JSON-LD payload is correct`() { - val jsonLdFile = ClassPathResource("/ngsild/aquac/BreedingService.json") + val jsonLdFile = ClassPathResource("/ngsild/aquac/breedingService.jsonld") val breedingServiceId = "urn:ngsi-ld:BreedingService:0214".toUri() coEvery { authorizationService.userCanCreateEntities(sub) } returns Unit.right() @@ -133,7 +133,7 @@ class EntityHandlerTests { @Test fun `create entity should return a 409 if the entity already exists`() { - val jsonLdFile = ClassPathResource("/ngsild/aquac/BreedingService.json") + val jsonLdFile = ClassPathResource("/ngsild/aquac/breedingService.jsonld") coEvery { authorizationService.userCanCreateEntities(sub) } returns Unit.right() coEvery { @@ -156,7 +156,7 @@ class EntityHandlerTests { @Test fun `create entity should return a 500 error if there is an internal server error`() { - val jsonLdFile = ClassPathResource("/ngsild/aquac/BreedingService.json") + val jsonLdFile = ClassPathResource("/ngsild/aquac/breedingService.jsonld") coEvery { authorizationService.userCanCreateEntities(sub) } returns Unit.right() coEvery { entityPayloadService.checkEntityExistence(any(), any()) } returns Unit.right() @@ -228,7 +228,7 @@ class EntityHandlerTests { @Test fun `create entity should return a 400 if creation unexpectedly fails`() { - val jsonLdFile = ClassPathResource("/ngsild/aquac/BreedingService.json") + val jsonLdFile = ClassPathResource("/ngsild/aquac/breedingService.jsonld") coEvery { authorizationService.userCanCreateEntities(sub) } returns Unit.right() coEvery { entityPayloadService.checkEntityExistence(any(), any()) } returns Unit.right() @@ -255,7 +255,7 @@ class EntityHandlerTests { @Test fun `create entity should return a 403 if user is not allowed to create entities`() { - val jsonLdFile = ClassPathResource("/ngsild/aquac/BreedingService.json") + val jsonLdFile = ClassPathResource("/ngsild/aquac/breedingService.jsonld") coEvery { authorizationService.userCanCreateEntities(sub) @@ -1145,7 +1145,7 @@ class EntityHandlerTests { @Test fun `replace entity should return a 201 if JSON-LD payload is correct`() { - val jsonLdFile = ClassPathResource("/ngsild/aquac/BreedingService.json") + val jsonLdFile = ClassPathResource("/ngsild/aquac/breedingService.jsonld") val breedingServiceId = "urn:ngsi-ld:BreedingService:0214".toUri() coEvery { entityPayloadService.checkEntityExistence(breedingServiceId) } returns Unit.right() @@ -1185,7 +1185,7 @@ class EntityHandlerTests { @Test fun `replace entity should return a 403 if user is not allowed to update the entity`() { - val jsonLdFile = ClassPathResource("/ngsild/aquac/BreedingService.json") + val jsonLdFile = ClassPathResource("/ngsild/aquac/breedingService.jsonld") val breedingServiceId = "urn:ngsi-ld:BreedingService:0214".toUri() coEvery { entityPayloadService.checkEntityExistence(breedingServiceId) } returns Unit.right() @@ -1211,7 +1211,7 @@ class EntityHandlerTests { @Test fun `replace entity should return a 404 if entity does not exist`() { - val jsonLdFile = ClassPathResource("/ngsild/aquac/BreedingService.json") + val jsonLdFile = ClassPathResource("/ngsild/aquac/breedingService.jsonld") val breedingServiceId = "urn:ngsi-ld:BreedingService:0214".toUri() coEvery { @@ -1228,7 +1228,7 @@ class EntityHandlerTests { @Test fun `replace entity should return a 400 if id contained in payload is different from the one in URL`() { - val jsonLdFile = ClassPathResource("/ngsild/aquac/BreedingService.json") + val jsonLdFile = ClassPathResource("/ngsild/aquac/breedingService.jsonld") val breedingServiceId = "urn:ngsi-ld:BreedingService:0215".toUri() coEvery { entityPayloadService.checkEntityExistence(breedingServiceId) } returns Unit.right() diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt index 6f63fd71d..d0fcb3c62 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt @@ -101,7 +101,7 @@ class TemporalEntityHandlerTests { val data = loadSampleData("/temporal/beehive_create_temporal_entity_first_instance.jsonld").deserializeAsMap() - val jsonLdEntity = JsonLdUtils.expandJsonLdEntity(data, APIC_COMPOUND_CONTEXTS) + val expandedEntity = JsonLdUtils.expandJsonLdEntity(data, APIC_COMPOUND_CONTEXTS) val expectedInstancesFilePath = "/temporal/beehive_create_temporal_entity_without_first_instance_expanded.jsonld" val jsonInstances = @@ -119,7 +119,7 @@ class TemporalEntityHandlerTests { coVerify { entityPayloadService.createEntity( any(), - eq(jsonLdEntity), + eq(expandedEntity), eq(sub.value) ) } diff --git a/search-service/src/test/resources/ngsild/aquac/BreedingService.json b/search-service/src/test/resources/ngsild/aquac/breedingService.jsonld similarity index 100% rename from search-service/src/test/resources/ngsild/aquac/BreedingService.json rename to search-service/src/test/resources/ngsild/aquac/breedingService.jsonld diff --git a/search-service/src/test/resources/ngsild/entity_with_all_attributes_1.jsonld b/search-service/src/test/resources/ngsild/entity_with_all_attributes_1.jsonld index c719fa323..926d6d75b 100644 --- a/search-service/src/test/resources/ngsild/entity_with_all_attributes_1.jsonld +++ b/search-service/src/test/resources/ngsild/entity_with_all_attributes_1.jsonld @@ -103,6 +103,6 @@ } }, "@context": [ - "http://localhost:8093/jsonld-contexts/ngsi-ld-core-context-v1.8.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/search-service/src/test/resources/ngsild/entity_with_all_attributes_2.jsonld b/search-service/src/test/resources/ngsild/entity_with_all_attributes_2.jsonld index bb578e686..f0ceaf1dc 100644 --- a/search-service/src/test/resources/ngsild/entity_with_all_attributes_2.jsonld +++ b/search-service/src/test/resources/ngsild/entity_with_all_attributes_2.jsonld @@ -103,6 +103,6 @@ } }, "@context": [ - "http://localhost:8093/jsonld-contexts/ngsi-ld-core-context-v1.8.jsonld" + "http://localhost:8093/jsonld-contexts/apic-compound.jsonld" ] } diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt index b742116ab..cbbcc998f 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt @@ -16,10 +16,11 @@ typealias CompactedEntity = Map fun CompactedEntity.toKeyValues(): Map = this.mapValues { (_, value) -> simplifyRepresentation(value) } -private fun simplifyRepresentation(value: Any): Any { - return when (value) { - // entity property value is always a Map +private fun simplifyRepresentation(value: Any): Any = + when (value) { + // an attribute with a single instance is Map<*, *> -> simplifyValue(value as Map) + // an attribute with multiple instances is List<*> -> value.map { when (it) { is Map<*, *> -> simplifyValue(it as Map) @@ -27,18 +28,16 @@ private fun simplifyRepresentation(value: Any): Any { else -> it } } - // we keep id and type values as they are (String) + // keep id, type and other non-reified properties as they are (typically string or list) else -> value } -} -private fun simplifyValue(value: Map): Any { - return when (value[JSONLD_TYPE_TERM]) { +private fun simplifyValue(value: Map): Any = + when (value[JSONLD_TYPE_TERM]) { NGSILD_PROPERTY_TERM, NGSILD_GEOPROPERTY_TERM -> value.getOrDefault(JSONLD_VALUE_TERM, value) NGSILD_RELATIONSHIP_TERM -> value.getOrDefault(JSONLD_OBJECT, value) else -> value } -} fun CompactedEntity.toGeoJson(geometryProperty: String): Map { val geometryAttributeContent = this[geometryProperty] as? Map diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedEntity.kt index 07fcd8bee..9c699bf1b 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedEntity.kt @@ -70,13 +70,12 @@ data class ExpandedEntity( contexts = contexts ) - // FIXME kinda hacky but we often just need the id or type... how can it be improved? val id by lazy { - (members[JSONLD_ID] ?: InternalErrorException("Could not extract id from JSON-LD entity")) as String + (members[JSONLD_ID] ?: throw BadRequestDataException("Could not extract id from JSON-LD entity")) as String } val types by lazy { - (members[JSONLD_TYPE] ?: InternalErrorException("Could not extract type from JSON-LD entity")) + (members[JSONLD_TYPE] ?: throw BadRequestDataException("Could not extract type from JSON-LD entity")) as List } diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt index 24f59151e..139a5ff22 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt @@ -46,7 +46,6 @@ object JsonLdUtils { const val NGSILD_PROPERTY_VALUES = "https://uri.etsi.org/ngsi-ld/hasValues" const val NGSILD_GEOPROPERTY_VALUES = "https://uri.etsi.org/ngsi-ld/hasValues" const val NGSILD_RELATIONSHIP_OBJECTS = "https://uri.etsi.org/ngsi-ld/hasObjects" - const val NGSILD_JSONPROPERTY_VALUES = "https://uri.etsi.org/ngsi-ld/jsons" private const val JSONLD_GRAPH = "@graph" const val JSONLD_ID_TERM = "id" @@ -151,16 +150,11 @@ object JsonLdUtils { fun expandJsonLdTerm(term: String, contexts: List): String = try { - JsonLd.expand( - JsonDocument.of( - serializeObject( - mapOf( - term to mapOf(), - JSONLD_CONTEXT to contexts - ) - ).byteInputStream() - ) + val preparedTerm = mapOf( + term to mapOf(), + JSONLD_CONTEXT to contexts ) + JsonLd.expand(JsonDocument.of(serializeObject(preparedTerm).byteInputStream())) .options(jsonLdOptions) .get() .let { diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt index a779ea398..60803966e 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt @@ -202,9 +202,9 @@ class ExpandedEntityTests { } """.trimIndent() - val jsonLdEntity = expandJsonLdEntity(entity).populateCreationTimeDate(ngsiLdDateTime()) - assertThat(jsonLdEntity.members).containsKey(NGSILD_CREATED_AT_PROPERTY) - val nameAttributeInstances = jsonLdEntity.members[NGSILD_NAME_PROPERTY] as ExpandedAttributeInstances + val expandedEntity = expandJsonLdEntity(entity).populateCreationTimeDate(ngsiLdDateTime()) + assertThat(expandedEntity.members).containsKey(NGSILD_CREATED_AT_PROPERTY) + val nameAttributeInstances = expandedEntity.members[NGSILD_NAME_PROPERTY] as ExpandedAttributeInstances assertThat(nameAttributeInstances).hasSize(1) assertThat(nameAttributeInstances[0]).containsKey(NGSILD_CREATED_AT_PROPERTY) } diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt index e7fe7754b..02c2ad055 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/util/GeoQueryUtilsTests.kt @@ -137,9 +137,9 @@ class GeoQueryUtilsTests { "[[[0 1],[1, 1],[0, 1]]]", geoJsonToWkt(GeometryType.POLYGON, "[[[0 1],[1, 1],[0, 1]]]").getOrNull()!! ) - val jsonLdEntity = gimmeSimpleEntityWithGeoProperty("location", 24.30623, 60.07966) + val expandedEntity = gimmeSimpleEntityWithGeoProperty("location", 24.30623, 60.07966) - val queryStatement = buildGeoQuery(geoQuery, jsonLdEntity) + val queryStatement = buildGeoQuery(geoQuery, expandedEntity) assertEqualsIgnoringNoise( """ @@ -161,9 +161,9 @@ class GeoQueryUtilsTests { "[60.10000, 24.60000]", geoJsonToWkt(GeometryType.POINT, "[60.10000, 24.60000]").getOrNull()!! ) - val jsonLdEntity = gimmeSimpleEntityWithGeoProperty("location", 60.07966, 24.30623) + val expandedEntity = gimmeSimpleEntityWithGeoProperty("location", 60.07966, 24.30623) - val queryStatement = buildGeoQuery(geoQuery, jsonLdEntity) + val queryStatement = buildGeoQuery(geoQuery, expandedEntity) assertEqualsIgnoringNoise( """ @@ -185,9 +185,9 @@ class GeoQueryUtilsTests { "[60.10000, 24.60000]", geoJsonToWkt(GeometryType.POINT, "[60.10000, 24.60000]").getOrNull()!! ) - val jsonLdEntity = gimmeSimpleEntityWithGeoProperty("location", 60.30623, 30.07966) + val expandedEntity = gimmeSimpleEntityWithGeoProperty("location", 60.30623, 30.07966) - val queryStatement = buildGeoQuery(geoQuery, jsonLdEntity) + val queryStatement = buildGeoQuery(geoQuery, expandedEntity) assertEqualsIgnoringNoise( """ diff --git a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/support/JsonLdContextServerExtension.kt b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/support/JsonLdContextServerExtension.kt index 7d9c69200..d5ccbca1b 100644 --- a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/support/JsonLdContextServerExtension.kt +++ b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/support/JsonLdContextServerExtension.kt @@ -35,7 +35,7 @@ class JsonLdContextServerExtension : BeforeAllCallback, AfterAllCallback { .respond( callback().withCallbackClass(JsonLdContextResponseCallback::class.java) ) - logger.debug("WireMock server is started") + logger.debug("JSON-LD context server is started") } override fun afterAll(context: ExtensionContext) { diff --git a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt index 0431917ce..a3d3e80b4 100644 --- a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt +++ b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/TestUtils.kt @@ -21,6 +21,11 @@ suspend fun loadAndExpandSampleData(filename: String = "beehive.jsonld"): Expand return expandJsonLdEntity(String(sampleData.inputStream.readAllBytes())) } +suspend fun loadAndPrepareSampleData( + filename: String = "beehive.jsonld" +): Either> = + loadSampleData(filename).sampleDataToNgsiLdEntity() + fun loadMinimalEntity( entityId: URI, entityTypes: Set, @@ -73,10 +78,10 @@ suspend fun loadAndExpandMinimalEntity( } suspend fun String.sampleDataToNgsiLdEntity(): Either> { - val jsonLdEntity = expandJsonLdEntity(this) - return when (val ngsiLdEntity = jsonLdEntity.toNgsiLdEntity()) { + val expandedEntity = expandJsonLdEntity(this) + return when (val ngsiLdEntity = expandedEntity.toNgsiLdEntity()) { is Either.Left -> BadRequestDataException("Invalid NGSI-LD input for sample data: $this").left() - is Either.Right -> Pair(jsonLdEntity, ngsiLdEntity.value).right() + is Either.Right -> Pair(expandedEntity, ngsiLdEntity.value).right() } } diff --git a/subscription-service/build.gradle.kts b/subscription-service/build.gradle.kts index 7a9b677d9..9e3f8e619 100644 --- a/subscription-service/build.gradle.kts +++ b/subscription-service/build.gradle.kts @@ -27,6 +27,7 @@ dependencies { runtimeOnly("org.postgresql:postgresql") + testImplementation("org.wiremock:wiremock-standalone:3.3.1") testImplementation("org.testcontainers:postgresql") testImplementation("org.testcontainers:r2dbc") testImplementation(testFixtures(project(":shared"))) diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt index f47bc9ccd..4ecaeb3f5 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt @@ -74,7 +74,7 @@ class NotificationServiceTests { @Test fun `it should notify the subscriber and update the subscription`() = runTest { val subscription = gimmeRawSubscription() - val jsonLdEntity = expandJsonLdEntity(rawEntity) + val expandedEntity = expandJsonLdEntity(rawEntity) coEvery { subscriptionService.getMatchingSubscriptions(any(), any(), any()) @@ -87,7 +87,7 @@ class NotificationServiceTests { ) notificationService.notifyMatchingSubscribers( - jsonLdEntity, + expandedEntity, setOf(NGSILD_NAME_PROPERTY), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -99,7 +99,7 @@ class NotificationServiceTests { coVerify { subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, setOf(NGSILD_NAME_PROPERTY), ATTRIBUTE_UPDATED ) @@ -117,7 +117,7 @@ class NotificationServiceTests { ), contexts = APIC_COMPOUND_CONTEXTS ) - val jsonLdEntity = expandJsonLdEntity(rawEntity) + val expandedEntity = expandJsonLdEntity(rawEntity) coEvery { subscriptionService.getMatchingSubscriptions(any(), any(), any()) @@ -130,7 +130,7 @@ class NotificationServiceTests { ) notificationService.notifyMatchingSubscribers( - jsonLdEntity, + expandedEntity, setOf(NGSILD_NAME_PROPERTY), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -162,7 +162,7 @@ class NotificationServiceTests { ), contexts = listOf(NGSILD_TEST_CORE_CONTEXT) ) - val jsonLdEntity = expandJsonLdEntity(rawEntity) + val expandedEntity = expandJsonLdEntity(rawEntity) coEvery { subscriptionService.getMatchingSubscriptions(any(), any(), any()) @@ -175,7 +175,7 @@ class NotificationServiceTests { ) notificationService.notifyMatchingSubscribers( - jsonLdEntity, + expandedEntity, setOf(NGSILD_NAME_PROPERTY), ATTRIBUTE_UPDATED ).shouldSucceedWith { notificationResults -> @@ -196,7 +196,7 @@ class NotificationServiceTests { val subscription = gimmeRawSubscription( withNotifParams = Pair(FormatType.KEY_VALUES, listOf(NGSILD_LOCATION_TERM)) ) - val jsonLdEntity = expandJsonLdEntity(rawEntity) + val expandedEntity = expandJsonLdEntity(rawEntity) coEvery { subscriptionService.getMatchingSubscriptions(any(), any(), any()) @@ -209,7 +209,7 @@ class NotificationServiceTests { ) notificationService.notifyMatchingSubscribers( - jsonLdEntity, + expandedEntity, setOf(NGSILD_NAME_PROPERTY), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -221,7 +221,7 @@ class NotificationServiceTests { coVerify { subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, setOf(NGSILD_NAME_PROPERTY), ATTRIBUTE_UPDATED ) @@ -234,7 +234,7 @@ class NotificationServiceTests { fun `it should notify the two subscribers`() = runTest { val subscription1 = gimmeRawSubscription() val subscription2 = gimmeRawSubscription() - val jsonLdEntity = expandJsonLdEntity(rawEntity) + val expandedEntity = expandJsonLdEntity(rawEntity) coEvery { subscriptionService.getMatchingSubscriptions(any(), any(), any()) @@ -247,7 +247,7 @@ class NotificationServiceTests { ) notificationService.notifyMatchingSubscribers( - jsonLdEntity, + expandedEntity, setOf(NGSILD_NAME_PROPERTY), ATTRIBUTE_DELETED ).shouldSucceedWith { @@ -256,7 +256,7 @@ class NotificationServiceTests { coVerify { subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, setOf(NGSILD_NAME_PROPERTY), ATTRIBUTE_DELETED ) @@ -280,7 +280,7 @@ class NotificationServiceTests { ) ) val subscription2 = gimmeRawSubscription() - val jsonLdEntity = expandJsonLdEntity(rawEntity) + val expandedEntity = expandJsonLdEntity(rawEntity) coEvery { subscriptionService.getMatchingSubscriptions(any(), any(), any()) @@ -293,7 +293,7 @@ class NotificationServiceTests { ) notificationService.notifyMatchingSubscribers( - jsonLdEntity, + expandedEntity, setOf(NGSILD_NAME_PROPERTY), ATTRIBUTE_CREATED ).shouldSucceedWith { results -> @@ -308,7 +308,7 @@ class NotificationServiceTests { coVerify { subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, setOf(NGSILD_NAME_PROPERTY), ATTRIBUTE_CREATED ) diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt index 49003c65b..35a44cc74 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/SubscriptionServiceTests.kt @@ -388,9 +388,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:12345678", BEEKEEPER_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:12345678", BEEKEEPER_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, emptySet(), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -409,9 +409,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:3456789", BEEKEEPER_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:3456789", BEEKEEPER_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, emptySet(), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -430,9 +430,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, emptySet(), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -451,9 +451,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, emptySet(), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -472,9 +472,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, emptySet(), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -489,9 +489,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, setOf(TEMPERATURE_PROPERTY), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -510,9 +510,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", SENSOR_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", SENSOR_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, emptySet(), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -532,9 +532,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beekeeper:01", BEEKEEPER_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, emptySet(), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -551,9 +551,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, setOf(INCOMING_PROPERTY), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -570,9 +570,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, setOf(TEMPERATURE_PROPERTY), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -590,9 +590,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, setOf(TEMPERATURE_PROPERTY), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -610,9 +610,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, setOf(TEMPERATURE_PROPERTY), ENTITY_CREATED ).shouldSucceedWith { @@ -630,9 +630,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, setOf(TEMPERATURE_PROPERTY), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -651,9 +651,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", BEEHIVE_COMPACT_TYPE) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, setOf(TEMPERATURE_PROPERTY), ATTRIBUTE_UPDATED ).shouldSucceedWith { @@ -919,9 +919,9 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - val jsonLdEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", types.split(",")) + val expandedEntity = loadAndExpandMinimalEntity("urn:ngsi-ld:Beehive:1234567890", types.split(",")) subscriptionService.getMatchingSubscriptions( - jsonLdEntity, + expandedEntity, emptySet(), ATTRIBUTE_UPDATED ).shouldSucceedWith { assertEquals(expectedSize, it.size) } @@ -929,7 +929,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should not return a subscription if q query is invalid`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) + val expandedEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -938,13 +938,13 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - subscriptionService.getMatchingSubscriptions(jsonldEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) + subscriptionService.getMatchingSubscriptions(expandedEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) .shouldSucceedWith { assertEquals(0, it.size) } } @Test fun `it should return a subscription if entity matches q query`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) + val expandedEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -953,13 +953,13 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - subscriptionService.getMatchingSubscriptions(jsonldEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) + subscriptionService.getMatchingSubscriptions(expandedEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) .shouldSucceedWith { assertEquals(1, it.size) } } @Test fun `it should not return a subscription if entity doesn't match q query`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) + val expandedEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -968,13 +968,13 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - subscriptionService.getMatchingSubscriptions(jsonldEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) + subscriptionService.getMatchingSubscriptions(expandedEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) .shouldSucceedWith { assertEquals(0, it.size) } } @Test fun `it should return a subscription if entity matches a complex q query`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) + val expandedEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -983,13 +983,13 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - subscriptionService.getMatchingSubscriptions(jsonldEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) + subscriptionService.getMatchingSubscriptions(expandedEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) .shouldSucceedWith { assertEquals(1, it.size) } } @Test fun `it should return a subscription if entity matches a complex q query with AND logical operator`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) + val expandedEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -998,13 +998,13 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - subscriptionService.getMatchingSubscriptions(jsonldEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) + subscriptionService.getMatchingSubscriptions(expandedEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) .shouldSucceedWith { assertEquals(1, it.size) } } @Test fun `it should return a subscription if entity matches a complex q query with OR logical operator`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) + val expandedEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1013,13 +1013,13 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - subscriptionService.getMatchingSubscriptions(jsonldEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) + subscriptionService.getMatchingSubscriptions(expandedEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) .shouldSucceedWith { assertEquals(1, it.size) } } @Test fun `it should return a subscription if entity matched a q query with a boolean value`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) + val expandedEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1028,13 +1028,13 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - subscriptionService.getMatchingSubscriptions(jsonldEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) + subscriptionService.getMatchingSubscriptions(expandedEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) .shouldSucceedWith { assertEquals(1, it.size) } } @Test fun `it should return a subscription if entity matches a scope query`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) + val expandedEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1043,13 +1043,13 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - subscriptionService.getMatchingSubscriptions(jsonldEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) + subscriptionService.getMatchingSubscriptions(expandedEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) .shouldSucceedWith { assertEquals(1, it.size) } } @Test fun `it should not return a subscription if entity does not match a scope query`() = runTest { - val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) + val expandedEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(NGSILD_LOCATION_TERM), @@ -1058,7 +1058,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - subscriptionService.getMatchingSubscriptions(jsonldEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) + subscriptionService.getMatchingSubscriptions(expandedEntity, setOf(NGSILD_LOCATION_PROPERTY), ATTRIBUTE_UPDATED) .shouldSucceedWith { assertEquals(0, it.size) } } @@ -1081,7 +1081,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { coordinates: String, expectedSize: Int ) = runTest { - val jsonldEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) + val expandedEntity = expandJsonLdEntity(entity, APIC_COMPOUND_CONTEXTS) val subscription = gimmeSubscriptionFromMembers( mapOf( "watchedAttributes" to listOf(INCOMING_COMPACT_PROPERTY), @@ -1094,7 +1094,7 @@ class SubscriptionServiceTests : WithTimescaleContainer, WithKafkaContainer { ) subscriptionService.create(subscription, mockUserSub).shouldSucceed() - subscriptionService.getMatchingSubscriptions(jsonldEntity, setOf(INCOMING_PROPERTY), ATTRIBUTE_UPDATED) + subscriptionService.getMatchingSubscriptions(expandedEntity, setOf(INCOMING_PROPERTY), ATTRIBUTE_UPDATED) .shouldSucceedWith { assertEquals(expectedSize, it.size) } } From bdde76d08a9ca3fb1d8ae2986fcf5b4e0f7d7457 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Wed, 3 Jan 2024 13:55:09 +0100 Subject: [PATCH 14/19] feat(temporal): merge uri value type to string for properties --- .../V0_38__update_uri_type_to_string_for_properties.sql | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 search-service/src/main/resources/db/migration/V0_38__update_uri_type_to_string_for_properties.sql diff --git a/search-service/src/main/resources/db/migration/V0_38__update_uri_type_to_string_for_properties.sql b/search-service/src/main/resources/db/migration/V0_38__update_uri_type_to_string_for_properties.sql new file mode 100644 index 000000000..b768a3cb7 --- /dev/null +++ b/search-service/src/main/resources/db/migration/V0_38__update_uri_type_to_string_for_properties.sql @@ -0,0 +1,4 @@ +update temporal_entity_attribute + set attribute_value_type = 'STRING' + where attribute_value_type = 'URI' + and attribute_type = 'Property'; From 0841693dd1b3a4799b42770faf7bc404dbaa2858 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Wed, 3 Jan 2024 15:17:06 +0100 Subject: [PATCH 15/19] refactor: extract some constants from JsonLdUtils --- .../egm/stellio/search/authorization/EntityAccessRights.kt | 2 +- .../kotlin/com/egm/stellio/search/authorization/Group.kt | 4 ++-- .../com/egm/stellio/search/util/AttributeInstanceUtils.kt | 1 - .../search/authorization/EntityAccessRightsServiceTests.kt | 2 +- .../egm/stellio/search/service/EntityQueryServiceTests.kt | 1 - .../stellio/search/web/EntityAccessControlHandlerTests.kt | 1 - .../src/main/kotlin/com/egm/stellio/shared/util/AuthUtils.kt | 3 +++ .../main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt | 5 ----- .../com/egm/stellio/shared/model/ExpandedEntityTests.kt | 1 - .../kotlin/com/egm/stellio/shared/util/JsonLdContextUtils.kt | 3 +++ .../subscription/listener/EntityEventListenerServiceTests.kt | 2 +- .../stellio/subscription/service/NotificationServiceTests.kt | 2 -- 12 files changed, 11 insertions(+), 16 deletions(-) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt index 7d33ccb70..e6f3761dc 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/EntityAccessRights.kt @@ -12,7 +12,7 @@ import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SUBJECT_INFO import com.egm.stellio.shared.util.AuthContextModel.AUTH_REL_CAN_ADMIN import com.egm.stellio.shared.util.AuthContextModel.AUTH_REL_CAN_READ import com.egm.stellio.shared.util.AuthContextModel.AUTH_REL_CAN_WRITE -import com.egm.stellio.shared.util.JsonLdUtils.DATASET_ID_PREFIX +import com.egm.stellio.shared.util.AuthContextModel.DATASET_ID_PREFIX import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_PROPERTY diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/Group.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/Group.kt index 438a65f5c..a664c6bf1 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/Group.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/Group.kt @@ -1,10 +1,10 @@ package com.egm.stellio.search.authorization +import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_NAME import com.egm.stellio.shared.util.AuthContextModel.AUTH_REL_IS_MEMBER_OF import com.egm.stellio.shared.util.AuthContextModel.GROUP_ENTITY_PREFIX import com.egm.stellio.shared.util.AuthContextModel.GROUP_TYPE import com.egm.stellio.shared.util.JsonLdUtils -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue data class Group( @@ -18,7 +18,7 @@ data class Group( resultEntity[JsonLdUtils.JSONLD_ID] = GROUP_ENTITY_PREFIX + id resultEntity[JsonLdUtils.JSONLD_TYPE] = listOf(type) - resultEntity[NGSILD_NAME_PROPERTY] = buildExpandedPropertyValue(name) + resultEntity[AUTH_PROP_NAME] = buildExpandedPropertyValue(name) isMember.run { resultEntity[AUTH_REL_IS_MEMBER_OF] = buildExpandedPropertyValue(isMember.toString()) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/util/AttributeInstanceUtils.kt b/search-service/src/main/kotlin/com/egm/stellio/search/util/AttributeInstanceUtils.kt index 775fe91ee..a7252aa04 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/util/AttributeInstanceUtils.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/util/AttributeInstanceUtils.kt @@ -10,7 +10,6 @@ import com.egm.stellio.search.model.TemporalEntityAttribute.AttributeValueType import com.egm.stellio.shared.model.* import com.egm.stellio.shared.util.JsonLdUtils.logger import com.egm.stellio.shared.util.JsonUtils.serializeObject -import java.net.URI import java.time.LocalDate import java.time.LocalTime import java.time.ZonedDateTime diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt index b8aea8ba4..6f88e1847 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/EntityAccessRightsServiceTests.kt @@ -11,9 +11,9 @@ import com.egm.stellio.shared.model.PaginationQuery import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.AuthContextModel.AUTH_TERM_NAME import com.egm.stellio.shared.util.AuthContextModel.CLIENT_ENTITY_PREFIX +import com.egm.stellio.shared.util.AuthContextModel.DATASET_ID_PREFIX import com.egm.stellio.shared.util.AuthContextModel.GROUP_ENTITY_PREFIX import com.egm.stellio.shared.util.AuthContextModel.SpecificAccessPolicy.AUTH_READ -import com.egm.stellio.shared.util.JsonLdUtils.DATASET_ID_PREFIX import com.ninjasquad.springmockk.SpykBean import io.mockk.Called import io.mockk.coEvery diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityQueryServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityQueryServiceTests.kt index b2cc67694..8afce0713 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityQueryServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/EntityQueryServiceTests.kt @@ -8,7 +8,6 @@ import com.egm.stellio.search.support.WithTimescaleContainer import com.egm.stellio.shared.model.GeoQuery import com.egm.stellio.shared.model.PaginationQuery import com.egm.stellio.shared.util.* -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_PROPERTY import com.ninjasquad.springmockk.MockkBean import io.mockk.coEvery import kotlinx.coroutines.runBlocking diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt index 633414c3b..2267e1191 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityAccessControlHandlerTests.kt @@ -27,7 +27,6 @@ import com.egm.stellio.shared.util.AuthContextModel.GROUP_TYPE import com.egm.stellio.shared.util.AuthContextModel.SpecificAccessPolicy.AUTH_READ import com.egm.stellio.shared.util.AuthContextModel.USER_COMPACT_TYPE import com.egm.stellio.shared.util.AuthContextModel.USER_TYPE -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue import com.ninjasquad.springmockk.MockkBean import io.mockk.Called diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/AuthUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/AuthUtils.kt index 5bf2863c0..d239385aa 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/AuthUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/AuthUtils.kt @@ -39,10 +39,13 @@ object AuthContextModel { const val CLIENT_ENTITY_PREFIX = "urn:ngsi-ld:Client:" const val GROUP_ENTITY_PREFIX = "urn:ngsi-ld:Group:" + const val DATASET_ID_PREFIX = "urn:ngsi-ld:Dataset:" + const val AUTH_TERM_SUB = "sub" const val AUTH_PROP_SUB = AUTHORIZATION_ONTOLOGY + AUTH_TERM_SUB const val AUTH_TERM_CLIENT_ID = "clientId" const val AUTH_TERM_NAME = "name" + const val AUTH_PROP_NAME = "https://schema.org/$AUTH_TERM_NAME" const val AUTH_TERM_SID = "serviceAccountId" const val AUTH_TERM_SUBJECT_INFO = "subjectInfo" const val AUTH_PROP_SUBJECT_INFO = AUTHORIZATION_ONTOLOGY + AUTH_TERM_SUBJECT_INFO diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt index 139a5ff22..787ee81c5 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt @@ -94,11 +94,6 @@ object JsonLdUtils { const val NGSILD_DATE_TYPE = "https://uri.etsi.org/ngsi-ld/Date" const val NGSILD_TIME_TYPE = "https://uri.etsi.org/ngsi-ld/Time" - const val NGSILD_NAME_TERM = "name" - const val NGSILD_NAME_PROPERTY = "https://schema.org/name" - - const val DATASET_ID_PREFIX = "urn:ngsi-ld:Dataset:" - val logger: Logger = LoggerFactory.getLogger(javaClass) private const val CONTEXT_CACHE_CAPACITY = 128 diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt index 60803966e..1c70d3cc8 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedEntityTests.kt @@ -4,7 +4,6 @@ import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_ID import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_TERM -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_PROPERTY import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat diff --git a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/JsonLdContextUtils.kt b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/JsonLdContextUtils.kt index 4e81b3c63..506cb2e57 100644 --- a/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/JsonLdContextUtils.kt +++ b/shared/src/testFixtures/kotlin/com/egm/stellio/shared/util/JsonLdContextUtils.kt @@ -36,3 +36,6 @@ const val TEMPERATURE_PROPERTY = "https://ontology.eglobalmark.com/apic#$TEMPERA const val MANAGED_BY_COMPACT_RELATIONSHIP = "managedBy" const val MANAGED_BY_RELATIONSHIP = "https://ontology.eglobalmark.com/egm#$MANAGED_BY_COMPACT_RELATIONSHIP" + +const val NGSILD_NAME_TERM = "name" +const val NGSILD_NAME_PROPERTY = "https://schema.org/name" diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/listener/EntityEventListenerServiceTests.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/listener/EntityEventListenerServiceTests.kt index 65b59272e..419310939 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/listener/EntityEventListenerServiceTests.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/listener/EntityEventListenerServiceTests.kt @@ -1,7 +1,7 @@ package com.egm.stellio.subscription.listener import arrow.core.right -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_PROPERTY +import com.egm.stellio.shared.util.NGSILD_NAME_PROPERTY import com.egm.stellio.shared.util.loadSampleData import com.egm.stellio.subscription.model.Notification import com.egm.stellio.subscription.model.NotificationTrigger diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt index 4ecaeb3f5..883469364 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/service/NotificationServiceTests.kt @@ -5,8 +5,6 @@ import com.egm.stellio.shared.util.* import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_COMPACTED_ENTITY_CORE_MEMBERS import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LOCATION_TERM -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_PROPERTY -import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NAME_TERM import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap import com.egm.stellio.shared.web.NGSILD_TENANT_HEADER import com.egm.stellio.subscription.model.Endpoint From 5f6dc341e5ab67aca167d78e52cee701a41de41c Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Wed, 3 Jan 2024 15:37:05 +0100 Subject: [PATCH 16/19] refactor: rename extractRelationshipObject et getRelationshipObject --- .../com/egm/stellio/shared/model/ExpandedMembers.kt | 2 +- .../com/egm/stellio/shared/model/NgsiLdEntity.kt | 2 +- .../egm/stellio/shared/model/ExpandedMembersTests.kt | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt index 24c92bd3c..b4ed57866 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/ExpandedMembers.kt @@ -171,7 +171,7 @@ fun ExpandedAttributeInstance.getMemberValueAsDateTime(memberName: ExpandedTerm) fun ExpandedAttributeInstance.getMemberValueAsString(memberName: ExpandedTerm): String? = String::class.safeCast(this.getMemberValue(memberName)) -fun ExpandedAttributeInstance.extractRelationshipObject(name: String): Either = +fun ExpandedAttributeInstance.getRelationshipObject(name: String): Either = this.right() .flatMap { if (!it.containsKey(NGSILD_RELATIONSHIP_OBJECT)) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt index 0012a24ad..05543e2ec 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt @@ -223,7 +223,7 @@ class NgsiLdRelationshipInstance private constructor( name: String, values: ExpandedAttributeInstance ): Either = either { - val objectId = values.extractRelationshipObject(name).bind() + val objectId = values.getRelationshipObject(name).bind() val createdAt = values.getMemberValueAsDateTime(NGSILD_CREATED_AT_PROPERTY) val modifiedAt = values.getMemberValueAsDateTime(NGSILD_MODIFIED_AT_PROPERTY) val observedAt = values.getMemberValueAsDateTime(NGSILD_OBSERVED_AT_PROPERTY) diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt index 8d784a2ef..14ebcf37a 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/model/ExpandedMembersTests.kt @@ -116,7 +116,7 @@ class ExpandedMembersTests { fun `it should return an error if a relationship has no object field`() { val relationshipValues = buildExpandedPropertyValue("something")[0] - val result = relationshipValues.extractRelationshipObject("isARelationship") + val result = relationshipValues.getRelationshipObject("isARelationship") assertTrue(result.isLeft()) result.mapLeft { assertEquals("Relationship isARelationship does not have an object field", it.message) @@ -129,7 +129,7 @@ class ExpandedMembersTests { NGSILD_RELATIONSHIP_OBJECT to emptyList() ) - val result = relationshipValues.extractRelationshipObject("isARelationship") + val result = relationshipValues.getRelationshipObject("isARelationship") assertTrue(result.isLeft()) result.mapLeft { assertEquals("Relationship isARelationship is empty", it.message) @@ -142,7 +142,7 @@ class ExpandedMembersTests { NGSILD_RELATIONSHIP_OBJECT to listOf("invalid") ) - val result = relationshipValues.extractRelationshipObject("isARelationship") + val result = relationshipValues.getRelationshipObject("isARelationship") assertTrue(result.isLeft()) result.mapLeft { assertEquals( @@ -160,7 +160,7 @@ class ExpandedMembersTests { ) ) - relationshipValues.extractRelationshipObject("isARelationship") + relationshipValues.getRelationshipObject("isARelationship") .shouldFail { assertEquals("Relationship isARelationship has an invalid or no object id: null", it.message) } @@ -171,7 +171,7 @@ class ExpandedMembersTests { val relationshipObjectId = "urn:ngsi-ld:T:1" val relationshipValues = buildExpandedRelationshipValue(relationshipObjectId.toUri()) - relationshipValues[0].extractRelationshipObject("isARelationship") + relationshipValues[0].getRelationshipObject("isARelationship") .shouldSucceedWith { assertEquals(relationshipObjectId.toUri(), it) } From 31e57ed02e63e7a0b068a32450fa8c7641a829e7 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Wed, 3 Jan 2024 16:02:34 +0100 Subject: [PATCH 17/19] refactor: extract creation of a simplified or aggregated temporal instance into an utility function --- .../search/scope/TemporalScopeBuilder.kt | 45 ++++++++----------- .../search/util/TemporalEntityBuilder.kt | 44 +++++++----------- shared/config/detekt/baseline.xml | 1 + .../egm/stellio/shared/util/JsonLdUtils.kt | 12 +++++ 4 files changed, 48 insertions(+), 54 deletions(-) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilder.kt b/search-service/src/main/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilder.kt index 828052a70..f4f37d764 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilder.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilder.kt @@ -11,6 +11,7 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUES import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SCOPE_PROPERTY +import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedTemporalValue import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue object TemporalScopeBuilder { @@ -54,19 +55,14 @@ object TemporalScopeBuilder { .filter { aggregateResult -> aggregateResult.aggregate == aggregate } - attributeInstance[NGSILD_PREFIX + aggregate.method] = listOf( - mapOf( - JSONLD_LIST to valuesForAggregate.map { aggregateResult -> - mapOf( - JSONLD_LIST to listOf( - mapOf(JSONLD_VALUE to aggregateResult.value), - mapOf(JSONLD_VALUE to aggregateResult.startDateTime), - mapOf(JSONLD_VALUE to aggregateResult.endDateTime) - ) - ) - } - ) - ) + attributeInstance[NGSILD_PREFIX + aggregate.method] = + buildExpandedTemporalValue(valuesForAggregate) { aggregateResult -> + listOf( + mapOf(JSONLD_VALUE to aggregateResult.value), + mapOf(JSONLD_VALUE to aggregateResult.startDateTime), + mapOf(JSONLD_VALUE to aggregateResult.endDateTime) + ) + } } return mapOf(NGSILD_SCOPE_PROPERTY to attributeInstance.toMap()) @@ -77,21 +73,16 @@ object TemporalScopeBuilder { ): Map { val attributeInstance = mapOf( JSONLD_TYPE to listOf(NGSILD_PROPERTY_TYPE.uri), - NGSILD_PROPERTY_VALUES to listOf( - mapOf( - JSONLD_LIST to scopeHistory.map { scopeInstanceResult -> - scopeInstanceResult as SimplifiedScopeInstanceResult + NGSILD_PROPERTY_VALUES to + buildExpandedTemporalValue(scopeHistory) { scopeInstanceResult -> + scopeInstanceResult as SimplifiedScopeInstanceResult + listOf( mapOf( - JSONLD_LIST to listOf( - mapOf( - JSONLD_LIST to scopeInstanceResult.scopes.map { mapOf(JSONLD_VALUE to it) } - ), - mapOf(JSONLD_VALUE to scopeInstanceResult.time) - ) - ) - } - ) - ) + JSONLD_LIST to scopeInstanceResult.scopes.map { mapOf(JSONLD_VALUE to it) } + ), + mapOf(JSONLD_VALUE to scopeInstanceResult.time) + ) + } ) return mapOf(NGSILD_SCOPE_PROPERTY to attributeInstance) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt index 60aee47bc..f606d6ac6 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/util/TemporalEntityBuilder.kt @@ -5,7 +5,6 @@ import com.egm.stellio.search.scope.TemporalScopeBuilder import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.util.AuthContextModel.AUTH_PROP_SUB -import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_LIST import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE_TERM @@ -16,6 +15,7 @@ import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PREFIX import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_VALUES import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_OBJECTS import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedPropertyValue +import com.egm.stellio.shared.util.JsonLdUtils.buildExpandedTemporalValue import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedPropertyValue import com.egm.stellio.shared.util.JsonLdUtils.buildNonReifiedTemporalValue import com.egm.stellio.shared.util.JsonUtils @@ -127,19 +127,14 @@ object TemporalEntityBuilder { TemporalEntityAttribute.AttributeType.Relationship -> NGSILD_RELATIONSHIP_OBJECTS TemporalEntityAttribute.AttributeType.GeoProperty -> NGSILD_GEOPROPERTY_VALUES } - attributeInstance[valuesKey] = listOf( - mapOf( - JSONLD_LIST to it.value.map { attributeInstanceResult -> - attributeInstanceResult as SimplifiedAttributeInstanceResult - mapOf( - JSONLD_LIST to listOf( - mapOf(JSONLD_VALUE to attributeInstanceResult.value), - mapOf(JSONLD_VALUE to attributeInstanceResult.time) - ) - ) - } - ) - ) + attributeInstance[valuesKey] = + buildExpandedTemporalValue(it.value) { attributeInstanceResult -> + attributeInstanceResult as SimplifiedAttributeInstanceResult + listOf( + mapOf(JSONLD_VALUE to attributeInstanceResult.value), + mapOf(JSONLD_VALUE to attributeInstanceResult.time) + ) + } attributeInstance.toMap() } } @@ -175,19 +170,14 @@ object TemporalEntityBuilder { val resultsForAggregate = aggregatedResultsForTEA.filter { aggregateResult -> aggregateResult.aggregate.method == aggregate.method } - attributeInstance[NGSILD_PREFIX + aggregate.method] = listOf( - mapOf( - JSONLD_LIST to resultsForAggregate.map { aggregateResult -> - mapOf( - JSONLD_LIST to listOf( - mapOf(JSONLD_VALUE to aggregateResult.value), - mapOf(JSONLD_VALUE to aggregateResult.startDateTime), - mapOf(JSONLD_VALUE to aggregateResult.endDateTime) - ) - ) - } - ) - ) + attributeInstance[NGSILD_PREFIX + aggregate.method] = + buildExpandedTemporalValue(resultsForAggregate) { aggregateResult -> + listOf( + mapOf(JSONLD_VALUE to aggregateResult.value), + mapOf(JSONLD_VALUE to aggregateResult.startDateTime), + mapOf(JSONLD_VALUE to aggregateResult.endDateTime) + ) + } } attributeInstance.toMap() diff --git a/shared/config/detekt/baseline.xml b/shared/config/detekt/baseline.xml index 407fa1a07..4f8418074 100644 --- a/shared/config/detekt/baseline.xml +++ b/shared/config/detekt/baseline.xml @@ -13,5 +13,6 @@ LongParameterList:NgsiLdEntity.kt$NgsiLdRelationshipInstance$( val objectId: URI, createdAt: ZonedDateTime?, modifiedAt: ZonedDateTime?, observedAt: ZonedDateTime?, datasetId: URI?, properties: List<NgsiLdProperty>, relationships: List<NgsiLdRelationship> ) SpreadOperator:EntityEvent.kt$EntityEvent$( *[ JsonSubTypes.Type(value = EntityCreateEvent::class), JsonSubTypes.Type(value = EntityReplaceEvent::class), JsonSubTypes.Type(value = EntityDeleteEvent::class), JsonSubTypes.Type(value = AttributeAppendEvent::class), JsonSubTypes.Type(value = AttributeReplaceEvent::class), JsonSubTypes.Type(value = AttributeUpdateEvent::class), JsonSubTypes.Type(value = AttributeDeleteEvent::class), JsonSubTypes.Type(value = AttributeDeleteAllInstancesEvent::class) ] ) SwallowedException:JsonLdUtils.kt$JsonLdUtils$e: JsonLdError + TooManyFunctions:JsonLdUtils.kt$JsonLdUtils diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt index 787ee81c5..5e951b035 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt @@ -471,4 +471,16 @@ object JsonLdUtils { listOf( mapOf(JSONLD_ID to value) ) + + fun buildExpandedTemporalValue( + values: List, + transform: (T) -> List> + ): List>> = + listOf( + mapOf( + JSONLD_LIST to values.map { value -> + mapOf(JSONLD_LIST to transform(value)) + } + ) + ) } From b527e04e799647930498acc7f731f3419259d9bd Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Sat, 6 Jan 2024 09:57:49 +0100 Subject: [PATCH 18/19] chore(subscription): update contexts references --- .../V0_25__update_contexts_references.sql | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 subscription-service/src/main/resources/db/migration/V0_25__update_contexts_references.sql diff --git a/subscription-service/src/main/resources/db/migration/V0_25__update_contexts_references.sql b/subscription-service/src/main/resources/db/migration/V0_25__update_contexts_references.sql new file mode 100644 index 000000000..6488889e0 --- /dev/null +++ b/subscription-service/src/main/resources/db/migration/V0_25__update_contexts_references.sql @@ -0,0 +1,15 @@ +CREATE FUNCTION replace_in_contexts(contexts text[], old_value text, new_value text) + RETURNS text[] + LANGUAGE sql IMMUTABLE PARALLEL SAFE AS +$func$ +SELECT ARRAY ( + SELECT regexp_replace(elem, old_value, new_value, 'g') + FROM unnest(contexts) elem +) +$func$; + +UPDATE subscription +SET contexts = replace_in_contexts(contexts, 'https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.3.jsonld', 'https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld'); + +UPDATE subscription +SET contexts = replace_in_contexts(contexts, 'https://raw.githubusercontent.com/easy-global-market/ngsild-api-data-models/master', 'https://easy-global-market.github.io/ngsild-api-data-models'); From 10879769227056057708ee5ff4282cb26d8d9ab4 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Tue, 9 Jan 2024 10:57:08 +0100 Subject: [PATCH 19/19] fix(temporal): do not restore geo-properties in temporal or aggregated representation --- .../kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt index 5e951b035..c548ba70c 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt @@ -250,7 +250,8 @@ object JsonLdUtils { when (it.value) { is Map<*, *> -> { val geoValues = it.value as MutableMap - if (geoValues.isNotEmpty()) { + // in case of an aggregated or temporalValues query, there is no "value" member + if (geoValues.isNotEmpty() && geoValues.containsKey(JSONLD_VALUE_TERM)) { geoValues[JSONLD_VALUE_TERM] = wktToGeoJson(geoValues[JSONLD_VALUE_TERM] as String) geoValues } else geoValues @@ -259,8 +260,11 @@ object JsonLdUtils { is List<*> -> (it.value as List>).map { geoInstance -> val geoValues = geoInstance.toMutableMap() - geoValues[JSONLD_VALUE_TERM] = wktToGeoJson(geoValues[JSONLD_VALUE_TERM] as String) - geoValues + // in case of an aggregated or temporalValues query, there is no "value" member + if (geoValues.containsKey(JSONLD_VALUE_TERM)) { + geoValues[JSONLD_VALUE_TERM] = wktToGeoJson(geoValues[JSONLD_VALUE_TERM] as String) + geoValues + } else geoValues } else -> it.value }