summaryrefslogtreecommitdiffstats
path: root/configserver
diff options
context:
space:
mode:
authorHarald Musum <musum@yahoo-inc.com>2017-01-06 08:44:09 +0100
committerHarald Musum <musum@yahoo-inc.com>2017-01-06 08:44:09 +0100
commit0b0b72c9dff286d3cc0c7fd79f1bea9bd2c6f0a7 (patch)
tree06122cccf108ad5899aaff8c345b2e398c23543e /configserver
parente22014851a75fd89b78e05aa860ba5532883027c (diff)
Refactor content handlers, first step
* Move most of logic into ApplicationRepository * Remove unnneded base class
Diffstat (limited to 'configserver')
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java33
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/ContentRequest.java19
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationContentRequest.java18
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java18
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandler.java31
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentRequestV2.java21
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/SessionContentHandlerTestBase.java126
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandlerTest.java116
8 files changed, 194 insertions, 188 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
index 8ba71d7533e..8e706b7056a 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
@@ -1,16 +1,16 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server;
+import com.yahoo.config.application.api.ApplicationFile;
import com.yahoo.config.application.api.ApplicationMetaData;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.HostFilter;
import com.yahoo.config.provision.Provisioner;
import com.yahoo.config.provision.TenantName;
-import com.yahoo.config.provision.Zone;
-import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.log.LogLevel;
+import com.yahoo.path.Path;
import com.yahoo.transaction.NestedTransaction;
import com.yahoo.vespa.config.server.application.Application;
import com.yahoo.vespa.config.server.application.ApplicationConvergenceChecker;
@@ -19,8 +19,6 @@ import com.yahoo.vespa.config.server.application.LogServerLogGrabber;
import com.yahoo.vespa.config.server.application.TenantApplications;
import com.yahoo.vespa.config.server.configchange.ConfigChangeActions;
import com.yahoo.vespa.config.server.deploy.Deployment;
-import com.yahoo.vespa.config.server.http.ContentHandler;
-import com.yahoo.vespa.config.server.http.v2.ApplicationContentRequest;
import com.yahoo.vespa.config.server.provision.HostProvisionerProvider;
import com.yahoo.vespa.config.server.session.LocalSession;
import com.yahoo.vespa.config.server.session.LocalSessionRepo;
@@ -60,7 +58,6 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
private final Curator curator;
private final LogServerLogGrabber logServerLogGrabber;
private final ApplicationConvergenceChecker convergeChecker;
- private final ContentHandler contentHandler = new ContentHandler();
private final Clock clock;
private final DeployLogger logger = new SilentDeployLogger();
@@ -141,8 +138,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
transaction.add(tenantApplications.deleteApplication(applicationId));
- if (hostProvisioner.isPresent())
- hostProvisioner.get().remove(transaction, applicationId);
+ hostProvisioner.ifPresent(provisioner -> provisioner.remove(transaction, applicationId));
transaction.onCommitted(() -> log.log(LogLevel.INFO, "Deleted " + applicationId));
transaction.commit();
@@ -173,25 +169,24 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
return getApplication(tenant, applicationId).getApplicationGeneration();
}
- public HttpResponse getContent(Tenant tenant, ApplicationId applicationId, Zone zone, HttpRequest request) {
- LocalSession session = getLocalSession(tenant, tenant.getApplicationRepo().getSessionIdForApplication(applicationId));
- return contentHandler.get(ApplicationContentRequest.create(request, session, applicationId, zone));
- }
-
private Application getApplication(Tenant tenant, ApplicationId applicationId) {
- long sessionId = tenant.getApplicationRepo().getSessionIdForApplication(applicationId);
+ long sessionId = getSessionIdForApplication(tenant, applicationId);
RemoteSession session = tenant.getRemoteSessionRepo().getSession(sessionId, 0);
return session.ensureApplicationLoaded().getForVersionOrLatest(Optional.empty());
}
- public LocalSession getLocalSession(Tenant tenant, long sessionId) {
+ public long getSessionIdForApplication(Tenant tenant, ApplicationId applicationId) {
+ return tenant.getApplicationRepo().getSessionIdForApplication(applicationId);
+ }
+
+ private LocalSession getLocalSession(Tenant tenant, long sessionId) {
LocalSession session = tenant.getLocalSessionRepo().getSession(sessionId);
if (session == null) throw new NotFoundException("Session " + sessionId + " was not found");
return session;
}
- public RemoteSession getRemoteSession(Tenant tenant, long sessionId) {
+ private RemoteSession getRemoteSession(Tenant tenant, long sessionId) {
RemoteSession session = tenant.getRemoteSessionRepo().getSession(sessionId);
if (session == null) throw new NotFoundException("Session " + sessionId + " was not found");
@@ -199,8 +194,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
}
public void restart(ApplicationId applicationId, HostFilter hostFilter) {
- if (hostProvisioner.isPresent())
- hostProvisioner.get().restart(applicationId, hostFilter);
+ hostProvisioner.ifPresent(provisioner -> provisioner.restart(applicationId, hostFilter));
}
public Tenant verifyTenantAndApplication(ApplicationId applicationId) {
@@ -310,6 +304,11 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
return session.getSessionId();
}
+ public ApplicationFile getApplicationFileFromSession(TenantName tenantName, long sessionId, String path, LocalSession.Mode mode) {
+ Tenant tenant = tenants.getTenant(tenantName);
+ return getLocalSession(tenant, sessionId).getApplicationFile(Path.fromString(path), mode);
+ }
+
private LocalSession getExistingSession(Tenant tenant, ApplicationId applicationId) {
TenantApplications applicationRepo = tenant.getApplicationRepo();
return getLocalSession(tenant, applicationRepo.getSessionIdForApplication(applicationId));
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/ContentRequest.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/ContentRequest.java
index d71987449bf..3446d84bdf1 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/ContentRequest.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/ContentRequest.java
@@ -3,11 +3,11 @@ package com.yahoo.vespa.config.server.http;
import com.yahoo.config.application.api.ApplicationFile;
import com.yahoo.container.jdisc.HttpRequest;
-import com.yahoo.path.Path;
-import com.yahoo.vespa.config.server.session.LocalSession;
import java.io.InputStream;
+import static com.yahoo.vespa.config.server.session.LocalSession.Mode;
+
/**
* Represents a {@link ContentRequest}, and contains common functionality for content requests for all content handlers.
*
@@ -24,20 +24,20 @@ public abstract class ContentRequest {
private final ApplicationFile file;
private final HttpRequest request;
- protected ContentRequest(HttpRequest request, LocalSession session) {
+ protected ContentRequest(HttpRequest request, long sessionId, String path, ApplicationFile applicationFile) {
this.request = request;
- this.sessionId = session.getSessionId();
- this.path = getContentPath(request);
- this.file = session.getApplicationFile(Path.fromString(path), getApplicationFileMode(request.getMethod()));
+ this.sessionId = sessionId;
+ this.path = path;
+ this.file = applicationFile;
}
- private LocalSession.Mode getApplicationFileMode(com.yahoo.jdisc.http.HttpRequest.Method method) {
+ public static Mode getApplicationFileMode(com.yahoo.jdisc.http.HttpRequest.Method method) {
switch (method) {
case GET:
case OPTIONS:
- return LocalSession.Mode.READ;
+ return Mode.READ;
default:
- return LocalSession.Mode.WRITE;
+ return Mode.WRITE;
}
}
@@ -59,7 +59,6 @@ public abstract class ContentRequest {
}
protected abstract String getPathPrefix();
- protected abstract String getContentPath(HttpRequest request);
String getUrlBase(String appendStr) {
return Utils.getUrlBase(request, getPathPrefix() + appendStr);
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationContentRequest.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationContentRequest.java
index 2b5bc4b3d35..823300a3f85 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationContentRequest.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationContentRequest.java
@@ -1,13 +1,13 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.http.v2;
+import com.yahoo.config.application.api.ApplicationFile;
import com.yahoo.config.provision.Zone;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.jdisc.application.BindingMatch;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.vespa.config.server.http.ContentRequest;
import com.yahoo.vespa.config.server.http.Utils;
-import com.yahoo.vespa.config.server.session.LocalSession;
/**
* Represents a content request for an application.
@@ -21,18 +21,18 @@ public class ApplicationContentRequest extends ContentRequest {
private final ApplicationId applicationId;
private final Zone zone;
- private ApplicationContentRequest(HttpRequest request, LocalSession session, ApplicationId applicationId, Zone zone) {
- super(request, session);
+ ApplicationContentRequest(HttpRequest request,
+ long sessionId,
+ ApplicationId applicationId,
+ Zone zone,
+ String contentPath,
+ ApplicationFile applicationFile) {
+ super(request, sessionId, contentPath, applicationFile);
this.applicationId = applicationId;
this.zone = zone;
}
- public static ContentRequest create(HttpRequest request, LocalSession session, ApplicationId applicationId, Zone zone) {
- return new ApplicationContentRequest(request, session, applicationId, zone);
- }
-
- @Override
- protected String getContentPath(HttpRequest request) {
+ static String getContentPath(HttpRequest request) {
BindingMatch<?> bm = Utils.getBindingMatch(request, uriPattern);
return bm.group(7);
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
index 21e97cf0fa8..b51eede04bb 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
@@ -1,6 +1,7 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.http.v2;
+import com.yahoo.config.application.api.ApplicationFile;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ApplicationName;
import com.yahoo.config.provision.HostFilter;
@@ -11,6 +12,8 @@ import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.container.logging.AccessLog;
import com.yahoo.jdisc.Response;
import com.yahoo.jdisc.application.BindingMatch;
+import com.yahoo.vespa.config.server.http.ContentHandler;
+import com.yahoo.vespa.config.server.http.ContentRequest;
import com.yahoo.vespa.config.server.http.HttpConfigResponse;
import com.yahoo.vespa.config.server.tenant.Tenant;
import com.yahoo.vespa.config.server.TimeoutBudget;
@@ -69,7 +72,20 @@ public class ApplicationHandler extends HttpHandler {
return applicationRepository.nodeConvergenceCheck(tenant, applicationId, getHostFromRequest(request), request.getUri());
}
if (isContentRequest(request)) {
- return applicationRepository.getContent(tenant, applicationId, zone, request);
+ long sessionId = applicationRepository.getSessionIdForApplication(tenant, applicationId);
+ String contentPath = ApplicationContentRequest.getContentPath(request);
+ ApplicationFile applicationFile =
+ applicationRepository.getApplicationFileFromSession(tenant.getName(),
+ sessionId,
+ contentPath,
+ ContentRequest.getApplicationFileMode(request.getMethod()));
+ ApplicationContentRequest contentRequest = new ApplicationContentRequest(request,
+ sessionId,
+ applicationId,
+ zone,
+ contentPath,
+ applicationFile);
+ return new ContentHandler().get(contentRequest);
}
// TODO: Remove this once the config convergence logic is moved to client and is live for all clusters.
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandler.java
index 7b55fdea11a..f776062d194 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandler.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandler.java
@@ -2,17 +2,17 @@
package com.yahoo.vespa.config.server.http.v2;
import com.google.inject.Inject;
+import com.yahoo.config.application.api.ApplicationFile;
import com.yahoo.config.provision.TenantName;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.container.logging.AccessLog;
import com.yahoo.vespa.config.server.ApplicationRepository;
-import com.yahoo.vespa.config.server.tenant.Tenant;
+import com.yahoo.vespa.config.server.http.ContentRequest;
import com.yahoo.vespa.config.server.tenant.Tenants;
import com.yahoo.vespa.config.server.http.ContentHandler;
import com.yahoo.vespa.config.server.http.SessionHandler;
import com.yahoo.vespa.config.server.http.Utils;
-import com.yahoo.vespa.config.server.session.LocalSession;
import java.util.concurrent.Executor;
@@ -38,27 +38,34 @@ public class SessionContentHandler extends SessionHandler {
@Override
public HttpResponse handleGET(HttpRequest request) {
- LocalSession session = validateRequestAndGetSession(request);
- return contentHandler.get(SessionContentRequestV2.create(request, session));
+ return contentHandler.get(getContentRequest(request));
}
@Override
public HttpResponse handlePUT(HttpRequest request) {
- LocalSession session = validateRequestAndGetSession(request);
- return contentHandler.put(SessionContentRequestV2.create(request, session));
+ return contentHandler.put(getContentRequest(request));
}
@Override
public HttpResponse handleDELETE(HttpRequest request) {
- LocalSession session = validateRequestAndGetSession(request);
- return contentHandler.delete(SessionContentRequestV2.create(request, session));
+ return contentHandler.delete(getContentRequest(request));
}
- private LocalSession validateRequestAndGetSession(HttpRequest request) {
- final TenantName tenantName = Utils.getTenantNameFromSessionRequest(request);
+ private void validateRequest(TenantName tenantName) {
Utils.checkThatTenantExists(tenants, tenantName);
- Tenant tenant = tenants.getTenant(tenantName);
- return applicationRepository.getLocalSession(tenant, getSessionIdV2(request));
+ }
+
+ private SessionContentRequestV2 getContentRequest(HttpRequest request) {
+ final TenantName tenantName = Utils.getTenantNameFromSessionRequest(request);
+ validateRequest(tenantName);
+ long sessionId = getSessionIdV2(request);
+ String contentPath = SessionContentRequestV2.getContentPath(request);
+ ApplicationFile applicationFile =
+ applicationRepository.getApplicationFileFromSession(tenantName,
+ sessionId,
+ contentPath,
+ ContentRequest.getApplicationFileMode(request.getMethod()));
+ return new SessionContentRequestV2(request, sessionId, tenantName, contentPath, applicationFile);
}
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentRequestV2.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentRequestV2.java
index 30af00dd4d1..af69d67cf22 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentRequestV2.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionContentRequestV2.java
@@ -1,12 +1,12 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.http.v2;
+import com.yahoo.config.application.api.ApplicationFile;
import com.yahoo.config.provision.TenantName;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.jdisc.application.BindingMatch;
import com.yahoo.vespa.config.server.http.ContentRequest;
import com.yahoo.vespa.config.server.http.Utils;
-import com.yahoo.vespa.config.server.session.LocalSession;
/**
* Requests for content and content status (v2)
@@ -15,19 +15,19 @@ import com.yahoo.vespa.config.server.session.LocalSession;
* @author hmusum
* @since 5.3
*/
-class SessionContentRequestV2 extends ContentRequest {
+public class SessionContentRequestV2 extends ContentRequest {
private static final String uriPattern = "http://*/application/v2/tenant/*/session/*/content/*";
private final TenantName tenantName;
private final long sessionId;
- private SessionContentRequestV2(HttpRequest request, LocalSession session, TenantName tenantName) {
- super(request, session);
+ SessionContentRequestV2(HttpRequest request,
+ long sessionId,
+ TenantName tenantName,
+ String path,
+ ApplicationFile applicationFile) {
+ super(request, sessionId, path, applicationFile);
this.tenantName = tenantName;
- this.sessionId = session.getSessionId();
- }
-
- static ContentRequest create(HttpRequest request, LocalSession session) {
- return new SessionContentRequestV2(request, session, Utils.getTenantNameFromSessionRequest(request));
+ this.sessionId = sessionId;
}
@Override
@@ -35,8 +35,7 @@ class SessionContentRequestV2 extends ContentRequest {
return "/application/v2/tenant/" + tenantName.value() + "/session/" + sessionId;
}
- @Override
- protected String getContentPath(HttpRequest request) {
+ static String getContentPath(HttpRequest request) {
BindingMatch<?> bm = Utils.getBindingMatch(request, uriPattern);
return bm.group(4);
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/SessionContentHandlerTestBase.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/SessionContentHandlerTestBase.java
deleted file mode 100644
index 43fdb2d747a..00000000000
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/SessionContentHandlerTestBase.java
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.config.server.http;
-
-import com.google.common.io.Files;
-import com.yahoo.container.jdisc.HttpResponse;
-import com.yahoo.jdisc.Response;
-import com.yahoo.jdisc.http.HttpRequest;
-import com.yahoo.text.Utf8;
-import org.apache.commons.io.FileUtils;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-
-public abstract class SessionContentHandlerTestBase extends ContentHandlerTestBase {
-
- @Test
- public void require_that_directories_can_be_created() throws IOException {
- assertMkdir("/bar/");
- assertMkdir("/bar/brask/");
- assertMkdir("/bar/brask/");
- assertMkdir("/bar/brask/bram/");
- assertMkdir("/brask/og/bram/");
- }// TODO: Enable when we have a predictable way of checking request body existence.
-
- @Test
- @Ignore
- public void require_that_mkdir_with_body_is_illegal() throws IOException {
- HttpResponse response = put("/foobio/", "foo");
- assertNotNull(response);
- assertThat(response.getStatus(), is(Response.Status.BAD_REQUEST));
- }
-
- @Test
- public void require_that_nonexistant_session_returns_not_found() throws IOException {
- HttpResponse response = doRequest(HttpRequest.Method.GET, "/test.txt", 2l);
- assertNotNull(response);
- assertThat(response.getStatus(), is(Response.Status.NOT_FOUND));
- }
-
- protected HttpResponse put(String path, String content) {
- ByteArrayInputStream data = new ByteArrayInputStream(Utf8.toBytes(content));
- return doRequest(HttpRequest.Method.PUT, path, data);
- }
-
- @Test
- public void require_that_file_write_without_body_is_illegal() throws IOException {
- HttpResponse response = doRequest(HttpRequest.Method.PUT, "/foobio.txt");
- assertNotNull(response);
- assertThat(response.getStatus(), is(Response.Status.BAD_REQUEST));
- }
-
- @Test
- public void require_that_files_can_be_written() throws IOException {
- assertWriteFile("/foo/minfil.txt", "Mycontent");
- assertWriteFile("/foo/minfil.txt", "Differentcontent");
- }
-
- @Test
- public void require_that_nonexistant_file_returs_not_found_when_deleted() throws IOException {
- assertDeleteFile(Response.Status.NOT_FOUND, "/test2.txt", "{\"error-code\":\"NOT_FOUND\",\"message\":\"Session 1 does not contain a file 'test2.txt'\"}");
- }
-
- @Test
- public void require_that_files_can_be_deleted() throws IOException {
- assertDeleteFile(Response.Status.OK, "/test.txt");
- assertDeleteFile(Response.Status.NOT_FOUND, "/test.txt", "{\"error-code\":\"NOT_FOUND\",\"message\":\"Session 1 does not contain a file 'test.txt'\"}");
- assertDeleteFile(Response.Status.BAD_REQUEST, "/newtest", "{\"error-code\":\"BAD_REQUEST\",\"message\":\"File 'newtest' is not an empty directory\"}");
- assertDeleteFile(Response.Status.OK, "/newtest/testfile.txt");
- assertDeleteFile(Response.Status.OK, "/newtest");
- }
-
- @Test
- public void require_that_status_is_given_for_new_files() throws IOException {
- assertStatus("/test.txt?return=status",
- "{\"status\":\"new\",\"md5\":\"d3b07384d113edec49eaa6238ad5ff00\",\"name\":\"http://foo:1337" + pathPrefix + "1/content/test.txt\"}");
- assertWriteFile("/test.txt", "Mycontent");
- assertStatus("/test.txt?return=status",
- "{\"status\":\"changed\",\"md5\":\"01eabd73c69d78d0009ec93cd62d7f77\",\"name\":\"http://foo:1337" + pathPrefix + "1/content/test.txt\"}");
- }
-
- private void assertWriteFile(String path, String content) throws IOException {
- HttpResponse response = put(path, content);
- assertNotNull(response);
- assertThat(response.getStatus(), is(Response.Status.OK));
- assertContent(path, content);
- assertThat(SessionHandlerTest.getRenderedString(response),
- is("{\"prepared\":\"http://foo:1337" + pathPrefix + "1/prepared\"}"));
- }
-
- private void assertDeleteFile(int statusCode, String filePath) throws IOException {
- assertDeleteFile(statusCode, filePath, "{\"prepared\":\"http://foo:1337" + pathPrefix + "1/prepared\"}");
- }
-
- private void assertDeleteFile(int statusCode, String filePath, String expectedResponse) throws IOException {
- HttpResponse response = doRequest(HttpRequest.Method.DELETE, filePath);
- assertNotNull(response);
- assertThat(response.getStatus(), is(statusCode));
- assertThat(SessionHandlerTest.getRenderedString(response), is(expectedResponse));
- }
-
- private void assertMkdir(String path) throws IOException {
- HttpResponse response = doRequest(HttpRequest.Method.PUT, path);
- assertNotNull(response);
- assertThat(response.getStatus(), is(Response.Status.OK));
- assertThat(SessionHandlerTest.getRenderedString(response),
- is("{\"prepared\":\"http://foo:1337" + pathPrefix + "1/prepared\"}"));
- }
-
- protected File createTestApp() throws IOException {
- File testApp = Files.createTempDir();
- FileUtils.copyDirectory(new File("src/test/apps/content"), testApp);
- return testApp;
- }
-
- protected abstract HttpResponse doRequest(HttpRequest.Method method, String path, long sessionId);
- protected abstract HttpResponse doRequest(HttpRequest.Method method, String path, InputStream data);
- protected abstract HttpResponse doRequest(HttpRequest.Method method, String path, long sessionId, InputStream data);
-} \ No newline at end of file
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandlerTest.java
index 0f6a400ca1e..224cd5d28d1 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandlerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionContentHandlerTest.java
@@ -1,28 +1,41 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.http.v2;
+import com.google.common.io.Files;
import com.yahoo.config.model.application.provider.FilesApplicationPackage;
import com.yahoo.config.provision.TenantName;
import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.container.logging.AccessLog;
+import com.yahoo.jdisc.Response;
import com.yahoo.jdisc.http.HttpRequest;
+import com.yahoo.text.Utf8;
import com.yahoo.vespa.config.server.ApplicationRepository;
import com.yahoo.vespa.config.server.application.ApplicationConvergenceChecker;
import com.yahoo.vespa.config.server.application.LogServerLogGrabber;
-import com.yahoo.vespa.config.server.http.SessionContentHandlerTestBase;
+import com.yahoo.vespa.config.server.http.ContentHandlerTestBase;
import com.yahoo.vespa.config.server.http.SessionHandlerTest;
import com.yahoo.vespa.config.server.provision.HostProvisionerProvider;
import com.yahoo.vespa.curator.mock.MockCurator;
+import org.apache.commons.io.FileUtils;
import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Executor;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+
/**
* @author lulf
* @since 5.1
*/
-public class SessionContentHandlerTest extends SessionContentHandlerTestBase {
+public class SessionContentHandlerTest extends ContentHandlerTestBase {
private static final TenantName tenant = TenantName.from("contenttest");
private SessionContentHandler handler = null;
@@ -33,6 +46,105 @@ public class SessionContentHandlerTest extends SessionContentHandlerTestBase {
baseUrl = "http://foo:1337/application/v2/tenant/" + tenant + "/session/1/content/";
}
+ @Test
+ public void require_that_directories_can_be_created() throws IOException {
+ assertMkdir("/bar/");
+ assertMkdir("/bar/brask/");
+ assertMkdir("/bar/brask/");
+ assertMkdir("/bar/brask/bram/");
+ assertMkdir("/brask/og/bram/");
+ }// TODO: Enable when we have a predictable way of checking request body existence.
+
+ @Test
+ @Ignore
+ public void require_that_mkdir_with_body_is_illegal() throws IOException {
+ HttpResponse response = put("/foobio/", "foo");
+ assertNotNull(response);
+ assertThat(response.getStatus(), is(Response.Status.BAD_REQUEST));
+ }
+
+ @Test
+ public void require_that_nonexistant_session_returns_not_found() throws IOException {
+ HttpResponse response = doRequest(HttpRequest.Method.GET, "/test.txt", 2l);
+ assertNotNull(response);
+ assertThat(response.getStatus(), is(Response.Status.NOT_FOUND));
+ }
+
+ protected HttpResponse put(String path, String content) {
+ ByteArrayInputStream data = new ByteArrayInputStream(Utf8.toBytes(content));
+ return doRequest(HttpRequest.Method.PUT, path, data);
+ }
+
+ @Test
+ public void require_that_file_write_without_body_is_illegal() throws IOException {
+ HttpResponse response = doRequest(HttpRequest.Method.PUT, "/foobio.txt");
+ assertNotNull(response);
+ assertThat(response.getStatus(), is(Response.Status.BAD_REQUEST));
+ }
+
+ @Test
+ public void require_that_files_can_be_written() throws IOException {
+ assertWriteFile("/foo/minfil.txt", "Mycontent");
+ assertWriteFile("/foo/minfil.txt", "Differentcontent");
+ }
+
+ @Test
+ public void require_that_nonexistant_file_returs_not_found_when_deleted() throws IOException {
+ assertDeleteFile(Response.Status.NOT_FOUND, "/test2.txt", "{\"error-code\":\"NOT_FOUND\",\"message\":\"Session 1 does not contain a file 'test2.txt'\"}");
+ }
+
+ @Test
+ public void require_that_files_can_be_deleted() throws IOException {
+ assertDeleteFile(Response.Status.OK, "/test.txt");
+ assertDeleteFile(Response.Status.NOT_FOUND, "/test.txt", "{\"error-code\":\"NOT_FOUND\",\"message\":\"Session 1 does not contain a file 'test.txt'\"}");
+ assertDeleteFile(Response.Status.BAD_REQUEST, "/newtest", "{\"error-code\":\"BAD_REQUEST\",\"message\":\"File 'newtest' is not an empty directory\"}");
+ assertDeleteFile(Response.Status.OK, "/newtest/testfile.txt");
+ assertDeleteFile(Response.Status.OK, "/newtest");
+ }
+
+ @Test
+ public void require_that_status_is_given_for_new_files() throws IOException {
+ assertStatus("/test.txt?return=status",
+ "{\"status\":\"new\",\"md5\":\"d3b07384d113edec49eaa6238ad5ff00\",\"name\":\"http://foo:1337" + pathPrefix + "1/content/test.txt\"}");
+ assertWriteFile("/test.txt", "Mycontent");
+ assertStatus("/test.txt?return=status",
+ "{\"status\":\"changed\",\"md5\":\"01eabd73c69d78d0009ec93cd62d7f77\",\"name\":\"http://foo:1337" + pathPrefix + "1/content/test.txt\"}");
+ }
+
+ private void assertWriteFile(String path, String content) throws IOException {
+ HttpResponse response = put(path, content);
+ assertNotNull(response);
+ assertThat(response.getStatus(), is(Response.Status.OK));
+ assertContent(path, content);
+ assertThat(SessionHandlerTest.getRenderedString(response),
+ is("{\"prepared\":\"http://foo:1337" + pathPrefix + "1/prepared\"}"));
+ }
+
+ private void assertDeleteFile(int statusCode, String filePath) throws IOException {
+ assertDeleteFile(statusCode, filePath, "{\"prepared\":\"http://foo:1337" + pathPrefix + "1/prepared\"}");
+ }
+
+ private void assertDeleteFile(int statusCode, String filePath, String expectedResponse) throws IOException {
+ HttpResponse response = doRequest(HttpRequest.Method.DELETE, filePath);
+ assertNotNull(response);
+ assertThat(response.getStatus(), is(statusCode));
+ assertThat(SessionHandlerTest.getRenderedString(response), is(expectedResponse));
+ }
+
+ private void assertMkdir(String path) throws IOException {
+ HttpResponse response = doRequest(HttpRequest.Method.PUT, path);
+ assertNotNull(response);
+ assertThat(response.getStatus(), is(Response.Status.OK));
+ assertThat(SessionHandlerTest.getRenderedString(response),
+ is("{\"prepared\":\"http://foo:1337" + pathPrefix + "1/prepared\"}"));
+ }
+
+ protected File createTestApp() throws IOException {
+ File testApp = Files.createTempDir();
+ FileUtils.copyDirectory(new File("src/test/apps/content"), testApp);
+ return testApp;
+ }
+
protected HttpResponse doRequest(HttpRequest.Method method, String path) {
return doRequest(method, path, 1l);
}