Package com.elasticinbox.itests

Source Code of com.elasticinbox.itests.RestV2IT

/**
* Copyright (c) 2011-2014 Optimax Software Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*  * Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*  * Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*  * Neither the name of Optimax Software, ElasticInbox, nor the names
*    of its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.elasticinbox.itests;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static com.jayway.restassured.RestAssured.*;
import static com.jayway.restassured.path.json.JsonPath.*;

import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.lang3.tuple.Pair;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.junit.ExamReactorStrategy;
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
import org.ops4j.pax.exam.spi.reactors.EagerSingleStagedReactorFactory;

import com.elasticinbox.core.model.LabelConstants;
import com.elasticinbox.core.model.LabelCounters;
import com.elasticinbox.core.model.LabelMap;
import com.elasticinbox.core.model.Marker;
import com.elasticinbox.core.model.ReservedLabels;
import com.google.common.io.ByteStreams;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.response.Response;

/**
* Integration test for REST APIs
*
* @author Rustam Aliyev
*/
@RunWith(JUnit4TestRunner.class)
@ExamReactorStrategy(EagerSingleStagedReactorFactory.class)
public class RestV2IT extends AbstractIntegrationTest
{
  @Test
  public void reservedLabelsTest()
  {
    initAccount();
   
    // check reserved labels
    expect().
      statusCode(200).and().
      body("'" + ReservedLabels.ALL_MAILS.getId() + "'",    equalTo(ReservedLabels.ALL_MAILS.getName())).
      body("'" + ReservedLabels.INBOX.getId() + "'",      equalTo(ReservedLabels.INBOX.getName())).
      body("'" + ReservedLabels.DRAFTS.getId() + "'",      equalTo(ReservedLabels.DRAFTS.getName())).
      body("'" + ReservedLabels.SENT.getId() + "'",      equalTo(ReservedLabels.SENT.getName())).
      body("'" + ReservedLabels.TRASH.getId() + "'",      equalTo(ReservedLabels.TRASH.getName())).
      body("'" + ReservedLabels.SPAM.getId() + "'",      equalTo(ReservedLabels.SPAM.getName())).
      body("'" + ReservedLabels.STARRED.getId() + "'",    equalTo(ReservedLabels.STARRED.getName())).
      body("'" + ReservedLabels.IMPORTANT.getId() + "'",    equalTo(ReservedLabels.IMPORTANT.getName())).
      body("'" + ReservedLabels.NOTIFICATIONS.getId() + "'",  equalTo(ReservedLabels.NOTIFICATIONS.getName())).
      body("'" + ReservedLabels.ATTACHMENTS.getId() + "'",  equalTo(ReservedLabels.ATTACHMENTS.getName())).
      body("'" + ReservedLabels.POP3.getId() + "'",      equalTo(ReservedLabels.POP3.getName())).
    when().
      get(REST_PATH + "/mailbox");
  }

  @Test
  public void reservedLabelsWithMetadataTest()
  {
    initAccount();

    // check labels metadata
    expect().
      statusCode(200).and().
      body("'" + ReservedLabels.ALL_MAILS.getId() + "'.size",  greaterThanOrEqualTo(0)).
      body("'" + ReservedLabels.INBOX.getId() + "'.name",    equalTo(ReservedLabels.INBOX.getName())).
      body("'" + ReservedLabels.INBOX.getId() + "'.unread",  greaterThanOrEqualTo(0)).
      body("'" + ReservedLabels.INBOX.getId() + "'.total",  greaterThanOrEqualTo(0)).
    when().
      get(REST_PATH + "/mailbox?metadata=true");
  }

  @Test
  public void labelListAddDeleteTest()
  {
    initAccount();

    final String labelA = "MyLabel";
    final String labelACase = "mYlaBel";
    final String labelB = "MyAnotherLabel";
    final String labelBCase = "MYanOTHerLABel";

    // add label
    Integer labelId = addLabel(labelA);

    // check added label
    expect().
      statusCode(200).and().
      body("'" + labelId + "'", equalTo(labelA)).
    when().
      get(REST_PATH + "/mailbox");

    logger.info("Add label test OK");

    // rename label, same name different letter cases
    given().
      pathParam("labelId", labelId).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/label/{labelId}?name=" + labelACase);

    // check renamed label
    expect().
      statusCode(200).and().
      body("'" + labelId + "'", equalTo(labelACase)).
    when().
      get(REST_PATH + "/mailbox");

    // rename label
    given().
      pathParam("labelId", labelId).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/label/{labelId}?name=" + labelB);

    // check renamed label
    expect().
      statusCode(200).and().
      body("'" + labelId + "'", equalTo(labelB)).
    when().
      get(REST_PATH + "/mailbox");
   
    logger.info("Rename label test OK");

    // adding existing label, should fail
    given().
      pathParam("labelName", labelB).
    expect().
      statusCode(409).
    when().
      post(REST_PATH + "/mailbox/label?name={labelName}");

    // adding existing label with different letter case, should fail
    given().
      pathParam("labelName", labelBCase).
    expect().
      statusCode(409).
    when().
      post(REST_PATH + "/mailbox/label?name={labelName}");

    // adding nested label for reserved label should fail
    given().
      pathParam("labelName", ReservedLabels.INBOX.getName() +
          LabelConstants.NESTED_LABEL_SEPARATOR + "nestedLabel").
    expect().
      statusCode(400).
    when().
      post(REST_PATH + "/mailbox/label?name={labelName}");

    // delete label
    given().
      pathParam("labelId", labelId).
    expect().
      statusCode(204).
    when().
      delete(REST_PATH + "/mailbox/label/{labelId}");
   
    // check deleted label
    expect().
      statusCode(200).and().
      body("'" + labelId + "'", is(nullValue())).
    when().
      get(REST_PATH + "/mailbox").asString();

    logger.info("Delete label test OK");
  }
 
