/**
   * Create an all-day appointment on the server
   *
   * @param account The appointment organizer
   * @param date The appointment start date
   * @param duration The appointment duration (in days)
   * @param subject The appointment subject
   * @param content The appointment text content
   * @param location The appointment location (null if none)
   * @param attendees A list of attendees (null for none)
   * @return
   * @throws HarnessException
   */
  public static AppointmentItem createAppointmentAllDay(
      ZimbraAccount account,
      Calendar date,
      int duration,
      String subject,
      String content,
      String location,
      List<ZimbraAccount> attendees)
      throws HarnessException {

    // If location is null, don't specify the loc attribute
    String loc = (location == null ? "" : "loc='" + location + "'");

    // Convert the calendar to a ZDate
    ZDate start =
        new ZDate(
            date.get(Calendar.YEAR),
            date.get(Calendar.MONTH) + 1,
            date.get(Calendar.DAY_OF_MONTH),
            12,
            0,
            0);

    account.soapSend(
        "<CreateAppointmentRequest xmlns='urn:zimbraMail'>"
            + "<m l='10'>"
            + "<inv>"
            + "<comp allDay='1' name='"
            + subject
            + "' "
            + loc
            + " draft='0' status='CONF' class='PUB' transp='O' fb='F'>"
            + "<s d='"
            + start.toYYYYMMDD()
            + "'/>"
            + "<e d='"
            + start.addDays(duration > 0 ? duration - 1 : 0).toYYYYMMDD()
            + "'/>"
            + "<or a='"
            + account.EmailAddress
            + "'/>"
            + "</comp>"
            + "</inv>"
            + "<su>"
            + subject
            + "</su>"
            + "<mp ct='text/plain'>"
            + "<content>"
            + content
            + "</content>"
            + "</mp>"
            + "</m>"
            + "</CreateAppointmentRequest>");

    AppointmentItem result =
        AppointmentItem.importFromSOAP(
            account, "subject:(" + subject + ")", start.addDays(-7), start.addDays(7));

    return (result);
  }
