package org.jboss.resteasy.test.client;

import java.io.File;

import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.core.Response;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient43Engine;
import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
import org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder;
import org.jboss.resteasy.test.client.resource.ChunkedTransferEncodingResource;
import org.jboss.resteasy.utils.PortProviderUtil;
import org.jboss.resteasy.utils.TestUtil;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
 * @tpSubChapter Resteasy-client
 * @tpChapter Integration tests
 * @tpTestCaseDetails Test facility for sending requests in chunked format
 * @tpSince RESTEasy 3.0.24
 */
@RunWith(Arquillian.class)
@RunAsClient
public class ChunkedTransferEncodingTest {

   static ResteasyClient clientDefault;
   static ResteasyClient clientEngine43;
   static ResteasyClient clientEngine4;
   static final String testFilePath;
   static long fileLength;
   static File file;

   static {
      testFilePath = TestUtil.getResourcePath(ChunkedTransferEncodingTest.class, "ChunkedTransferEncodingTestFile");
   }

   @Deployment
   public static Archive<?> deploy() {
      WebArchive war = TestUtil.prepareArchive(ChunkedTransferEncodingTest.class.getSimpleName());
      return TestUtil.finishContainerPrepare(war, null, ChunkedTransferEncodingResource.class);
   }

   @Before
   public void init() {
      file = new File(testFilePath);
      fileLength = file.length();
      clientDefault = new ResteasyClientBuilder().build();
      clientEngine43 = new ResteasyClientBuilder().httpEngine(new ApacheHttpClient43Engine()).build();
      clientEngine4 = new ResteasyClientBuilder().httpEngine(new ApacheHttpClient4Engine()).build();
   }

   @After
   public void after() throws Exception {
      clientDefault.close();
      clientEngine43.close();
      clientEngine4.close();
   }

   private String generateURL(String path) {
      return PortProviderUtil.generateURL(path, ChunkedTransferEncodingTest.class.getSimpleName());
   }

   /**
    * @tpTestDetails Tests that chunked Transfer-encoding header is set on ResteasyWebTarget. Tests that Content-Length
    * header is set only in case when chunked transfer encoding is set to false. Headers are tested with the default client,
    * client with te underlying http engines ApacheHttpClient4Engine and ApacheHttpClient43Engine.
    * @tpSince RESTEasy 3.0.24
    */
   @Test
   public void testTarget() throws Exception {
      doTestTarget(clientDefault, Boolean.TRUE, "chunked null");
      doTestTarget(clientDefault, Boolean.FALSE, "null " + fileLength);
      doTestTarget(clientDefault,null, "null " + fileLength);
      doTestTarget(clientEngine43, Boolean.TRUE, "chunked null");
      doTestTarget(clientEngine43, Boolean.FALSE, "null " + fileLength);
      doTestTarget(clientEngine43,null, "null " + fileLength);
      doTestTarget(clientEngine4, Boolean.TRUE, "chunked null");
      doTestTarget(clientEngine4, Boolean.FALSE, "null " + fileLength);
      doTestTarget(clientEngine4,null, "null " + fileLength);
   }

   public void doTestTarget(ResteasyClient client, Boolean b, String expected) throws Exception
   {
      ResteasyWebTarget target = client.target(generateURL("/test"));
      if (b == Boolean.TRUE || b == Boolean.FALSE ) {
         target.setChunked(b.booleanValue());
      }
      Invocation.Builder request = target.request();
      Response response = request.post(Entity.entity(file, "text/plain"));
      String header = response.readEntity(String.class);
      Assert.assertEquals(200, response.getStatus());
      Assert.assertEquals(expected, header);
   }

   /**
    * @tpTestDetails Tests that chunked Transfer-encoding header is set on ClientInvocationBuilder. Tests that Content-Length
    * header is set only in case when chunked transfer encoding is set to false. Headers are tested with the default client,
    * client with te underlying http engines ApacheHttpClient4Engine and ApacheHttpClient43Engine.
    * @tpSince RESTEasy 3.0.24
    */
   @Test
   public void testRequest() throws Exception {
      doTestRequest(clientDefault, Boolean.TRUE, "chunked null");
      doTestRequest(clientDefault, Boolean.FALSE, "null " + fileLength);
      doTestRequest(clientDefault, null, "null " + fileLength);
      doTestRequest(clientEngine43, Boolean.TRUE, "chunked null");
      doTestRequest(clientEngine43, Boolean.FALSE, "null " + fileLength);
      doTestRequest(clientEngine43, null, "null " + fileLength);
      doTestRequest(clientEngine4, Boolean.TRUE, "chunked null");
      doTestRequest(clientEngine4, Boolean.FALSE, "null " + fileLength);
      doTestRequest(clientEngine4, null, "null " + fileLength);
   }

   protected void doTestRequest(ResteasyClient client, Boolean b, String expected) throws Exception
   {
      ResteasyWebTarget target = client.target(generateURL("/test"));
      ClientInvocationBuilder request = (ClientInvocationBuilder) target.request();
      if (b != null){
         request.setChunked(b);
      }
      Response response = request.post(Entity.entity(file, "text/plain"));
      String header = response.readEntity(String.class);
      Assert.assertEquals(200, response.getStatus());
      Assert.assertEquals(expected, header);
   }
}
