Java tutorial
/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.trellisldp.http.impl; import static java.nio.charset.StandardCharsets.UTF_8; import static java.time.Instant.ofEpochSecond; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static java.util.Optional.empty; import static java.util.UUID.randomUUID; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.CompletableFuture.runAsync; import static java.util.stream.Collectors.toSet; import static java.util.stream.Stream.concat; import static java.util.stream.Stream.of; import static javax.ws.rs.HttpMethod.DELETE; import static javax.ws.rs.HttpMethod.GET; import static javax.ws.rs.HttpMethod.HEAD; import static javax.ws.rs.HttpMethod.OPTIONS; import static javax.ws.rs.HttpMethod.POST; import static javax.ws.rs.HttpMethod.PUT; import static javax.ws.rs.core.HttpHeaders.ALLOW; import static javax.ws.rs.core.Link.TYPE; import static org.apache.commons.io.IOUtils.readLines; import static org.apache.commons.rdf.api.RDFSyntax.JSONLD; import static org.apache.commons.rdf.api.RDFSyntax.RDFA; import static org.apache.commons.rdf.api.RDFSyntax.TURTLE; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.AdditionalAnswers.returnsFirstArg; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import static org.mockito.MockitoAnnotations.initMocks; import static org.trellisldp.api.Syntax.SPARQL_UPDATE; import static org.trellisldp.api.TrellisUtils.TRELLIS_BNODE_PREFIX; import static org.trellisldp.api.TrellisUtils.TRELLIS_DATA_PREFIX; import static org.trellisldp.api.TrellisUtils.getInstance; import static org.trellisldp.http.core.HttpConstants.PATCH; import static org.trellisldp.http.core.RdfMediaType.TEXT_TURTLE_TYPE; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.security.MessageDigest; import java.time.Instant; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionStage; import java.util.function.Predicate; import java.util.stream.Stream; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Link; import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.Response; import org.apache.commons.rdf.api.BlankNode; import org.apache.commons.rdf.api.Dataset; import org.apache.commons.rdf.api.IRI; import org.apache.commons.rdf.api.Literal; import org.apache.commons.rdf.api.RDF; import org.apache.commons.rdf.api.RDFTerm; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.function.Executable; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.trellisldp.agent.SimpleAgentService; import org.trellisldp.api.AgentService; import org.trellisldp.api.AuditService; import org.trellisldp.api.Binary; import org.trellisldp.api.BinaryMetadata; import org.trellisldp.api.BinaryService; import org.trellisldp.api.EventService; import org.trellisldp.api.IOService; import org.trellisldp.api.MementoService; import org.trellisldp.api.Metadata; import org.trellisldp.api.NoopAuditService; import org.trellisldp.api.NoopMementoService; import org.trellisldp.api.Resource; import org.trellisldp.api.ResourceService; import org.trellisldp.api.RuntimeTrellisException; import org.trellisldp.api.ServiceBundler; import org.trellisldp.http.core.TrellisRequest; import org.trellisldp.vocabulary.LDP; /** * Base class for the HTTP handler tests. */ abstract class BaseTestHandler { protected static final String baseUrl = "http://example.org/"; protected static final RDF rdf = getInstance(); protected static final IRI root = rdf.createIRI(TRELLIS_DATA_PREFIX); protected static final Set<IRI> allInteractionModels = new HashSet<>(asList(LDP.Resource, LDP.RDFSource, LDP.NonRDFSource, LDP.Container, LDP.BasicContainer, LDP.DirectContainer, LDP.IndirectContainer)); protected static final IRI identifier = rdf.createIRI(TRELLIS_DATA_PREFIX + "resource"); protected static final Instant time = ofEpochSecond(1496262729); protected final AgentService agentService = new SimpleAgentService(); protected final AuditService auditService = new NoopAuditService(); protected final MementoService mementoService = new NoopMementoService(); @Mock protected ServiceBundler mockBundler; @Mock protected ResourceService mockResourceService; @Mock protected EventService mockEventService; @Mock protected IOService mockIoService; @Mock protected BinaryService mockBinaryService; @Mock protected Binary mockBinary; @Mock protected MessageDigest mockDigest; @Mock protected Resource mockResource, mockParent; @Mock protected TrellisRequest mockTrellisRequest; @Captor protected ArgumentCaptor<IRI> iriArgument; @Captor protected ArgumentCaptor<BinaryMetadata> metadataArgument; @BeforeEach public void setUp() throws Exception { initMocks(this); setUpBundler(); setUpResourceService(); setUpBinaryService(); setUpIoService(); setUpResources(); when(mockTrellisRequest.getPath()).thenReturn(""); when(mockTrellisRequest.getBaseUrl()).thenReturn(baseUrl); when(mockTrellisRequest.getAcceptableMediaTypes()).thenReturn(singletonList(TEXT_TURTLE_TYPE)); when(mockTrellisRequest.getHeaders()).thenReturn(new MultivaluedHashMap<>()); } protected Stream<Executable> checkAllowHeader(final Response res, final List<String> methods) { final String allow = res.getHeaderString(ALLOW); return concat(of(() -> assertNotNull(allow, "Missing Allow header!")), of(GET, HEAD, OPTIONS, PUT, DELETE, POST, PATCH).map(m -> checkAllowHeader(methods, allow, m))); } private static Executable checkAllowHeader(final List<String> expected, final String actual, final String method) { final boolean expectation = expected.contains(method); return () -> assertEquals(expectation, actual.contains(method), "Expecting method " + method + " to be " + (expectation ? "present" : "absent")); } protected Stream<Executable> checkLdpType(final Response res, final IRI type) { final Set<String> types = HttpUtils.ldpResourceTypes(type).map(IRI::getIRIString).collect(toSet()); final Set<String> responseTypes = res.getLinks().stream().filter(link -> TYPE.equals(link.getRel())) .map(link -> link.getUri().toString()).collect(toSet()); return of(LDP.Resource, LDP.RDFSource, LDP.NonRDFSource, LDP.Container, LDP.BasicContainer, LDP.DirectContainer, LDP.IndirectContainer).map(t -> checkLdpType(types, responseTypes, t)); } private static Executable checkLdpType(final Set<String> expected, final Set<String> actual, final IRI type) { final boolean expectation = expected.contains(type); return () -> assertEquals(expectation, actual.contains(type), "Expecting " + type + " to be " + (expectation ? "present" : "absent")); } protected void unwrapAsyncError(final CompletionStage async) { try { async.toCompletableFuture().join(); } catch (final CompletionException ex) { if (ex.getCause() instanceof WebApplicationException) { throw (WebApplicationException) ex.getCause(); } throw ex; } } protected static Predicate<Link> hasLink(final IRI iri, final String rel) { return link -> rel.equals(link.getRel()) && iri.getIRIString().equals(link.getUri().toString()); } protected static Predicate<Link> hasType(final IRI iri) { return hasLink(iri, TYPE); } protected static CompletionStage<Void> asyncException() { return runAsync(() -> { throw new RuntimeTrellisException("Expected exception"); }); } private void setUpResourceService() { when(mockResourceService.supportedInteractionModels()).thenReturn(allInteractionModels); when(mockResourceService.get(any(IRI.class))).thenAnswer(inv -> completedFuture(mockResource)); when(mockResourceService.create(any(Metadata.class), any(Dataset.class))).thenReturn(completedFuture(null)); when(mockResourceService.replace(any(Metadata.class), any(Dataset.class))) .thenReturn(completedFuture(null)); when(mockResourceService.delete(any(Metadata.class))).thenReturn(completedFuture(null)); when(mockResourceService.add(any(IRI.class), any(Dataset.class))).thenReturn(completedFuture(null)); when(mockResourceService.skolemize(any(Literal.class))).then(returnsFirstArg()); when(mockResourceService.skolemize(any(IRI.class))).then(returnsFirstArg()); when(mockResourceService.skolemize(any(BlankNode.class))).thenAnswer( inv -> rdf.createIRI(TRELLIS_BNODE_PREFIX + ((BlankNode) inv.getArgument(0)).uniqueReference())); when(mockResourceService.toInternal(any(RDFTerm.class), any())).thenCallRealMethod(); when(mockResourceService.toExternal(any(RDFTerm.class), any())).thenCallRealMethod(); when(mockResourceService.touch(any(IRI.class))).thenReturn(completedFuture(null)); } private void setUpBinaryService() throws Exception { when(mockBinary.getContent(eq(3), eq(10))).thenReturn(new ByteArrayInputStream("e input".getBytes(UTF_8))); when(mockBinary.getContent()).thenReturn(new ByteArrayInputStream("Some input stream".getBytes(UTF_8))); when(mockBinaryService.generateIdentifier()).thenReturn("file:///" + randomUUID()); when(mockBinaryService.supportedAlgorithms()).thenReturn(new HashSet<>(asList("MD5", "SHA-1"))); when(mockDigest.digest()).thenReturn("computed-digest".getBytes(UTF_8)); when(mockBinaryService.calculateDigest(any(IRI.class), any(MessageDigest.class))) .thenReturn(completedFuture(mockDigest)); when(mockBinaryService.get(any(IRI.class))).thenAnswer(inv -> completedFuture(mockBinary)); when(mockBinaryService.purgeContent(any(IRI.class))).thenReturn(completedFuture(null)); when(mockBinaryService.setContent(any(BinaryMetadata.class), any(InputStream.class), any())) .thenAnswer(inv -> { readLines((InputStream) inv.getArguments()[1], UTF_8); return completedFuture(null); }); when(mockBinaryService.setContent(any(BinaryMetadata.class), any(InputStream.class))).thenAnswer(inv -> { readLines((InputStream) inv.getArguments()[1], UTF_8); return completedFuture(null); }); doCallRealMethod().when(mockBinaryService).setContent(any(BinaryMetadata.class), any(InputStream.class), any()); } private void setUpBundler() { when(mockBundler.getResourceService()).thenReturn(mockResourceService); when(mockBundler.getBinaryService()).thenReturn(mockBinaryService); when(mockBundler.getIOService()).thenReturn(mockIoService); when(mockBundler.getAuditService()).thenReturn(auditService); when(mockBundler.getMementoService()).thenReturn(mementoService); when(mockBundler.getAgentService()).thenReturn(agentService); when(mockBundler.getEventService()).thenReturn(mockEventService); } private void setUpIoService() { when(mockIoService.supportedReadSyntaxes()).thenReturn(asList(TURTLE, JSONLD, RDFA)); when(mockIoService.supportedWriteSyntaxes()).thenReturn(asList(TURTLE, JSONLD)); when(mockIoService.supportedUpdateSyntaxes()).thenReturn(asList(SPARQL_UPDATE)); } private void setUpResources() { when(mockResource.getInteractionModel()).thenReturn(LDP.RDFSource); when(mockResource.getContainer()).thenReturn(Optional.of(root)); when(mockResource.getIdentifier()).thenReturn(identifier); when(mockResource.getBinaryMetadata()).thenReturn(empty()); when(mockResource.getModified()).thenReturn(time); when(mockResource.getExtraLinkRelations()).thenAnswer(inv -> Stream.empty()); when(mockParent.getInteractionModel()).thenReturn(LDP.Container); when(mockParent.getIdentifier()).thenReturn(root); when(mockParent.getMembershipResource()).thenReturn(empty()); } }