Newer
Older
/*
* This file is part of vospace-rest
* Copyright (C) 2021 Istituto Nazionale di Astrofisica
* SPDX-License-Identifier: GPL-3.0-or-later
*/
Sonia Zorba
committed
import it.inaf.oats.vospace.persistence.NodeDAO;
import java.nio.charset.StandardCharsets;
import net.ivoa.xml.vospace.v2.Property;
Nicola Fulvio Calabria
committed
import it.inaf.oats.vospace.datamodel.NodeProperties;
import net.ivoa.xml.vospace.v2.UnstructuredDataNode;
import org.junit.jupiter.api.Test;
import static org.mockito.ArgumentMatchers.argThat;
Nicola Fulvio Calabria
committed
import static org.mockito.ArgumentMatchers.eq;
Nicola Fulvio Calabria
committed
import static org.mockito.Mockito.when;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
Sonia Zorba
committed
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
Sonia Zorba
committed
import static org.mockito.ArgumentMatchers.any;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
Nicola Fulvio Calabria
committed
import net.ivoa.xml.vospace.v2.ContainerNode;
import net.ivoa.xml.vospace.v2.LinkNode;
import java.util.List;
import java.util.Objects;
Nicola Fulvio Calabria
committed
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.mockito.ArgumentCaptor;
import static org.mockito.Mockito.times;
Nicola Fulvio Calabria
committed
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
Sonia Zorba
committed
@SpringBootTest
Nicola Fulvio Calabria
committed
@ContextConfiguration(classes = {TokenFilterConfig.class})
@TestPropertySource(properties = "spring.main.allow-bean-definition-overriding=true")
@AutoConfigureMockMvc
Sonia Zorba
committed
@MockBean
private NodeDAO nodeDao;
Sonia Zorba
committed
@SpyBean
@Autowired
Sonia Zorba
committed
@Autowired
Nicola Fulvio Calabria
committed
private ContainerNode getContainerParentNode(String path) {
ContainerNode parentNode = new ContainerNode();
// Set parent node address at /
parentNode.setUri("vos://example.com!vospace" + path);
// Set groupwrite property
Property groups = new Property();
groups.setUri("ivo://ivoa.net/vospace/core#groupwrite");
Nicola Fulvio Calabria
committed
groups.setValue("group1 group2");
Nicola Fulvio Calabria
committed
parentNode.setProperties(List.of(groups));
return parentNode;
}
private ContainerNode getContainerParentNodeWithCreator(String path) {
Nicola Fulvio Calabria
committed
ContainerNode parentNode = new ContainerNode();
// Set parent node address at /
parentNode.setUri("vos://example.com!vospace" + path);
Property creator = new Property();
creator.setUri("ivo://ivoa.net/vospace/core#creator");
creator.setValue("user2");
Nicola Fulvio Calabria
committed
parentNode.setProperties(List.of(creator));
Nicola Fulvio Calabria
committed
return parentNode;
}
Nicola Fulvio Calabria
committed
private LinkNode getLinkParentNode(String path) {
LinkNode parentNode = new LinkNode();
// Set parent node address at /
parentNode.setUri("vos://example.com!vospace" + path);
// Set groupwrite property
Property groups = new Property();
groups.setUri("ivo://ivoa.net/vospace/core#groupwrite");
Nicola Fulvio Calabria
committed
groups.setValue("group1 group2");
Nicola Fulvio Calabria
committed
parentNode.setProperties(List.of(groups));
return parentNode;
}
@Test
public void testFromJsonToXml() throws Exception {
Nicola Fulvio Calabria
committed
String requestBody
= getResourceFileContent("create-unstructured-data-node.json");
Nicola Fulvio Calabria
committed
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getContainerParentNode("/")));
Sonia Zorba
committed
mockMvc.perform(put("/nodes/mydata1")
Nicola Fulvio Calabria
committed
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().isOk());
@Test
public void testFromXmlToJson() throws Exception {
String requestBody = getResourceFileContent("create-unstructured-data-node.xml");
Nicola Fulvio Calabria
committed
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getContainerParentNode("/")));
Sonia Zorba
committed
mockMvc.perform(put("/nodes/mydata1")
Nicola Fulvio Calabria
committed
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk());
verify(nodeDao, times(1)).createNode(any());
@Test
public void testFromXmlToXml() throws Exception {
String requestBody = getResourceFileContent("create-unstructured-data-node.xml");
Nicola Fulvio Calabria
committed
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getContainerParentNode("/")));
Sonia Zorba
committed
mockMvc.perform(put("/nodes/mydata1")
Nicola Fulvio Calabria
committed
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().isOk());
verify(nodeDao, times(1)).createNode(any());
@Test
public void testFromJsonToJson() throws Exception {
String requestBody = getResourceFileContent("create-unstructured-data-node.json");
Nicola Fulvio Calabria
committed
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getContainerParentNode("/")));
Sonia Zorba
committed
mockMvc.perform(put("/nodes/mydata1")
Nicola Fulvio Calabria
committed
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk());
verify(nodeDao, times(1)).createNode(any());
Nicola Fulvio Calabria
committed
@Test
public void testURIConsistence() throws Exception {
String requestBody = getResourceFileContent("create-unstructured-data-node.xml");
Nicola Fulvio Calabria
committed
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getContainerParentNode("/")));
Nicola Fulvio Calabria
committed
mockMvc.perform(put("/nodes/mydata2")
Nicola Fulvio Calabria
committed
.header("Authorization", "Bearer user2_token")
Nicola Fulvio Calabria
committed
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is4xxClientError());
Nicola Fulvio Calabria
committed
verifyArguments();
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
}
@Test
public void testCreateInternalLinkNode() throws Exception {
String requestBody = getResourceFileContent("create-internal-link-node.xml");
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getContainerParentNode("/")));
mockMvc.perform(put("/nodes/myInternalLink")
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().isOk());
verifyLinkArguments("vos://example.com!vospace/myDummyDataNode1");
}
@Test
public void testCreateExternalLinkNode() throws Exception {
String requestBody = getResourceFileContent("create-external-link-node.xml");
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getContainerParentNode("/")));
mockMvc.perform(put("/nodes/myExternalLink")
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is4xxClientError());
verifyLinkArguments("vos://external.com!vospace/myDummyDataNode1");
}
@Test
public void testCreateLinkNodeNoTarget() throws Exception {
String requestBody = getResourceFileContent("create-link-node-notarget.xml");
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getContainerParentNode("/")));
mockMvc.perform(put("/nodes/myNoTargetLink")
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is4xxClientError());
verifyLinkArguments(null);
Nicola Fulvio Calabria
committed
}
@Test
public void testCreateLinkNodeExternalHttp() throws Exception {
String requestBody = getResourceFileContent("create-link-node-external-http.xml");
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getContainerParentNode("/")));
mockMvc.perform(put("/nodes/myExternalHttpLink")
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().isOk());
verifyLinkArguments("http://www.external.com/files/file.txt");
}
Nicola Fulvio Calabria
committed
@Test
public void testNodeAlreadyExisting() throws Exception {
String requestBody = getResourceFileContent("create-unstructured-data-node.xml");
Nicola Fulvio Calabria
committed
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getContainerParentNode("/")));
when(nodeDao.listNode(eq("/mydata1")))
.thenReturn(Optional.of(getContainerParentNode("/mydata1")));
Nicola Fulvio Calabria
committed
mockMvc.perform(put("/nodes/mydata1")
Nicola Fulvio Calabria
committed
.header("Authorization", "Bearer user2_token")
Nicola Fulvio Calabria
committed
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is4xxClientError());
Nicola Fulvio Calabria
committed
verifyArguments();
}
Nicola Fulvio Calabria
committed
@Test
public void testContainerNotFound() throws Exception {
String requestBody = getResourceFileContent("create-unstructured-data-node.xml");
Nicola Fulvio Calabria
committed
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.ofNullable(null));
Nicola Fulvio Calabria
committed
mockMvc.perform(put("/nodes/mydata1")
Nicola Fulvio Calabria
committed
.header("Authorization", "Bearer user2_token")
Nicola Fulvio Calabria
committed
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is4xxClientError());
Nicola Fulvio Calabria
committed
verifyArguments();
}
Nicola Fulvio Calabria
committed
@Test
public void testLinkNodeFound() throws Exception {
String requestBody = getResourceFileContent("create-unstructured-data-node.xml");
Nicola Fulvio Calabria
committed
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getLinkParentNode("/")));
Nicola Fulvio Calabria
committed
mockMvc.perform(put("/nodes/mydata1")
Nicola Fulvio Calabria
committed
.header("Authorization", "Bearer user2_token")
Nicola Fulvio Calabria
committed
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is4xxClientError());
Nicola Fulvio Calabria
committed
verifyArguments();
}
Nicola Fulvio Calabria
committed
@Test
public void testPermissionDenied() throws Exception {
String requestBody = getResourceFileContent("create-unstructured-data-node.xml");
Nicola Fulvio Calabria
committed
when(nodeDao.listNode(eq("/")))
Nicola Fulvio Calabria
committed
.thenReturn(Optional.of(getContainerParentNode("/")));
Nicola Fulvio Calabria
committed
mockMvc.perform(put("/nodes/mydata1")
Nicola Fulvio Calabria
committed
.header("Authorization", "Bearer user1_token")
Nicola Fulvio Calabria
committed
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is4xxClientError());
Nicola Fulvio Calabria
committed
verifyArguments();
}
Nicola Fulvio Calabria
committed
@Test
public void testWriteWithOnlyOwnership() throws Exception {
String requestBody = getResourceFileContent("create-unstructured-data-node.xml");
Nicola Fulvio Calabria
committed
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getContainerParentNodeWithCreator("/")));
Nicola Fulvio Calabria
committed
mockMvc.perform(put("/nodes/mydata1")
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is2xxSuccessful());
Nicola Fulvio Calabria
committed
verifyArguments();
verify(nodeDao, times(1)).createNode(any());
Nicola Fulvio Calabria
committed
}
Nicola Fulvio Calabria
committed
@Test
public void testWriteOwnerAbsent() throws Exception {
Nicola Fulvio Calabria
committed
String requestBody
= getResourceFileContent("create-unstructured-data-node.xml");
Nicola Fulvio Calabria
committed
when(nodeDao.listNode(eq("/")))
Nicola Fulvio Calabria
committed
.thenReturn(Optional.of(getContainerParentNodeWithCreator("/")));
Nicola Fulvio Calabria
committed
// no node creator specified in xml file
mockMvc.perform(put("/nodes/mydata1")
Nicola Fulvio Calabria
committed
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is2xxSuccessful());
Nicola Fulvio Calabria
committed
Nicola Fulvio Calabria
committed
// assert creator properties now matches user2
Nicola Fulvio Calabria
committed
verify(nodeDao, times(1)).createNode(argThat(node -> {
UnstructuredDataNode udn = (UnstructuredDataNode) node;
String creator = NodeProperties.getNodePropertyByURI(
udn, NodeProperties.CREATOR_URI);
return (creator != null && creator.equals("user2"));
Nicola Fulvio Calabria
committed
}
Nicola Fulvio Calabria
committed
@Test
public void testGroupPropertiesAbsent() throws Exception {
String requestBody
= getResourceFileContent("create-unstructured-data-node.xml");
Nicola Fulvio Calabria
committed
ContainerNode cdn = getContainerParentNode("/");
Nicola Fulvio Calabria
committed
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(cdn));
// no node creator specified in xml file
mockMvc.perform(put("/nodes/mydata1")
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is2xxSuccessful());
// assert creator properties now matches user2
verify(nodeDao, times(1)).createNode(argThat(node -> {
UnstructuredDataNode udn = (UnstructuredDataNode) node;
String groupRead = NodeProperties.getNodePropertyByURI(
udn, NodeProperties.GROUP_READ_URI);
String groupWrite = NodeProperties.getNodePropertyByURI(
udn, NodeProperties.GROUP_WRITE_URI);
return (groupRead == null && groupWrite.equals("group1 group2"));
Nicola Fulvio Calabria
committed
}
Nicola Fulvio Calabria
committed
@Test
public void testWriteOwnerMismatch() throws Exception {
Nicola Fulvio Calabria
committed
String requestBody
= getResourceFileContent("create-unstructured-data-node-user1.xml");
Nicola Fulvio Calabria
committed
when(nodeDao.listNode(eq("/")))
Nicola Fulvio Calabria
committed
.thenReturn(Optional.of(getContainerParentNodeWithCreator("/")));
Nicola Fulvio Calabria
committed
// no node creator specified in xml file
mockMvc.perform(put("/nodes/mydata1")
Nicola Fulvio Calabria
committed
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is4xxClientError());
Nicola Fulvio Calabria
committed
Nicola Fulvio Calabria
committed
// assert createNode is not called
verify(nodeDao, times(0)).createNode(any());
Nicola Fulvio Calabria
committed
}
Nicola Fulvio Calabria
committed
@Test
public void testSubPath() throws Exception {
String requestBody = getResourceFileContent("create-unstructured-data-node.xml")
.replace("/mydata1", "/mydata1/anothernode");
mockMvc.perform(put("/nodes/mydata1/anothernode")
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().isNotFound());
// Using ArgumentCaptor for verifying multiple method invocations
ArgumentCaptor<String> argCaptor = ArgumentCaptor.forClass(String.class);
verify(nodeDao, times(2)).listNode(argCaptor.capture());
assertEquals("/mydata1/anothernode", argCaptor.getAllValues().get(0));
assertEquals("/mydata1", argCaptor.getAllValues().get(1));
}
@Test
public void testIllegalChars() throws Exception {
String requestBody = getResourceFileContent("create-unstructured-data-node.xml")
.replace("/mydata1", "/mydata1/?anothernode");
String message = mockMvc.perform(put(new URI("/nodes/mydata1/%3Fanothernode"))
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().isBadRequest())
.andReturn().getResolvedException().getMessage();
assertTrue(message.contains("contains an illegal character"));
}
Sonia Zorba
committed
verify(controller).createNode(
argThat(node -> {
UnstructuredDataNode udn = (UnstructuredDataNode) node;
Property property = udn.getProperties().get(0);
return "vos:UnstructuredDataNode".equals(udn.getType())
&& "test value".equals(property.getValue())
&& "ivo://ivoa.net/vospace/core#description".equals(property.getUri());
Sonia Zorba
committed
}), any());
private void verifyLinkArguments(String target) {
verify(controller).createNode(
argThat(node -> {
LinkNode linkNode = (LinkNode) node;
Property property = linkNode.getProperties().get(0);
return "vos:LinkNode".equals(linkNode.getType())
&& "test value".equals(property.getValue())
&& "ivo://ivoa.net/vospace/core#description".equals(property.getUri())
&& Objects.equals(target, linkNode.getTarget());
}), any());
}
protected static String getResourceFileContent(String fileName) throws Exception {
Nicola Fulvio Calabria
committed
try (InputStream in = CreateNodeControllerTest.class.getClassLoader().getResourceAsStream(fileName)) {
return new String(in.readAllBytes(), StandardCharsets.UTF_8);
}
}
}