/**
* See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Board of Regents of the University of Wisconsin System
* licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.microsoft.exchange.integration;
import static org.junit.Assert.*;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ibm.icu.util.Region;
import com.ibm.icu.util.TimeZone;
import com.microsoft.exchange.exception.ExchangeCannotDeleteRuntimeException;
import com.microsoft.exchange.exception.ExchangeRuntimeException;
import com.microsoft.exchange.impl.BaseExchangeCalendarDataDao;
import com.microsoft.exchange.messages.GetServerTimeZones;
import com.microsoft.exchange.types.BaseFolderType;
import com.microsoft.exchange.types.CalendarItemType;
import com.microsoft.exchange.types.DisposalType;
import com.microsoft.exchange.types.FolderIdType;
import com.microsoft.exchange.types.ItemIdType;
import com.microsoft.exchange.types.ItemType;
import com.microsoft.exchange.types.TimeZoneDefinitionType;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:test-contexts/exchangeContext.xml"})
public class BaseExchangeCalendarDataDaoIntegrationTest {
protected final Log log = LogFactory.getLog(this.getClass());
String username = "someusername";
@Value("${integration.email:someemailaddress@on.yourexchangeserver.edu}")
String upn;
@Autowired
BaseExchangeCalendarDataDao exchangeCalendarDataDao;
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void isAutowired() {
assertNotNull(exchangeCalendarDataDao);
assertNotNull(upn);
}
@Test
public void resolveEmailAddresses() {
Set<String> results = exchangeCalendarDataDao.resolveEmailAddresses(upn);
assertNotNull(results);
for(String r: results) log.info(r);
}
@Test
public void resolveUpn() {
String resolved = exchangeCalendarDataDao.resolveUpn(upn);
assertNotNull(resolved);
log.info(upn+" resolved to "+ resolved);
}
/**
* Executes a {@link GetServerTimeZones} request, retrieving all {@link TimeZoneDefinitionType}s from Exchange.
* Attempts to map each {@link TimeZoneDefinitionType} to an {@link TimeZone} and logs the result.
*/
@Test
public void getTimeZoneIds(){
int validTimeZoneCount = 0;
List<TimeZoneDefinitionType> zones = exchangeCalendarDataDao.getServerTimeZones(null, false);
log.info("Found "+zones.size() +" exchange time zones.");
for(TimeZoneDefinitionType zone: zones){
String sysTimeZoneID = TimeZone.getIDForWindowsID(zone.getId(), "US");
if(StringUtils.isNotBlank(sysTimeZoneID)){
log.info(zone.getId() +" mapped to "+ sysTimeZoneID);
String windowsID = TimeZone.getWindowsID(sysTimeZoneID);
assertEquals(zone.getId(), windowsID);
validTimeZoneCount++;
}else{
log.warn("no mapping for windowsID="+zone.getId());
}
}
log.info("Succesfully mapped "+validTimeZoneCount+"/"+zones.size()+" WindowsTimeZones");
}
@Test
public void getPrimaryCalendarFolder(){
BaseFolderType primaryCalendarFolder = exchangeCalendarDataDao.getPrimaryCalendarFolder(upn);
assertNotNull(primaryCalendarFolder);
}
@Test
public void getPrimaryTaskFolder(){
BaseFolderType primaryCalendarFolder = exchangeCalendarDataDao.getPrimaryCalendarFolder(upn);
assertNotNull(primaryCalendarFolder);
}
@Test
public void getCalendarFolders(){
Map<String, String> folderMap = exchangeCalendarDataDao.getCalendarFolderMap(upn);
for(String folderId: folderMap.keySet()){
String folderName = folderMap.get(folderId);
log.info(folderName);
}
}
@Test
public void getTaskFolders(){
Map<String, String> folderMap = exchangeCalendarDataDao.getTaskFolderMap(upn);
for(String folderId: folderMap.keySet()){
String folderName = folderMap.get(folderId);
log.info(folderName);
}
}
@Test
public void deleteTaskFolders(){
Map<String, String> taskFoldersMap = exchangeCalendarDataDao.getTaskFolderMap(upn);
for(String taskId : taskFoldersMap.keySet()){
String taskFolderName = taskFoldersMap.get(taskId);
if(taskFolderName.equals("Tasks")) continue;
FolderIdType taskFolderId= new FolderIdType();
taskFolderId.setId(taskId);
log.info("deleting taskFolder '"+taskFolderName+"' ");
boolean deleteTaskFolderSuccess = exchangeCalendarDataDao.deleteFolder(upn, DisposalType.SOFT_DELETE, taskFolderId);
assertTrue(deleteTaskFolderSuccess);
}
}
/**
* This method can fail when there are many (1k+) items in a folder, probably due to throttling limits....
* "Exchange Web Services are not currently available for this request because none of the Client Access Servers in the destination site could process the request."
*
*This method can also fail when disposalType is set to MOVE_TO_DELETED_ITEMS
*If impersonation is used you have to use the MoveToDeletedItems method...
*see note here: http://msdn.microsoft.com/en-us/library/office/aa580484(v=exchg.150).aspx
*
*
*/
@Test
public void deleteFolder(){
FolderIdType calendarFolderId = exchangeCalendarDataDao.getCalendarFolderId(upn, "A2");
assertNotNull(calendarFolderId);
boolean deleteFolderResult = exchangeCalendarDataDao.deleteFolder(upn,DisposalType.SOFT_DELETE,calendarFolderId);
assertTrue(deleteFolderResult);
}
@Test
public void findAllItemIds(){
FolderIdType calendarFolderId = exchangeCalendarDataDao.getCalendarFolderId(upn, "A2");
assertNotNull(calendarFolderId);
Set<FolderIdType> singleton = Collections.singleton(calendarFolderId);
Set<ItemIdType> itemIds = exchangeCalendarDataDao.findAllItemIds(upn, singleton);
for(ItemIdType itemId :itemIds){
log.info(itemId.getId());
}
}
@Test
public void emptyCalendarFolder(){
FolderIdType calendarFolderId = exchangeCalendarDataDao.getCalendarFolderId(upn, "A1");
assertNotNull(calendarFolderId);
boolean emptyCalendarFolder = exchangeCalendarDataDao.emptyCalendarFolder(upn, calendarFolderId);
assertTrue(emptyCalendarFolder);
Set<ItemIdType> findItemIds = exchangeCalendarDataDao.findItemIds(upn, Collections.singleton(calendarFolderId));
assertTrue(findItemIds.isEmpty());
}
/**
* An error response that includes the ErrorCannotDeleteObject error
* code will be returned for a DeleteItem operation when a delegate
* tries to delete an item in the principal's mailbox by setting the
* DisposalType to MoveToDeletedItems. To delete an item by moving it to
* the Deleted Items folder, a delegate must use the MoveItem operation.
*
* @see http://msdn.microsoft.com/en-us/library/office/aa580484(v=exchg.150).aspx
*/
@Test
public void createDeleteCalendarFolder(){
String displayName = "TEST "+upn;
FolderIdType folderId = exchangeCalendarDataDao.createCalendarFolder(upn, displayName);
assertNotNull(folderId);
boolean deleteFolderSuccess = false;
try{
deleteFolderSuccess =exchangeCalendarDataDao.deleteFolder(upn, DisposalType.MOVE_TO_DELETED_ITEMS, folderId);
fail("MOVE_TO_DELETED_ITEMS should have thrown an exception!");
}catch(ExchangeCannotDeleteRuntimeException e){ }
assertFalse(deleteFolderSuccess);
log.info("deleteFolder via MOVE_TO_DELETED_ITEMS failed as expected, attempting SOFT_DELETE");
deleteFolderSuccess = exchangeCalendarDataDao.deleteFolder(upn, DisposalType.SOFT_DELETE, folderId);
if(deleteFolderSuccess){
log.info("deleteFolder via SOFT_DELETE success!");
}else{
log.info("deleteFolder via SOFT_DELETE failure, attempting HARD_DELETE");
deleteFolderSuccess = exchangeCalendarDataDao.deleteFolder(upn, DisposalType.HARD_DELETE, folderId);
}
assertTrue(deleteFolderSuccess);
exception.expect(ExchangeRuntimeException.class);
folderId = exchangeCalendarDataDao.getCalendarFolderId(upn, displayName);
}
@Test
public void getEmptyDeleteCalendarFolder(){
String displayName = "TEST "+upn;
FolderIdType calendarFolderId = exchangeCalendarDataDao.getCalendarFolderId(upn, displayName);
assertNotNull(calendarFolderId);
boolean result = exchangeCalendarDataDao.deleteCalendarFolder(upn, calendarFolderId);
assertTrue(result);
exception.expect(ExchangeRuntimeException.class);
calendarFolderId = exchangeCalendarDataDao.getCalendarFolderId(upn, displayName);
assertNull(calendarFolderId);
}
@Test
public void createGetDeleteEmptyCalendarItem(){
CalendarItemType calendarItem = new CalendarItemType();
ItemIdType calendarItemId = exchangeCalendarDataDao.createCalendarItem(upn, calendarItem);
assertNotNull(calendarItemId);
Set<CalendarItemType> createdCalendarItems = exchangeCalendarDataDao.getCalendarItems(upn, Collections.singleton(calendarItemId));
CalendarItemType createdCalendarItem = DataAccessUtils.singleResult(createdCalendarItems);
assertNotNull(createdCalendarItem);
assertNotNull(createdCalendarItem.getStart());
boolean deleteSuccess = exchangeCalendarDataDao.deleteCalendarItems(upn, Collections.singleton(calendarItemId));
assertTrue(deleteSuccess);
}
}