com.zimbra.qa.unittest.TestUserServlet.java Source code

Java tutorial

Introduction

Here is the source code for com.zimbra.qa.unittest.TestUserServlet.java

Source

/*
 * ***** BEGIN LICENSE BLOCK *****
 * Zimbra Collaboration Suite Server
 * Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software Foundation,
 * version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with this program.
 * If not, see <https://www.gnu.org/licenses/>.
 * ***** END LICENSE BLOCK *****
 */
package com.zimbra.qa.unittest;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.mail.internet.MimeMessage;
import javax.mail.util.SharedByteArrayInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import junit.framework.TestCase;
import net.fortuna.ical4j.data.CalendarOutputter;
import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.model.Property;
import net.fortuna.ical4j.model.ValidationException;
import net.fortuna.ical4j.model.component.VEvent;
import net.fortuna.ical4j.model.parameter.FmtType;
import net.fortuna.ical4j.model.parameter.Value;
import net.fortuna.ical4j.model.parameter.XParameter;
import net.fortuna.ical4j.model.property.Attach;
import net.fortuna.ical4j.model.property.CalScale;
import net.fortuna.ical4j.model.property.ProdId;
import net.fortuna.ical4j.model.property.Uid;
import net.fortuna.ical4j.model.property.Version;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.zimbra.client.ZDocument;
import com.zimbra.client.ZFolder;
import com.zimbra.client.ZMailbox;
import com.zimbra.common.httpclient.HttpClientUtil;
import com.zimbra.common.mime.MimeConstants;
import com.zimbra.common.service.ServiceException;
import com.zimbra.common.util.ByteUtil;
import com.zimbra.common.util.ZimbraLog;
import com.zimbra.common.util.tar.TarEntry;
import com.zimbra.common.util.tar.TarInputStream;
import com.zimbra.common.zmime.ZMimeMessage;
import com.zimbra.cs.account.Account;
import com.zimbra.cs.account.Provisioning;
import com.zimbra.cs.mailbox.Mailbox;
import com.zimbra.cs.util.JMSession;

public class TestUserServlet extends TestCase {

    private static final String NAME_PREFIX = TestUserServlet.class.getSimpleName();
    private static final String USER_NAME = "user1";
    private static String id1;
    private static String id2;
    private String originalSanitizeHtml;

    @Override
    public void setUp() throws Exception {
        cleanUp();

        // Add a test message, in case the account is empty.
        ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
        id1 = TestUtil.addMessage(mbox, NAME_PREFIX);
        Thread.sleep(1000); //so that timestamps are different
        id2 = TestUtil.addMessage(mbox, NAME_PREFIX + " 2");
        originalSanitizeHtml = TestUtil.getAccountAttr(USER_NAME, Provisioning.A_zimbraNotebookSanitizeHtml);
    }

    public void testTarFormatter() throws Exception {
        ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);

