/** * 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; } }