TransactionStartControllerTest.java
/*******************************************************************************
* Copyright (c) 2022 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.repository.transaction;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.fail;
import static org.eclipse.rdf4j.common.transaction.IsolationLevels.READ_COMMITTED;
import static org.eclipse.rdf4j.common.transaction.IsolationLevels.SNAPSHOT;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import java.util.UUID;
import org.eclipse.rdf4j.common.transaction.IsolationLevel;
import org.eclipse.rdf4j.common.transaction.IsolationLevels;
import org.eclipse.rdf4j.http.server.repository.RepositoryInterceptor;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.sail.SailRepository;
import org.eclipse.rdf4j.sail.memory.MemoryStore;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
class TransactionStartControllerTest {
private final static String REPO_ID = "test-repo";
private final TransactionStartController controller = new TransactionStartController();
private MockHttpServletRequest request;
private MockHttpServletResponse response;
@BeforeEach
public void setUp() {
request = new MockHttpServletRequest();
request.setRequestURI("/repositories/" + REPO_ID + "/transactions");
request.setAttribute("repositoryID", REPO_ID);
request.setAttribute("repository", new SailRepository(new MemoryStore()));
request.setMethod(HttpMethod.POST.name());
response = new MockHttpServletResponse();
}
@Test
void createTransactionLocation_default() throws Exception {
// Arrange
controller.setExternalUrl(null);
// Act
final ModelAndView result = controller.handleRequest(request, response);
// Assert
assertThat(getHeaders(result).get("Location"))
.startsWith("http://localhost/repositories/test-repo/transactions/");
}
@Test
void createTransactionLocation_overrideExternalUrl() throws Exception {
// Arrange
controller.setExternalUrl("https://external-url.com/subpath/");
// Act
final ModelAndView result = controller.handleRequest(request, response);
// Assert
assertThat(getHeaders(result).get("Location")).startsWith(
"https://external-url.com/subpath/repositories/test-repo/transactions/");
}
@Test
void createTransactionLocation_overrideExternalUrl_withoutEndingSlash() throws Exception {
// Arrange
controller.setExternalUrl("https://external-url.com/subpath");
// Act
final ModelAndView result = controller.handleRequest(request, response);
// Assert
assertThat(getHeaders(result).get("Location")).startsWith(
"https://external-url.com/subpath/repositories/test-repo/transactions/");
}
private HashMap<String, String> getHeaders(final ModelAndView result) {
if (result == null) {
return fail("Result is null");
}
return (HashMap<String, String>) result.getModel().get("headers");
}
@Test
void positiveIsolationEnumsOldPath() {
for (IsolationLevel level : IsolationLevels.values()) {
request.addParameter("isolation-level", level.toString());
assertThat(controller.getIsolationLevel(request).size() == 1);
}
}
@Test
void negativeIsolationEnumsOldPath() {
request.addParameter("isolation-level", "GARBAGE");
assertThatIllegalArgumentException().isThrownBy(() -> controller.getIsolationLevel(request));
}
@Test
void createTransactionLocation_withPositiveIsolationOldPath() throws Exception {
TransactionStartController controller = spy(TransactionStartController.class);
Transaction tx = mock(Transaction.class);
// Arrange
controller.setExternalUrl(null);
request.addParameter("isolation-level", "SNAPSHOT");
Repository repository = RepositoryInterceptor.getRepository(request);
when(controller.createTransaction(repository)).thenReturn(tx);
when(tx.getID()).thenReturn(UUID.randomUUID());
// Act
controller.handleRequest(request, response);
verify(tx).begin(SNAPSHOT);
}
@Test
void createTransactionLocation_withIsolationOldPath() throws Exception {
TransactionStartController controller = spy(TransactionStartController.class);
Transaction tx = mock(Transaction.class);
// Arrange
controller.setExternalUrl(null);
request.addParameter("isolation-level", "http://www.openrdf.org/schema/sesame#READ_COMMITTED");
Repository repository = RepositoryInterceptor.getRepository(request);
when(controller.createTransaction(repository)).thenReturn(tx);
when(tx.getID()).thenReturn(UUID.randomUUID());
// Act
controller.handleRequest(request, response);
verify(tx).begin(READ_COMMITTED);
}
@Test
void createTransactionLocation_withNegativeIsolationOldPath() throws Exception {
TransactionStartController controller = spy(TransactionStartController.class);
Transaction tx = mock(Transaction.class);
controller.setExternalUrl(null);
request.addParameter("isolation-level", "GARBAGE");
Repository repository = RepositoryInterceptor.getRepository(request);
when(controller.createTransaction(repository)).thenReturn(tx);
when(tx.getID()).thenReturn(UUID.randomUUID());
assertThatIllegalArgumentException().isThrownBy(() -> controller.handleRequest(request, response));
}
}