  @Test
  public void labelCustomAttributesAddUpdateDeleteTest()
  {
    initAccount();
   
    final String labelA = "MyLabel";
    final String labelB = "MyAnotherLabel";

    // add label with attributes
    Response response =
      given().
        pathParam("labelName", labelA).
        request().
          body("{\"name\" : \"" + labelB + "\", \"attributes\": { \"order\" : \"3\", \"color\" : \"red\"} }").
          contentType(ContentType.JSON).
      expect().
        statusCode(201).
      when().
        post(REST_PATH + "/mailbox/label?name={labelName}");

    int labelId = with(response.asString()).getInt("id");
   
    // check added label
    expect().
      statusCode(200).and().
      body("'" + labelId + "'.name",        equalTo(labelB)).
      body("'" + labelId + "'.attributes.order",  equalTo("3")).
      body("'" + labelId + "'.attributes.color",  equalTo("red")).
    when().
      get(REST_PATH + "/mailbox?metadata=true");

    // update label and delete some attributes
    given().
      pathParam("labelId", labelId).
      request().
        body("{\"name\" : \"" + labelA + "\", \"attributes\": { \"order\" : \"22\", \"icon\" : \"qutab.png\", \"color\" : \"\"} }").
        contentType(ContentType.JSON).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/label/{labelId}");

    // check label updates
    expect().
      statusCode(200).and().
      body("'" + labelId + "'.name",        equalTo(labelA)).
      body("'" + labelId + "'.attributes.order",  equalTo("22")).
      body("'" + labelId + "'.attributes.icon",  equalTo("qutab.png")).
      body("'" + labelId + "'.attributes",    not(hasItems("color"))).
    when().
      get(REST_PATH + "/mailbox?metadata=true");

    // delete attributes
    given().
      pathParam("labelId", labelId).
      request().
        body("{\"attributes\": { \"order\" : null, \"icon\" : \"\" } }").
        contentType(ContentType.JSON).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/label/{labelId}");

    // check label updates
    expect().
      statusCode(200).and().
      body("'" + labelId + "'.attributes", not(hasItems("order", "icon", "color"))).
    when().
      get(REST_PATH + "/mailbox?metadata=true");
   
    // add invalid attribute name
    given().
      pathParam("labelId", labelId).
      request().
        body("{\"attributes\": { \"new:attr\" : \"bad\"} }").
        contentType(ContentType.JSON).
    expect().
      statusCode(400).
    when().
      put(REST_PATH + "/mailbox/label/{labelId}");

  }

  @SuppressWarnings("unchecked")
  @Test
  public void messageAddListViewDeletePurgeTest() throws IOException
  {
    initAccount();

    long fileSizeA = getResourceSize(EMAIL_REGULAR);

    String messageId = null;
    Map<String, UUID> messages = new HashMap<String, UUID>(2);
    Integer labelId = ReservedLabels.INBOX.getId();

    // add message
    messages.put("headers", addMessage(EMAIL_REGULAR, labelId));
    messages.put("attach",  addMessage(EMAIL_LARGE_ATT, labelId));

    logger.info("Message Store Test OK");

    // check message listing
    given().
      pathParam("labelId", labelId).
    expect().
      statusCode(200).and().
      body("", hasItems(messages.get("headers").toString(), messages.get("attach").toString())).
    when().
      get(REST_PATH + "/mailbox/label/{labelId}");

    logger.info("Message List Test OK");

    // TODO: need to implement sequence order to test reverese
    // check reverse message listing (only oldest message should be listed)
//    given().
//      pathParam("labelId", labelId).
//    expect().
//      statusCode(200).and().
//      body("", not( hasItems(messages.get("headers").toString()) )).
//      body("", not( hasItems(messages.get("attach").toString()) )).
//    when().
//      get(REST_PATH + "/mailbox/label/{labelId}?reverse=false&count=1");
//
//    logger.info("Message Reverse List Test OK");

    // check message list with metadata
    messageId = messages.get("headers").toString();
    given().
      pathParam("labelId", labelId).
      pathParam("messageId", messageId).
    expect().
      statusCode(200).and().
      body(messageId + ".labels", hasItems(0, 1)).
      body(messageId + ".size", equalTo((int) fileSizeA)).
      body(messageId + ".from.address", hasItems(containsString("@"))).
      body(messageId + ".to.address", hasItems(containsString("@"))).
      body(messageId + ".replyTo.address", hasItems(containsString("@"))).
      body(messageId + ".messageId", containsString("@elasticinbox")).
      body(messageId + ".subject", not(isEmptyOrNullString())).
      body(messageId, not(hasKey("htmlBody"))).
      body(messageId, not(hasKey("plainBody"))).
      body(messageId, not(hasKey("bcc"))).
    when().
      get(REST_PATH + "/mailbox/label/{labelId}?metadata=true&count=2&start={messageId}");

    logger.info("Message List with Metadata Test OK");

    // check message list with bodies
    messageId = messages.get("headers").toString();
    given().
      pathParam("labelId", labelId).
      pathParam("messageId", messageId).
    expect().
      statusCode(200).and().
      body(messageId + ".htmlBody", not(isEmptyOrNullString())).
      body(messageId + ".plainBody", not(isEmptyOrNullString())).
    when().
      get(REST_PATH + "/mailbox/label/{labelId}?metadata=true&includebody=true&count=2&start={messageId}");

    logger.info("Message List with Metadata & Bodies Test OK");

    // check parsed message
    messageId = messages.get("headers").toString();
    given().
      pathParam("labelId", labelId).
      pathParam("messageId", messageId).
    expect().
      statusCode(200).and().
      body("message.labels", hasItems(0, 1)).
      body("message.size", equalTo((int) fileSizeA)).
      body("message.from.address", hasItems(containsString("@"))).
      body("message.to.address", hasItems(containsString("@"))).
      body("message.replyTo.address", hasItems(containsString("@"))).
      body("message.messageId", containsString("@elasticinbox")).
      body("message.subject", is(notNullValue())).
      body("message.htmlBody", is(notNullValue())).
      body("message.textBody", is(nullValue())).
    when().
      get(REST_PATH + "/mailbox/message/{messageId}?adjacent=true&label={labelId}");

    logger.info("Parsed Message Fetch Test OK");

    // delete message (from all labels)
    given().
      pathParam("messageId", messageId).
    expect().
      statusCode(204).
    when().
      delete(REST_PATH + "/mailbox/message/{messageId}");

    // check deleted message in labels
    given().
      pathParam("labelId", labelId).
    expect().
      statusCode(200).and().
      body(messageId, is(nullValue())).
    when().
      get(REST_PATH + "/mailbox/label/{labelId}?metadata=true");

    // message should remain until purged
    given().
      pathParam("messageId", messageId).
    expect().
      statusCode(200).and().
      body("message.labels", hasItems(0, 1)).
    when().
      get(REST_PATH + "/mailbox/message/{messageId}");

    logger.info("Delete Message Test OK");

    // purge deleted messages
    given().
      pathParam("ageDate", new SimpleDateFormat("yyyy/MM/dd").format(new Date()) + " 23:59").
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/purge?age={ageDate}");

    // check purged message
    given().
      pathParam("messageId", messageId).
    expect().
      statusCode(400).
    when().
      get(REST_PATH + "/mailbox/message/{messageId}");

    logger.info("Purge Message Test OK");
  }