Exemple #2
0
	@Bugs(ids = "69132")
	@Test(	description = "View a basic all-day appointment in the work week view",
			groups = { "smoke" })
	public void GetAllDayAppointment_01() throws HarnessException {
		
		// Create the appointment on the server
		String apptSubject = "appointment" + ZimbraSeleniumProperties.getUniqueString();
		String apptLocation = "location" + ZimbraSeleniumProperties.getUniqueString();
		String apptBody = "content" + ZimbraSeleniumProperties.getUniqueString();
		
		// Absolute dates in UTC zone
		Calendar now = this.calendarWeekDayUTC;
		ZDate startUTC = new ZDate(now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1, now.get(Calendar.DAY_OF_MONTH), 12, 0, 0);
		ZDate endUTC   = new ZDate(now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1, now.get(Calendar.DAY_OF_MONTH), 14, 0, 0);
		
		// EST timezone string
		String tz = ZTimeZone.TimeZoneEST.getID();

		// Create a meeting request from AccountA to the test account
		ZimbraAccount.AccountA().soapSend(
					"<CreateAppointmentRequest xmlns='urn:zimbraMail'>" +
						"<m>" +
							"<inv>" +
								"<comp status='CONF' fb='B' class='PUB' transp='O' allDay='1' name='"+ apptSubject +"' loc='"+ apptLocation +"'>" +
									"<s d='"+ startUTC.toTimeZone(tz).toYYYYMMDDTHHMMSS() +"' tz='"+ tz +"'/>" +
									"<e d='"+ endUTC.toTimeZone(tz).toYYYYMMDDTHHMMSS() +"' tz='"+ tz +"'/>" +
									"<at role='REQ' ptst='NE' rsvp='1' a='"+ app.zGetActiveAccount().EmailAddress +"'/>" +
									"<or a='"+ ZimbraAccount.AccountA().EmailAddress + "'/>" +
								"</comp>" +
							"</inv>" +
							"<e a='"+ app.zGetActiveAccount().EmailAddress +"' t='t'/>" +
							"<su>"+ apptSubject + "</su>" +
							"<mp ct='text/plain'>" +
							"<content>"+ apptBody +"</content>" +
							"</mp>" +
						"</m>" +
					"</CreateAppointmentRequest>");
		
		AppointmentItem appt = AppointmentItem.importFromSOAP(app.zGetActiveAccount(), "subject:("+ apptSubject +")", startUTC.addDays(-7), endUTC.addDays(7));
		ZAssert.assertNotNull(appt, "Verify the new appointment is created");

		app.zPageCalendar.zToolbarPressButton(Button.B_REFRESH);
		
		//wait for the appointment displayed in the view
		ZAssert.assertEquals(app.zPageCalendar.sIsElementPresent(app.zPageCalendar.zGetReadOnlyAllDayApptLocator(apptSubject)), true, "Verify all-day appointment is deleted");
		
	}
  /**
   * Get an AppointmentItem using soap
   *
   * @param account
   * @param query
   * @param start
   * @param end
   * @return
   * @throws HarnessException
   */
  public static AppointmentItem importFromSOAP(
      ZimbraAccount account, String query, ZDate start, ZDate end) throws HarnessException {

    try {
      account.soapSend(
          "<SearchRequest xmlns='urn:zimbraMail' types='appointment' calExpandInstStart='"
              + start.toMillis()
              + "' calExpandInstEnd='"
              + end.toMillis()
              + "'>"
              + "<query>"
              + query
              + "</query>"
              + "</SearchRequest>");

      Element[] results = account.soapSelectNodes("//mail:SearchResponse/mail:appt");
      if (results.length != 1)
        // throw new HarnessException("Query should return 1 result, not "+ results.length);
        return null;

      String id = account.soapSelectValue("//mail:appt", "id");

      account.soapSend(
          "<GetAppointmentRequest xmlns='urn:zimbraMail' id='"
              + id
              + "' includeContent='1'>"
              + "</GetAppointmentRequest>");
      Element getAppointmentResponse = account.soapSelectNode("//mail:GetAppointmentResponse", 1);

      // Using the response, create this item
      return (importFromSOAP(getAppointmentResponse));

    } catch (Exception e) {
      throw new HarnessException(
          "Unable to import using SOAP query("
              + query
              + ") and account("
              + account.EmailAddress
              + ")",
          e);
    }
  }
  /**
   * ZimbraAccount.AccountA() sends a two-hour appointment to app.zGetActiveAccount() with subject
   * and start time
   *
   * @param subject
   * @param start
   * @throws HarnessException
   */
  private void SendCreateAppointmentRequest(String subject, ZDate start) throws HarnessException {

    ZimbraAccount.AccountA()
        .soapSend(
            "<CreateAppointmentRequest xmlns='urn:zimbraMail'>"
                + "<m>"
                + "<inv method='REQUEST' type='event' status='CONF' draft='0' class='PUB' fb='B' transp='O' allDay='0' name='"
                + subject
                + "'>"
                + "<s d='"
                + start.toTimeZone(ZTimeZone.TimeZoneEST.getID()).toYYYYMMDDTHHMMSS()
                + "' tz='"
                + ZTimeZone.TimeZoneEST.getID()
                + "'/>"
                + "<e d='"
                + start.addHours(2).toTimeZone(ZTimeZone.TimeZoneEST.getID()).toYYYYMMDDTHHMMSS()
                + "' tz='"
                + ZTimeZone.TimeZoneEST.getID()
                + "'/>"
                + "<or a='"
                + ZimbraAccount.AccountA().EmailAddress
                + "'/>"
                + "<at role='REQ' ptst='NE' rsvp='1' a='"
                + app.zGetActiveAccount().EmailAddress
                + "'/>"
                + "</inv>"
                + "<e a='"
                + app.zGetActiveAccount().EmailAddress
                + "' t='t'/>"
                + "<su>"
                + subject
                + "</su>"
                + "<mp content-type='text/plain'>"
                + "<content>content</content>"
                + "</mp>"
                + "</m>"
                + "</CreateAppointmentRequest>");
  }
  @Test(
      description = "Run a saved search",
      groups = {"smoke"})
  public void RunSavedSearch_01() throws HarnessException {

    // Create the message data to be sent
    String name = "search" + ZimbraSeleniumProperties.getUniqueString();
    String subject1 = "subject" + ZimbraSeleniumProperties.getUniqueString();
    String subject2 = "subject" + ZimbraSeleniumProperties.getUniqueString();
    String query = "subject:(" + subject1 + ")";

    // Send two messages with different subjects to the account
    ZimbraAccount.AccountA()
        .soapSend(
            "<SendMsgRequest xmlns='urn:zimbraMail'>"
                + "<m>"
                + "<e t='t' a='"
                + app.zGetActiveAccount().EmailAddress
                + "'/>"
                + "<su>"
                + subject1
                + "</su>"
                + "<mp ct='text/plain'>"
                + "<content>content1"
                + ZimbraSeleniumProperties.getUniqueString()
                + "</content>"
                + "</mp>"
                + "</m>"
                + "</SendMsgRequest>");

    ZimbraAccount.AccountA()
        .soapSend(
            "<SendMsgRequest xmlns='urn:zimbraMail'>"
                + "<m>"
                + "<e t='t' a='"
                + app.zGetActiveAccount().EmailAddress
                + "'/>"
                + "<su>"
                + subject2
                + "</su>"
                + "<mp ct='text/plain'>"
                + "<content>content1"
                + ZimbraSeleniumProperties.getUniqueString()
                + "</content>"
                + "</mp>"
                + "</m>"
                + "</SendMsgRequest>");

    // Create the saved search
    app.zGetActiveAccount()
        .soapSend(
            "<CreateSearchFolderRequest xmlns='urn:zimbraMail'>"
                + "<search name='"
                + name
                + "' query='"
                + query
                + "' l='1'/>"
                + "</CreateSearchFolderRequest>");

    // Get the item
    SavedSearchFolderItem item =
        SavedSearchFolderItem.importFromSOAP(app.zGetActiveAccount(), name);

    // Refresh the folder list
    app.zPageMail.zToolbarPressButton(Button.B_GETMAIL);

    // Left click on the search
    app.zTreeMail.zTreeItem(Action.A_LEFTCLICK, item);

    // Verify the correct messages appear
    List<MailItem> messages = app.zPageMail.zListGetMessages();
    ZAssert.assertNotNull(messages, "Verify the message list exists");

    MailItem found1 = null;
    MailItem found2 = null;
    for (MailItem m : messages) {
      logger.info("Subject: looking for " + subject1 + " found: " + m.gSubject);
      if (subject1.equals(m.gSubject)) {
        found1 = m;
        break;
      }
      logger.info("Subject: looking for " + subject2 + " found: " + m.gSubject);
      if (subject2.equals(m.gSubject)) {
        found2 = m;
        break;
      }
    }
    ZAssert.assertNotNull(found1, "Verify the matched message exists in the inbox");
    ZAssert.assertNull(found2, "Verify the un-match message does not exist in the inbox");
  }
