| // Copyright 2011 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.adaptor.prebuilt; |
| |
| import static com.google.enterprise.adaptor.TestHelper.getDocIds; |
| import static java.util.Map.Entry; |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| |
| import com.google.enterprise.adaptor.Acl; |
| import com.google.enterprise.adaptor.AuthnIdentity; |
| import com.google.enterprise.adaptor.AuthzStatus; |
| import com.google.enterprise.adaptor.DocId; |
| import com.google.enterprise.adaptor.GroupPrincipal; |
| import com.google.enterprise.adaptor.Metadata; |
| import com.google.enterprise.adaptor.Request; |
| import com.google.enterprise.adaptor.Response; |
| import com.google.enterprise.adaptor.UserPrincipal; |
| import com.google.enterprise.adaptor.prebuilt.StreamingCommand.InputSource; |
| import com.google.enterprise.adaptor.prebuilt.StreamingCommand.OutputSink; |
| |
| import org.junit.Test; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.io.UnsupportedEncodingException; |
| import java.net.URI; |
| import java.nio.charset.Charset; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| |
| /** |
| * Tests for {@link CommandLineAdaptor}. |
| */ |
| public class CommandLineAdaptorTest { |
| private final Charset charset = Charset.forName("US-ASCII"); |
| |
| private static class CommandLineAdaptorTestMock extends CommandLineAdaptor { |
| |
| static final List<DocId> original = Arrays.asList(new DocId[] { |
| new DocId("1001"), |
| new DocId("1002"), |
| new DocId("1003"), |
| }); |
| |
| @Override |
| public int executeLister(String[] command, InputSource stdin, final OutputSink stdout, |
| OutputSink stderr) throws IOException, InterruptedException { |
| assertEquals(command[0], "./lister_cmd.sh"); |
| assertEquals(command[1], "lister_arg1"); |
| |
| final StringBuilder result = new StringBuilder(); |
| result.append("GSA Adaptor Data Version 1 [\n]\n"); |
| for (DocId docId : original) { |
| result.append("id=").append(docId.getUniqueId()).append("\n"); |
| } |
| Thread out = new Thread() { |
| @Override |
| public void run() { |
| try { |
| stdout.sink(new ByteArrayInputStream(result.toString().getBytes())); |
| } catch (IOException ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| }; |
| |
| out.start(); |
| out.join(); |
| |
| return 0; |
| } |
| |
| private static final Map<String, String> ID_TO_CONTENT; |
| private static final Map<String, String> ID_TO_MIME_TYPE; |
| private static final Map<String, Date> ID_TO_LAST_MODIFIED; |
| private static final Map<String, Date> ID_TO_LAST_CRAWLED; |
| private static final Map<String, Metadata> ID_TO_METADATA; |
| |
| static { |
| Map<String, String> idToContent = new HashMap<String, String>(); |
| idToContent.put("1002", "Content of document 1002"); |
| idToContent.put("1003", "Content of document 1003"); |
| ID_TO_CONTENT = Collections.unmodifiableMap(idToContent); |
| |
| Map<String, String> idToMimeType = new HashMap<String, String>(); |
| idToMimeType.put("1002", "application/pdf"); |
| idToMimeType.put("1003", "text/plain"); |
| ID_TO_MIME_TYPE = Collections.unmodifiableMap(idToMimeType); |
| |
| |
| Map<String, Date> idToLastModified = new HashMap<String, Date>(); |
| idToLastModified.put("1001", new Date(50)); |
| idToLastModified.put("1002", new Date(100)); |
| idToLastModified.put("1003", new Date(8000)); |
| ID_TO_LAST_MODIFIED = Collections.unmodifiableMap(idToLastModified); |
| |
| Map<String, Date> idToLastCrawled = new HashMap<String, Date>(); |
| idToLastCrawled.put("1001", new Date(100)); |
| idToLastCrawled.put("1002", new Date(99)); |
| idToLastCrawled.put("1003", new Date(5000)); |
| ID_TO_LAST_CRAWLED = Collections.unmodifiableMap(idToLastCrawled); |
| |
| Metadata id1002Metadata = new Metadata(); |
| id1002Metadata.add("metaname-1002a", "metavalue-1002a"); |
| id1002Metadata.add("metaname-1002b", "metavalue-1002b"); |
| Metadata id1003Metadata = new Metadata(); |
| id1003Metadata.add("metaname-1003", "metavalue-1003"); |
| |
| Map<String, Metadata> idToMetadata = new HashMap<String, Metadata>(); |
| idToMetadata.put("1002", id1002Metadata.unmodifiableView()); |
| idToMetadata.put("1003", id1003Metadata.unmodifiableView()); |
| |
| ID_TO_METADATA = Collections.unmodifiableMap(idToMetadata); |
| } |
| |
| @Override |
| public int executeRetriever(String[] command, InputSource stdin, final OutputSink stdout, |
| OutputSink stderr) throws IOException, InterruptedException { |
| assertEquals(command[0], "./retriever_cmd.sh"); |
| assertEquals(command[1], "retriever_arg1"); |
| assertEquals(command[2], "retriever_arg2"); |
| |
| String docId = command[3]; |
| String content = ID_TO_CONTENT.get(docId); |
| Metadata metadata = ID_TO_METADATA.get(docId); |
| Date lastModified = ID_TO_LAST_MODIFIED.get(docId); |
| Date lastCrawled = ID_TO_LAST_CRAWLED.get(docId); |
| String mimeType = ID_TO_MIME_TYPE.get(docId); |
| |
| final StringBuffer result = new StringBuffer(); |
| result.append("GSA Adaptor Data Version 1 [\n]\n"); |
| result.append("id=").append(docId).append("\n"); |
| if (lastCrawled.after(lastModified)) { |
| result.append("up-to-date").append("\n"); |
| } |
| if (mimeType != null) { |
| result.append("mime-type=").append(mimeType).append("\n"); |
| } |
| if (metadata != null) { |
| for (Map.Entry<String, String> item : metadata) { |
| result.append("meta-name=").append(item.getKey()).append("\n"); |
| result.append("meta-value=").append(item.getValue()).append("\n"); |
| } |
| } |
| if (content != null) { |
| result.append("content").append("\n"); |
| result.append(content); |
| } |
| Thread out = new Thread() { |
| @Override |
| public void run() { |
| try { |
| stdout.sink(new ByteArrayInputStream(result.toString().getBytes())); |
| } catch (IOException ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| }; |
| |
| out.start(); |
| out.join(); |
| |
| return 0; |
| } |
| |
| private static final Map<String, String> ID_TO_AUTHZ_STATUS; |
| |
| static { |
| Map<String, String> idToAuthzStatus = new HashMap<String, String>(); |
| idToAuthzStatus.put("1001", "PERMIT"); |
| idToAuthzStatus.put("1002", "DENY"); |
| idToAuthzStatus.put("1003", "INDETERMINATE"); |
| ID_TO_AUTHZ_STATUS = Collections.unmodifiableMap(idToAuthzStatus); |
| } |
| |
| @Override |
| public Command.Result executeAuthorizer(String[] command, byte[] stdin) |
| throws UnsupportedEncodingException{ |
| assertEquals(command[0], "./authorizer_cmd.sh"); |
| String expectedText = "GSA Adaptor Data Version 1 [\n]\n" |
| + "username=user1\n" |
| + "password=password1\n" |
| + "group=group1\n" |
| + "group=group2\n" |
| + "id=1001\n" |
| + "id=1002\n" |
| + "id=1003\n" |
| + "id=1004\n"; |
| assertEquals(expectedText, new String(stdin, "UTF-8")); |
| |
| StringBuffer result = new StringBuffer(); |
| result.append("GSA Adaptor Data Version 1 [\n]\n"); |
| result.append("id=1001").append("\n"); |
| result.append("authz-status=PERMIT").append("\n"); |
| result.append("id=1002").append("\n"); |
| result.append("authz-status=DENY").append("\n"); |
| result.append("id=1003").append("\n"); |
| result.append("authz-status=INDETERMINATE").append("\n"); |
| byte[] stdout = result.toString().getBytes(); |
| return new Command.Result(0, stdout, new byte[0]); |
| } |
| } |
| |
| private static class ContentsRequestTestMock implements Request { |
| private DocId docId; |
| private Date lastCrawled; |
| |
| public ContentsRequestTestMock(DocId docId) { |
| this.docId = docId; |
| } |
| |
| @Override |
| public boolean hasChangedSinceLastAccess(Date lastModified) { |
| Date date = getLastAccessTime(); |
| if (date == null) { |
| return true; |
| } |
| return date.before(lastModified); |
| } |
| |
| @Override |
| public Date getLastAccessTime() { |
| return lastCrawled; |
| } |
| |
| @Override |
| public DocId getDocId() { |
| return docId; |
| } |
| } |
| |
| private static class ContentsResponseTestMock implements Response { |
| private OutputStream os; |
| private String contentType; |
| private Date lastModified; |
| private Metadata metadata = new Metadata(); |
| private Acl acl; |
| private boolean secure; |
| private List<URI> anchorUris = new ArrayList<URI>(); |
| private List<String> anchorTexts = new ArrayList<String>(); |
| private boolean notModified; |
| private boolean notFound; |
| private boolean noIndex; |
| private boolean noFollow; |
| private boolean noArchive; |
| private URI displayUrl; |
| private boolean crawlOnce; |
| private boolean lock; |
| private Map<String, Acl> fragments = new TreeMap<String, Acl>(); |
| |
| public ContentsResponseTestMock(OutputStream os) { |
| this.os = os; |
| notModified = false; |
| } |
| |
| @Override |
| public void respondNotModified() { |
| notModified = true; |
| } |
| |
| @Override |
| public void respondNotFound() { |
| notFound = true; |
| } |
| |
| @Override |
| public OutputStream getOutputStream() { |
| return os; |
| } |
| |
| @Override |
| public void setContentType(String contentType) { |
| this.contentType = contentType; |
| } |
| |
| @Override |
| public void setLastModified(Date lastModified) { |
| this.lastModified = lastModified; |
| } |
| |
| @Override |
| public void addMetadata(String key, String value) { |
| this.metadata.add(key, value); |
| } |
| |
| @Override |
| public void setAcl(Acl acl) { |
| this.acl = acl; |
| } |
| |
| @Override |
| public void putNamedResource(String fname, Acl facl) { |
| this.fragments.put(fname, facl); |
| } |
| |
| @Override |
| public void setSecure(boolean secure) { |
| this.secure = secure; |
| } |
| |
| @Override |
| public void addAnchor(URI uri, String text) { |
| anchorUris.add(uri); |
| anchorTexts.add(text); |
| } |
| |
| @Override |
| public void setNoIndex(boolean noIndex) { |
| this.noIndex = noIndex; |
| } |
| |
| @Override |
| public void setNoFollow(boolean noFollow) { |
| this.noFollow = noFollow; |
| } |
| |
| @Override |
| public void setNoArchive(boolean noArchive) { |
| this.noArchive = noArchive; |
| } |
| |
| @Override |
| public void setDisplayUrl(URI displayUrl) { |
| this.displayUrl = displayUrl; |
| } |
| |
| @Override |
| public void setCrawlOnce(boolean crawlOnce) { |
| this.crawlOnce = crawlOnce; |
| } |
| |
| @Override |
| public void setLock(boolean lock) { |
| this.lock = lock; |
| } |
| |
| public String getContentType() { |
| return contentType; |
| } |
| |
| public Date getLastModified() { |
| return lastModified; |
| } |
| |
| /** Returns unmodifibale view of metadata. */ |
| Metadata getMetadata() { |
| return metadata.unmodifiableView(); |
| } |
| |
| public Acl getAcl() { |
| return acl; |
| } |
| |
| public boolean getNotModified() { |
| return notModified; |
| } |
| |
| public boolean getNotFound() { |
| return notFound; |
| } |
| |
| public boolean isNoIndex() { |
| return noIndex; |
| } |
| |
| public boolean isNoFollow() { |
| return noFollow; |
| } |
| |
| public boolean isNoArchive() { |
| return noArchive; |
| } |
| |
| public URI getDisplayUrl() { |
| return displayUrl; |
| } |
| |
| public boolean isCrawlOnce() { |
| return crawlOnce; |
| } |
| |
| public boolean isLock() { |
| return lock; |
| } |
| } |
| |
| @Test |
| public void testListerAndRetriever() throws Exception { |
| |
| CommandLineAdaptor adaptor = new CommandLineAdaptorTestMock(); |
| |
| Map<String, String> config = new HashMap<String, String>(); |
| config.put("commandline.lister.cmd", "./lister_cmd.sh"); |
| config.put("commandline.lister.arg1", "lister_arg1"); |
| config.put("commandline.retriever.cmd", "./retriever_cmd.sh"); |
| config.put("commandline.retriever.arg1", "retriever_arg1"); |
| config.put("commandline.retriever.arg2", "retriever_arg2"); |
| config.put("commandline.authorizer.cmd", "./authorizer_cmd.sh"); |
| config.put("commandline.authorizer.arg1", "authorizer_arg1"); |
| config.put("commandline.authorizer.delimeter", "\n"); |
| |
| // Test lister |
| List<DocId> idList = getDocIds(adaptor, config); |
| assertEquals(CommandLineAdaptorTestMock.original, idList); |
| |
| // Test authorizer |
| final UserPrincipal user = new UserPrincipal("user1"); |
| final String password = "password1"; |
| final Set<GroupPrincipal> groups = new TreeSet<GroupPrincipal>(); |
| groups.add(new GroupPrincipal("group1")); |
| groups.add(new GroupPrincipal("group2")); |
| AuthnIdentity authnIdentity = new AuthnIdentity() { |
| @Override |
| public UserPrincipal getUser() { |
| return user; |
| } |
| @Override |
| public String getPassword() { |
| return password; |
| } |
| @Override |
| public Set<GroupPrincipal> getGroups() { |
| return groups; |
| } |
| }; |
| |
| Map<DocId, AuthzStatus> expectedAuthzResult = new HashMap<DocId, AuthzStatus>(); |
| expectedAuthzResult.put(new DocId("1001"), AuthzStatus.PERMIT); |
| expectedAuthzResult.put(new DocId("1002"), AuthzStatus.DENY); |
| expectedAuthzResult.put(new DocId("1003"), AuthzStatus.INDETERMINATE); |
| |
| final List<DocId> docIds = Arrays.asList(new DocId("1001"), new DocId("1002"), |
| new DocId("1003"), new DocId("1004")); |
| Map<DocId, AuthzStatus> authzResult = adaptor.isUserAuthorized(authnIdentity, docIds); |
| assertEquals(expectedAuthzResult, authzResult); |
| |
| // Test retriever |
| for (DocId docId : idList) { |
| |
| ContentsRequestTestMock request = new ContentsRequestTestMock(docId); |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| ContentsResponseTestMock response = new ContentsResponseTestMock(baos); |
| |
| adaptor.getDocContent(request, response); |
| |
| boolean notModified = !CommandLineAdaptorTestMock.ID_TO_LAST_MODIFIED.get(docId.getUniqueId()) |
| .after(CommandLineAdaptorTestMock.ID_TO_LAST_CRAWLED.get(docId.getUniqueId())); |
| |
| assertEquals(notModified, response.getNotModified()); |
| |
| if (!notModified) { |
| assertEquals(CommandLineAdaptorTestMock.ID_TO_MIME_TYPE.get(docId.getUniqueId()), |
| response.getContentType()); |
| |
| assertEquals(CommandLineAdaptorTestMock.ID_TO_METADATA.get(docId.getUniqueId()), |
| response.getMetadata()); |
| |
| byte[] expected = CommandLineAdaptorTestMock.ID_TO_CONTENT.get( |
| docId.getUniqueId()).getBytes(); |
| byte[] actual = baos.toByteArray(); |
| String expectedString = new String(expected); |
| String actualString = new String(actual); |
| assertArrayEquals( |
| CommandLineAdaptorTestMock.ID_TO_CONTENT.get(docId.getUniqueId()).getBytes(), |
| baos.toByteArray()); |
| } |
| } |
| } |
| } |