  @Test
  public void messageAddRemoveLabelsMarkersTest() throws IOException
  {
    initAccount();

    // add labels
    Integer labelId1 = addLabel("CustomLabelTest3739");
    Integer labelId2 = addLabel("CustomLabelTest2398");

    // add message
    UUID messageId = addMessage(EMAIL_REGULAR, ReservedLabels.INBOX.getId());

    // assign labels and marker to the message
    given().
      pathParam("messageId", messageId.toString()).
      pathParam("labelId1", labelId1).
      pathParam("labelId2", labelId2).
      pathParam("seenMarker", Marker.SEEN.toString().toLowerCase()).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/message/{messageId}?addlabel={labelId1}&addlabel={labelId2}&addmarker={seenMarker}");

    // verify labels and marker
    given().
      pathParam("messageId", messageId.toString()).
    expect().
      statusCode(200).and().
      // TODO: uncomment when fixed http://code.google.com/p/rest-assured/issues/detail?id=169
      //body("message.labels", hasItems(0, 1, labelId1, labelId2)).
      body("message.labels", hasItems(0, 1, labelId2)).
      body("message.markers", hasItems(Marker.SEEN.toString().toUpperCase())).
    when().
      get(REST_PATH + "/mailbox/message/{messageId}");

    // assign/remove labels and markers to the message
    given().
      pathParam("messageId", messageId.toString()).
      pathParam("removeLabel", labelId1).
      pathParam("addLabel", ReservedLabels.SPAM.getId()).
      pathParam("removeMarker", Marker.SEEN.toString().toLowerCase()).
      pathParam("addMarker", Marker.REPLIED.toString().toLowerCase()).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/message/{messageId}?addlabel={addLabel}&removelabel={removeLabel}&removemarker={removeMarker}&addmarker={addMarker}");
   
    // verify labels and markers
    given().
      pathParam("messageId", messageId.toString()).
    expect().
      statusCode(200).and().
      body("message.labels", hasItems(0, 1, labelId2, ReservedLabels.SPAM.getId())).
      body("message.labels", not( hasItems(labelId1) )).
      body("message.markers", hasItems(Marker.REPLIED.toString().toUpperCase())).
      body("message.markers", not( hasItems(Marker.SEEN.toString().toUpperCase()) )).
    when().
      get(REST_PATH + "/mailbox/message/{messageId}");
  }

  /**
   * Adding label to the message which already has same label should not
   * result in overcounting.
   *
   * @throws IOException
   */
  @Test
  public void overcountingTest() throws IOException
  {
    initAccount();

    // Step 1: add message to label TRASH
    UUID messageId = addMessage(EMAIL_REGULAR, ReservedLabels.TRASH.getId());

    // counters before operation
    String jsonResponse = expect().statusCode(200).when().get(REST_PATH + "/mailbox?metadata=true").asString();
    LabelCounters initialAllCounters = getCounters(jsonResponse, ReservedLabels.ALL_MAILS.getId());
    LabelCounters initialTrashCounters = getCounters(jsonResponse, ReservedLabels.TRASH.getId());

    // Repeat add label TRASH
    for (int i=0; i<5; i++)
    {
      given().
        pathParam("messageId", messageId.toString()).
        pathParam("labelId", ReservedLabels.TRASH.getId()).
      expect().
        statusCode(204).
      when().
        put(REST_PATH + "/mailbox/message/{messageId}?addlabel={labelId}");
    }

    // counters after operation
    jsonResponse = expect().statusCode(200).when().get(REST_PATH + "/mailbox?metadata=true").asString();
    LabelCounters finalAllCounters = getCounters(jsonResponse, ReservedLabels.ALL_MAILS.getId());
    LabelCounters finalTrashCounters = getCounters(jsonResponse, ReservedLabels.TRASH.getId());
   
    assertThat(finalAllCounters, equalTo(initialAllCounters));
    assertThat(finalTrashCounters, equalTo(initialTrashCounters));
   
    // STEP 2: remove label and add marker
    given().
      pathParam("messageId", messageId.toString()).
      pathParam("labelId", ReservedLabels.TRASH.getId()).
      pathParam("seenMarker", Marker.SEEN.toString().toLowerCase()).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/message/{messageId}?removelabel={labelId}&addmarker={seenMarker}");

    // counters before operation
    jsonResponse = expect().statusCode(200).when().get(REST_PATH + "/mailbox?metadata=true").asString();
    initialAllCounters = getCounters(jsonResponse, ReservedLabels.ALL_MAILS.getId());
    initialTrashCounters = getCounters(jsonResponse, ReservedLabels.TRASH.getId());

    // Repeat remove label and add marker
    for (int i=0; i<5; i++)
    {
      given().
        pathParam("messageId", messageId.toString()).
        pathParam("labelId", ReservedLabels.TRASH.getId()).
        pathParam("seenMarker", Marker.SEEN.toString().toLowerCase()).
      expect().
        statusCode(204).
      when().
        put(REST_PATH + "/mailbox/message/{messageId}?removelabel={labelId}&addmarker={seenMarker}");
    }
   
    // counters after operation
    jsonResponse = expect().statusCode(200).when().get(REST_PATH + "/mailbox?metadata=true").asString();
    finalAllCounters = getCounters(jsonResponse, ReservedLabels.ALL_MAILS.getId());
    finalTrashCounters = getCounters(jsonResponse, ReservedLabels.TRASH.getId());
   
    assertThat(finalAllCounters, equalTo(initialAllCounters));
    assertThat(finalTrashCounters, equalTo(initialTrashCounters));

    // STEP 3: Remove Marker
    given().
      pathParam("messageId", messageId.toString()).
      pathParam("seenMarker", Marker.SEEN.toString().toLowerCase()).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/message/{messageId}?removemarker={seenMarker}");

    // counters before operation
    jsonResponse = expect().statusCode(200).when().get(REST_PATH + "/mailbox?metadata=true").asString();
    initialAllCounters = getCounters(jsonResponse, ReservedLabels.ALL_MAILS.getId());
    initialTrashCounters = getCounters(jsonResponse, ReservedLabels.TRASH.getId());

    // Repeat remove marker
    for (int i=0; i<5; i++)
    {
      given().
        pathParam("messageId", messageId.toString()).
        pathParam("seenMarker", Marker.SEEN.toString().toLowerCase()).
      expect().
        statusCode(204).
      when().
        put(REST_PATH + "/mailbox/message/{messageId}?removemarker={seenMarker}");
    }

    // counters after operation
    jsonResponse = expect().statusCode(200).when().get(REST_PATH + "/mailbox?metadata=true").asString();
    finalAllCounters = getCounters(jsonResponse, ReservedLabels.ALL_MAILS.getId());
    finalTrashCounters = getCounters(jsonResponse, ReservedLabels.TRASH.getId());
   
    assertThat(finalAllCounters, equalTo(initialAllCounters));
    assertThat(finalTrashCounters, equalTo(initialTrashCounters));
  }
 
  @Test
  public void messageBatchMofifyDeleteTest() throws IOException
  {
    initAccount();

    // add labels
    Integer labelId1 = addLabel("BatchLabelTest0912");
    Integer labelId2 = addLabel("BatchLabelTest1290");

    // add messages
    UUID messageId1 = addMessage(EMAIL_REGULAR, ReservedLabels.INBOX.getId());
    UUID messageId2 = addMessage(EMAIL_LARGE_ATT, ReservedLabels.INBOX.getId());

    // batch add labels and markers
    given().
      pathParam("labelId1", labelId1).
      pathParam("labelId2", labelId2).
      pathParam("seenMarker", Marker.SEEN.toString().toLowerCase()).
      request().body("[\"" + messageId1.toString() + "\", \"" + messageId2.toString() + "\"]").contentType(ContentType.JSON).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/message?addlabel={labelId1}&addlabel={labelId2}&addmarker={seenMarker}");

    // verify labels and markers
    given().
      pathParam("labelId", ReservedLabels.ALL_MAILS.getId()).
    expect().
      statusCode(200).and().
      body(messageId1.toString() + ".labels", hasItems(0, 1, labelId2)).
      body(messageId2.toString() + ".labels", hasItems(0, 1, labelId2)).
      // TODO: uncomment when fixed http://code.google.com/p/rest-assured/issues/detail?id=169
      //body(messageId1.toString() + ".labels", hasItems(0, 1, labelId1, labelId2)).
      //body(messageId2.toString() + ".labels", hasItems(0, 1, labelId1, labelId2)).
      body(messageId1.toString() + ".markers", hasItems(Marker.SEEN.toString().toUpperCase())).
      body(messageId2.toString() + ".markers", hasItems(Marker.SEEN.toString().toUpperCase())).
    when().
      get(REST_PATH + "/mailbox/label/{labelId}?metadata=true");

    // batch delete messages
    given().
      request().body("[\"" + messageId1.toString() + "\", \"" + messageId2.toString() + "\"]").contentType(ContentType.JSON).
    expect().
      statusCode(204).
    when().
      delete(REST_PATH + "/mailbox/message");

    // verify batch delete
    given().
      pathParam("labelId", ReservedLabels.ALL_MAILS.getId()).
    expect().
      statusCode(200).and().
      body(messageId1.toString(), is(nullValue())).
      body(messageId2.toString(), is(nullValue())).
    when().
      get(REST_PATH + "/mailbox/label/{labelId}?metadata=true");
  }

