Skip to content
Snippets Groups Projects
Commit abe8db57 authored by Adam Laskowski's avatar Adam Laskowski
Browse files

SSDM-13251: Added support for list and read methods to client. Refactored and reformatted tests.

parent 3f1f86f0
No related branches found
No related tags found
1 merge request!40SSDM-13578 : 2PT : Database and V3 Implementation - include the new AFS "free"...
...@@ -21,6 +21,7 @@ import ch.ethz.sis.afsjson.JsonObjectMapper; ...@@ -21,6 +21,7 @@ import ch.ethz.sis.afsjson.JsonObjectMapper;
import ch.ethz.sis.afsjson.jackson.JacksonObjectMapper; import ch.ethz.sis.afsjson.jackson.JacksonObjectMapper;
import lombok.NonNull; import lombok.NonNull;
public final class AfsClient implements PublicAPI public final class AfsClient implements PublicAPI
{ {
...@@ -89,22 +90,15 @@ public final class AfsClient implements PublicAPI ...@@ -89,22 +90,15 @@ public final class AfsClient implements PublicAPI
@Override @Override
public @NonNull Boolean isSessionValid() throws Exception public @NonNull Boolean isSessionValid() throws Exception
{ {
if (getSessionToken() == null) validateSessionToken();
{
throw new IllegalStateException("No session information detected!");
}
return request("GET", "isSessionValid", Map.of("sessionToken", getSessionToken())); return request("GET", "isSessionValid", Map.of("sessionToken", getSessionToken()));
} }
@Override @Override
public @NonNull Boolean logout() throws Exception public @NonNull Boolean logout() throws Exception
{ {
if (getSessionToken() == null) validateSessionToken();
{ Boolean result = request("POST", "logout", Map.of(), getSessionToken().getBytes());
throw new IllegalStateException("No session information detected!");
}
// Boolean result = request("POST", "logout", Map.of(), getSessionToken().getBytes());
Boolean result = request("POST", "logout", Map.of("sessionToken", getSessionToken()));
setSessionToken(null); setSessionToken(null);
return result; return result;
} }
...@@ -113,14 +107,21 @@ public final class AfsClient implements PublicAPI ...@@ -113,14 +107,21 @@ public final class AfsClient implements PublicAPI
public @NonNull List<File> list(@NonNull final String owner, @NonNull final String source, public @NonNull List<File> list(@NonNull final String owner, @NonNull final String source,
@NonNull final Boolean recursively) throws Exception @NonNull final Boolean recursively) throws Exception
{ {
return null; validateSessionToken();
return request("GET", "list",
Map.of("owner", owner, "source", source, "recursively",
recursively.toString(), "sessionToken", getSessionToken()));
} }
@Override @Override
public @NonNull byte[] read(@NonNull final String owner, @NonNull final String source, public @NonNull byte[] read(@NonNull final String owner, @NonNull final String source,
@NonNull final Long offset, @NonNull final Integer limit) throws Exception @NonNull final Long offset, @NonNull final Integer limit) throws Exception
{ {
return new byte[0]; validateSessionToken();
return request("GET", "read",
Map.of("owner", owner, "source", source, "offset",
offset.toString(), "limit", limit.toString(), "sessionToken",
getSessionToken()));
} }
@Override @Override
...@@ -229,16 +230,22 @@ public final class AfsClient implements PublicAPI ...@@ -229,16 +230,22 @@ public final class AfsClient implements PublicAPI
final int statusCode = httpResponse.statusCode(); final int statusCode = httpResponse.statusCode();
if (statusCode >= 200 && statusCode < 300) if (statusCode >= 200 && statusCode < 300)
{ {
final ApiResponse response = if (!httpResponse.headers().map().containsKey("content-type"))
jsonObjectMapper.readValue(new ByteArrayInputStream(httpResponse.body()),
ApiResponse.class);
if (response.getError() != null)
{ {
throw ClientExceptions.API_ERROR.getInstance(response.getError()); throw new IllegalArgumentException(
} else "Server error HTTP response. Missing content-type");
}
String content = httpResponse.headers().map().get("content-type").get(0);
switch (content)
{ {
return (T) response.getResult(); case "application/json":
return parseJsonResponse(httpResponse);
case "application/octet-stream":
return (T) httpResponse.body();
default:
throw new IllegalArgumentException(
"Client error HTTP response. Unsupported content-type received.");
} }
} else if (statusCode >= 400 && statusCode < 500) } else if (statusCode >= 400 && statusCode < 500)
{ {
...@@ -252,4 +259,27 @@ public final class AfsClient implements PublicAPI ...@@ -252,4 +259,27 @@ public final class AfsClient implements PublicAPI
} }
} }
private <T> T parseJsonResponse(final HttpResponse<byte[]> httpResponse) throws Exception
{
final ApiResponse response =
jsonObjectMapper.readValue(new ByteArrayInputStream(httpResponse.body()),
ApiResponse.class);
if (response.getError() != null)
{
throw ClientExceptions.API_ERROR.getInstance(response.getError());
} else
{
return (T) response.getResult();
}
}
private void validateSessionToken()
{
if (getSessionToken() == null)
{
throw new IllegalStateException("No session information detected!");
}
}
} }
...@@ -14,11 +14,14 @@ public class AfsClientTest ...@@ -14,11 +14,14 @@ public class AfsClientTest
private static DummyHttpServer httpServer; private static DummyHttpServer httpServer;
private AfsClient afsClient; private AfsClient afsClient;
private static final int HTTP_SERVER_PORT = 8085; private static final int HTTP_SERVER_PORT = 8085;
private static final String HTTP_SERVER_PATH = "/fileserver"; private static final String HTTP_SERVER_PATH = "/fileserver";
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception
{
httpServer = new DummyHttpServer(HTTP_SERVER_PORT, HTTP_SERVER_PATH); httpServer = new DummyHttpServer(HTTP_SERVER_PORT, HTTP_SERVER_PATH);
httpServer.start(); httpServer.start();
afsClient = new AfsClient( afsClient = new AfsClient(
...@@ -27,7 +30,8 @@ public class AfsClientTest ...@@ -27,7 +30,8 @@ public class AfsClientTest
} }
@After @After
public void tearDown() { public void tearDown()
{
httpServer.stop(); httpServer.stop();
} }
...@@ -45,9 +49,10 @@ public class AfsClientTest ...@@ -45,9 +49,10 @@ public class AfsClientTest
{ {
try try
{ {
afsClient.isSessionValid(); afsClient.isSessionValid();
fail(); fail();
} catch (IllegalStateException e) { } catch (IllegalStateException e)
{
assertThat(e.getMessage(), containsString("No session information detected!")); assertThat(e.getMessage(), containsString("No session information detected!"));
} }
} }
...@@ -71,7 +76,8 @@ public class AfsClientTest ...@@ -71,7 +76,8 @@ public class AfsClientTest
{ {
afsClient.logout(); afsClient.logout();
fail(); fail();
} catch (IllegalStateException e) { } catch (IllegalStateException e)
{
assertThat(e.getMessage(), containsString("No session information detected!")); assertThat(e.getMessage(), containsString("No session information detected!"));
} }
} }
...@@ -91,27 +97,42 @@ public class AfsClientTest ...@@ -91,27 +97,42 @@ public class AfsClientTest
} }
@Test @Test
public void testList() throws Exception public void list_methodIsGet() throws Exception
{ {
login();
httpServer.setNextResponse("{\"result\": null}");
afsClient.list("", "", true);
assertEquals("GET", httpServer.getHttpExchange().getRequestMethod());
} }
@Test @Test
public void testRead()throws Exception public void read_methodIsGet() throws Exception
{ {
login();
byte[] data = "ABCD".getBytes();
httpServer.setNextResponse(data);
byte[] result = afsClient.read("admin", "/", 0L, 1000);
assertEquals("GET", httpServer.getHttpExchange().getRequestMethod());
assertArrayEquals(data, result);
} }
@Test @Test
public void testWrite()throws Exception public void testWrite() throws Exception
{ {
} }
@Test @Test
public void testDelete()throws Exception public void testDelete() throws Exception
{ {
} }
@Test @Test
public void testCopy()throws Exception public void testCopy() throws Exception
{ {
} }
...@@ -145,4 +166,8 @@ public class AfsClientTest ...@@ -145,4 +166,8 @@ public class AfsClientTest
{ {
} }
private void login() throws Exception {
afsClient.login("test", "test");
}
} }
\ No newline at end of file
...@@ -35,7 +35,9 @@ public final class DummyHttpServer ...@@ -35,7 +35,9 @@ public final class DummyHttpServer
private static final String DEFAULT_RESPONSE = "{\"result\": \"success\"}"; private static final String DEFAULT_RESPONSE = "{\"result\": \"success\"}";
private String nextResponse = DEFAULT_RESPONSE; private byte[] nextResponse = DEFAULT_RESPONSE.getBytes();
private String nextResponseType = "application/json";
private HttpExchange httpExchange; private HttpExchange httpExchange;
public DummyHttpServer(int httpServerPort, String httpServerPath) throws IOException public DummyHttpServer(int httpServerPort, String httpServerPath) throws IOException
...@@ -47,8 +49,10 @@ public final class DummyHttpServer ...@@ -47,8 +49,10 @@ public final class DummyHttpServer
{ {
public void handle(HttpExchange exchange) throws IOException public void handle(HttpExchange exchange) throws IOException
{ {
byte[] response = nextResponse.getBytes(); byte[] response = nextResponse;
exchange.getResponseHeaders().set("content-type", nextResponseType);
exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, response.length); exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, response.length);
exchange.getResponseBody().write(response); exchange.getResponseBody().write(response);
exchange.close(); exchange.close();
httpExchange = exchange; httpExchange = exchange;
...@@ -67,11 +71,19 @@ public final class DummyHttpServer ...@@ -67,11 +71,19 @@ public final class DummyHttpServer
} }
public void setNextResponse(String response) public void setNextResponse(String response)
{
this.nextResponse = response.getBytes();
this.nextResponseType = "application/json";
}
public void setNextResponse(byte[] response)
{ {
this.nextResponse = response; this.nextResponse = response;
this.nextResponseType = "application/octet-stream";
} }
public HttpExchange getHttpExchange() { public HttpExchange getHttpExchange()
{
return httpExchange; return httpExchange;
} }
......
...@@ -156,6 +156,7 @@ public class ApiServerAdapter<CONNECTION, API> implements HttpServerHandler ...@@ -156,6 +156,7 @@ public class ApiServerAdapter<CONNECTION, API> implements HttpServerHandler
} }
} }
// Process body parameters
switch (method) { switch (method) {
case "write": case "write":
methodParameters.put("data", requestBody); methodParameters.put("data", requestBody);
...@@ -166,9 +167,11 @@ public class ApiServerAdapter<CONNECTION, API> implements HttpServerHandler ...@@ -166,9 +167,11 @@ public class ApiServerAdapter<CONNECTION, API> implements HttpServerHandler
methodParameters.put("userId", credentials[0]); methodParameters.put("userId", credentials[0]);
methodParameters.put("password", credentials[1]); methodParameters.put("password", credentials[1]);
break; break;
case "logout":
sessionToken = new String(requestBody, UTF_8);
break;
} }
ApiRequest apiRequest = new ApiRequest("1", method, methodParameters, sessionToken, ApiRequest apiRequest = new ApiRequest("1", method, methodParameters, sessionToken,
interactiveSessionKey, transactionManagerKey); interactiveSessionKey, transactionManagerKey);
Response response = Response response =
......
...@@ -64,7 +64,7 @@ public class ExecutorProxy extends AbstractProxy { ...@@ -64,7 +64,7 @@ public class ExecutorProxy extends AbstractProxy {
// //
public String getPath(String owner, String source) { public String getPath(String owner, String source) {
return IOUtils.PATH_SEPARATOR + owner.toString() + source; return String.join(""+IOUtils.PATH_SEPARATOR, "", owner.toString(), source);
} }
@Override @Override
......
...@@ -21,9 +21,15 @@ import static org.hamcrest.MatcherAssert.assertThat; ...@@ -21,9 +21,15 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.UUID;
import ch.ethz.sis.afsapi.dto.File;
import ch.ethz.sis.shared.io.IOUtils;
import org.apache.commons.io.FileUtils;
import org.junit.*; import org.junit.*;
import ch.ethz.sis.afs.manager.TransactionConnection; import ch.ethz.sis.afs.manager.TransactionConnection;
...@@ -32,6 +38,7 @@ import ch.ethz.sis.afsserver.server.Server; ...@@ -32,6 +38,7 @@ import ch.ethz.sis.afsserver.server.Server;
import ch.ethz.sis.afsserver.server.observer.impl.DummyServerObserver; import ch.ethz.sis.afsserver.server.observer.impl.DummyServerObserver;
import ch.ethz.sis.afsserver.startup.AtomicFileSystemServerParameter; import ch.ethz.sis.afsserver.startup.AtomicFileSystemServerParameter;
import ch.ethz.sis.shared.startup.Configuration; import ch.ethz.sis.shared.startup.Configuration;
import org.junit.rules.TemporaryFolder;
public final class ApiClientTest public final class ApiClientTest
{ {
...@@ -43,6 +50,16 @@ public final class ApiClientTest ...@@ -43,6 +50,16 @@ public final class ApiClientTest
private static String httpServerPath; private static String httpServerPath;
private static String storageRoot;
public static final String FILE_A = "A.txt";
public static final byte[] DATA = "ABCD".getBytes();
public static final String FILE_B = "B.txt";
public static String owner = UUID.randomUUID().toString();
@BeforeClass @BeforeClass
public static void classSetUp() throws Exception public static void classSetUp() throws Exception
{ {
...@@ -55,25 +72,33 @@ public final class ApiClientTest ...@@ -55,25 +72,33 @@ public final class ApiClientTest
configuration.getIntegerProperty(AtomicFileSystemServerParameter.httpServerPort); configuration.getIntegerProperty(AtomicFileSystemServerParameter.httpServerPort);
httpServerPath = httpServerPath =
configuration.getStringProperty(AtomicFileSystemServerParameter.httpServerUri); configuration.getStringProperty(AtomicFileSystemServerParameter.httpServerUri);
storageRoot = configuration.getStringProperty(AtomicFileSystemServerParameter.storageRoot);
}
@AfterClass
public static void classTearDown() throws Exception
{
afsServer.shutdown(true);
} }
@Before @Before
public void setUp() throws Exception public void setUp() throws Exception
{ {
String testDataRoot = IOUtils.getPath(storageRoot, owner.toString());
IOUtils.createDirectories(testDataRoot);
String testDataFile = IOUtils.getPath(testDataRoot, FILE_A);
IOUtils.createFile(testDataFile);
IOUtils.write(testDataFile, 0, DATA);
afsClient = new AfsClient( afsClient = new AfsClient(
new URI("http", null, "localhost", httpServerPort, new URI("http", null, "localhost", httpServerPort,
httpServerPath, null, null)); httpServerPath, null, null));
} }
private String login() throws Exception @After
{ public void deleteTestData() throws IOException
return afsClient.login("test", "test");
}
@AfterClass
public static void classTearDown() throws Exception
{ {
afsServer.shutdown(true); IOUtils.delete(storageRoot);
} }
@Test @Test
...@@ -128,4 +153,29 @@ public final class ApiClientTest ...@@ -128,4 +153,29 @@ public final class ApiClientTest
assertTrue(result); assertTrue(result);
} }
@Test
public void list_getsDataListFromTemporaryFolder() throws Exception
{
login();
List<File> list = afsClient.list(owner, "", Boolean.TRUE);
assertEquals(1, list.size());
assertEquals(FILE_A, list.get(0).getName());
}
@Test
public void read_getsDataFromTemporaryFile() throws Exception {
login();
byte[] bytes = afsClient.read(owner, FILE_A, 0L, DATA.length);
assertArrayEquals(DATA, bytes);
}
private String login() throws Exception
{
return afsClient.login("test", "test");
}
} }
...@@ -33,27 +33,27 @@ import static org.junit.Assert.assertArrayEquals; ...@@ -33,27 +33,27 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public abstract class PublicApiTest extends AbstractTest { public abstract class PublicApiTest extends AbstractTest
{
public abstract PublicAPI getPublicAPI() throws Exception; public abstract PublicAPI getPublicAPI() throws Exception;
public static final String ROOT = IOUtils.PATH_SEPARATOR_AS_STRING; public static final String ROOT = IOUtils.PATH_SEPARATOR_AS_STRING;
// public static final String DIR_A = "A";
// public static final String DIR_B = "B";
public static final String FILE_A = "A.txt"; public static final String FILE_A = "A.txt";
public static final byte[] DATA = "ABCD".getBytes(); public static final byte[] DATA = "ABCD".getBytes();
public static final String FILE_B = "B.txt"; public static final String FILE_B = "B.txt";
// public static final String DIR_A_PATH = IOUtils.PATH_SEPARATOR + getPath(DIR_A);
// public static final String DIR_B_PATH = IOUtils.PATH_SEPARATOR + getPath(DIR_B);
// public static final String FILE_A_PATH = getPath(DIR_A_PATH, FILE_A);
// public static final String FILE_B_PATH = getPath(DIR_B_PATH, FILE_B);
public String owner = UUID.randomUUID().toString(); public String owner = UUID.randomUUID().toString();
@Before @Before
public void createTestData() throws IOException { public void createTestData() throws IOException
{
String storageRoot = ServerClientEnvironmentFS.getInstance() String storageRoot = ServerClientEnvironmentFS.getInstance()
.getDefaultServerConfiguration().getStringProperty(AtomicFileSystemServerParameter.storageRoot); .getDefaultServerConfiguration()
.getStringProperty(AtomicFileSystemServerParameter.storageRoot);
String testDataRoot = IOUtils.getPath(storageRoot, owner.toString()); String testDataRoot = IOUtils.getPath(storageRoot, owner.toString());
IOUtils.createDirectories(testDataRoot); IOUtils.createDirectories(testDataRoot);
String testDataFile = IOUtils.getPath(testDataRoot, FILE_A); String testDataFile = IOUtils.getPath(testDataRoot, FILE_A);
...@@ -62,43 +62,51 @@ public abstract class PublicApiTest extends AbstractTest { ...@@ -62,43 +62,51 @@ public abstract class PublicApiTest extends AbstractTest {
} }
@After @After
public void deleteTestData() throws IOException { public void deleteTestData() throws IOException
{
String storageRoot = ServerClientEnvironmentFS.getInstance() String storageRoot = ServerClientEnvironmentFS.getInstance()
.getDefaultServerConfiguration().getStringProperty(AtomicFileSystemServerParameter.storageRoot); .getDefaultServerConfiguration()
.getStringProperty(AtomicFileSystemServerParameter.storageRoot);
IOUtils.delete(storageRoot); IOUtils.delete(storageRoot);
String writeAheadLogRoot = ServerClientEnvironmentFS.getInstance() String writeAheadLogRoot = ServerClientEnvironmentFS.getInstance()
.getDefaultServerConfiguration().getStringProperty(AtomicFileSystemServerParameter.writeAheadLogRoot); .getDefaultServerConfiguration()
.getStringProperty(AtomicFileSystemServerParameter.writeAheadLogRoot);
IOUtils.delete(writeAheadLogRoot); IOUtils.delete(writeAheadLogRoot);
} }
@Test @Test
public void list() throws Exception { public void list() throws Exception
{
List<File> list = getPublicAPI().list(owner, ROOT, Boolean.TRUE); List<File> list = getPublicAPI().list(owner, ROOT, Boolean.TRUE);
assertEquals(1, list.size()); assertEquals(1, list.size());
assertEquals(FILE_A, list.get(0).getName()); assertEquals(FILE_A, list.get(0).getName());
} }
@Test @Test
public void read() throws Exception { public void read() throws Exception
{
byte[] bytes = getPublicAPI().read(owner, "/" + FILE_A, 0L, DATA.length); byte[] bytes = getPublicAPI().read(owner, "/" + FILE_A, 0L, DATA.length);
assertArrayEquals(DATA, bytes); assertArrayEquals(DATA, bytes);
} }
@Test(expected = RuntimeException.class) @Test(expected = RuntimeException.class)
public void read_big_failure() throws Exception { public void read_big_failure() throws Exception
{
byte[] bytes = getPublicAPI().read(owner, "/" + FILE_A, 0L, Integer.MAX_VALUE); byte[] bytes = getPublicAPI().read(owner, "/" + FILE_A, 0L, Integer.MAX_VALUE);
assertArrayEquals(DATA, bytes); assertArrayEquals(DATA, bytes);
} }
@Test @Test
public void write() throws Exception { public void write() throws Exception
{
getPublicAPI().write(owner, "/" + FILE_B, 0L, DATA, IOUtils.getMD5(DATA)); getPublicAPI().write(owner, "/" + FILE_B, 0L, DATA, IOUtils.getMD5(DATA));
byte[] bytes = getPublicAPI().read(owner, "/" + FILE_B, 0L, DATA.length); byte[] bytes = getPublicAPI().read(owner, "/" + FILE_B, 0L, DATA.length);
assertArrayEquals(DATA, bytes); assertArrayEquals(DATA, bytes);
} }
@Test @Test
public void delete() throws Exception { public void delete() throws Exception
{
Boolean deleted = getPublicAPI().delete(owner, "/" + FILE_A); Boolean deleted = getPublicAPI().delete(owner, "/" + FILE_A);
assertTrue(deleted); assertTrue(deleted);
List<File> list = getPublicAPI().list(owner, ROOT, Boolean.TRUE); List<File> list = getPublicAPI().list(owner, ROOT, Boolean.TRUE);
...@@ -106,14 +114,16 @@ public abstract class PublicApiTest extends AbstractTest { ...@@ -106,14 +114,16 @@ public abstract class PublicApiTest extends AbstractTest {
} }
@Test @Test
public void copy() throws Exception { public void copy() throws Exception
{
getPublicAPI().copy(owner, "/" + FILE_A, owner, "/" + FILE_B); getPublicAPI().copy(owner, "/" + FILE_A, owner, "/" + FILE_B);
byte[] bytes = getPublicAPI().read(owner, "/" + FILE_B, 0L, DATA.length); byte[] bytes = getPublicAPI().read(owner, "/" + FILE_B, 0L, DATA.length);
assertArrayEquals(DATA, bytes); assertArrayEquals(DATA, bytes);
} }
@Test @Test
public void move() throws Exception { public void move() throws Exception
{
getPublicAPI().move(owner, "/" + FILE_A, owner, "/" + FILE_B); getPublicAPI().move(owner, "/" + FILE_A, owner, "/" + FILE_B);
List<File> list = getPublicAPI().list(owner, ROOT, Boolean.TRUE); List<File> list = getPublicAPI().list(owner, ROOT, Boolean.TRUE);
assertEquals(1, list.size()); assertEquals(1, list.size());
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment