Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/main/java/io/neonbee/endpoint/odatav4/ODataV4Endpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,16 @@ protected Future<Void> refreshRouter(Vertx vertx, Router router, String basePath
models.values().stream()
.filter(this::filterModels)
.flatMap(entityModel -> entityModel.getAllEdmxMetadata().entrySet().stream())
.filter(entry -> {
if (entry.getValue().getEdm().getEntityContainer() == null) {
if (LOGGER.isErrorEnabled()) {
LOGGER.error("Skipping OData service endpoint for {} — EntityContainer is null",
entry.getKey());
}
return false;
}
return true;
})
.map(entryFunction(
(schemaNamespace, edmxModel) -> Map.entry(uriConversion.apply(schemaNamespace), edmxModel)))
.sorted(Map.Entry.comparingByKey(Comparator.comparingInt(String::length).reversed()))
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/io/neonbee/entity/EntityModelLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,12 @@ Future<Void> parseModel(String csnFile, byte[] csnPayload, Map<String, byte[]> a
return Future.all(EntityModelDefinition.resolveEdmxPaths(Path.of(csnFile), cdsModel).stream()
.map(Path::toString).map(path -> {
// we do not know if the path uses windows / unix path separators, try both!
return FileSystemHelper.getPathFromMap(associatedModels, path);
byte[] payload = FileSystemHelper.getPathFromMap(associatedModels, path);
if (payload == null && LOGGER.isWarnEnabled()) {
LOGGER.warn("Associated model {} not found in associatedModels map (keys={})", path,
associatedModels.keySet());
}
return payload;
}).map(this::parseEdmxModel).toList()).onComplete(result -> {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Parsing associated models of {} {}", csnFile,
Expand Down Expand Up @@ -244,6 +249,7 @@ private void buildModelMap(CdsModel cdsModel, List<ServiceMetadata> edmxModels)
}

Map<String, ServiceMetadata> edmxMap = edmxModels.stream()
.filter(java.util.Objects::nonNull)
.collect(Collectors.toMap(EntityModelLoader::getSchemaNamespace, Function.identity()));
if (models.put(namespace, EntityModel.of(cdsModel, edmxMap)) != null) {
LOGGER.warn("Model with schema namespace {} replaced an existing model in the model map", namespace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ class ODataV4EndpointTest extends ODataEndpointTestBase {
@Override
protected List<Path> provideEntityModels() {
return List.of(TEST_RESOURCES.resolveRelated("TestService1.csn"),
TEST_RESOURCES.resolveRelated("TestService2.csn"), TEST_RESOURCES.resolveRelated("TestService3.csn"));
TEST_RESOURCES.resolveRelated("TestService2.csn"), TEST_RESOURCES.resolveRelated("TestService3.csn"),
TEST_RESOURCES.resolveRelated("EmptyContainerService.csn"));
}

@Override
Expand Down Expand Up @@ -101,6 +102,23 @@ void testODataEndpointLazyLoading(VertxTestContext testContext) {
.onComplete(testContext.succeedingThenComplete());
}

@Test
@DisplayName("service with empty EntityContainer is skipped, other services still registered")
void testEmptyEntityContainerServiceIsSkipped(VertxTestContext testContext) {
requestMetadata("io.neonbee.handler.empty.EmptyContainerService")
.compose(emptyResp -> {
testContext.verify(() -> assertThat(emptyResp.statusCode()).isEqualTo(HTTP_NOT_FOUND));
return requestMetadata("io.neonbee.handler.TestService");
})
.onComplete(testContext.succeeding(validResp -> {
testContext.verify(() -> {
assertThat(validResp.statusCode()).isEqualTo(200);
assertThat(validResp.body().toString()).contains("<edmx:Edmx");
});
testContext.completeNow();
}));
}

@Test
void testUriConversionRules() {
// strict should not convert anything!
Expand Down
17 changes: 10 additions & 7 deletions src/test/java/io/neonbee/entity/EntityModelLoaderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;

import com.sap.cds.reflect.CdsModel;
import com.sap.cds.reflect.CdsEntity;
import com.sap.cds.reflect.CdsService;

import io.neonbee.NeonBeeOptions;
import io.neonbee.test.base.NeonBeeTestBase;
Expand Down Expand Up @@ -120,12 +121,14 @@ void loadFromModuleTest(Vertx vertx, VertxTestContext testContext) throws IOExce
@DisplayName("check if getting CSN Model works")
void getCSNModelTest(Vertx vertx, VertxTestContext testContext) {
EntityModelLoader loader = new EntityModelLoader(vertx);
Future<CdsModel> csnModelFuture = loader.readCsnModel(TEST_SERVICE_1_MODEL_PATH);
csnModelFuture.compose(v -> loader.loadModel(TEST_SERVICE_1_MODEL_PATH))
.onComplete(testContext.succeeding(result -> testContext.verify(() -> {
CdsModel expectedCsnModel = csnModelFuture.result();
EntityModel model = loader.models.get("io.neonbee.test1");
assertThat(model.getCsnModel()).isEqualTo(expectedCsnModel);
loader.loadModel(TEST_SERVICE_1_MODEL_PATH)
.onComplete(testContext.succeeding(v -> testContext.verify(() -> {
var csnModel = loader.models.get("io.neonbee.test1").getCsnModel();
assertThat(csnModel.services().map(CdsService::getQualifiedName).toList())
.containsExactly("io.neonbee.test1.TestService1");
assertThat(csnModel.entities().map(CdsEntity::getQualifiedName).toList())
.containsExactly("io.neonbee.test1.TestService1.AllPropertiesNullable",
"io.neonbee.test.TestService1.TestProducts");
testContext.completeNow();
})));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"namespace": "io.neonbee.handler.empty",
"definitions": {
"io.neonbee.handler.empty.EmptyContainerService": {
"kind": "service"
}
},
"meta": {
"creator": "CDS Compiler v1.26.2"
},
"$version": "1.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:DataServices>
<Schema Namespace="io.neonbee.handler.empty.EmptyContainerService" xmlns="http://docs.oasis-open.org/odata/ns/edm"/>
</edmx:DataServices>
</edmx:Edmx>