  @Test
  public void messageAttachmentAndRawTest() throws IOException
  {
    initAccount();

    // add message
    UUID messageId = addMessage(EMAIL_LARGE_ATT, ReservedLabels.INBOX.getId());
    //long fileSize = getResourceSize(EMAIL_LARGE_ATT);

    // get attachment by part id
    given().
      pathParam("messageId", messageId.toString()).
      pathParam("partId", 3).
    expect().
      statusCode(200).and().
      header("Content-Type", equalTo("application/pdf")).
      //header("Content-Length", equalTo("64736")).
      header("Content-Disposition", containsString("attachment; filename=")).
    when().
      get(REST_PATH + "/mailbox/message/{messageId}/{partId}");

    // get attachment by content id
    given().
      pathParam("messageId", messageId.toString()).
      pathParam("contentId", "<image-001>").
    expect().
      statusCode(200).and().
      header("Content-Type", equalTo("image/png")).
      //header("Content-Length", equalTo("27136")).
      header("Content-Disposition", containsString("attachment; filename=")).
    when().
      get(REST_PATH + "/mailbox/message/{messageId}/{contentId}");

    // get uncompressed raw message
    // TODO: currently this tests does not validate size due to bug in RESTAssured.
    //       see {@link http://code.google.com/p/rest-assured/issues/detail?id=154}
    given().
      header("Accept-Encoding", "none").
      pathParam("messageId", messageId.toString()).
    expect().
      statusCode(200).and().
      header("Content-Type", equalTo("text/plain")).
//      header("Content-Length", equalTo(String.valueOf(fileSize))).
//      header("Content-Encoding", not(equalTo("deflate"))).
    when().
      get(REST_PATH + "/mailbox/message/{messageId}/raw");

    // get compressed raw message
    given().
      header("Accept-Encoding", "deflate").
      pathParam("messageId", messageId.toString()).
    expect().
      statusCode(200).and().
      header("Content-Encoding", equalTo("deflate")).
      header("Content-Type", equalTo("text/plain")).
    when().
      get(REST_PATH + "/mailbox/message/{messageId}/raw");
  }

  @Test
  public void messageUpdateTest() throws IOException
  {
    initAccount();

    // add message
    UUID messageId = addMessage(EMAIL_LARGE_ATT, ReservedLabels.INBOX.getId());

    // add labels and markers
    given().
      pathParam("messageId", messageId.toString()).
      pathParam("labelId1", ReservedLabels.IMPORTANT.getId()).
      pathParam("marker1", Marker.SEEN.toString().toLowerCase()).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/message/{messageId}?addlabel={labelId1}&addmarker={marker1}");

    // TODO: merge labelId2 to above request when fixed http://code.google.com/p/rest-assured/issues/detail?id=169
    given().
      pathParam("messageId", messageId.toString()).
      pathParam("labelId2", ReservedLabels.STARRED.getId()).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/message/{messageId}?addlabel={labelId2}");

    // overwrite message
    InputStream fin = this.getClass().getResourceAsStream(EMAIL_REGULAR);
    byte[] messageBytes = ByteStreams.toByteArray(fin);
    fin.close();

    Response response =
      given().
        pathParam("messageId", messageId.toString()).
        request().body(messageBytes).contentType(ContentType.BINARY).
      expect().
        statusCode(201).
      when().
        post(REST_PATH + "/mailbox/message/{messageId}");

    UUID newMessageId = UUID.fromString( with(response.asString()).getString("id") );

    // verify that message updated and labels/markers preserved
    given().
      pathParam("messageId", newMessageId.toString()).
    expect().
      statusCode(200).and().
      body("message.labels", hasItems(ReservedLabels.IMPORTANT.getId(), ReservedLabels.STARRED.getId())).
      body("message.markers", hasItems(Marker.SEEN.toString().toUpperCase())).
    when().
      get(REST_PATH + "/mailbox/message/{messageId}");
  }
 
