Skip to content
Snippets Groups Projects
Commit 386de80c authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Implemented import of portal files to DataNodes

parent 9a87b926
No related branches found
No related tags found
No related merge requests found
Pipeline #1017 passed
Showing
with 570 additions and 53 deletions
package it.inaf.oats.vospace; package it.inaf.oats.vospace;
import it.inaf.oats.vospace.exception.InternalFaultException;
import it.inaf.oats.vospace.persistence.JobDAO; import it.inaf.oats.vospace.persistence.JobDAO;
import net.ivoa.xml.uws.v1.ExecutionPhase; import net.ivoa.xml.uws.v1.ExecutionPhase;
import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.uws.v1.JobSummary;
import net.ivoa.xml.vospace.v2.Protocol;
import net.ivoa.xml.vospace.v2.Transfer; import net.ivoa.xml.vospace.v2.Transfer;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -43,35 +45,48 @@ public class JobService { ...@@ -43,35 +45,48 @@ public class JobService {
private void startJob(JobSummary job) { private void startJob(JobSummary job) {
switch (getJobType(job)) { Transfer transfer = uriService.getTransfer(job);
switch (getJobType(transfer)) {
case pullToVoSpace: case pullToVoSpace:
handlePullToVoSpace(job); handlePullToVoSpace(job, transfer);
break; break;
case pullFromVoSpace: case pullFromVoSpace:
case pushToVoSpace: case pushToVoSpace:
handleVoSpaceUrlsListResult(job); handleVoSpaceUrlsListResult(job, transfer);
break; break;
default: default:
throw new UnsupportedOperationException("Not implemented yet"); throw new UnsupportedOperationException("Not implemented yet");
} }
} }
private void handlePullToVoSpace(JobSummary job) { private void handlePullToVoSpace(JobSummary job, Transfer transfer) {
// TODO: check protocol
for (Protocol protocol : transfer.getProtocols()) {
switch (protocol.getUri()) {
case "ia2:async-recall":
asyncTransfService.startJob(job); 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); job.setPhase(ExecutionPhase.EXECUTING);
uriService.setTransferJobResult(job); uriService.setTransferJobResult(job, transfer);
jobDAO.updateJob(job); jobDAO.updateJob(job);
} }
private JobType getJobType(JobSummary job) { private JobType getJobType(Transfer transfer) {
// TODO: check types
Transfer transfer = (Transfer) job.getJobInfo().getAny().get(0);
return JobType.valueOf(transfer.getDirection()); return JobType.valueOf(transfer.getDirection());
} }
......
...@@ -5,11 +5,18 @@ import it.inaf.ia2.aa.data.User; ...@@ -5,11 +5,18 @@ import it.inaf.ia2.aa.data.User;
import it.inaf.ia2.rap.client.call.TokenExchangeRequest; import it.inaf.ia2.rap.client.call.TokenExchangeRequest;
import it.inaf.oats.vospace.datamodel.NodeProperties; import it.inaf.oats.vospace.datamodel.NodeProperties;
import static it.inaf.oats.vospace.datamodel.NodeUtils.urlEncodePath; 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.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.NodeDAO;
import it.inaf.oats.vospace.persistence.model.Location;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest; 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.JobSummary;
import net.ivoa.xml.uws.v1.ResultReference; import net.ivoa.xml.uws.v1.ResultReference;
import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Node;
...@@ -31,21 +38,25 @@ public class UriService { ...@@ -31,21 +38,25 @@ public class UriService {
@Autowired @Autowired
private NodeDAO nodeDao; private NodeDAO nodeDao;
@Autowired
private LocationDAO locationDAO;
@Autowired @Autowired
private HttpServletRequest servletRequest; private HttpServletRequest servletRequest;
@Autowired @Autowired
private ServletRapClient rapClient; private ServletRapClient rapClient;
public void setTransferJobResult(JobSummary job) { public void setTransferJobResult(JobSummary job, Transfer transfer) {
List<ResultReference> results = new ArrayList<>(); List<ResultReference> results = new ArrayList<>();
ResultReference result = new ResultReference(); ResultReference result = new ResultReference();
result.setHref(getEndpoint(job)); result.setHref(getEndpoint(job, transfer));
results.add(result); results.add(result);
job.setResults(results); job.setResults(results);
job.setPhase(ExecutionPhase.COMPLETED);
} }
public void setSyncTransferEndpoints(JobSummary job) { public void setSyncTransferEndpoints(JobSummary job) {
...@@ -58,20 +69,33 @@ public class UriService { ...@@ -58,20 +69,33 @@ public class UriService {
&& !"ivo://ivoa.net/vospace/core#httpput".equals(protocol.getUri())) { && !"ivo://ivoa.net/vospace/core#httpput".equals(protocol.getUri())) {
throw new IllegalStateException("Unsupported protocol " + protocol.getUri()); throw new IllegalStateException("Unsupported protocol " + protocol.getUri());
} }
protocol.setEndpoint(getEndpoint(job)); protocol.setEndpoint(getEndpoint(job, transfer));
} }
private String getEndpoint(JobSummary job) { private String getEndpoint(JobSummary job, Transfer transfer) {
Transfer transfer = getTransfer(job);
String relativePath = transfer.getTarget().substring("vos://".length() + authority.length()); String relativePath = transfer.getTarget().substring("vos://".length() + authority.length());
Node node = nodeDao.listNode(relativePath).orElseThrow(() -> new NodeNotFoundException(relativePath)); Node node = nodeDao.listNode(relativePath).orElseThrow(() -> new NodeNotFoundException(relativePath));
// TODO build the path according to node type Location location = locationDAO.getNodeLocation(relativePath).orElseThrow(()
// -> new InternalFaultException("No registered location found for vos_path " + relativePath));
String endpoint = fileServiceUrl + urlEncodePath(relativePath) + "?jobId=" + job.getJobId();
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.getNodePropertyByURI(node, NodeProperties.PUBLIC_READ_URI))) { if (!"true".equals(NodeProperties.getNodePropertyByURI(node, NodeProperties.PUBLIC_READ_URI))) {
endpoint += "&token=" + getEndpointToken(fileServiceUrl + relativePath); endpoint += "&token=" + getEndpointToken(fileServiceUrl + relativePath);
...@@ -85,8 +109,7 @@ public class UriService { ...@@ -85,8 +109,7 @@ public class UriService {
String token = ((User) servletRequest.getUserPrincipal()).getAccessToken(); String token = ((User) servletRequest.getUserPrincipal()).getAccessToken();
if (token == null) { if (token == null) {
// TODO: use PermissionDenied VoSpaceException throw new PermissionDeniedException("Token is null");
throw new IllegalStateException("Token is null");
} }
TokenExchangeRequest exchangeRequest = new TokenExchangeRequest() TokenExchangeRequest exchangeRequest = new TokenExchangeRequest()
...@@ -97,8 +120,39 @@ public class UriService { ...@@ -97,8 +120,39 @@ public class UriService {
return rapClient.exchangeToken(exchangeRequest, servletRequest); return rapClient.exchangeToken(exchangeRequest, servletRequest);
} }
private Transfer getTransfer(JobSummary job) { public void setNodeRemoteLocation(String nodeUri, String contentUri) {
// TODO add checks on data type
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); 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; package it.inaf.oats.vospace.exception;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) // Status code 500 @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) // Status code 500
public class InternalFaultException extends VoSpaceException { public class InternalFaultException extends VoSpaceException {
private static final Logger LOG = LoggerFactory.getLogger(InternalFaultException.class);
public InternalFaultException(String msg) { public InternalFaultException(String msg) {
super("InternalFaultException: " + 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());
}
}
package it.inaf.oats.vospace.persistence; package it.inaf.oats.vospace.persistence;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import it.inaf.oats.vospace.exception.InternalFaultException;
import java.sql.Array; import java.sql.Array;
import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Node;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
...@@ -240,6 +242,35 @@ public class NodeDAO { ...@@ -240,6 +242,35 @@ public class NodeDAO {
return jdbcTemplate.queryForObject(sql, args, types, Integer.class); 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 getPropertyURI(String propertyName) { private String getPropertyURI(String propertyName) {
return "ivo://ivoa.net/vospace/core#".concat(propertyName); return "ivo://ivoa.net/vospace/core#".concat(propertyName);
} }
......
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);
}
}
...@@ -3,7 +3,11 @@ package it.inaf.oats.vospace; ...@@ -3,7 +3,11 @@ package it.inaf.oats.vospace;
import it.inaf.ia2.aa.data.User; import it.inaf.ia2.aa.data.User;
import static it.inaf.oats.vospace.VOSpaceXmlTestUtil.loadDocument; import static it.inaf.oats.vospace.VOSpaceXmlTestUtil.loadDocument;
import it.inaf.oats.vospace.persistence.JobDAO; 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.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.io.InputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.sql.Timestamp; import java.sql.Timestamp;
...@@ -41,6 +45,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers. ...@@ -41,6 +45,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import java.util.List; 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 @SpringBootTest
@AutoConfigureMockMvc @AutoConfigureMockMvc
...@@ -55,11 +62,32 @@ public class TransferControllerTest { ...@@ -55,11 +62,32 @@ public class TransferControllerTest {
private NodeDAO nodeDao; private NodeDAO nodeDao;
@MockBean @MockBean
private AsyncTransferService tapeService; private LocationDAO locationDao;
@MockBean
private AsyncTransferService asyncTransfService;
@Autowired @Autowired
private MockMvc mockMvc; 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 @Test
public void testPullFromVoSpaceAsync() throws Exception { public void testPullFromVoSpaceAsync() throws Exception {
...@@ -99,9 +127,32 @@ public class TransferControllerTest { ...@@ -99,9 +127,32 @@ public class TransferControllerTest {
} }
@Test @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") String redirect = mockMvc.perform(post("/transfers?PHASE=RUN")
.content(requestBody) .content(requestBody)
...@@ -112,8 +163,6 @@ public class TransferControllerTest { ...@@ -112,8 +163,6 @@ public class TransferControllerTest {
.andReturn().getResponse().getHeader("Location"); .andReturn().getResponse().getHeader("Location");
assertThat(redirect, matchesPattern("^/transfers/.*")); assertThat(redirect, matchesPattern("^/transfers/.*"));
verify(tapeService, times(1)).startJob(any());
} }
@Test @Test
...@@ -210,7 +259,6 @@ public class TransferControllerTest { ...@@ -210,7 +259,6 @@ public class TransferControllerTest {
.andDo(print()) .andDo(print())
.andExpect(status().is4xxClientError()); .andExpect(status().is4xxClientError());
String xml2 = mockMvc.perform(get("/transfers") String xml2 = mockMvc.perform(get("/transfers")
.header("Authorization", "Bearer user1_token") .header("Authorization", "Bearer user1_token")
.accept(MediaType.APPLICATION_XML)) .accept(MediaType.APPLICATION_XML))
......
...@@ -2,7 +2,10 @@ package it.inaf.oats.vospace; ...@@ -2,7 +2,10 @@ package it.inaf.oats.vospace;
import it.inaf.ia2.aa.ServletRapClient; import it.inaf.ia2.aa.ServletRapClient;
import it.inaf.ia2.aa.data.User; 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.NodeDAO;
import it.inaf.oats.vospace.persistence.model.Location;
import it.inaf.oats.vospace.persistence.model.LocationType;
import java.util.Optional; import java.util.Optional;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.uws.v1.JobSummary;
...@@ -11,11 +14,13 @@ import net.ivoa.xml.vospace.v2.Node; ...@@ -11,11 +14,13 @@ import net.ivoa.xml.vospace.v2.Node;
import net.ivoa.xml.vospace.v2.Property; import net.ivoa.xml.vospace.v2.Property;
import net.ivoa.xml.vospace.v2.Transfer; import net.ivoa.xml.vospace.v2.Transfer;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
...@@ -32,7 +37,10 @@ import org.springframework.test.context.TestPropertySource; ...@@ -32,7 +37,10 @@ import org.springframework.test.context.TestPropertySource;
public class UriServiceTest { public class UriServiceTest {
@MockBean @MockBean
private NodeDAO dao; private NodeDAO nodeDAO;
@MockBean
private LocationDAO locationDAO;
@MockBean @MockBean
private ServletRapClient rapClient; private ServletRapClient rapClient;
...@@ -56,6 +64,13 @@ public class UriServiceTest { ...@@ -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 @Test
public void testPublicUrl() { public void testPublicUrl() {
...@@ -65,10 +80,10 @@ public class UriServiceTest { ...@@ -65,10 +80,10 @@ public class UriServiceTest {
property.setValue("true"); property.setValue("true");
node.getProperties().add(property); 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(); 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()); assertEquals("http://file-service/mydata1?jobId=job-id", job.getResults().get(0).getHref());
} }
...@@ -78,7 +93,7 @@ public class UriServiceTest { ...@@ -78,7 +93,7 @@ public class UriServiceTest {
Node node = new DataNode(); 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); User user = mock(User.class);
when(user.getAccessToken()).thenReturn("<token>"); when(user.getAccessToken()).thenReturn("<token>");
...@@ -92,11 +107,27 @@ public class UriServiceTest { ...@@ -92,11 +107,27 @@ public class UriServiceTest {
}), any())).thenReturn("<new-token>"); }), any())).thenReturn("<new-token>");
JobSummary job = getJob(); 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()); 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() { private JobSummary getJob() {
Transfer transfer = new Transfer(); 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; package it.inaf.oats.vospace.persistence;
import it.inaf.oats.vospace.datamodel.NodeProperties; 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.ArrayList;
import java.util.List; import java.util.List;
import javax.sql.DataSource; import javax.sql.DataSource;
...@@ -90,6 +90,27 @@ public class NodeDAOTest { ...@@ -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) { private String getProperty(Node node, String uri) {
for (Property property : node.getProperties()) { for (Property property : node.getProperties()) {
if (uri.equals(property.getUri())) { 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:transfer xmlns:vos="http://www.ivoa.net/xml/VOSpace/v2.0" version="2.1">
<vos:target>vos://example.com!vospace/mynode</vos:target> <vos:target>vos://example.com!vospace/mynode</vos:target>
<vos:direction>pullToVoSpace</vos:direction> <vos:direction>pullToVoSpace</vos:direction>
<vos:protocol uri="ivo://ivoa.net/vospace/core#httpget" /> <vos:protocol uri="ia2:async-recall" />
</vos:transfer> </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