LmdbInvalidIndexDeletionIT.java
/**
* Copyright (c) 2025 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.rdf4j.http.server;
import static org.assertj.core.api.Assertions.assertThat;
import org.eclipse.rdf4j.http.protocol.Protocol;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Model;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.RepositoryException;
import org.eclipse.rdf4j.repository.config.RepositoryConfig;
import org.eclipse.rdf4j.repository.http.HTTPRepository;
import org.eclipse.rdf4j.repository.manager.RemoteRepositoryManager;
import org.eclipse.rdf4j.repository.sail.config.SailRepositoryConfig;
import org.eclipse.rdf4j.sail.config.AbstractSailImplConfig;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
/**
* Jetty-based integration test that reproduces a user report: Creating an LMDB repository with an invalid triple index
* (e.g., "cposc") then attempting to delete it via HTTP fails.
*
* Expected behavior: either reject creation upfront or allow deletion. This test asserts deletion succeeds; it
* currently fails, exposing the bug.
*/
public class LmdbInvalidIndexDeletionIT {
private static TestServer server;
@BeforeAll
public static void startServer() throws Exception {
server = new TestServer();
try {
server.start();
} catch (Exception e) {
server.stop();
throw e;
}
}
@AfterAll
public static void stopServer() throws Exception {
server.stop();
}
@Test
void deletionSucceedsAfterInvalidLmdbInit() throws Exception {
String id = "badlmdb-server";
// Build a minimal LMDB Sail config without depending on LMDB classes
// by exporting with the LMDB sail type and the tripleIndexes property.
class GenericLmdbConfig extends AbstractSailImplConfig {
private final String tripleIndexes;
GenericLmdbConfig(String type, String tripleIndexes) {
super(type);
this.tripleIndexes = tripleIndexes;
}
@Override
public Resource export(Model m) {
Resource node = super.export(m);
ValueFactory vf = SimpleValueFactory.getInstance();
IRI tripleIdx = vf.createIRI("http://rdf4j.org/config/sail/lmdb#tripleIndexes");
m.add(node, tripleIdx, vf.createLiteral(tripleIndexes));
return node;
}
}
GenericLmdbConfig lmdbConfig = new GenericLmdbConfig("rdf4j:LmdbStore", "cposc");
RepositoryConfig repoConfig = new RepositoryConfig(id, new SailRepositoryConfig(lmdbConfig));
RemoteRepositoryManager manager = RemoteRepositoryManager.getInstance(TestServer.SERVER_URL);
try {
try {
// Create config on server (does not initialize the underlying store yet)
manager.addRepositoryConfig(repoConfig);
} catch (Exception ignored) {
}
// Trigger initialization by opening a connection; expected to fail due to invalid index
Repository httpRepo = new HTTPRepository(
Protocol.getRepositoryLocation(TestServer.SERVER_URL, id));
try (RepositoryConnection conn = httpRepo.getConnection()) {
// attempt a trivial call to ensure init
conn.size();
} catch (RepositoryException expected) {
// initialization fails as LMDB rejects invalid index spec
}
// Now attempt to delete the repository; expected to succeed
boolean removed = manager.removeRepository(id);
assertThat(removed).isTrue();
} finally {
// best-effort cleanup if assertion failed
try {
manager.removeRepository(id);
} catch (Exception ignore) {
} finally {
manager.shutDown();
}
}
}
}