  @Test
  public void countersTest() throws IOException
  {
    initAccount();

    LabelCounters allCounters = new LabelCounters();
    LabelCounters inboxCounters = new LabelCounters();
    LabelCounters spamCounters = new LabelCounters();

    // check label counter before message added
    String jsonResponse = expect().statusCode(200).when().get(REST_PATH + "/mailbox?metadata=true").asString();
    allCounters = getCounters(jsonResponse, ReservedLabels.ALL_MAILS.getId());
    inboxCounters = getCounters(jsonResponse, ReservedLabels.INBOX.getId());
    spamCounters = getCounters(jsonResponse, ReservedLabels.SPAM.getId());

    // add message A
    long fileSizeA = getResourceSize(EMAIL_REGULAR);
    UUID messageIdA = addMessage(EMAIL_REGULAR, ReservedLabels.INBOX.getId());

    // check label counters
    jsonResponse =
      expect().
        statusCode(200).and().
        body("'" + ReservedLabels.ALL_MAILS.getId() + "'.size",
            equalTo((int) (allCounters.getTotalBytes().longValue() + fileSizeA))).
        body("'" + ReservedLabels.ALL_MAILS.getId() + "'.total",
            equalTo((int) (allCounters.getTotalMessages().longValue() + 1))).
        body("'" + ReservedLabels.ALL_MAILS.getId() + "'.unread",
            equalTo((int) (allCounters.getUnreadMessages().longValue() + 1))).
        body("'" + ReservedLabels.INBOX.getId() + "'.total",
            equalTo((int) (inboxCounters.getTotalMessages().longValue() + 1))).
        body("'" + ReservedLabels.INBOX.getId() + "'.unread",
            equalTo((int) (inboxCounters.getUnreadMessages().longValue() + 1))).
      when().
        get(REST_PATH + "/mailbox?metadata=true").asString();

    // add label SPAM to message A
    given().
      pathParam("messageId", messageIdA.toString()).
      pathParam("labelId", ReservedLabels.SPAM.getId()).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/message/{messageId}?addlabel={labelId}");

    // check label counters
    jsonResponse =
      expect().
        statusCode(200).and().
        body("'" + ReservedLabels.SPAM.getId() + "'.total",
            equalTo((int) (spamCounters.getTotalMessages().longValue() + 1))).
        body("'" + ReservedLabels.SPAM.getId() + "'.unread",
            equalTo((int) (spamCounters.getUnreadMessages().longValue() + 1))).
      when().
        get(REST_PATH + "/mailbox?metadata=true").asString();

    // update counters
    allCounters = getCounters(jsonResponse, ReservedLabels.ALL_MAILS.getId());
    inboxCounters = getCounters(jsonResponse, ReservedLabels.INBOX.getId());
    spamCounters = getCounters(jsonResponse, ReservedLabels.SPAM.getId());

    // mark message as read
    given().
      pathParam("messageId", messageIdA.toString()).
      pathParam("marker", Marker.SEEN.toString().toLowerCase()).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/message/{messageId}?addmarker={marker}");

    // check label counters
    jsonResponse =
      expect().
        statusCode(200).and().
        body("'" + ReservedLabels.ALL_MAILS.getId() + "'.unread",
            equalTo((int) (allCounters.getUnreadMessages().longValue() - 1))).
        body("'" + ReservedLabels.INBOX.getId() + "'.unread",
            equalTo((int) (inboxCounters.getUnreadMessages().longValue() - 1))).
        body("'" + ReservedLabels.SPAM.getId() + "'.unread",
            equalTo((int) (spamCounters.getUnreadMessages().longValue() - 1))).
      when().
        get(REST_PATH + "/mailbox?metadata=true").asString();

    // update counters
    allCounters = getCounters(jsonResponse, ReservedLabels.ALL_MAILS.getId());
    inboxCounters = getCounters(jsonResponse, ReservedLabels.INBOX.getId());
    spamCounters = getCounters(jsonResponse, ReservedLabels.SPAM.getId());

    // remove label INBOX from message A
    given().
      pathParam("messageId", messageIdA.toString()).
      pathParam("labelId", ReservedLabels.INBOX.getId()).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/message/{messageId}?removelabel={labelId}");

    // check label counters
    jsonResponse =
      expect().
        statusCode(200).and().
        body("'" + ReservedLabels.ALL_MAILS.getId() + "'.size",
            equalTo((int) (allCounters.getTotalBytes().longValue()))).
        body("'" + ReservedLabels.ALL_MAILS.getId() + "'.total",
            equalTo((int) (allCounters.getTotalMessages().longValue()))).
        body("'" + ReservedLabels.ALL_MAILS.getId() + "'.unread",
            equalTo((int) (allCounters.getUnreadMessages().longValue()))).
        body("'" + ReservedLabels.INBOX.getId() + "'.total",
            equalTo((int) (inboxCounters.getTotalMessages().longValue() - 1))).
        body("'" + ReservedLabels.INBOX.getId() + "'.unread",
            equalTo((int) (inboxCounters.getUnreadMessages().longValue()))).
        body("'" + ReservedLabels.SPAM.getId() + "'.total",
            equalTo((int) (spamCounters.getTotalMessages().longValue()))).
        body("'" + ReservedLabels.SPAM.getId() + "'.unread",
            equalTo((int) (spamCounters.getUnreadMessages().longValue()))).
      when().
        get(REST_PATH + "/mailbox?metadata=true").asString();

    // update counters
    allCounters = getCounters(jsonResponse, ReservedLabels.ALL_MAILS.getId());
    inboxCounters = getCounters(jsonResponse, ReservedLabels.INBOX.getId());
    spamCounters = getCounters(jsonResponse, ReservedLabels.SPAM.getId());

    // add message B to SPAM
    long fileSizeB = getResourceSize(EMAIL_LARGE_ATT);
    addMessage(EMAIL_LARGE_ATT, ReservedLabels.SPAM.getId());

    // check label counters
    jsonResponse =
      expect().
        statusCode(200).and().
        body("'" + ReservedLabels.ALL_MAILS.getId() + "'.size",
            equalTo((int) (allCounters.getTotalBytes().longValue() + fileSizeB))).
        body("'" + ReservedLabels.ALL_MAILS.getId() + "'.total",
            equalTo((int) (allCounters.getTotalMessages().longValue() + 1))).
        body("'" + ReservedLabels.ALL_MAILS.getId() + "'.unread",
            equalTo((int) (allCounters.getUnreadMessages().longValue() + 1))).
        body("'" + ReservedLabels.INBOX.getId() + "'.total",
            equalTo((int) (inboxCounters.getTotalMessages().longValue()))).
        body("'" + ReservedLabels.INBOX.getId() + "'.unread",
            equalTo((int) (inboxCounters.getUnreadMessages().longValue()))).
        body("'" + ReservedLabels.SPAM.getId() + "'.total",
            equalTo((int) (spamCounters.getTotalMessages().longValue() + 1))).
        body("'" + ReservedLabels.SPAM.getId() + "'.unread",
            equalTo((int) (spamCounters.getUnreadMessages().longValue() + 1))).
      when().
        get(REST_PATH + "/mailbox?metadata=true").asString();

    // update counters
    allCounters = getCounters(jsonResponse, ReservedLabels.ALL_MAILS.getId());
    inboxCounters = getCounters(jsonResponse, ReservedLabels.INBOX.getId());
    spamCounters = getCounters(jsonResponse, ReservedLabels.SPAM.getId());

    // remove message A
    given().
      pathParam("messageId", messageIdA.toString()).
    expect().
      statusCode(204).
    when().
      delete(REST_PATH + "/mailbox/message/{messageId}");

    // check label counters
    jsonResponse =
      expect().
        statusCode(200).and().
        body("'" + ReservedLabels.ALL_MAILS.getId() + "'.size",
            equalTo((int) (allCounters.getTotalBytes().longValue() - fileSizeA))).
        body("'" + ReservedLabels.ALL_MAILS.getId() + "'.total",
            equalTo((int) (allCounters.getTotalMessages().longValue() - 1))).
        body("'" + ReservedLabels.ALL_MAILS.getId() + "'.unread",
            equalTo((int) (allCounters.getUnreadMessages().longValue()))).
        body("'" + ReservedLabels.SPAM.getId() + "'.total",
            equalTo((int) (spamCounters.getTotalMessages().longValue() - 1))).
        body("'" + ReservedLabels.SPAM.getId() + "'.unread",
            equalTo((int) (spamCounters.getUnreadMessages().longValue()))).
      when().
        get(REST_PATH + "/mailbox?metadata=true").asString();

    logger.info("Counters Test OK");
  }
 
  @Test
  public void mailboxScrubTest() throws IOException
  {
    initAccount();
   
    Pair<LabelMap, Map<Integer, List<UUID>>> pair = populateMailbox();
    LabelMap labels = pair.getLeft();
    Map<Integer, List<UUID>> messages = pair.getRight();
   
    // TODO: wipe off counters and indexes here. need to communicate with metadata store directly

    // check label counters before scrub
    expect().
      statusCode(200).and().
      body("'" + ReservedLabels.INBOX.getId() + "'.total",
          equalTo(labels.get(ReservedLabels.INBOX.getId()).getCounters().getTotalMessages().intValue())).
      body("'" + ReservedLabels.INBOX.getId() + "'.unread",
          equalTo(labels.get(ReservedLabels.INBOX.getId()).getCounters().getUnreadMessages().intValue())).
      body("'" + ReservedLabels.NOTIFICATIONS.getId() + "'.total",
          equalTo(labels.get(ReservedLabels.NOTIFICATIONS.getId()).getCounters().getTotalMessages().intValue())).
      body("'" + ReservedLabels.NOTIFICATIONS.getId() + "'.unread",
          equalTo(labels.get(ReservedLabels.NOTIFICATIONS.getId()).getCounters().getUnreadMessages().intValue())).
      body("'" + ReservedLabels.SPAM.getId() + "'.total",
          equalTo(labels.get(ReservedLabels.SPAM.getId()).getCounters().getTotalMessages().intValue())).
      body("'" + ReservedLabels.SPAM.getId() + "'.unread",
          equalTo(labels.get(ReservedLabels.SPAM.getId()).getCounters().getUnreadMessages().intValue())).
      body("'" + ReservedLabels.TRASH.getId() + "'.total",
          equalTo(labels.get(ReservedLabels.TRASH.getId()).getCounters().getTotalMessages().intValue())).
      body("'" + ReservedLabels.TRASH.getId() + "'.unread",
          equalTo(labels.get(ReservedLabels.TRASH.getId()).getCounters().getUnreadMessages().intValue())).
    when().
      get(REST_PATH + "/mailbox?metadata=true").asString();

    // scrub label counters
    expect().
      statusCode(204).
    when().
      post(REST_PATH + "/mailbox/scrub/counters");

    // check label counters after scrub
    expect().
      statusCode(200).and().
      body("'" + ReservedLabels.INBOX.getId() + "'.total",
          equalTo(labels.get(ReservedLabels.INBOX.getId()).getCounters().getTotalMessages().intValue())).
      body("'" + ReservedLabels.INBOX.getId() + "'.unread",
          equalTo(labels.get(ReservedLabels.INBOX.getId()).getCounters().getUnreadMessages().intValue())).
      body("'" + ReservedLabels.NOTIFICATIONS.getId() + "'.total",
          equalTo(labels.get(ReservedLabels.NOTIFICATIONS.getId()).getCounters().getTotalMessages().intValue())).
      body("'" + ReservedLabels.NOTIFICATIONS.getId() + "'.unread",
          equalTo(labels.get(ReservedLabels.NOTIFICATIONS.getId()).getCounters().getUnreadMessages().intValue())).
      body("'" + ReservedLabels.SPAM.getId() + "'.total",
          equalTo(labels.get(ReservedLabels.SPAM.getId()).getCounters().getTotalMessages().intValue())).
      body("'" + ReservedLabels.SPAM.getId() + "'.unread",
          equalTo(labels.get(ReservedLabels.SPAM.getId()).getCounters().getUnreadMessages().intValue())).
      body("'" + ReservedLabels.TRASH.getId() + "'.total",
          equalTo(labels.get(ReservedLabels.TRASH.getId()).getCounters().getTotalMessages().intValue())).
      body("'" + ReservedLabels.TRASH.getId() + "'.unread",
          equalTo(labels.get(ReservedLabels.TRASH.getId()).getCounters().getUnreadMessages().intValue())).
    when().
      get(REST_PATH + "/mailbox?metadata=true").asString();
   
    // scrub label indexes
    expect().
      statusCode(204).
    when().
      post(REST_PATH + "/mailbox/scrub/indexes");
   
    //check indexes
    for (int labelId : new int[] {
          ReservedLabels.INBOX.getId(), ReservedLabels.NOTIFICATIONS.getId(),
          ReservedLabels.SPAM.getId(), ReservedLabels.TRASH.getId()} )
    {
      given().
        pathParam("labelId", labelId).
      expect().
        statusCode(200).and().
        body("", hasItems(asStringArray(messages.get(labelId)))).
        body("", hasSize(messages.get(labelId).size())).
      when().
        get(REST_PATH + "/mailbox/label/{labelId}");
    }
}
 
