NativeStoreRDFStarRejectionTest.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.sail.nativerdf;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.nio.charset.StandardCharsets;
import org.eclipse.rdf4j.common.transaction.IsolationLevel;
import org.eclipse.rdf4j.common.transaction.IsolationLevels;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.RepositoryResult;
import org.eclipse.rdf4j.repository.sail.SailRepository;
import org.eclipse.rdf4j.rio.RDFFormat;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
/**
* Reproduces a reported issue where attempting to add Turtle-star data to a NativeStore throws, and subsequently the
* repository becomes unusable for normal operations. After the rejection, the repository should remain usable.
*/
public class NativeStoreRDFStarRejectionTest {
@TempDir
public File dataDir;
@Test
public void nativeStoreRejectsTurtleStarButRemainsUsable() {
String data = "@prefix ex: <http://example.org/> .\n" +
"@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n" +
"\n" +
"# Basic triple\n" +
"ex:JohnDoe ex:worksAt ex:CompanyX .\n" +
"\n" +
"# RDF* triple (unsupported by NativeStore)\n" +
"<<ex:JohnDoe ex:worksAt ex:CompanyX>> ex:since \"2022-01-01\"^^xsd:date .\n";
Repository repo = new SailRepository(new NativeStore(dataDir));
// First: attempt to add data that includes RDF*-star. Expect an exception (rejection).
try (RepositoryConnection conn = repo.getConnection()) {
try {
conn.add(new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)), null, RDFFormat.TURTLE);
} catch (Exception expected) {
// Expected: Turtle-star should be rejected by NativeStore
}
}
// Then: repository should still be usable. Getting statements must not throw.
assertDoesNotThrow(() -> {
try (RepositoryConnection conn = repo.getConnection();
RepositoryResult<Statement> result = conn.getStatements(null, null, null)) {
// iterate to fully exercise the result set
while (result.hasNext()) {
result.next();
}
}
}, "Repository became unusable after rejecting Turtle-star input");
}
@Test
public void nativeStoreRejectsTurtleStarButRemainsUsableSnapshot() {
String data = "@prefix ex: <http://example.org/> .\n" +
"@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n" +
"\n" +
"# Basic triple\n" +
"ex:JohnDoe ex:worksAt ex:CompanyX .\n" +
"\n" +
"# RDF* triple (unsupported by NativeStore)\n" +
"<<ex:JohnDoe ex:worksAt ex:CompanyX>> ex:since \"2022-01-01\"^^xsd:date .\n";
Repository repo = new SailRepository(new NativeStore(dataDir));
// First: attempt to add data that includes RDF*-star. Expect an exception (rejection).
try (RepositoryConnection conn = repo.getConnection()) {
try {
conn.begin(IsolationLevels.SNAPSHOT);
conn.add(new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)), null, RDFFormat.TURTLE);
conn.commit();
} catch (Exception expected) {
// Expected: Turtle-star should be rejected by NativeStore
}
}
// Then: repository should still be usable. Getting statements must not throw.
assertDoesNotThrow(() -> {
try (RepositoryConnection conn = repo.getConnection();
RepositoryResult<Statement> result = conn.getStatements(null, null, null)) {
// iterate to fully exercise the result set
while (result.hasNext()) {
result.next();
}
}
}, "Repository became unusable after rejecting Turtle-star input");
}
}