blob: 0ea0fd7689d183ec7cd2c963d4b582b908d4deec [file] [log] [blame]
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
package org.apache.james.jmap.draft.methods.integration.cucumber;
import static org.apache.james.jmap.JmapURIBuilder.baseUri;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.BufferedInputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import jakarta.inject.Inject;
import org.apache.http.HttpResponse;
import org.apache.http.client.fluent.Async;
import org.apache.http.client.fluent.Content;
import org.apache.http.client.fluent.Executor;
import org.apache.http.client.fluent.Request;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.james.jmap.AccessToken;
import org.apache.james.util.io.CountDownConsumeInputStream;
import org.apache.james.util.io.ZeroedInputStream;
import com.google.common.base.CharMatcher;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import io.cucumber.guice.ScenarioScoped;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
@ScenarioScoped
public class UploadStepdefs {
private static final int _24K = 24 * 1024;
private static final int _1M = 1024 * 1024;
private static final int _10M = 10 * _1M;
private final UserStepdefs userStepdefs;
private final MainStepdefs mainStepdefs;
private final URI uploadUri;
private HttpResponse response;
private Future<Content> async;
private boolean isCanceled;
@Inject
private UploadStepdefs(UserStepdefs userStepdefs, MainStepdefs mainStepdefs) throws URISyntaxException {
this.userStepdefs = userStepdefs;
this.mainStepdefs = mainStepdefs;
uploadUri = baseUri(mainStepdefs.jmapServer).setPath("/upload").build();
}
@Given("^\"([^\"]*)\" is starting uploading a content$")
public void userStartUploadContent(String username) {
AccessToken accessToken = userStepdefs.authenticate(username);
CountDownLatch startSignal = new CountDownLatch(2);
CountDownConsumeInputStream bodyStream = new CountDownConsumeInputStream(startSignal);
Request request = Request.Post(uploadUri)
.bodyStream(new BufferedInputStream(bodyStream, _1M), org.apache.http.entity.ContentType.DEFAULT_BINARY);
if (accessToken != null) {
request.addHeader("Authorization", accessToken.asString());
}
async = Async.newInstance().execute(request, new FutureCallback<Content>() {
@Override
public void failed(Exception ex) {
}
@Override
public void completed(Content result) {
}
@Override
public void cancelled() {
bodyStream.getStartSignal().countDown();
if (bodyStream.getStartSignal().getCount() == 1) {
isCanceled = true;
}
}
});
}
@When("^\"([^\"]*)\" upload a content$")
public void userUploadContent(String username) throws Throwable {
AccessToken accessToken = userStepdefs.authenticate(username);
Request request = Request.Post(uploadUri)
.bodyStream(new BufferedInputStream(new ZeroedInputStream(_1M), _1M), org.apache.http.entity.ContentType.DEFAULT_BINARY);
request.addHeader("Authorization", accessToken.asString());
response = Executor.newInstance(newClient())
.execute(request)
.returnResponse();
}
@When("^someone upload a content without authentification$")
public void userUploadContentWithoutAuthentification() throws Throwable {
Request request = Request.Post(uploadUri)
.bodyStream(new BufferedInputStream(new ZeroedInputStream(_24K), _24K), org.apache.http.entity.ContentType.DEFAULT_BINARY);
response = Executor.newInstance(newClient())
.execute(request)
.returnResponse();
}
private CloseableHttpClient newClient() {
return HttpClientBuilder.create()
.disableAutomaticRetries()
.build();
}
@When("^\"([^\"]*)\" upload a content without content type$")
public void userUploadContentWithoutContentType(String username) throws Throwable {
AccessToken accessToken = userStepdefs.authenticate(username);
Request request = Request.Post(uploadUri)
.bodyByteArray("some text".getBytes(StandardCharsets.UTF_8));
if (accessToken != null) {
request.addHeader("Authorization", accessToken.asString());
}
response = request.execute().returnResponse();
}
@When("^\"([^\"]*)\" upload a too big content$")
public void userUploadTooBigContent(String username) throws Throwable {
AccessToken accessToken = userStepdefs.authenticate(username);
Request request = Request.Post(uploadUri)
.bodyStream(new BufferedInputStream(new ZeroedInputStream(_10M), _10M), org.apache.http.entity.ContentType.DEFAULT_BINARY);
if (accessToken != null) {
request.addHeader("Authorization", accessToken.asString());
}
response = request.execute().returnResponse();
}
@When("^\"([^\"]*)\" checks for the availability of the upload endpoint$")
public void optionUpload(String username) throws Throwable {
userStepdefs.authenticate(username);
Request request = Request.Options(uploadUri);
response = request.execute().returnResponse();
}
@When("^someone checks without authentification for the availability of the upload endpoint$")
public void optionUploadWithoutAuthentification() throws Throwable {
Request request = Request.Options(uploadUri);
response = request.execute().returnResponse();
}
@Then("^the user disconnect$")
public void stopUpload() {
async.cancel(true);
}
@Then("^the user should receive an authorized response$")
public void httpAuthorizedStatus() {
assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
}
@Then("^the user should receive a created response$")
public void httpCreatedStatus() {
assertThat(response.getStatusLine().getStatusCode()).isEqualTo(201);
}
@Then("^the user should receive bad request response$")
public void httpBadRequestStatus() {
assertThat(response.getStatusLine().getStatusCode()).isEqualTo(400);
}
@Then("^the user should receive a not authorized response$")
public void httpUnauthorizedStatus() {
assertThat(response.getStatusLine().getStatusCode()).isEqualTo(401);
}
@Then("^the user should receive a request entity too large response$")
public void httpRequestEntityTooBigStatus() {
assertThat(response.getStatusLine().getStatusCode()).isEqualTo(413);
}
@Then("^the user should receive a specified JSON content$")
public void jsonResponse() throws Exception {
assertThat(response.getHeaders("Content-Type"))
.extracting(header ->
normalizeContentType(header.getValue()))
.containsExactly(
normalizeContentType(org.apache.http.entity.ContentType.APPLICATION_JSON.toString()));
DocumentContext jsonPath = JsonPath.parse(response.getEntity().getContent());
jsonPath.<String>read("blobId");
assertThat(jsonPath.<String>read("type")).isEqualTo("application/octet-stream");
assertThat(jsonPath.<Integer>read("size")).isEqualTo(_1M);
}
private String normalizeContentType(String input) {
return CharMatcher.whitespace().removeFrom(input.toLowerCase(Locale.US));
}
@Then("^\"([^\"]*)\" should be able to retrieve the content$")
public void contentShouldBeRetrievable(String username) throws Exception {
AccessToken accessToken = userStepdefs.authenticate(username);
DocumentContext jsonPath = JsonPath.parse(response.getEntity().getContent());
Request request = Request.Get(baseUri(mainStepdefs.jmapServer).setPath("/download/" + jsonPath.<String>read("blobId")).build());
if (accessToken != null) {
request.addHeader("Authorization", accessToken.asString());
}
response = request.execute().returnResponse();
httpAuthorizedStatus();
}
@Then("^the request should be marked as canceled$")
public void requestHasBeenCanceled() {
assertThat(isCanceled).isTrue();
}
}