private CompletionStage<Void> createOrReplace(final Metadata metadata, final TrellisDataset ds) { if (isNull(getResource())) { LOGGER.debug("Creating new resource {}", internalId); return getServices().getResourceService().create(metadata, ds.asDataset()); } else { LOGGER.debug("Replacing old resource {}", internalId); return getServices().getResourceService().replace(metadata, ds.asDataset()); } }
private Stream<Executable> verifyInteractions(final ResourceService svc) { return of( () -> verify(svc, never().description("Don't re-initialize the root if it already exists")) .create(any(Metadata.class), any(Dataset.class)), () -> verify(svc, never().description("Don't re-initialize the root if it already exists")) .replace(any(Metadata.class), any(Dataset.class)), () -> verify(svc, description("Verify that the root resource is fetched only once")).get(root)); } }
@Test public void testInitializeoDeletedLdpResource() throws Exception { final ResourceService mockService = mock(ResourceService.class); when(mockBundler.getResourceService()).thenReturn(mockService); when(mockService.get(eq(root))).thenAnswer(inv -> completedFuture(DELETED_RESOURCE)); when(mockService.create(any(Metadata.class), any(Dataset.class))).thenReturn(completedFuture(null)); final TrellisHttpResource matcher = new TrellisHttpResource(mockBundler); matcher.initialize(); verify(mockService, description("A previously deleted root resource should be re-created upon initialization")) .create(any(Metadata.class), any(Dataset.class)); verify(mockService, never().description("replace shouldn't be called when re-initializing a deleted root")) .replace(any(Metadata.class), any(Dataset.class)); verify(mockService, description("Verify that the root resource is fetched only once")).get(root); }
@BeforeEach public void setUp() { initMocks(this); doCallRealMethod().when(mockResourceService).skolemize(any()); doCallRealMethod().when(mockResourceService).unskolemize(any()); doCallRealMethod().when(mockResourceService).toInternal(any(), any()); doCallRealMethod().when(mockResourceService).toExternal(any(), any()); doCallRealMethod().when(mockResourceService).create(any(), any()); when(mockRetrievalService.get(eq(existing))).thenAnswer(inv -> completedFuture(mockResource)); }
@Test public void testInitializeoNoLdpResource() throws Exception { final ResourceService mockService = mock(ResourceService.class); when(mockBundler.getResourceService()).thenReturn(mockService); when(mockService.get(eq(root))).thenAnswer(inv -> completedFuture(MISSING_RESOURCE)); when(mockService.create(any(Metadata.class), any(Dataset.class))).thenReturn(completedFuture(null)); final TrellisHttpResource matcher = new TrellisHttpResource(mockBundler); matcher.initialize(); verify(mockService, description("Re-create a missing root resource on initialization")) .create(any(Metadata.class), any(Dataset.class)); verify(mockService, never().description("Don't try to replace a non-existent root on initialization")) .replace(any(Metadata.class), any(Dataset.class)); verify(mockService, description("Verify that the root resource is fetched only once")).get(root); }
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 Stream<Executable> checkBinaryEntityResponse() { return Stream.of( () -> verify(mockResourceService, description("ResourceService::create not called!")) .create(any(Metadata.class), any(Dataset.class)), () -> verify(mockIoService, never().description("entity shouldn't be read!")).read(any(), any(), any()), () -> verify(mockBinaryService, description("content not set on binary service!")) .setContent(metadataArgument.capture(), any(InputStream.class)), () -> assertEquals(of("text/plain"), metadataArgument.getValue().getMimeType(), "Invalid content-type"), () -> assertTrue(metadataArgument.getValue().getIdentifier().getIRIString().startsWith("file:///"), "Invalid binary ID!")); } }
@Test public void testInitializeExistingLdpResourceWithNoACL() throws Exception { final ResourceService mockService = mock(ResourceService.class); when(mockBundler.getResourceService()).thenReturn(mockService); when(mockService.get(eq(root))).thenAnswer(inv -> completedFuture(mockRootResource)); when(mockRootResource.hasAcl()).thenReturn(false); when(mockService.replace(any(Metadata.class), any(Dataset.class))).thenReturn(completedFuture(null)); final TrellisHttpResource matcher = new TrellisHttpResource(mockBundler); matcher.initialize(); verify(mockService, never().description("When re-initializing the root ACL, create should not be called")) .create(any(Metadata.class), any(Dataset.class)); verify(mockService, description("Use replace when re-initializing the root ACL")) .replace(any(Metadata.class), any(Dataset.class)); verify(mockService, description("Verify that the root resource is fetched only once")).get(root); }
private CompletionStage<Void> initialize(final IRI id, final Resource res, final TrellisDataset dataset) { if (MISSING_RESOURCE.equals(res) || DELETED_RESOURCE.equals(res)) { LOGGER.info("Initializing root container: {}", id); return trellis.getResourceService().create(Metadata.builder(id).interactionModel(LDP.BasicContainer) .build(), dataset.asDataset()); } else if (!res.hasAcl()) { LOGGER.info("Initializeing root ACL: {}", id); try (final Stream<Triple> triples = res.stream(Trellis.PreferUserManaged)) { triples.map(toQuad(Trellis.PreferUserManaged)).forEach(dataset::add); } return trellis.getResourceService().replace(Metadata.builder(res).build(), dataset.asDataset()); } return completedFuture(null); }
@Test public void testDefaultCreate() { final IRI root = rdf.createIRI("trellis:data/"); final Dataset dataset = rdf.createDataset(); final Metadata metadata = Metadata.builder(existing).container(root).interactionModel(LDP.RDFSource).build(); when(mockResourceService.replace(eq(metadata), eq(dataset))).thenReturn(completedFuture(null)); assertDoesNotThrow(() -> mockResourceService.create(metadata, dataset).toCompletableFuture().join()); verify(mockResourceService).replace(eq(metadata), eq(dataset)); }
@Test public void testRdfEntity() throws IOException { final String path = "newresource"; final Triple triple = rdf.createTriple(rdf.createIRI(baseUrl + path), DC.title, rdf.createLiteral("A title")); when(mockIoService.supportedWriteSyntaxes()).thenReturn(asList(TURTLE, JSONLD, NTRIPLES)); when(mockIoService.read(any(), eq(TURTLE), any())).thenAnswer(x -> Stream.of(triple)); when(mockTrellisRequest.getContentType()).thenReturn("text/turtle"); final PostHandler handler = buildPostHandler("/simpleTriple.ttl", "newresource", null); final Response res = handler.createResource(handler.initialize(mockParent, MISSING_RESOURCE)) .toCompletableFuture().join().build(); assertEquals(CREATED, res.getStatusInfo(), "Incorrect response code!"); assertEquals(create(baseUrl + path), res.getLocation(), "Incorrect Location header!"); assertAll("Check LDP type Link headers", checkLdpType(res, LDP.RDFSource)); verify(mockBinaryService, never()).setContent(any(BinaryMetadata.class), any(InputStream.class), any()); verify(mockIoService).read(any(InputStream.class), eq(TURTLE), eq(baseUrl + path)); verify(mockResourceService).create(any(Metadata.class), any(Dataset.class)); }
/** * Test creating a resource. * @throws Exception if the operation failed */ @Test @DisplayName("Test creating resource") default void testCreateResource() throws Exception { final RDF rdf = getInstance(); final IRI identifier = rdf.createIRI(TRELLIS_DATA_PREFIX + getResourceService().generateIdentifier()); final Dataset dataset = buildDataset(identifier, "Creation Test", SUBJECT1); assertEquals(MISSING_RESOURCE, getResourceService().get(identifier).toCompletableFuture().join(), "Check for no pre-existing LDP-RS"); assertDoesNotThrow(() -> getResourceService().create(Metadata.builder(identifier) .interactionModel(LDP.RDFSource).container(ROOT_CONTAINER).build(), dataset) .toCompletableFuture().join(), "Check that the resource was successfully created"); final Resource res = getResourceService().get(identifier).toCompletableFuture().join(); assertAll("Check resource stream", res.stream(Trellis.PreferUserManaged).map(toQuad(Trellis.PreferUserManaged)) .map(q -> () -> assertTrue(dataset.contains(q), "Verify that the quad is from the dataset: " + q))); }
/** * Test an LDP:RDFSource. * @throws Exception if the create operation fails */ @Test @DisplayName("Test LDP-RS") default void testLdpRs() throws Exception { final Instant time = now(); final RDF rdf = getInstance(); final IRI identifier = rdf.createIRI(TRELLIS_DATA_PREFIX + getResourceService().generateIdentifier()); final Dataset dataset = buildDataset(identifier, "Create LDP-RS Test", SUBJECT1); assertEquals(MISSING_RESOURCE, getResourceService().get(identifier).toCompletableFuture().join(), "Check for no pre-existing LDP-RS"); assertDoesNotThrow(() -> getResourceService().create(Metadata.builder(identifier) .interactionModel(LDP.RDFSource).container(ROOT_CONTAINER).build(), dataset) .toCompletableFuture().join(), "Check the creation of an LDP-RS"); final Resource res = getResourceService().get(identifier).toCompletableFuture().join(); assertAll("Check the LDP-RS resource", checkResource(res, identifier, LDP.RDFSource, time, dataset)); assertEquals(3L, res.stream(Trellis.PreferUserManaged).count(), "Check the user triple count"); }
@Test public void testError() throws IOException { when(mockResourceService.create(any(Metadata.class), any(Dataset.class))).thenReturn(asyncException()); when(mockTrellisRequest.getContentType()).thenReturn("text/turtle"); final PostHandler handler = buildPostHandler("/emptyData.txt", "newresource", baseUrl); assertThrows(CompletionException.class, () -> unwrapAsyncError(handler.createResource(handler.initialize(mockParent, MISSING_RESOURCE))), "No exception thrown when the backend errors!"); }
/** * Test an LDP:RDFSource. * @throws Exception if the create operation fails */ @Test @DisplayName("Test LDP-RS") default void testLdpRs() throws Exception { final Instant time = now(); final RDF rdf = getInstance(); final IRI identifier = rdf.createIRI(TRELLIS_DATA_PREFIX + getResourceService().generateIdentifier()); final Dataset dataset = buildDataset(identifier, "Create LDP-RS Test", SUBJECT1); assertEquals(MISSING_RESOURCE, getResourceService().get(identifier).toCompletableFuture().join(), "Check for no pre-existing LDP-RS"); assertDoesNotThrow(() -> getResourceService().create(Metadata.builder(identifier) .interactionModel(LDP.RDFSource).container(ROOT_CONTAINER).build(), dataset) .toCompletableFuture().join(), "Check the creation of an LDP-RS"); final Resource res = getResourceService().get(identifier).toCompletableFuture().join(); assertAll("Check the LDP-RS resource", checkResource(res, identifier, LDP.RDFSource, time, dataset)); assertEquals(3L, res.stream(Trellis.PreferUserManaged).count(), "Check the user triple count"); }
/** * Test creating a resource. * @throws Exception if the operation failed */ @Test @DisplayName("Test creating resource") default void testCreateResource() throws Exception { final RDF rdf = getInstance(); final IRI identifier = rdf.createIRI(TRELLIS_DATA_PREFIX + getResourceService().generateIdentifier()); final Dataset dataset = buildDataset(identifier, "Creation Test", SUBJECT1); assertEquals(MISSING_RESOURCE, getResourceService().get(identifier).toCompletableFuture().join(), "Check for no pre-existing LDP-RS"); assertDoesNotThrow(() -> getResourceService().create(Metadata.builder(identifier) .interactionModel(LDP.RDFSource).container(ROOT_CONTAINER).build(), dataset) .toCompletableFuture().join(), "Check that the resource was successfully created"); final Resource res = getResourceService().get(identifier).toCompletableFuture().join(); assertAll("Check resource stream", res.stream(Trellis.PreferUserManaged).map(toQuad(Trellis.PreferUserManaged)) .map(q -> () -> assertTrue(dataset.contains(q), "Verify that the quad is from the dataset: " + q))); }
/** * Test deleting a resource. * @throws Exception if the operation failed */ @Test @DisplayName("Test deleting resource") default void testDeleteResource() throws Exception { final RDF rdf = getInstance(); final IRI identifier = rdf.createIRI(TRELLIS_DATA_PREFIX + getResourceService().generateIdentifier()); final Dataset dataset = buildDataset(identifier, "Deletion Test", SUBJECT1); assertEquals(MISSING_RESOURCE, getResourceService().get(identifier).toCompletableFuture().join(), "Check that the resource doesn't exist"); assertDoesNotThrow(() -> getResourceService().create(Metadata.builder(identifier) .interactionModel(LDP.RDFSource).container(ROOT_CONTAINER).build(), dataset) .toCompletableFuture().join(), "Check that the resource was successfully created"); assertNotEquals(DELETED_RESOURCE, getResourceService().get(identifier).toCompletableFuture().join(), "Check that the resource isn't currently 'deleted'"); assertDoesNotThrow(() -> getResourceService().delete(Metadata.builder(identifier) .interactionModel(LDP.RDFSource).container(ROOT_CONTAINER).build()).toCompletableFuture().join(), "Check that the delete operation succeeded"); final Resource resource = getResourceService().get(identifier).toCompletableFuture().join(); assertTrue(DELETED_RESOURCE.equals(resource) || MISSING_RESOURCE.equals(resource), "Verify that the resource is marked as deleted or missing"); }
@Test public void testBadPersist() { final Quad testQuad = createQuad(badId, testResourceId1, testResourceId1, badId); final Resource testResource = new TestResource(badId, testQuad); assertThrows(CompletionException.class, () -> testable.create(Metadata.builder(testResource).build(), testResource.dataset()).toCompletableFuture() .join(), "Could create a resource when underlying services should reject it!"); }
@Test public void testRoundtripping() { final Quad testQuad = createQuad(testResourceId1, testResourceId1, testResourceId1, badId); final Resource testResource = new TestResource(testResourceId1, testQuad); assertNull(testable.create(Metadata.builder(testResourceId1).interactionModel(LDP.RDFSource).build(), testResource.dataset()).toCompletableFuture().join(), "Couldn't create a resource!"); Resource retrieved = testable.get(testResourceId1).toCompletableFuture().join(); assertEquals(testResource.getIdentifier(), retrieved.getIdentifier(), "Resource was retrieved with wrong ID!"); assertEquals(testResource.stream().findFirst().get(), retrieved.stream().findFirst().get(), "Resource was retrieved with wrong data!"); final Quad testQuad2 = createQuad(testResourceId1, badId, testResourceId1, badId); final Resource testResource2 = new TestResource(testResourceId1, testQuad2); assertNull(testable.replace(Metadata.builder(testResource2).interactionModel(LDP.RDFSource).build(), testResource2.dataset()).toCompletableFuture().join(), "Couldn't replace resource!"); retrieved = testable.get(testResourceId1).toCompletableFuture().join(); assertEquals(testResource2.getIdentifier(), retrieved.getIdentifier(), "Resource was retrieved with wrong ID!"); assertEquals(testResource2.stream().findFirst().get(), retrieved.stream().findFirst().get(), "Resource was retrieved with wrong data!"); assertNull(testable.delete(Metadata.builder(testResourceId1).interactionModel(LDP.RDFSource).build()) .toCompletableFuture().join(), "Couldn't delete resource!"); assertEquals(MISSING_RESOURCE, testable.get(testResourceId1).toCompletableFuture().join(), "Found resource after deleting it!"); }
@Test public void testMergingBehavior() { final Quad testMutableQuad = createQuad(testResourceId2, testResourceId2, testResourceId1, badId); final Quad testImmutableQuad = createQuad(testResourceId2, testResourceId2, testResourceId1, badId); // store some data in mutable and immutable sides under the same resource ID final Resource testMutableResource = new TestResource(testResourceId2, testMutableQuad); assertNull(testable.create(Metadata.builder(testMutableResource).build(), testMutableResource.dataset()) .toCompletableFuture().join(), "Couldn't create a resource!"); final Resource testImmutableResource = new TestResource(testResourceId2, testImmutableQuad); assertNull(testable.add(testResourceId2, testImmutableResource.dataset()).toCompletableFuture().join(), "Couldn't create an immutable resource!"); final Resource retrieved = testable.get(testResourceId2).toCompletableFuture().join(); assertEquals(testMutableResource.getIdentifier(), retrieved.getIdentifier(), "Resource was retrieved with wrong ID!"); final Dataset quads = retrieved.dataset(); assertTrue(quads.contains(testImmutableQuad), "Resource was retrieved without its immutable data!"); assertTrue(quads.contains(testMutableQuad), "Resource was retrieved without its mutable data!"); quads.remove(testImmutableQuad); quads.remove(testMutableQuad); assertEquals(0, quads.size(), "Resource was retrieved with too much data!"); }