Exemple #6
0
  @Test(
      description = "Flag a mail by using shortcut 'mf'",
      groups = {"functional"})
  public void FlagMail_02() throws HarnessException {

    // Create the message data to be sent
    String subject = "subject" + ZimbraSeleniumProperties.getUniqueString();

    ZimbraAccount.AccountA()
        .soapSend(
            "<SendMsgRequest xmlns='urn:zimbraMail'>"
                + "<m>"
                + "<e t='t' a='"
                + app.zGetActiveAccount().EmailAddress
                + "'/>"
                + "<su>"
                + subject
                + "</su>"
                + "<mp ct='text/plain'>"
                + "<content>content"
                + ZimbraSeleniumProperties.getUniqueString()
                + "</content>"
                + "</mp>"
                + "</m>"
                + "</SendMsgRequest>");

    // Create a mail item to represent the message
    MailItem mail = MailItem.importFromSOAP(app.zGetActiveAccount(), "subject:(" + subject + ")");

    // Click Get Mail button
    app.zPageMail.zToolbarPressButton(Button.B_GETMAIL);

    // Select the item
    app.zPageMail.zListItem(Action.A_LEFTCLICK, mail.dSubject);

    // Flag the item
    app.zPageMail.zKeyboardShortcut(Shortcut.S_MAIL_MARKFLAG);

    // Get the item from the list
    List<MailItem> messages = app.zPageMail.zListGetMessages();
    ZAssert.assertNotNull(messages, "Verify the message list exists");

    MailItem listmail = null;
    for (MailItem m : messages) {
      logger.info("Subject: looking for " + mail.dSubject + " found: " + m.gSubject);
      if (mail.dSubject.equals(m.gSubject)) {
        listmail = m;
        break;
      }
    }

    GeneralUtility.syncDesktopToZcsWithSoap(app.zGetActiveAccount());

    // Make sure the GUI shows "flagged"
    ZAssert.assertNotNull(listmail, "Verify the message is in the list");
    ZAssert.assertTrue(listmail.gIsFlagged, "Verify the message is flagged in the list");

    // Make sure the server shows "flagged"
    mail = MailItem.importFromSOAP(app.zGetActiveAccount(), "subject:(" + subject + ")");
    ZAssert.assertStringContains(
        mail.getFlags(), "f", "Verify the message is flagged in the server");
  }
  @Bugs(ids = "69132")
  @Test(
      description = "Accept a meeting using Accept button from invitation message",
      groups = {"smoke"})
  public void AcceptMeeting_01() throws HarnessException {

    // ------------------------ Test data ------------------------------------

    String apptSubject = "appointment" + ZimbraSeleniumProperties.getUniqueString();

    Calendar now = Calendar.getInstance();
    ZDate startUTC =
        new ZDate(
            now.get(Calendar.YEAR),
            now.get(Calendar.MONTH) + 1,
            now.get(Calendar.DAY_OF_MONTH),
            12,
            0,
            0);
    ZDate endUTC =
        new ZDate(
            now.get(Calendar.YEAR),
            now.get(Calendar.MONTH) + 1,
            now.get(Calendar.DAY_OF_MONTH),
            14,
            0,
            0);

    // --------------- Creating invitation (organizer) ----------------------------

    ZimbraAccount.AccountA()
        .soapSend(
            "<CreateAppointmentRequest xmlns='urn:zimbraMail'>"
                + "<m>"
                + "<inv method='REQUEST' type='event' status='CONF' draft='0' class='PUB' fb='B' transp='O' allDay='0' name='"
                + apptSubject
                + "'>"
                + "<s d='"
                + startUTC.toTimeZone(ZTimeZone.TimeZoneEST.getID()).toYYYYMMDDTHHMMSS()
                + "' tz='"
                + ZTimeZone.TimeZoneEST.getID()
                + "'/>"
                + "<e d='"
                + endUTC.toTimeZone(ZTimeZone.TimeZoneEST.getID()).toYYYYMMDDTHHMMSS()
                + "' tz='"
                + ZTimeZone.TimeZoneEST.getID()
                + "'/>"
                + "<or a='"
                + ZimbraAccount.AccountA().EmailAddress
                + "'/>"
                + "<at role='REQ' ptst='NE' rsvp='1' a='"
                + app.zGetActiveAccount().EmailAddress
                + "'/>"
                + "</inv>"
                + "<e a='"
                + app.zGetActiveAccount().EmailAddress
                + "' t='t'/>"
                + "<su>"
                + apptSubject
                + "</su>"
                + "<mp content-type='text/plain'>"
                + "<content>content</content>"
                + "</mp>"
                + "</m>"
                + "</CreateAppointmentRequest>");

    // --------------- Login to attendee & accept invitation
    // ----------------------------------------------------

    // Refresh the view
    app.zPageMail.zToolbarPressButton(Button.B_GETMAIL);

    // Select the invitation
    DisplayMail display = (DisplayMail) app.zPageMail.zListItem(Action.A_LEFTCLICK, apptSubject);

    // Click Accept
    display.zPressButton(Button.B_ACCEPT);

    // ---------------- Verification at organizer & invitee side both
    // -------------------------------------

    // --- Check that the organizer shows the attendee as "ACCEPT" ---

    // Organizer: Search for the appointment (InvId)
    ZimbraAccount.AccountA()
        .soapSend(
            "<SearchRequest xmlns='urn:zimbraMail' types='appointment' calExpandInstStart='"
                + startUTC.addDays(-10).toMillis()
                + "' calExpandInstEnd='"
                + endUTC.addDays(10).toMillis()
                + "'>"
                + "<query>"
                + apptSubject
                + "</query>"
                + "</SearchRequest>");

    String organizerInvId = ZimbraAccount.AccountA().soapSelectValue("//mail:appt", "invId");

    // Get the appointment details
    ZimbraAccount.AccountA()
        .soapSend("<GetAppointmentRequest  xmlns='urn:zimbraMail' id='" + organizerInvId + "'/>");

    String attendeeStatus =
        ZimbraAccount.AccountA()
            .soapSelectValue(
                "//mail:at[@a='" + app.zGetActiveAccount().EmailAddress + "']", "ptst");

    // Verify attendee status shows as psts=AC
    ZAssert.assertEquals(attendeeStatus, "AC", "Verify that the attendee shows as 'ACCEPTED'");

    // --- Check that the attendee showing status as "ACCEPT" ---

    // Attendee: Search for the appointment (InvId)
    app.zGetActiveAccount()
        .soapSend(
            "<SearchRequest xmlns='urn:zimbraMail' types='appointment' calExpandInstStart='"
                + startUTC.addDays(-10).toMillis()
                + "' calExpandInstEnd='"
                + endUTC.addDays(10).toMillis()
                + "'>"
                + "<query>"
                + apptSubject
                + "</query>"
                + "</SearchRequest>");

    String attendeeInvId = app.zGetActiveAccount().soapSelectValue("//mail:appt", "invId");

    // Get the appointment details
    app.zGetActiveAccount()
        .soapSend("<GetAppointmentRequest  xmlns='urn:zimbraMail' id='" + attendeeInvId + "'/>");

    String myStatus =
        app.zGetActiveAccount()
            .soapSelectValue(
                "//mail:at[@a='" + app.zGetActiveAccount().EmailAddress + "']", "ptst");

    // Verify attendee status shows as psts=AC
    ZAssert.assertEquals(myStatus, "AC", "Verify that the attendee shows as 'ACCEPTED'");
  }
  @Bugs(ids = "69132")
  @Test(
      description = "Accept meeting using 'Accept -> Edit Reply' and verify modified content",
      groups = {"functional"})
  public void AcceptMeeting_04() throws HarnessException {

    // ------------------------ Test data ------------------------------------

    String apptSubject = "appointment" + ZimbraSeleniumProperties.getUniqueString();
    String modifiedBody = "modified" + ZimbraSeleniumProperties.getUniqueString();

    Calendar now = Calendar.getInstance();
    ZDate startUTC =
        new ZDate(
            now.get(Calendar.YEAR),
            now.get(Calendar.MONTH) + 1,
            now.get(Calendar.DAY_OF_MONTH),
            12,
            0,
            0);
    ZDate endUTC =
        new ZDate(
            now.get(Calendar.YEAR),
            now.get(Calendar.MONTH) + 1,
            now.get(Calendar.DAY_OF_MONTH),
            14,
            0,
            0);

    // --------------- Creating invitation (organizer) ----------------------------

    ZimbraAccount.AccountA()
        .soapSend(
            "<CreateAppointmentRequest xmlns='urn:zimbraMail'>"
                + "<m>"
                + "<inv method='REQUEST' type='event' status='CONF' draft='0' class='PUB' fb='B' transp='O' allDay='0' name='"
                + apptSubject
                + "'>"
                + "<s d='"
                + startUTC.toTimeZone(ZTimeZone.TimeZoneEST.getID()).toYYYYMMDDTHHMMSS()
                + "' tz='"
                + ZTimeZone.TimeZoneEST.getID()
                + "'/>"
                + "<e d='"
                + endUTC.toTimeZone(ZTimeZone.TimeZoneEST.getID()).toYYYYMMDDTHHMMSS()
                + "' tz='"
                + ZTimeZone.TimeZoneEST.getID()
                + "'/>"
                + "<or a='"
                + ZimbraAccount.AccountA().EmailAddress
                + "'/>"
                + "<at role='REQ' ptst='NE' rsvp='1' a='"
                + app.zGetActiveAccount().EmailAddress
                + "'/>"
                + "</inv>"
                + "<e a='"
                + app.zGetActiveAccount().EmailAddress
                + "' t='t'/>"
                + "<su>"
                + apptSubject
                + "</su>"
                + "<mp content-type='text/plain'>"
                + "<content>content</content>"
                + "</mp>"
                + "</m>"
                + "</CreateAppointmentRequest>");

    // --------------- Login to attendee & accept invitation
    // ----------------------------------------------------

    // Refresh the view
    app.zPageMail.zToolbarPressButton(Button.B_GETMAIL);

    // Select the invitation
    DisplayMail display = (DisplayMail) app.zPageMail.zListItem(Action.A_LEFTCLICK, apptSubject);

    // Click Accept -> Edit Reply , which will open a new reply compose
    FormMailNew editReply =
        (FormMailNew) display.zPressButtonPulldown(Button.B_ACCEPT, Button.O_ACCEPT_EDIT_REPLY);
    editReply.zFillField(Field.Body, modifiedBody);
    editReply.zSubmit();

    // ---------------- Verification at organizer & invitee side both
    // -------------------------------------

    // --- Check that the organizer shows the attendee as "ACCEPT" ---

    // Organizer: Search for the appointment (InvId)
    ZimbraAccount.AccountA()
        .soapSend(
            "<SearchRequest xmlns='urn:zimbraMail' types='appointment' calExpandInstStart='"
                + startUTC.addDays(-10).toMillis()
                + "' calExpandInstEnd='"
                + endUTC.addDays(10).toMillis()
                + "'>"
                + "<query>"
                + apptSubject
                + "</query>"
                + "</SearchRequest>");

    String organizerInvId = ZimbraAccount.AccountA().soapSelectValue("//mail:appt", "invId");

    // Get the appointment details
    ZimbraAccount.AccountA()
        .soapSend("<GetAppointmentRequest  xmlns='urn:zimbraMail' id='" + organizerInvId + "'/>");

    String attendeeStatus =
        ZimbraAccount.AccountA()
            .soapSelectValue(
                "//mail:at[@a='" + app.zGetActiveAccount().EmailAddress + "']", "ptst");

    // Verify attendee status shows as psts=AC
    ZAssert.assertEquals(attendeeStatus, "AC", "Verify that the attendee shows as 'ACCEPTED'");

    // --- Check that the attendee showing status as "ACCEPT" ---

    // Attendee: Search for the appointment (InvId)
    app.zGetActiveAccount()
        .soapSend(
            "<SearchRequest xmlns='urn:zimbraMail' types='appointment' calExpandInstStart='"
                + startUTC.addDays(-10).toMillis()
                + "' calExpandInstEnd='"
                + endUTC.addDays(10).toMillis()
                + "'>"
                + "<query>"
                + apptSubject
                + "</query>"
                + "</SearchRequest>");

    String attendeeInvId = app.zGetActiveAccount().soapSelectValue("//mail:appt", "invId");

    // Get the appointment details
    app.zGetActiveAccount()
        .soapSend("<GetAppointmentRequest  xmlns='urn:zimbraMail' id='" + attendeeInvId + "'/>");

    String myStatus =
        app.zGetActiveAccount()
            .soapSelectValue(
                "//mail:at[@a='" + app.zGetActiveAccount().EmailAddress + "']", "ptst");

    // Verify attendee status shows as psts=AC
    ZAssert.assertEquals(myStatus, "AC", "Verify that the attendee shows as 'ACCEPTED'");

    // Organizer: Search for the appointment response
    String inboxId =
        FolderItem.importFromSOAP(ZimbraAccount.AccountA(), FolderItem.SystemFolder.Inbox).getId();

    ZimbraAccount.AccountA()
        .soapSend(
            "<SearchRequest xmlns='urn:zimbraMail' types='message'>"
                + "<query>inid:"
                + inboxId
                + " subject:("
                + apptSubject
                + ")</query>"
                + "</SearchRequest>");

    // Verify message body content
    String body = ZimbraAccount.AccountA().soapSelectValue("//mail:m/mail:fr", null);
    ZAssert.assertStringContains(body, modifiedBody, "Verify modified body value");
  }
  @Bugs(ids = "69132")
  @Test(
      description = "Accept meeting - Verify organizer gets notification message",
      groups = {"functional"})
  public void AcceptMeeting_02() throws HarnessException {

    // ------------------------ Test data ------------------------------------

    String apptSubject = "appointment" + ZimbraSeleniumProperties.getUniqueString();
    Calendar now = Calendar.getInstance();
    ZDate startUTC =
        new ZDate(
            now.get(Calendar.YEAR),
            now.get(Calendar.MONTH) + 1,
            now.get(Calendar.DAY_OF_MONTH),
            12,
            0,
            0);

    // --------------- Creating invitation (organizer) ----------------------------

    this.SendCreateAppointmentRequest(apptSubject, startUTC);

    // --------------- Login to attendee & accept invitation
    // ----------------------------------------------------

    app.zPageMail.zToolbarPressButton(Button.B_GETMAIL);

    // Select the invitation
    DisplayMail display = (DisplayMail) app.zPageMail.zListItem(Action.A_LEFTCLICK, apptSubject);

    // Click Accept
    display.zPressButton(Button.B_ACCEPT);

    // ---------------- Verification at organizer & invitee side both
    // -------------------------------------

    // --- Check that the organizer shows the attendee as "ACCEPT" ---

    // Organizer: Search for the appointment response
    String inboxId =
        FolderItem.importFromSOAP(ZimbraAccount.AccountA(), FolderItem.SystemFolder.Inbox).getId();

    ZimbraAccount.AccountA()
        .soapSend(
            "<SearchRequest xmlns='urn:zimbraMail' types='message'>"
                + "<query>inid:"
                + inboxId
                + " subject:("
                + apptSubject
                + ")</query>"
                + "</SearchRequest>");

    String messageId = ZimbraAccount.AccountA().soapSelectValue("//mail:m", "id");

    // Get the appointment details
    ZimbraAccount.AccountA()
        .soapSend(
            "<GetMsgRequest  xmlns='urn:zimbraMail'>"
                + "<m id='"
                + messageId
                + "'/>"
                + "</GetMsgRequest>");
  }
  /**
   * Create a single-day appointment on the server
   *
   * @param account Appointment Organizer
   * @param start Start time of the appointment, which will be rounded to the nearest hour
   * @param duration Duration of the appointment, in minutes
   * @param timezone Timezone of the appointment (null if default)
   * @param subject Subject of the appointment
   * @param content Content of the appointment (text)
   * @param location Location of the appointment (null if none)
   * @param attendees List of attendees for the appointment
   * @return
   * @throws HarnessException
   */
  public static AppointmentItem createAppointmentSingleDay(
      ZimbraAccount account,
      Calendar start,
      int duration,
      TimeZone tz,
      String subject,
      String content,
      String location,
      List<ZimbraAccount> attendees)
      throws HarnessException {

    // If location is null, don't specify the loc attribute
    String loc = (location == null ? "" : "loc='" + location + "'");

    // TODO: determine the timezone
    String timezoneString = ZTimeZone.TimeZoneEST.getID();

    // Convert the calendar to a ZDate
    ZDate beginning =
        new ZDate(
            start.get(Calendar.YEAR),
            start.get(Calendar.MONTH) + 1,
            start.get(Calendar.DAY_OF_MONTH),
            start.get(Calendar.HOUR_OF_DAY),
            0,
            0);
    ZDate ending = beginning.addMinutes(duration);

    account.soapSend(
        "<CreateAppointmentRequest xmlns='urn:zimbraMail'>"
            + "<m l='10'>"
            + "<inv>"
            + "<comp name='"
            + subject
            + "' "
            + loc
            + " draft='0' status='CONF' class='PUB' transp='O' fb='B'>"
            + "<s d='"
            + beginning.toTimeZone(timezoneString).toYYYYMMDDTHHMMSS()
            + "' tz='"
            + timezoneString
            + "'/>"
            + "<e d='"
            + ending.toTimeZone(timezoneString).toYYYYMMDDTHHMMSS()
            + "' tz='"
            + timezoneString
            + "'/>"
            + "<or a='"
            + account.EmailAddress
            + "'/>"
            + "</comp>"
            + "</inv>"
            + "<su>"
            + subject
            + "</su>"
            + "<mp ct='text/plain'>"
            + "<content>"
            + content
            + "</content>"
            + "</mp>"
            + "</m>"
            + "</CreateAppointmentRequest>");

    AppointmentItem result =
        AppointmentItem.importFromSOAP(
            account, "subject:(" + subject + ")", beginning.addDays(-7), beginning.addDays(7));

    return (result);
  }