// Copyright 2007 Google Inc. All Rights Reserved.
//
// Licensed 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.google.enterprise.connector.afyd;
import com.google.enterprise.connector.spi.RepositoryException;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.client.Query;
import com.google.gdata.data.BaseFeed;
import com.google.gdata.data.Feed;
import com.google.gdata.data.Entry;
import com.google.gdata.data.DateTime;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.NotModifiedException;
import junit.framework.TestCase;
import java.util.List;
import java.util.LinkedList;
import java.util.Collections;
/**
* This class is a test case that verifies several properties of the
* CalendarEntryProvider implementation, namely:
* (1) the NotModifiedException from service.query() results in no entries
* (2) entries are sorted properly
* (3) checkpoint is used to skip entries from query result
* (4) provider can read its own checkpoint
*
* @author amsmith@google.com (Adam Smith)
*/
public class CalendarEntryProviderTest extends TestCase {
public static String aCheckpoint = DateTime.now() + "!" + "whatever";
public void testHandlesNotModifiedException()
throws RepositoryException, AuthenticationException {
RiggedCalendarService service = new RiggedCalendarService(null);
CalendarEntryProvider provider =
new CalendarEntryProvider(service, "admin@example.com", "secret");
List entries = provider.getOrderedEntriesForUser("somebody", aCheckpoint);
assertEquals(0, entries.size());
}
public void testSortsEntriesProperly()
throws RepositoryException, AuthenticationException {
List entries = new LinkedList();
int id = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
Entry entry = new Entry();
String dateString = "200" + i + "-01-01T00:00:00.000Z";
entry.setUpdated(DateTime.parseDateTime(dateString));
entry.setId("j=" + j + ", i=" + i);
entries.add(entry);
id++;
}
}
Collections.reverse(entries);
Collections.rotate(entries, entries.size() / 2);
Collections.swap(entries, 0, entries.size() - 1);
Feed riggedFeed = new Feed();
riggedFeed.getEntries().addAll(entries);
RiggedCalendarService service = new RiggedCalendarService(riggedFeed);
CalendarEntryProvider provider =
new CalendarEntryProvider(service, "admin@example.com", "secret");
List results = provider.getOrderedEntriesForUser("lolcat", aCheckpoint);
for (int idx = 0; idx < entries.size() - 1; idx++) {
Entry current = (Entry) results.get(idx);
Entry next = (Entry) results.get(idx + 1);
int updatedResult = current.getUpdated().compareTo(next.getUpdated());
int idResult = current.getId().compareTo(next.getId());
if (updatedResult == 0 && idResult > 0)
fail("Id-order violation within single second.");
if (updatedResult > 1)
fail("Updated-order violation.");
}
}
public void testSkipsUsingCheckpoint()
throws RepositoryException, AuthenticationException {
final int COUNT = 9;
final int SKIP = 6;
List entries = new LinkedList();
DateTime sometime = DateTime.now();
for (int idx = 0; idx < COUNT; idx++) {
Entry entry = new Entry();
entry.setUpdated(sometime);
entry.setId("" + idx);
entries.add(entry);
}
Feed riggedFeed = new Feed();
riggedFeed.getEntries().addAll(entries);
RiggedCalendarService service = new RiggedCalendarService(riggedFeed);
CalendarEntryProvider provider =
new CalendarEntryProvider(service, "admin@example.com", "secret");
String checkpoint = sometime.toString() + "!" + (SKIP - 1);
List results = provider.getOrderedEntriesForUser("loltapir", checkpoint);
assertEquals(COUNT - SKIP, results.size());
}
public void testParsesCheckpoints()
throws RepositoryException, AuthenticationException {
List entries = new LinkedList();
Entry entry = new Entry();
entry.setUpdated(DateTime.now());
entry.setId("meow");
entries.add(entry);
Feed riggedFeed = new Feed();
riggedFeed.getEntries().addAll(entries);
RiggedCalendarService service = new RiggedCalendarService(riggedFeed);
CalendarEntryProvider provider =
new CalendarEntryProvider(service, "admin@example.com", "secret");
// In this test we are not interested in the results, just what exceptions
// are thrown.
List results = null;
String checkpoint = null;
try {
results = provider.getOrderedEntriesForUser("somebody", null);
fail("Should have thrown DidNotPassIfModifiedSinceException.");
} catch (DidNotPassIfModifiedSinceException dnpimse) {
// this is the desired behavior
}
String realCheckpoint = provider.getCheckpointForEntry(entry);
try {
results = provider.getOrderedEntriesForUser("somebody", realCheckpoint);
} catch (DidNotPassIfModifiedSinceException dnpimse) {
// checkpoint was generated by this provider, it should be able to parse
fail(dnpimse.toString());
}
try {
String brokenCheckpoint = "123hax" + "!" + entry.getId();
results = provider.getOrderedEntriesForUser("somebody", brokenCheckpoint);
fail("Should have thrown DidNotPassIfModifiedSinceException.");
} catch (DidNotPassIfModifiedSinceException dnpimse) {
// this is the desired behavior again
}
}
/**
* This class hacks CalendarService to skip authentication as well as return
* a fixed response to any query.
*/
public static class RiggedCalendarService extends CalendarService {
private BaseFeed riggedFeed;
public RiggedCalendarService(BaseFeed riggedFeed) {
super("Google-AfydConnector-0");
this.riggedFeed = riggedFeed;
}
public void setUserCredentials(String email, String password)
throws AuthenticationException {
if (email.equals("admin@example.com") && password.equals("secret")) {
return;
} else {
throw new AuthenticationException("Failed rigged login.");
}
}
public BaseFeed query(Query query, Class klass, DateTime ifModifiedSince)
throws NotModifiedException {
if (ifModifiedSince == null) {
throw new DidNotPassIfModifiedSinceException();
}
if (riggedFeed == null) {
throw new NotModifiedException();
} else {
return riggedFeed;
}
}
}
/**
* This exception signals that no (a null) value was passed to the
* ifModifiedSince parameter of query(). While this is just fine to do in
* practice we catch it in a test above to make sure that the provider can
* parse it's own checkpoints.
*/
public static class DidNotPassIfModifiedSinceException
extends RuntimeException {
// nothing special
}
}