Skip to content
Snippets Groups Projects
Commit 761620eb authored by Sara Bertocco's avatar Sara Bertocco
Browse files

Aligning with master

parents 78ff2e26 386de80c
No related branches found
No related tags found
No related merge requests found
Showing
with 681 additions and 60 deletions
package it.inaf.oats.vospace;
import it.inaf.oats.vospace.exception.InternalFaultException;
import it.inaf.oats.vospace.persistence.JobDAO;
import net.ivoa.xml.uws.v1.ExecutionPhase;
import net.ivoa.xml.uws.v1.JobSummary;
import net.ivoa.xml.vospace.v2.Protocol;
import net.ivoa.xml.vospace.v2.Transfer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......@@ -43,35 +45,48 @@ public class JobService {
private void startJob(JobSummary job) {
switch (getJobType(job)) {
Transfer transfer = uriService.getTransfer(job);
switch (getJobType(transfer)) {
case pullToVoSpace:
handlePullToVoSpace(job);
handlePullToVoSpace(job, transfer);
break;
case pullFromVoSpace:
case pushToVoSpace:
handleVoSpaceUrlsListResult(job);
handleVoSpaceUrlsListResult(job, transfer);
break;
default:
throw new UnsupportedOperationException("Not implemented yet");
}
}
private void handlePullToVoSpace(JobSummary job) {
// TODO: check protocol
private void handlePullToVoSpace(JobSummary job, Transfer transfer) {
for (Protocol protocol : transfer.getProtocols()) {
switch (protocol.getUri()) {
case "ia2:async-recall":
asyncTransfService.startJob(job);
return;
case "ivo://ivoa.net/vospace/core#httpget":
String nodeUri = transfer.getTarget();
String contentUri = protocol.getEndpoint();
uriService.setNodeRemoteLocation(nodeUri, contentUri);
uriService.setTransferJobResult(job, transfer);
jobDAO.updateJob(job);
return;
default:
throw new InternalFaultException("Unsupported pullToVoSpace protocol: " + protocol.getUri());
}
}
}
private void handleVoSpaceUrlsListResult(JobSummary job) {
private void handleVoSpaceUrlsListResult(JobSummary job, Transfer transfer) {
job.setPhase(ExecutionPhase.EXECUTING);
uriService.setTransferJobResult(job);
uriService.setTransferJobResult(job, transfer);
jobDAO.updateJob(job);
}
private JobType getJobType(JobSummary job) {
// TODO: check types
Transfer transfer = (Transfer) job.getJobInfo().getAny().get(0);
private JobType getJobType(Transfer transfer) {
return JobType.valueOf(transfer.getDirection());
}
......
package it.inaf.oats.vospace;
import it.inaf.ia2.aa.data.User;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import it.inaf.oats.vospace.exception.LinkFoundException;
import it.inaf.oats.vospace.exception.NodeNotFoundException;
import it.inaf.oats.vospace.exception.PermissionDeniedException;
import it.inaf.oats.vospace.persistence.NodeDAO;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import net.ivoa.xml.vospace.v2.Node;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SetNodeController extends BaseNodeController {
@Autowired
private NodeDAO nodeDao;
@Value("${vospace-authority}")
private String authority;
@PostMapping(value = {"/nodes", "/nodes/**"},
consumes = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE},
produces = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE})
public Node setNode(@RequestBody Node node, User principal, HttpServletRequest request) {
String path = getPath();
//The service SHALL throw a HTTP 404 status code including a NodeNotFound
//fault in the entity-body if the target Node does not exist
Node toBeModifiedNode = nodeDao.listNode(path)
.orElseThrow(() -> new NodeNotFoundException(path));
// The service SHALL throw a HTTP 403 status code including a PermissionDenied fault
// in the entity-body if the user does not have permissions to perform the operation
if(!NodeUtils.checkIfWritable(toBeModifiedNode, principal.getName(), principal.getGroups())) {
throw new PermissionDeniedException(path);
}
// The service SHALL throw a HTTP 403 status code including a PermissionDenied fault
// in the entity-body if the request attempts to modify a read-only Property.
// This method cannot be used to modify the Node type.
// This method cannot be used to modify the accepts or provides list of Views for the Node.
// This method cannot be used to create children of a container Node.
// If a parent node in the URI path does not exist then the service SHALL throw a
// HTTP 404 status code including a ContainerNotFound fault in the entity-body
// For example, given the URI path /a/b/c, the service must throw a HTTP 404 status
// code including a ContainerNotFound fault in the entity-body if either /a or /a/b
// do not exist.
List<String> pathComponents = NodeUtils.subPathComponents(path);
if (pathComponents.size() == 0) {
// Manage root node
throw new PermissionDeniedException("root");
} else {
// Manage all precursors in full path
for (int i = 0; i < pathComponents.size(); i++) {
String tmpPath = pathComponents.get(i);
Node mynode = nodeDao.listNode(tmpPath)
.orElseThrow(() -> new NodeNotFoundException(tmpPath));
if (mynode.getType().equals("vos:LinkNode") && i < pathComponents.size()-1) // a LinkNode leaf can be deleted
throw new LinkFoundException(tmpPath);
}
}
//The service SHOULD throw a HTTP 500 status code including an InternalFault fault
// in the entity-body if the operation fails
// to be fixed
// A HTTP 200 status code and a Node representation in the entity-body The full
// expanded record for the node SHALL be returned, including any xsi:type
// specific extensions.
return node;
}
}
......@@ -5,11 +5,18 @@ import it.inaf.ia2.aa.data.User;
import it.inaf.ia2.rap.client.call.TokenExchangeRequest;
import it.inaf.oats.vospace.datamodel.NodeProperties;
import static it.inaf.oats.vospace.datamodel.NodeUtils.urlEncodePath;
import it.inaf.oats.vospace.exception.InternalFaultException;
import it.inaf.oats.vospace.exception.NodeNotFoundException;
import it.inaf.oats.vospace.exception.PermissionDeniedException;
import it.inaf.oats.vospace.persistence.LocationDAO;
import it.inaf.oats.vospace.persistence.NodeDAO;
import it.inaf.oats.vospace.persistence.model.Location;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import net.ivoa.xml.uws.v1.ExecutionPhase;
import net.ivoa.xml.uws.v1.JobSummary;
import net.ivoa.xml.uws.v1.ResultReference;
import net.ivoa.xml.vospace.v2.Node;
......@@ -31,21 +38,25 @@ public class UriService {
@Autowired
private NodeDAO nodeDao;
@Autowired
private LocationDAO locationDAO;
@Autowired
private HttpServletRequest servletRequest;
@Autowired
private ServletRapClient rapClient;
public void setTransferJobResult(JobSummary job) {
public void setTransferJobResult(JobSummary job, Transfer transfer) {
List<ResultReference> results = new ArrayList<>();
ResultReference result = new ResultReference();
result.setHref(getEndpoint(job));
result.setHref(getEndpoint(job, transfer));
results.add(result);
job.setResults(results);
job.setPhase(ExecutionPhase.COMPLETED);
}
public void setSyncTransferEndpoints(JobSummary job) {
......@@ -58,22 +69,35 @@ public class UriService {
&& !"ivo://ivoa.net/vospace/core#httpput".equals(protocol.getUri())) {
throw new IllegalStateException("Unsupported protocol " + protocol.getUri());
}
protocol.setEndpoint(getEndpoint(job));
protocol.setEndpoint(getEndpoint(job, transfer));
}
private String getEndpoint(JobSummary job) {
Transfer transfer = getTransfer(job);
private String getEndpoint(JobSummary job, Transfer transfer) {
String relativePath = transfer.getTarget().substring("vos://".length() + authority.length());
Node node = nodeDao.listNode(relativePath).orElseThrow(() -> new NodeNotFoundException(relativePath));
// TODO build the path according to node type
//
String endpoint = fileServiceUrl + urlEncodePath(relativePath) + "?jobId=" + job.getJobId();
Location location = locationDAO.getNodeLocation(relativePath).orElseThrow(()
-> new InternalFaultException("No registered location found for vos_path " + relativePath));
if (!"true".equals(NodeProperties.getNodePropertiesListByURI(node, NodeProperties.PUBLIC_READ_URI))) {
String endpoint;
switch (location.getType()) {
case PORTAL:
String fileName = nodeDao.getNodeOsName(relativePath);
endpoint = "http://" + location.getSource().getHostname() + location.getSource().getBasePath();
if (!endpoint.endsWith("/")) {
endpoint += "/";
}
endpoint += fileName;
break;
default:
endpoint = fileServiceUrl + urlEncodePath(relativePath);
}
endpoint += "?jobId=" + job.getJobId();
if (!"true".equals(NodeProperties.getNodePropertyAsListByURI(node, NodeProperties.PUBLIC_READ_URI))) {
endpoint += "&token=" + getEndpointToken(fileServiceUrl + relativePath);
}
......@@ -85,8 +109,7 @@ public class UriService {
String token = ((User) servletRequest.getUserPrincipal()).getAccessToken();
if (token == null) {
// TODO: use PermissionDenied VoSpaceException
throw new IllegalStateException("Token is null");
throw new PermissionDeniedException("Token is null");
}
TokenExchangeRequest exchangeRequest = new TokenExchangeRequest()
......@@ -97,8 +120,39 @@ public class UriService {
return rapClient.exchangeToken(exchangeRequest, servletRequest);
}
private Transfer getTransfer(JobSummary job) {
// TODO add checks on data type
public void setNodeRemoteLocation(String nodeUri, String contentUri) {
URL url;
try {
url = new URL(contentUri);
} catch (MalformedURLException ex) {
throw new InternalFaultException(ex);
}
Location location = locationDAO.findPortalLocation(url.getHost()).orElseThrow(()
-> new InternalFaultException("No registered location found for host " + url.getHost()));
String vosPath = nodeUri.replaceAll("vos://[^/]+", "");
String fileName = url.getPath().substring(url.getPath().lastIndexOf("/") + 1);
nodeDao.setNodeLocation(vosPath, location.getId(), fileName);
}
public Transfer getTransfer(JobSummary job) {
List<Object> jobPayload = job.getJobInfo().getAny();
if (jobPayload.isEmpty()) {
throw new IllegalStateException("Empty job payload for job " + job.getJobId());
}
if (jobPayload.size() > 1) {
throw new IllegalStateException("Multiple objects in job payload not supported");
}
if (!(jobPayload.get(0) instanceof Transfer)) {
throw new IllegalStateException(jobPayload.get(0).getClass().getCanonicalName()
+ " not supported as job payload. Job id: " + job.getJobId());
}
return (Transfer) job.getJobInfo().getAny().get(0);
}
}
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package it.inaf.oats.vospace.exception;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) // Status code 500
public class InternalFaultException extends VoSpaceException {
private static final Logger LOG = LoggerFactory.getLogger(InternalFaultException.class);
public InternalFaultException(String msg) {
super("InternalFaultException: " + msg);
}
public InternalFaultException(Throwable cause) {
super("InternalFaultException: " + getMessage(cause));
}
private static String getMessage(Throwable cause) {
LOG.error("Exception caught", cause);
return cause.getMessage() != null ? cause.getMessage() : cause.getClass().getCanonicalName();
}
}
package it.inaf.oats.vospace.persistence;
import it.inaf.oats.vospace.persistence.model.Location;
import it.inaf.oats.vospace.persistence.model.LocationType;
import it.inaf.oats.vospace.persistence.model.Storage;
import it.inaf.oats.vospace.persistence.model.StorageType;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class LocationDAO {
private final JdbcTemplate jdbcTemplate;
@Autowired
public LocationDAO(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
public Optional<Location> findPortalLocation(String host) {
String sql = "SELECT location_id, location_type, storage_src_id, storage_dest_id,\n"
+ "storage_id, storage_type, base_path, hostname\n"
+ "FROM location l\n"
+ "JOIN storage s ON l.storage_src_id = s.storage_id OR l.storage_dest_id = s.storage_id\n"
+ "WHERE hostname = ?";
return jdbcTemplate.query(sql, ps -> {
ps.setString(1, host);
}, rs -> {
return getLocation(rs, () -> new IllegalStateException("Found multiple locations for the same hostname"));
});
}
public Optional<Location> getNodeLocation(String vosPath) {
String sql = "SELECT location_id, location_type, storage_src_id, storage_dest_id,\n"
+ "storage_id, storage_type, base_path, hostname\n"
+ "FROM location l\n"
+ "JOIN storage s ON l.storage_src_id = s.storage_id OR l.storage_dest_id = s.storage_id\n"
+ "WHERE location_id = (\n"
+ "SELECT location_id FROM node n\n"
+ "JOIN node_vos_path p ON n.node_id = p.node_id\n"
+ "WHERE p.vos_path = ?)";
return jdbcTemplate.query(sql, ps -> {
ps.setString(1, vosPath);
}, rs -> {
return getLocation(rs, () -> new IllegalStateException("Found multiple locations for the same vos_path"));
});
}
private Optional<Location> getLocation(ResultSet rs, Supplier<IllegalStateException> exceptionSupplier) throws SQLException {
List<Location> locations = getLocations(rs);
if (locations.isEmpty()) {
return Optional.empty();
}
if (locations.size() > 1) {
throw exceptionSupplier.get();
}
return Optional.of(locations.get(0));
}
private List<Location> getLocations(ResultSet rs) throws SQLException {
Map<Integer, Storage> storagesMap = new HashMap<>();
Map<Integer, Location> locationsMap = new HashMap<>();
while (rs.next()) {
int locationId = rs.getInt("location_id");
Location location = locationsMap.get(locationId);
if (location == null) {
location = new Location();
location.setId(locationId);
locationsMap.put(locationId, location);
}
location.setType(LocationType.parse(rs.getString("location_type")));
int storageId = rs.getInt("storage_id");
Storage storage = storagesMap.get(storageId);
if (storage == null) {
storage = new Storage();
storage.setId(storageId);
storagesMap.put(storageId, storage);
}
storage.setType(StorageType.parse(rs.getString("storage_type")));
storage.setBasePath(rs.getString("base_path"));
storage.setHostname(rs.getString("hostname"));
Storage storageSrc = storagesMap.get(rs.getInt("storage_src_id"));
if (storageSrc != null) {
location.setSource(storageSrc);
}
Storage storageDest = storagesMap.get(rs.getInt("storage_dest_id"));
if (storageDest != null) {
location.setDestination(storageDest);
}
}
return new ArrayList<>(locationsMap.values());
}
}
......@@ -2,6 +2,8 @@ package it.inaf.oats.vospace.persistence;
import it.inaf.oats.vospace.datamodel.NodeProperties;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import it.inaf.oats.vospace.exception.InternalFaultException;
import java.sql.Array;
import net.ivoa.xml.vospace.v2.Node;
import java.sql.PreparedStatement;
......@@ -242,6 +244,35 @@ public class NodeDAO {
return jdbcTemplate.queryForObject(sql, args, types, Integer.class);
}
public String getNodeOsName(String vosPath) {
String sql = "SELECT \n"
+ "(CASE WHEN os_name IS NOT NULL THEN os_name ELSE name END) AS os_name\n"
+ "FROM node n\n"
+ "JOIN node_vos_path p ON n.node_id = p.node_id\n"
+ "WHERE p.vos_path = ?";
Object[] args = {vosPath};
int[] types = {Types.VARCHAR};
return jdbcTemplate.queryForObject(sql, args, types, String.class);
}
public void setNodeLocation(String vosPath, int locationId, String nodeOsName) {
String sql = "UPDATE node SET location_id = ?, os_name = ? WHERE node_id = "
+ "(SELECT node_id FROM node_vos_path WHERE vos_path = ?)";
int updated = jdbcTemplate.update(sql, ps -> {
ps.setInt(1, locationId);
ps.setString(2, nodeOsName);
ps.setString(3, vosPath);
});
if (updated != 1) {
throw new InternalFaultException("Unable to set node location for path " + vosPath);
}
}
private String getGroupsString(ResultSet rs, String column) throws SQLException {
Array array = rs.getArray(column);
if (array == null) {
......
package it.inaf.oats.vospace.persistence.model;
public class Location {
private int id;
private LocationType type;
private Storage source;
private Storage destination;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public LocationType getType() {
return type;
}
public void setType(LocationType type) {
this.type = type;
}
public Storage getSource() {
return source;
}
public void setSource(Storage source) {
this.source = source;
}
public Storage getDestination() {
return destination;
}
public void setDestination(Storage destination) {
this.destination = destination;
}
}
package it.inaf.oats.vospace.persistence.model;
public enum LocationType {
ASYNC("async"),
PORTAL("portal"),
USER("user");
private final String name;
private LocationType(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
public static LocationType parse(String value) {
for (LocationType type : LocationType.values()) {
if (type.name.equals(value)) {
return type;
}
}
throw new IllegalArgumentException("Invalid LocationType " + value);
}
}
package it.inaf.oats.vospace.persistence.model;
public class Storage {
private int id;
private StorageType type;
private String basePath;
private String hostname;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public StorageType getType() {
return type;
}
public void setType(StorageType type) {
this.type = type;
}
public String getBasePath() {
return basePath;
}
public void setBasePath(String basePath) {
this.basePath = basePath;
}
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
}
package it.inaf.oats.vospace.persistence.model;
public enum StorageType {
COLD("cold"),
HOT("hot"),
LOCAL("local"),
PORTAL("portal");
private final String name;
private StorageType(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
public static StorageType parse(String value) {
for (StorageType type : StorageType.values()) {
if (type.name.equals(value)) {
return type;
}
}
throw new IllegalArgumentException("Invalid StorageType " + value);
}
}
......@@ -187,11 +187,6 @@ public class DeleteNodeControllerTest {
}
private LinkNode getWritableLinkNode(String path) {
LinkNode myNode = new LinkNode();
// Set parent node address at /
......
......@@ -3,7 +3,11 @@ package it.inaf.oats.vospace;
import it.inaf.ia2.aa.data.User;
import static it.inaf.oats.vospace.VOSpaceXmlTestUtil.loadDocument;
import it.inaf.oats.vospace.persistence.JobDAO;
import it.inaf.oats.vospace.persistence.LocationDAO;
import it.inaf.oats.vospace.persistence.NodeDAO;
import it.inaf.oats.vospace.persistence.model.Location;
import it.inaf.oats.vospace.persistence.model.LocationType;
import it.inaf.oats.vospace.persistence.model.Storage;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
......@@ -41,6 +45,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.w3c.dom.Document;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.BeforeEach;
import static org.mockito.ArgumentMatchers.argThat;
@SpringBootTest
@AutoConfigureMockMvc
......@@ -55,11 +62,32 @@ public class TransferControllerTest {
private NodeDAO nodeDao;
@MockBean
private AsyncTransferService tapeService;
private LocationDAO locationDao;
@MockBean
private AsyncTransferService asyncTransfService;
@Autowired
private MockMvc mockMvc;
@BeforeEach
public void init() {
Location asyncLocation = new Location();
asyncLocation.setType(LocationType.ASYNC);
asyncLocation.setId(1);
when(locationDao.getNodeLocation(eq("/mynode"))).thenReturn(Optional.of(asyncLocation));
Location portalLocation = new Location();
portalLocation.setType(LocationType.PORTAL);
portalLocation.setId(2);
Storage portalStorage = new Storage();
portalStorage.setHostname("archive.lbto.org");
portalStorage.setBasePath("/files");
portalLocation.setSource(portalStorage);
when(locationDao.getNodeLocation(eq("/portalnode"))).thenReturn(Optional.of(portalLocation));
when(locationDao.findPortalLocation(any())).thenReturn(Optional.of(portalLocation));
}
@Test
public void testPullFromVoSpaceAsync() throws Exception {
......@@ -99,9 +127,32 @@ public class TransferControllerTest {
}
@Test
public void testPullToVoSpace() throws Exception {
public void testPullToVoSpaceTape() throws Exception {
testPullToVoSpace("/mynode", getResourceFileContent("pullToVoSpace-tape.xml"));
verify(asyncTransfService, times(1)).startJob(any());
}
@Test
public void testPullToVoSpacePortal() throws Exception {
when(nodeDao.getNodeOsName(eq("/portalnode"))).thenReturn("file.fits");
String requestBody = getResourceFileContent("pullToVoSpace.xml");
testPullToVoSpace("/portalnode", getResourceFileContent("pullToVoSpace-portal.xml"));
verify(nodeDao, times(1)).setNodeLocation(eq("/portalnode"), eq(2), eq("lbcr.20130512.060722.fits.gz"));
verify(jobDao, times(1)).updateJob(argThat(j -> {
assertTrue(j.getResults().get(0).getHref().startsWith("http://archive.lbto.org"));
assertEquals(ExecutionPhase.COMPLETED, j.getPhase());
return true;
}));
}
private void testPullToVoSpace(String path, String requestBody) throws Exception {
Node node = mockPublicDataNode();
when(nodeDao.listNode(eq(path))).thenReturn(Optional.of(node));
String redirect = mockMvc.perform(post("/transfers?PHASE=RUN")
.content(requestBody)
......@@ -112,8 +163,6 @@ public class TransferControllerTest {
.andReturn().getResponse().getHeader("Location");
assertThat(redirect, matchesPattern("^/transfers/.*"));
verify(tapeService, times(1)).startJob(any());
}
@Test
......@@ -210,7 +259,6 @@ public class TransferControllerTest {
.andDo(print())
.andExpect(status().is4xxClientError());
String xml2 = mockMvc.perform(get("/transfers")
.header("Authorization", "Bearer user1_token")
.accept(MediaType.APPLICATION_XML))
......
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package it.inaf.oats.vospace;
/**
*
* @author bertocco
*/
public class UpdateNodeController {
}
......@@ -2,7 +2,10 @@ package it.inaf.oats.vospace;
import it.inaf.ia2.aa.ServletRapClient;
import it.inaf.ia2.aa.data.User;
import it.inaf.oats.vospace.persistence.LocationDAO;
import it.inaf.oats.vospace.persistence.NodeDAO;
import it.inaf.oats.vospace.persistence.model.Location;
import it.inaf.oats.vospace.persistence.model.LocationType;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import net.ivoa.xml.uws.v1.JobSummary;
......@@ -11,11 +14,13 @@ import net.ivoa.xml.vospace.v2.Node;
import net.ivoa.xml.vospace.v2.Property;
import net.ivoa.xml.vospace.v2.Transfer;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
......@@ -32,7 +37,10 @@ import org.springframework.test.context.TestPropertySource;
public class UriServiceTest {
@MockBean
private NodeDAO dao;
private NodeDAO nodeDAO;
@MockBean
private LocationDAO locationDAO;
@MockBean
private ServletRapClient rapClient;
......@@ -56,6 +64,13 @@ public class UriServiceTest {
}
}
@BeforeEach
public void init() {
Location location = new Location();
location.setType(LocationType.ASYNC);
when(locationDAO.getNodeLocation(any())).thenReturn(Optional.of(location));
}
@Test
public void testPublicUrl() {
......@@ -65,10 +80,10 @@ public class UriServiceTest {
property.setValue("true");
node.getProperties().add(property);
when(dao.listNode(eq("/mydata1"))).thenReturn(Optional.of(node));
when(nodeDAO.listNode(eq("/mydata1"))).thenReturn(Optional.of(node));
JobSummary job = getJob();
uriService.setTransferJobResult(job);
uriService.setTransferJobResult(job, uriService.getTransfer(job));
assertEquals("http://file-service/mydata1?jobId=job-id", job.getResults().get(0).getHref());
}
......@@ -78,7 +93,7 @@ public class UriServiceTest {
Node node = new DataNode();
when(dao.listNode(eq("/mydata1"))).thenReturn(Optional.of(node));
when(nodeDAO.listNode(eq("/mydata1"))).thenReturn(Optional.of(node));
User user = mock(User.class);
when(user.getAccessToken()).thenReturn("<token>");
......@@ -92,11 +107,27 @@ public class UriServiceTest {
}), any())).thenReturn("<new-token>");
JobSummary job = getJob();
uriService.setTransferJobResult(job);
uriService.setTransferJobResult(job, uriService.getTransfer(job));
assertEquals("http://file-service/mydata1?jobId=job-id&token=<new-token>", job.getResults().get(0).getHref());
}
@Test
public void setNodeRemoteLocationTest() {
String nodeUri = "vos://example.com!vospace/test/f1/lbtfile.fits";
String contentUri = "http://archive.lbto.org/files/lbtfile.fits";
Location location = new Location();
location.setId(5);
when(locationDAO.findPortalLocation(eq("archive.lbto.org"))).thenReturn(Optional.of(location));
uriService.setNodeRemoteLocation(nodeUri, contentUri);
verify(nodeDAO).setNodeLocation(eq("/test/f1/lbtfile.fits"), eq(5), eq("lbtfile.fits"));
}
private JobSummary getJob() {
Transfer transfer = new Transfer();
......
package it.inaf.oats.vospace.persistence;
import it.inaf.oats.vospace.persistence.model.Location;
import java.util.Optional;
import javax.sql.DataSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {DataSourceConfig.class})
@TestPropertySource(locations = "classpath:test.properties")
public class LocationDAOTest {
@Autowired
private DataSource dataSource;
private LocationDAO dao;
@BeforeEach
public void init() {
dao = new LocationDAO(dataSource);
}
@Test
public void testGetPortalLocation() {
String hostname = "archive.lbto.org";
Optional<Location> optLocation = dao.findPortalLocation(hostname);
assertTrue(optLocation.isPresent());
Location location = optLocation.get();
assertEquals(hostname, location.getSource().getHostname());
}
@Test
public void testInexistentLocation() {
assertTrue(dao.findPortalLocation("foo").isEmpty());
}
@Test
public void testGetRootLocation() {
dao.getNodeLocation("/");
}
}
package it.inaf.oats.vospace.persistence;
import it.inaf.oats.vospace.datamodel.NodeProperties;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import it.inaf.oats.vospace.exception.InternalFaultException;
import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;
......@@ -56,7 +56,7 @@ public class NodeDAOTest {
ContainerNode root = (ContainerNode) dao.listNode("/").get();
assertEquals(2, root.getNodes().size());
assertEquals("true", NodeProperties.getNodePropertiesListByURI(root, NodeProperties.PUBLIC_READ_URI).get(0));
assertEquals("true", NodeProperties.getNodePropertyAsListByURI(root, NodeProperties.PUBLIC_READ_URI).get(0));
assertEquals("group1 group2", getProperty(root.getNodes().get(0), "ivo://ivoa.net/vospace/core#groupread"));
}
......@@ -90,6 +90,27 @@ public class NodeDAOTest {
}
@Test
public void testSetNodeLocation() {
DataNode dataNode = new DataNode();
dataNode.setUri("vos://example.com!vospace/mydata2");
dao.createNode(dataNode);
dao.setNodeLocation("/mydata2", 1, "mydata2");
}
@Test
public void testSetNodeLocationFailure() {
boolean exception = false;
try {
dao.setNodeLocation("/foo", 1, "foo");
} catch (InternalFaultException ex) {
exception = true;
}
assertTrue(exception);
}
private String getProperty(Node node, String uri) {
for (Property property : node.getProperties()) {
if (uri.equals(property.getUri())) {
......
<vos:transfer xmlns:vos="http://www.ivoa.net/xml/VOSpace/v2.0" version="2.1">
<vos:target>vos://example.com!vospace/portalnode</vos:target>
<vos:direction>pullToVoSpace</vos:direction>
<vos:protocol uri="ivo://ivoa.net/vospace/core#httpget">
<vos:endpoint>http://archive.lbto.org/files/lbcr.20130512.060722.fits.gz</vos:endpoint>
</vos:protocol>
</vos:transfer>
\ No newline at end of file
<vos:transfer xmlns:vos="http://www.ivoa.net/xml/VOSpace/v2.0" version="2.1">
<vos:target>vos://example.com!vospace/mynode</vos:target>
<vos:direction>pullToVoSpace</vos:direction>
<vos:protocol uri="ivo://ivoa.net/vospace/core#httpget" />
<vos:protocol uri="ia2:async-recall" />
</vos:transfer>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment