/*
* (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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.
*
* Contributors:
* Florent Guillaume
*
*/
package org.nuxeo.ecm.directory.multi;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.core.api.model.PropertyNotFoundException;
import org.nuxeo.ecm.directory.BaseSession;
import org.nuxeo.ecm.directory.DirectoryException;
import org.nuxeo.ecm.directory.Session;
import org.nuxeo.ecm.directory.api.DirectoryService;
import org.nuxeo.ecm.directory.memory.MemoryDirectory;
import org.nuxeo.ecm.directory.memory.MemoryDirectoryDescriptor;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.test.runner.Features;
import org.nuxeo.runtime.test.runner.FeaturesRunner;
import org.nuxeo.runtime.test.runner.LocalDeploy;
/**
* @author Florent Guillaume
* @author Anahide Tchertchian
*/
@RunWith(FeaturesRunner.class)
@Features({ MultiDirectoryFeature.class })
@LocalDeploy("org.nuxeo.ecm.directory.multi.tests:directories-optional-config.xml")
public class TestMultiDirectoryOptional {
DirectoryService directoryService;
MemoryDirectory memdir1;
MemoryDirectory memdir2;
MemoryDirectory memdir3;
MultiDirectory multiDir;
MultiDirectorySession dir;
protected MemoryDirectoryDescriptor desc1;
protected MemoryDirectoryDescriptor desc2;
protected MemoryDirectoryDescriptor desc3;
@Before
public void setUp() throws Exception {
directoryService = Framework.getLocalService(DirectoryService.class);
// create and register mem directories
Map<String, Object> e;
// dir 1
desc1 = new MemoryDirectoryDescriptor();
desc1.name = "dir1";
desc1.schemaName = "schema1";
desc1.schemaSet = new HashSet<String>(Arrays.asList("uid", "foo"));
desc1.idField = "uid";
desc1.passwordField = "foo";
directoryService.registerDirectoryDescriptor(desc1);
memdir1 = (MemoryDirectory) directoryService.getDirectory("dir1");
try (Session dir1 = memdir1.getSession()) {
e = new HashMap<String, Object>();
e.put("uid", "2");
e.put("foo", "foo2");
dir1.createEntry(e);
e = new HashMap<String, Object>();
e.put("uid", "baz");
e.put("foo", "baz");
dir1.createEntry(e);
}
// dir 2
desc2 = new MemoryDirectoryDescriptor();
desc2.name = "dir2";
desc2.schemaName = "schema2";
desc2.schemaSet = new HashSet<String>(Arrays.asList("id", "bar"));
desc2.idField = "id";
desc2.passwordField = null;
directoryService.registerDirectoryDescriptor(desc2);
memdir2 = (MemoryDirectory) directoryService.getDirectory("dir2");
try (Session dir2 = memdir2.getSession()) {
e = new HashMap<String, Object>();
e.put("id", "1");
e.put("bar", "bar1");
dir2.createEntry(e);
e = new HashMap<String, Object>();
e.put("id", "2");
e.put("bar", "bar2");
dir2.createEntry(e);
}
// dir 3
desc3 = new MemoryDirectoryDescriptor();
desc3.name = "dir3";
desc3.schemaName = "schema3";
desc3.schemaSet = new HashSet<String>(Arrays.asList("uid", "thefoo", "thebar"));
desc3.idField = "uid";
desc3.passwordField = "thefoo";
directoryService.registerDirectoryDescriptor(desc3);
memdir3 = (MemoryDirectory) directoryService.getDirectory("dir3");
try (Session dir3 = memdir3.getSession()) {
e = new HashMap<String, Object>();
e.put("uid", "3");
e.put("thefoo", "foo3");
e.put("thebar", "bar3");
dir3.createEntry(e);
e = new HashMap<String, Object>();
e.put("uid", "4");
e.put("thefoo", "foo4");
e.put("thebar", "bar4");
dir3.createEntry(e);
}
// the multi directory
multiDir = (MultiDirectory) directoryService.getDirectory("multiOptional");
dir = (MultiDirectorySession) multiDir.getSession();
}
@After
public void tearDown() throws Exception {
if (dir != null) {
dir.close();
}
directoryService = Framework.getLocalService(DirectoryService.class);
directoryService.unregisterDirectoryDescriptor(desc1);
directoryService.unregisterDirectoryDescriptor(desc2);
directoryService.unregisterDirectoryDescriptor(desc3);
}
@Test
public void testDirectoryOptionalInvalid() throws Exception {
MultiDirectory multiDir = (MultiDirectory) directoryService.getDirectory("multiOptionalInvalid");
try (MultiDirectorySession dir = (MultiDirectorySession) multiDir.getSession()) {
// invalid config => will throw an exception
dir.query(null);
fail("Should have raised an DirectoryException");
} catch (DirectoryException e) {
}
}
@Test
public void testGetEntry() throws Exception {
DocumentModel entry;
entry = dir.getEntry("1");
assertEquals("1", entry.getProperty("schema3", "uid"));
assertEquals("defaultFooValue", entry.getProperty("schema3", "thefoo"));
assertEquals("bar1", entry.getProperty("schema3", "thebar"));
entry = dir.getEntry("2");
assertEquals("2", entry.getProperty("schema3", "uid"));
assertEquals("foo2", entry.getProperty("schema3", "thefoo"));
assertEquals("bar2", entry.getProperty("schema3", "thebar"));
entry = dir.getEntry("3");
assertEquals("3", entry.getProperty("schema3", "uid"));
assertEquals("foo3", entry.getProperty("schema3", "thefoo"));
assertEquals("bar3", entry.getProperty("schema3", "thebar"));
entry = dir.getEntry("4");
assertEquals("4", entry.getProperty("schema3", "uid"));
assertEquals("foo4", entry.getProperty("schema3", "thefoo"));
assertEquals("bar4", entry.getProperty("schema3", "thebar"));
entry = dir.getEntry("no-such-entry");
assertNull(entry);
}
@Test
public void testGetEntries() throws Exception {
DocumentModelList l;
l = dir.getEntries();
assertEquals(4, l.size());
DocumentModel entry = null;
for (DocumentModel e : l) {
if (e.getId().equals("1")) {
entry = e;
break;
}
}
assertNotNull(entry);
assertEquals("defaultFooValue", entry.getProperty("schema3", "thefoo"));
}
@Test
public void testCreate() throws Exception {
try (Session dir1 = memdir1.getSession();
Session dir2 = memdir2.getSession();
Session dir3 = memdir3.getSession()) {
// multi-subdir create
Map<String, Object> map = new HashMap<String, Object>();
map.put("uid", "5");
map.put("thefoo", "foo5");
map.put("thebar", "bar5");
DocumentModel entry = dir.createEntry(map);
assertEquals("5", entry.getProperty("schema3", "uid"));
assertEquals("foo5", entry.getProperty("schema3", "thefoo"));
assertEquals("bar5", entry.getProperty("schema3", "thebar"));
boolean exceptionThrown = false;
try {
entry.getProperty("schema3", "xyz");
} catch (PropertyNotFoundException ce) {
exceptionThrown = true;
}
assertTrue(exceptionThrown);
// check underlying directories
assertNotNull(dir1.getEntry("5"));
assertEquals("foo5", dir1.getEntry("5").getProperty("schema1", "foo"));
assertNotNull(dir2.getEntry("5"));
assertEquals("bar5", dir2.getEntry("5").getProperty("schema2", "bar"));
assertNull(dir3.getEntry("5"));
// create another with colliding id
map = new HashMap<String, Object>();
map.put("uid", "5");
try {
entry = dir.createEntry(map);
fail("Should raise an error, entry already exists");
} catch (DirectoryException e) {
}
}
}
@Test
public void testAuthenticate() throws Exception {
// sub dirs
try (Session dir1 = memdir1.getSession(); Session dir3 = memdir3.getSession()) {
// cannot authenticate using default value on sub directory directly
assertFalse(dir1.authenticate("1", "defaultFooValue"));
assertFalse(dir1.authenticate("1", "haha"));
assertFalse(dir1.authenticate("3", "foo3"));
assertFalse(dir3.authenticate("1", "defaultFooValue"));
assertTrue(dir3.authenticate("3", "foo3"));
assertFalse(dir3.authenticate("3", "haha"));
// multi dir
assertTrue(dir.authenticate("1", "defaultFooValue"));
assertFalse(dir.authenticate("1", "lalala"));
assertFalse(dir.authenticate("1", "haha"));
assertTrue(dir.authenticate("3", "foo3"));
assertFalse(dir.authenticate("3", "haha"));
}
}
@Test
public void testUpdateEntry() throws Exception {
try (Session dir1 = memdir1.getSession();
Session dir2 = memdir2.getSession();
Session dir3 = memdir3.getSession()) {
// multi-subdirs update
DocumentModel e = dir.getEntry("1");
assertEquals("defaultFooValue", e.getProperty("schema3", "thefoo"));
assertEquals("bar1", e.getProperty("schema3", "thebar"));
e.setProperty("schema3", "thefoo", "fffooo1");
e.setProperty("schema3", "thebar", "babar1");
dir.updateEntry(e);
e = dir.getEntry("1");
assertEquals("fffooo1", e.getProperty("schema3", "thefoo"));
assertEquals("babar1", e.getProperty("schema3", "thebar"));
// check underlying directories
assertEquals("fffooo1", dir1.getEntry("1").getProperty("schema1", "foo"));
assertEquals("babar1", dir2.getEntry("1").getProperty("schema2", "bar"));
assertNull(dir3.getEntry("1"));
// single subdir update
e = dir.getEntry("3");
assertEquals("foo3", e.getProperty("schema3", "thefoo"));
assertEquals("bar3", e.getProperty("schema3", "thebar"));
e.setProperty("schema3", "thefoo", "fffooo3");
e.setProperty("schema3", "thebar", "babar3");
dir.updateEntry(e);
e = dir.getEntry("3");
assertEquals("fffooo3", e.getProperty("schema3", "thefoo"));
assertEquals("babar3", e.getProperty("schema3", "thebar"));
// check underlying directories
assertNull(dir1.getEntry("3"));
assertNull(dir2.getEntry("3"));
assertNotNull(dir3.getEntry("3"));
assertEquals("fffooo3", dir3.getEntry("3").getProperty("schema3", "thefoo"));
assertEquals("babar3", dir3.getEntry("3").getProperty("schema3", "thebar"));
dir.getEntries();
}
}
@Test
public void testDeleteEntry() throws Exception {
try (Session dir1 = memdir1.getSession();
Session dir2 = memdir2.getSession();
Session dir3 = memdir3.getSession()) {
dir.deleteEntry("no-such-entry");
assertEquals(4, dir.getEntries().size());
assertEquals(2, dir1.getEntries().size());
assertEquals(2, dir2.getEntries().size());
assertEquals(2, dir3.getEntries().size());
dir.deleteEntry("1");
assertNull(dir.getEntry("1"));
assertEquals(3, dir.getEntries().size());
assertEquals(2, dir1.getEntries().size());
assertEquals(1, dir2.getEntries().size());
assertEquals(2, dir3.getEntries().size());
dir.deleteEntry("3");
assertNull(dir.getEntry("3"));
assertEquals(2, dir.getEntries().size());
assertEquals(2, dir1.getEntries().size());
assertEquals(1, dir2.getEntries().size());
assertEquals(1, dir3.getEntries().size());
}
}
@Test
public void testReadOnlyEntryFromGetEntry() throws Exception {
memdir1.setReadOnly(false);
memdir2.setReadOnly(true);
memdir3.setReadOnly(true);
assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("1")));
assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("2")));
assertTrue(BaseSession.isReadOnlyEntry(dir.getEntry("3")));
assertTrue(BaseSession.isReadOnlyEntry(dir.getEntry("4")));
memdir1.setReadOnly(true);
memdir2.setReadOnly(true);
memdir3.setReadOnly(true);
assertTrue(BaseSession.isReadOnlyEntry(dir.getEntry("1")));
assertTrue(BaseSession.isReadOnlyEntry(dir.getEntry("2")));
assertTrue(BaseSession.isReadOnlyEntry(dir.getEntry("3")));
assertTrue(BaseSession.isReadOnlyEntry(dir.getEntry("4")));
memdir1.setReadOnly(false);
memdir2.setReadOnly(false);
memdir3.setReadOnly(false);
assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("1")));
assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("2")));
assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("3")));
assertFalse(BaseSession.isReadOnlyEntry(dir.getEntry("4")));
}
@Test
public void testQuery() throws Exception {
Map<String, Serializable> filter = new HashMap<String, Serializable>();
DocumentModelList entries;
DocumentModel e;
// empty filter means everything (like getEntries)
entries = dir.query(filter);
assertNotNull(entries);
assertEquals(4, entries.size());
// no result
filter.put("thefoo", "f");
entries = dir.query(filter);
assertEquals(0, entries.size());
// query matching one source
// source with two subdirs
filter.put("thefoo", "defaultFooValue");
entries = dir.query(filter);
assertEquals(1, entries.size());
e = entries.get(0);
assertEquals("1", e.getId());
assertEquals("bar1", e.getProperty("schema3", "thebar"));
// simple source
filter.put("thefoo", "foo3");
entries = dir.query(filter);
assertEquals(1, entries.size());
e = entries.get(0);
assertEquals("3", e.getId());
assertEquals("bar3", e.getProperty("schema3", "thebar"));
// query matching two subdirectories in one source
filter.put("thefoo", "defaultFooValue");
filter.put("thebar", "bar1");
entries = dir.query(filter);
assertEquals(1, entries.size());
e = entries.get(0);
assertEquals("1", e.getId());
assertEquals("defaultFooValue", e.getProperty("schema3", "thefoo"));
assertEquals("bar1", e.getProperty("schema3", "thebar"));
// query not matching although each subdirectory in the source matches
filter.put("thefoo", "defaultFooValue");
filter.put("thebar", "bar2");
entries = dir.query(filter);
assertEquals(0, entries.size());
// query matching two sources
filter.clear();
e = dir.getEntry("1");
e.setProperty("schema3", "thefoo", "matchme");
dir.updateEntry(e);
e = dir.getEntry("3");
e.setProperty("schema3", "thefoo", "matchme");
dir.updateEntry(e);
filter.put("thefoo", "matchme");
entries = dir.query(filter);
assertEquals(2, entries.size());
e = entries.get(0);
assertEquals("1", e.getId());
assertEquals("bar1", e.getProperty("schema3", "thebar"));
e = entries.get(1);
assertEquals("3", e.getId());
assertEquals("bar3", e.getProperty("schema3", "thebar"));
}
@Test
public void testGetProjection() throws Exception {
Map<String, Serializable> filter = new HashMap<String, Serializable>();
List<String> list;
// empty filter means everything (like getEntries)
list = dir.getProjection(filter, "uid");
Collections.sort(list);
assertEquals(Arrays.asList("1", "2", "3", "4"), list);
list = dir.getProjection(filter, "thefoo");
Collections.sort(list);
assertEquals(Arrays.asList("defaultFooValue", "foo2", "foo3", "foo4"), list);
list = dir.getProjection(filter, "thebar");
Collections.sort(list);
assertEquals(Arrays.asList("bar1", "bar2", "bar3", "bar4"), list);
// XXX test projection on unknown column
// no result
filter.put("thefoo", "f");
list = dir.getProjection(filter, "uid");
assertEquals(0, list.size());
list = dir.getProjection(filter, "thefoo");
assertEquals(0, list.size());
list = dir.getProjection(filter, "thebar");
assertEquals(0, list.size());
// query matching one source
// source with two subdirs
filter.put("thefoo", "defaultFooValue");
list = dir.getProjection(filter, "uid");
assertEquals(Arrays.asList("1"), list);
list = dir.getProjection(filter, "thefoo");
assertEquals(Arrays.asList("defaultFooValue"), list);
list = dir.getProjection(filter, "thebar");
assertEquals(Arrays.asList("bar1"), list);
// simple source
filter.put("thefoo", "foo3");
list = dir.getProjection(filter, "uid");
assertEquals(Arrays.asList("3"), list);
list = dir.getProjection(filter, "thefoo");
assertEquals(Arrays.asList("foo3"), list);
list = dir.getProjection(filter, "thebar");
assertEquals(Arrays.asList("bar3"), list);
// query matching two subdirectories in one source
filter.put("thefoo", "defaultFooValue");
filter.put("thebar", "bar1");
list = dir.getProjection(filter, "uid");
assertEquals(Arrays.asList("1"), list);
list = dir.getProjection(filter, "thefoo");
assertEquals(Arrays.asList("defaultFooValue"), list);
list = dir.getProjection(filter, "thebar");
assertEquals(Arrays.asList("bar1"), list);
// query not matching although each subdirectory in the source matches
filter.put("thefoo", "defaultFooValue");
filter.put("thebar", "bar2");
list = dir.getProjection(filter, "uid");
assertEquals(0, list.size());
list = dir.getProjection(filter, "thefoo");
assertEquals(0, list.size());
list = dir.getProjection(filter, "thebar");
assertEquals(0, list.size());
// query matching two sources
DocumentModel e;
filter.clear();
e = dir.getEntry("1");
e.setProperty("schema3", "thefoo", "matchme");
dir.updateEntry(e);
e = dir.getEntry("3");
e.setProperty("schema3", "thefoo", "matchme");
dir.updateEntry(e);
filter.put("thefoo", "matchme");
list = dir.getProjection(filter, "uid");
Collections.sort(list);
assertEquals(Arrays.asList("1", "3"), list);
list = dir.getProjection(filter, "thefoo");
assertEquals(Arrays.asList("matchme", "matchme"), list);
list = dir.getProjection(filter, "thebar");
Collections.sort(list);
assertEquals(Arrays.asList("bar1", "bar3"), list);
}
@Test
public void testCreateFromModel() throws Exception {
String schema = "schema3";
DocumentModel entry = BaseSession.createEntryModel(null, schema, null, null);
entry.setProperty("schema3", "uid", "yo");
assertNull(dir.getEntry("yo"));
dir.createEntry(entry);
assertNotNull(dir.getEntry("yo"));
// create one with existing same id, must fail
entry.setProperty("schema3", "uid", "1");
try {
entry = dir.createEntry(entry);
fail("Should raise an error, entry already exists");
} catch (DirectoryException e) {
}
}
@Test
public void testHasEntry() throws Exception {
assertTrue(dir.hasEntry("1"));
assertFalse(dir.hasEntry("foo"));
}
}