// Copyright 2007 Google Inc.
//
// 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.enterprise.connector.spi.Document;
import com.google.enterprise.connector.spi.SpiConstants;
import com.google.enterprise.connector.spi.Value;
import com.google.gdata.data.Entry;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.TextContent;
import junit.framework.TestCase;
import java.util.List;
import java.util.LinkedList;
import java.io.File;
/**
* This class is a test case that verifies several properties of the
* StatelessDocumentList implementation.
*
* @author amsmith@google.com (Adam Smith)
*/
public class StatelessDocumentListTest extends TestCase {
private LinkedList users;
private LinkedList entries;
private String propertiesFilename;
private File propertiesFile;
private StatelessDocumentList docList;
private RiggedProvider provider;
public void setUp() throws Exception {
super.setUp();
users = new LinkedList();
entries = new LinkedList();
propertiesFile = File.createTempFile("traversal-", ".properties");
propertiesFilename = propertiesFile.getCanonicalPath();
provider = new RiggedProvider();
provider.setEntries(entries);
docList = new StatelessDocumentList(users, propertiesFilename, provider);
}
public void tearDown() throws Exception {
super.tearDown();
propertiesFile.delete();
}
/**
* In this test we ensure that the document list safely returns no documents
* when the user list is empty.
*/
public void testOkWithNoUsers() throws RepositoryException {
// users is empty
// entries is empty
assertNull(docList.nextDocument());
assertNull(docList.nextDocument()); // even when traversal is restarted
}
/**
* In this test we ensure that the document list safely returns no documents
* when the provider tells it there are no documents for any user despite
* there being several users to track.
*/
public void testOkWithNoEntries() throws RepositoryException {
// there are some users
users.add("a");
users.add("b");
users.add("c");
users.add("d");
// entries is empty (will be returned this way for each user)
assertNull(docList.nextDocument());
assertNull(docList.nextDocument()); // even when traversal is restarted
}
/**
* This test ensures that the walk through the list of user names is not
* affected by adding and removing entries including the current user.
*/
public void testResumesAfterMissingUser() throws RepositoryException {
// there are three users
users.add("a");
users.add("c");
users.add("d");
// each has an entry (the same one)
entries.add(getEntryWithId("id"));
docList.nextDocument(); // doc for a
assertEquals("a", provider.getLastUser());
docList.nextDocument(); // doc for c
assertEquals("c", provider.getLastUser());
docList.checkpoint();
docList = null; // forget the old document list
users.set(1, "b");
docList = new StatelessDocumentList(users, propertiesFilename, provider);
docList.nextDocument(); // doc for d
assertEquals("d", provider.getLastUser());
}
/**
* This tests that a users' checkpoints are persisted by checkpointing (not
* just the current user).
*/
public void testCheckpointsArePersisted() throws RepositoryException {
// there are two users
users.add("a");
users.add("b");
// they each have a document
entries.add(getEntryWithId("id"));
provider.setNextCheckpoint("checkpoint for a");
docList.nextDocument(); // doc for a
provider.setNextCheckpoint("checkpoint for b");
docList.nextDocument(); // doc for b
docList.nextDocument(); // null indicating end of list
docList.checkpoint();
docList = null; // forget the old document list
docList = new StatelessDocumentList(users, propertiesFilename, provider);
docList.nextDocument(); // doc for a
assertEquals("checkpoint for a", provider.getLastCheckpoint());
docList.nextDocument(); // doc for b
assertEquals("checkpoint for b", provider.getLastCheckpoint());
}
/**
* This test ensures an entry from the provider eventually becomes a document
* that represents it and that it gets returned through the list.
*/
public void testDataFlowsThroughDocumentList()
throws RepositoryException {
// id starts with unicode nuclear symbol
String nonceId = "\u9762" + System.currentTimeMillis();
// one user
users.add("a");
// one entry
entries.add(getEntryWithId(nonceId));
Document doc = docList.nextDocument();
assertNotNull(doc);
assertTrue(hasId(doc, nonceId));
}
/** This factory method creates Entry objects with a specified id. */
public static Entry getEntryWithId(String id) {
Entry entry = new Entry();
entry.setId(id);
entry.setUpdated(DateTime.now());
entry.addHtmlLink("http://0.0.0.0/" + id, "en", id);
PlainTextConstruct construct = new PlainTextConstruct();
construct.setText(id);
TextContent content = new TextContent();
content.setContent(construct);
entry.setContent(content);
return entry;
}
/** Check if a documentized entry from the above factory has a given id. */
public static boolean hasId(Document doc, String id) {
String docId = null;
try {
docId =
Value.getSingleValueString(doc, SpiConstants.PROPNAME_DOCID);
} catch (RepositoryException re) {
return false;
}
return docId.equals(id);
}
/**
* This class is a minimal FeedEntryProvider with instrumentation.
*
* The list passed to setResultList may be changed at any time outside of this
* class and the new contents will be reflected in the next call to the
* getOrderedEntriesForUsers method because this class holds but a reference
* to the resultList list.
*/
public static class RiggedProvider implements FeedEntryProvider {
private LinkedList entries;
private String lastUser;
private String lastCheckpoint;
public static final String DUMMY_CHECKPOINT = "whatever, this is fake...";
private String nextCheckpoint;
public String getCheckpointForEntry(Entry entry) {
if (nextCheckpoint != null) {
String toReturn = nextCheckpoint;
nextCheckpoint = null;
return toReturn;
} else {
return DUMMY_CHECKPOINT;
}
}
public List getOrderedEntriesForUser(String user, String checkpoint) {
lastUser = user;
lastCheckpoint = checkpoint;
return (List) entries.clone();
}
public String getLastUser() {
return lastUser;
}
public String getLastCheckpoint() {
return lastCheckpoint;
}
public void setEntries (LinkedList entries) {
this.entries = entries;
}
public void setNextCheckpoint (String nextCheckpoint) {
this.nextCheckpoint = nextCheckpoint;
}
}
}