        verifyTarball(mbox, "//?fmt=tgz", true, true);
        verifyTarball(mbox, "//?fmt=tgz&body=1", true, true);
        verifyTarball(mbox, "//?fmt=tgz&body=0", true, false);
        verifyTarball(mbox, "//?fmt=tgz&meta=1", true, true);
        verifyTarball(mbox, "//?fmt=tgz&meta=0", false, true);
    }

    private void verifyTarball(ZMailbox mbox, String relativePath, boolean hasMeta, boolean hasBody)
            throws Exception {
        InputStream in = mbox.getRESTResource(relativePath);
        TarInputStream tarIn = new TarInputStream(new GZIPInputStream(in), "UTF-8");
        TarEntry entry = null;
        boolean foundMeta = false;
        boolean foundMessage = false;
        while ((entry = tarIn.getNextEntry()) != null) {
            if (entry.getName().endsWith(".meta")) {
                assertTrue("Fround " + entry.getName(), hasMeta);
                foundMeta = true;
            }
            if (entry.getName().endsWith(".eml")) {
                byte[] content = new byte[(int) entry.getSize()];
                assertEquals(content.length, tarIn.read(content));
                MimeMessage message = new ZMimeMessage(JMSession.getSession(),
                        new SharedByteArrayInputStream(content));
                byte[] body = ByteUtil.getContent(message.getInputStream(), 0);
                if (hasBody) {
                    assertTrue(entry.getName() + " has no body", body.length > 0);
                } else {
                    assertEquals(entry.getName() + " has a body", 0, body.length);
                }
                foundMessage = true;
            }
        }
        tarIn.close();
        assertTrue(foundMessage);
        if (hasMeta) {
            assertTrue(foundMeta);
        }
    }

    public void testZipFormatter() throws Exception {
        ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);

        verifyZipFile(mbox, "/Inbox/?fmt=zip", true);
        verifyZipFile(mbox, "/Inbox/?fmt=zip&body=1", true);
        verifyZipFile(mbox, "/Inbox/?fmt=zip&body=0", false);
    }

    /**
     * Test that can import into a new calendar from ICALENDAR containing an inline ATTACHment.
     * Test that it is possible to export calendar entry with an attachment with the attachment
     * inlined if icalAttach=inline or ignoring the attachment if icalAttach=none
     */
    public void testIcsImportExport() throws IOException, ValidationException, ServiceException {
        ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
        String calName = NAME_PREFIX + "2ndCalendar";
        String calUri = String.format("/%s?fmt=ics", calName);
        TestUtil.createFolder(mbox, calName, ZFolder.View.appointment);
        net.fortuna.ical4j.model.Calendar calendar = new net.fortuna.ical4j.model.Calendar();
        calendar.getProperties().add(new ProdId("-//ZimbraTest 1.0//EN"));
        calendar.getProperties().add(Version.VERSION_2_0);
        calendar.getProperties().add(CalScale.GREGORIAN);
        java.util.Calendar start = java.util.Calendar.getInstance();
        start.set(java.util.Calendar.MONTH, java.util.Calendar.SEPTEMBER);
        start.set(java.util.Calendar.DAY_OF_MONTH, 03);

        VEvent wwII = new VEvent(new Date(start.getTime()), NAME_PREFIX + " Declarations of war");
        wwII.getProperties().getProperty(Property.DTSTART).getParameters().add(Value.DATE);
        wwII.getProperties().add(new Uid("3-14159"));
        Attach attach = new Attach("Attachment.\nIsn't it short.".getBytes(MimeConstants.P_CHARSET_ASCII));
        attach.getParameters().add(new XParameter("X-APPLE-FILENAME", "short.txt"));
        attach.getParameters().add(new FmtType(MimeConstants.CT_TEXT_PLAIN));
        wwII.getProperties().add(attach);
        calendar.getComponents().add(wwII);
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        CalendarOutputter outputter = new CalendarOutputter();
        outputter.setValidating(false);
        outputter.output(calendar, buf);
        URI uri = mbox.getRestURI(calUri);
        HttpClient client = mbox.getHttpClient(uri);
        PostMethod post = new PostMethod(uri.toString());
        post.setRequestEntity(new InputStreamRequestEntity(new ByteArrayInputStream(buf.toByteArray()),
                MimeConstants.CT_TEXT_CALENDAR));
        ZimbraLog.test.info("testIcsImportExport:ICS to be imported:%s", new String(buf.toByteArray()));
        TestCalDav.HttpMethodExecutor.execute(client, post, HttpStatus.SC_OK);
        uri = mbox.getRestURI(calUri + "&icalAttach=inline");
        GetMethod get = new GetMethod(uri.toString());
        TestCalDav.HttpMethodExecutor executor = new TestCalDav.HttpMethodExecutor(client, get, HttpStatus.SC_OK);
        String respIcal = new String(executor.responseBodyBytes, MimeConstants.P_CHARSET_UTF8);
        ZimbraLog.test.info("testIcsImportExport:ICS exported (with icalAttach=inline):%s", respIcal);
        int attachNdx = respIcal.indexOf("ATTACH;");
        assertTrue("ATTACH should be present", -1 != attachNdx);
        String fromAttach = respIcal.substring(attachNdx);
        assertTrue("BINARY should be present", -1 != fromAttach.indexOf("VALUE=BINARY"));
        uri = mbox.getRestURI(calUri + "&icalAttach=none");
        get = new GetMethod(uri.toString());
        executor = new TestCalDav.HttpMethodExecutor(client, get, HttpStatus.SC_OK);
        respIcal = new String(executor.responseBodyBytes, MimeConstants.P_CHARSET_UTF8);
        ZimbraLog.test.debug("testIcsImportExport:ICS exported (with icalAttach=none):%s", respIcal);
        assertTrue("ATTACH should be present", -1 == respIcal.indexOf("ATTACH;"));
        uri = mbox.getRestURI(calUri);
        get = new GetMethod(uri.toString());
        executor = new TestCalDav.HttpMethodExecutor(client, get, HttpStatus.SC_OK);
        respIcal = new String(executor.responseBodyBytes, MimeConstants.P_CHARSET_UTF8);
        ZimbraLog.test.debug("testIcsImportExport:ICS exported (default - same as icalAttach=none):%s", respIcal);
        assertTrue("ATTACH should be present", -1 == respIcal.indexOf("ATTACH;"));
    }

    /** Bug 84362 Confirm that import with London timezone incorrectly identified as "GMT" works */
    public void testIcsImportExportGMTtoLondon() throws IOException, ServiceException {
        ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
        String calName = NAME_PREFIX + "3rdCalendar";
        String calUri = String.format("/%s?fmt=ics", calName);
        TestUtil.createFolder(mbox, calName, ZFolder.View.appointment);
        URI uri = mbox.getRestURI(calUri);
        HttpClient client = mbox.getHttpClient(uri);
        PostMethod post = new PostMethod(uri.toString());
        post.setRequestEntity(new InputStreamRequestEntity(
                new ByteArrayInputStream(TestCalDav.LOTUS_NOTES_WITH_BAD_GMT_TZID.getBytes()),
                MimeConstants.CT_TEXT_CALENDAR));
        ZimbraLog.test.debug("testIcsImportExport:ICS to be imported:%s", TestCalDav.LOTUS_NOTES_WITH_BAD_GMT_TZID);
        TestCalDav.HttpMethodExecutor.execute(client, post, HttpStatus.SC_OK);
        uri = mbox.getRestURI(calUri);
        GetMethod get = new GetMethod(uri.toString());
        TestCalDav.HttpMethodExecutor executor = new TestCalDav.HttpMethodExecutor(client, get, HttpStatus.SC_OK);
        String respIcal = new String(executor.responseBodyBytes, MimeConstants.P_CHARSET_UTF8);
        ZimbraLog.test.debug("testIcsImportExport:ICS exported:%s", respIcal);
        // If this is present, it implies that both the timezone and the references have been correctly changed.
        String dtstartWithNewTZID = "DTSTART;TZID=\"Europe/London\":20150721T140000";
        int dtstartIndex = respIcal.indexOf(dtstartWithNewTZID);
        assertTrue(String.format("'%s' should be present", dtstartWithNewTZID), -1 != dtstartIndex);
    }

    private void verifyZipFile(ZMailbox mbox, String relativePath, boolean hasBody) throws Exception {
        InputStream in = mbox.getRESTResource(relativePath);
        ZipInputStream zipIn = new ZipInputStream(in);
        ZipEntry entry;
        boolean foundMessage = false;
        while ((entry = zipIn.getNextEntry()) != null) {
            if (entry.getName().endsWith(".eml")) {
                ByteArrayOutputStream buf = new ByteArrayOutputStream();
                ByteUtil.copy(zipIn, false, buf, true);
                byte[] content = buf.toByteArray();
                MimeMessage message = new ZMimeMessage(JMSession.getSession(),
                        new SharedByteArrayInputStream(content));
                byte[] body = ByteUtil.getContent(message.getInputStream(), 0);
                if (hasBody) {
                    assertTrue(entry.getName() + " has no body", body.length > 0);
                } else {
                    assertEquals(entry.getName() + " has a body", 0, body.length);
                }
                foundMessage = true;
            }
        }
        zipIn.close();
        assertTrue(foundMessage);
    }

    /**
     * Verifies that the value of {@code zimbraNotebookSanitizeHtml} does not
     * affect the {@code Content-Type} header (bug 67752).
     */
    public void testSanitizeHtmlContentType() throws ServiceException, IOException {
        ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
        ZDocument doc = TestUtil.createDocument(mbox, Integer.toString(Mailbox.ID_FOLDER_BRIEFCASE),
                NAME_PREFIX + " testSanitizeHtmlContentType.txt", "text/plain",
                "testSanitizeHtmlContentType".getBytes());

        Account account = TestUtil.getAccount(USER_NAME);
        account.setNotebookSanitizeHtml(false);
        checkContentType(mbox, doc);
        account.setNotebookSanitizeHtml(true);
        checkContentType(mbox, doc);
    }

    @Test
    public void testSort() throws Exception {
        ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
        List<String> dateDesc = new ArrayList<String>();
        dateDesc.add(id2);
        dateDesc.add(id1);
        List<String> dateAsc = new ArrayList<String>(dateDesc);
        Collections.reverse(dateAsc);
        checkResultOrder(mbox, "/inbox?fmt=xml&query=TestUserServlet", dateDesc); //check that default is dateDesc
        checkResultOrder(mbox, "/inbox?fmt=xml&sort=dateDesc&query=TestUserServlet", dateDesc);
        checkResultOrder(mbox, "/inbox?fmt=xml&sort=dateAsc&query=TestUserServlet", dateAsc);
        try {
            checkResultOrder(mbox, "/inbox?fmt=xml&sort=rubbish&query=TestUserServlet", dateAsc);
            fail(); //invalid sort order should throw an error
        } catch (ServiceException e) {
            String msg = e.getMessage();
            assertTrue(msg.contains("rubbish is not a valid sort order"));
        }
    }

    private void checkResultOrder(ZMailbox mbox, String uri, List<String> expectedOrder) throws Exception {
        InputStream is = mbox.getRESTResource(uri);
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(is);
        NodeList nodes = doc.getElementsByTagName("m");
        assertEquals(expectedOrder.size(), nodes.getLength());
        List<String> results = new ArrayList<String>();
        for (int i = 0; i < nodes.getLength(); i++) {
            Element node = (Element) nodes.item(i);
            String id = node.getAttribute("id");
            results.add(id);
        }
        assertEquals(expectedOrder, results);
    }

    private void checkContentType(ZMailbox mbox, ZDocument doc) throws ServiceException, IOException {
        URI uri = mbox.getRestURI("?id=" + doc.getId());
        HttpClient client = mbox.getHttpClient(uri);
        GetMethod get = new GetMethod(uri.toString());
        int statusCode = HttpClientUtil.executeMethod(client, get);
        get.releaseConnection();
        assertEquals(200, statusCode);
        assertEquals("text/plain", get.getResponseHeader("Content-Type").getValue());
    }

    @Override
    public void tearDown() throws Exception {
        TestUtil.setAccountAttr(USER_NAME, Provisioning.A_zimbraNotebookSanitizeHtml, originalSanitizeHtml);
        cleanUp();
    }

    private void cleanUp() throws Exception {
        TestUtil.deleteTestData(USER_NAME, NAME_PREFIX);
    }

    public static void main(String[] args) throws Exception {
        TestUtil.cliSetup();
        TestUtil.runTest(TestUserServlet.class);
    }
}