  /**
   * Populates mailbox with messages and returns expected counters and message IDs.
   *
   * @return
   * @throws IOException
   */
  protected static Pair<LabelMap, Map<Integer, List<UUID>>> populateMailbox() throws IOException
  {
    Map<Integer, List<UUID>> messages = new HashMap<Integer, List<UUID>>();
    LabelMap labels = new LabelMap();
    LabelCounters inboxCounters = new LabelCounters();
    LabelCounters notifCounters = new LabelCounters();
    LabelCounters trashCounters = new LabelCounters();
    LabelCounters spamCounters = new LabelCounters();

    // INBOX: add 5 messages, mark 2 as unread
    messages.put(ReservedLabels.INBOX.getId(), new ArrayList<UUID>());
    List<UUID> inboxMessages = messages.get(ReservedLabels.INBOX.getId());
    inboxMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.INBOX.getId()));
    inboxMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.INBOX.getId()));
    inboxMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.INBOX.getId()));
    inboxMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.INBOX.getId()));
    inboxMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.INBOX.getId()));
    markAsRead(inboxMessages.get(3));
    markAsRead(inboxMessages.get(4));
    inboxCounters.setTotalMessages(5L);
    inboxCounters.setUnreadMessages(3L);
    labels.put(ReservedLabels.INBOX);
    labels.get(ReservedLabels.INBOX.getId()).setCounters(inboxCounters);

    // NOTIFICATIONS: add 3 messages, mark 1 as read
    messages.put(ReservedLabels.NOTIFICATIONS.getId(), new ArrayList<UUID>());
    List<UUID> notifMessages = messages.get(ReservedLabels.NOTIFICATIONS.getId());
    notifMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.NOTIFICATIONS.getId()));
    notifMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.NOTIFICATIONS.getId()));
    notifMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.NOTIFICATIONS.getId()));
    markAsRead(notifMessages.get(1));
    notifCounters.setTotalMessages(3L);
    notifCounters.setUnreadMessages(2L);
    labels.put(ReservedLabels.NOTIFICATIONS);
    labels.get(ReservedLabels.NOTIFICATIONS.getId()).setCounters(notifCounters);

    // SPAM: add 5 messages, keep all unread
    messages.put(ReservedLabels.SPAM.getId(), new ArrayList<UUID>());
    List<UUID> spamMessages = messages.get(ReservedLabels.SPAM.getId());
    spamMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.SPAM.getId()));
    spamMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.SPAM.getId()));
    spamMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.SPAM.getId()));
    spamMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.SPAM.getId()));
    spamMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.SPAM.getId()));
    spamCounters.setTotalMessages(5L);
    spamCounters.setUnreadMessages(5L);
    labels.put(ReservedLabels.SPAM);
    labels.get(ReservedLabels.SPAM.getId()).setCounters(spamCounters);

    // TRASH: add 4 messages, mark 2 as read
    messages.put(ReservedLabels.TRASH.getId(), new ArrayList<UUID>());
    List<UUID> trashMessages = messages.get(ReservedLabels.TRASH.getId());
    trashMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.TRASH.getId()));
    trashMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.TRASH.getId()));
    trashMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.TRASH.getId()));
    trashMessages.add(addMessage(EMAIL_REGULAR, ReservedLabels.TRASH.getId()));
    markAsRead(trashMessages.get(0));
    markAsRead(trashMessages.get(2));
    trashCounters.setTotalMessages(4L);
    trashCounters.setUnreadMessages(2L);
    labels.put(ReservedLabels.TRASH);
    labels.get(ReservedLabels.TRASH.getId()).setCounters(trashCounters);

    return Pair.of(labels, messages);
  }

  /**
   * Adds message throught REST API and returns new message UUID
   *
   * @param messageFile
   * @param labelId
   * @return
   * @throws IOException
   */
  protected static UUID addMessage(String messageFile, Integer labelId) throws IOException
  {
    InputStream in = null;
    byte[] messageBytes;

    try {
      in = RestV2IT.class.getResourceAsStream(messageFile);
      messageBytes = ByteStreams.toByteArray(in);
    } finally {
      in.close();
    }

    Response response =
      given().
        pathParam("labelId", labelId).
        request().body(messageBytes).contentType(ContentType.BINARY).
      expect().
        statusCode(201).
      when().
        post(REST_PATH + "/mailbox/message?label={labelId}");

    return UUID.fromString( with(response.asString()).getString("id") );
  }
 
  /**
   * Mark given message as read (add SEEN marker)
   *
   * @param messageId
   */
  private static void markAsRead(UUID messageId)
  {
    // assign labels and marker to the message
    given().
      pathParam("messageId", messageId.toString()).
      pathParam("seenMarker", Marker.SEEN.toString().toLowerCase()).
    expect().
      statusCode(204).
    when().
      put(REST_PATH + "/mailbox/message/{messageId}?addmarker={seenMarker}");
  }

  /**
   * Adds labels through REST API and returns new label ID
   *
   * @param labelName
   * @return
   */
  private Integer addLabel(String labelName)
  {
    Response response =
      given().
        pathParam("labelName", labelName).
      expect().
        statusCode(201).
      when().
        post(REST_PATH + "/mailbox/label?name={labelName}");

    return with(response.asString()).getInt("id");
  }

  /**
   * Parses json response and returns {@link LabelCounters} for Label
   *
   * @param json
   * @param labelId
   * @return
   */
  private LabelCounters getCounters(String json, Integer labelId)
  {
    LabelCounters lc = new LabelCounters();
    String l = Integer.toString(labelId);

    lc.setUnreadMessages( (long) from(json).getInt("'" + l + "'.unread") );
    lc.setTotalMessages( (long) from(json).getInt("'" + l + "'.total") );
    // size returned only for ALL_MAILS
    if(labelId == ReservedLabels.ALL_MAILS.getId()) {
      lc.setTotalBytes( (long) from(json).getInt("'" + l + "'.size") );
    }

    return lc;
  }

  /**
   * Convert List<T> to String array by calling toString() on all elements.
   *
   * @param list
   * @return
   */
  private static <T> String[] asStringArray(List<T> list)
  {
    String result[] = new String[list.size()];
   
    for (int i = 0; i < list.size(); i++) {
      result[i] = list.get(i).toString();
    }
   
    return result;
  }
}
TOP

Related Classes of com.elasticinbox.itests.RestV2IT

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.