Added some integration tests for UserAdmin (also to test FELIX-3735)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1402138 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/BaseIntegrationTest.java b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/BaseIntegrationTest.java
new file mode 100644
index 0000000..6cf080a
--- /dev/null
+++ b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/BaseIntegrationTest.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.felix.useradmin.itest;
+
+import static org.junit.Assert.assertNotNull;
+import static org.ops4j.pax.exam.Constants.START_LEVEL_SYSTEM_BUNDLES;
+import static org.ops4j.pax.exam.Constants.START_LEVEL_TEST_BUNDLE;
+import static org.ops4j.pax.exam.CoreOptions.bootDelegationPackage;
+import static org.ops4j.pax.exam.CoreOptions.cleanCaches;
+import static org.ops4j.pax.exam.CoreOptions.felix;
+import static org.ops4j.pax.exam.CoreOptions.frameworkStartLevel;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.url;
+
+import javax.inject.Inject;
+
+import org.junit.Before;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Base class for integration tests.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class BaseIntegrationTest {
+
+ private static final int DEFAULT_TIMEOUT = 10000;
+
+ protected static final String ORG_APACHE_FELIX_USERADMIN = "org.apache.felix.useradmin";
+ protected static final String ORG_APACHE_FELIX_USERADMIN_FILESTORE = "org.apache.felix.useradmin.filestore";
+
+ @Inject
+ protected volatile BundleContext m_context;
+
+ @Configuration
+ public Option[] config() {
+ return options(
+ bootDelegationPackage("sun.*"),
+ cleanCaches(),
+ CoreOptions.systemProperty("logback.configurationFile").value("file:src/test/resources/logback.xml"),
+// CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8787"),
+
+ mavenBundle("org.slf4j", "slf4j-api").version("1.6.5").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ mavenBundle("ch.qos.logback", "logback-core").version("1.0.6").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ mavenBundle("ch.qos.logback", "logback-classic").version("1.0.6").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+
+ url("link:classpath:META-INF/links/org.ops4j.pax.exam.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ url("link:classpath:META-INF/links/org.ops4j.pax.exam.inject.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ url("link:classpath:META-INF/links/org.ops4j.pax.extender.service.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ url("link:classpath:META-INF/links/org.ops4j.base.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ url("link:classpath:META-INF/links/org.ops4j.pax.swissbox.core.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ url("link:classpath:META-INF/links/org.ops4j.pax.swissbox.extender.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ url("link:classpath:META-INF/links/org.ops4j.pax.swissbox.lifecycle.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ url("link:classpath:META-INF/links/org.ops4j.pax.swissbox.framework.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ url("link:classpath:META-INF/links/org.apache.geronimo.specs.atinject.link").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+
+ mavenBundle("org.osgi", "org.osgi.core").version("4.2.0").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ mavenBundle("org.osgi", "org.osgi.compendium").version("4.2.0").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ mavenBundle("org.apache.felix", "org.apache.felix.log").version("1.0.1").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ mavenBundle("org.apache.felix", ORG_APACHE_FELIX_USERADMIN).version("1.0.3-SNAPSHOT").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+ mavenBundle("org.apache.felix", ORG_APACHE_FELIX_USERADMIN_FILESTORE).version("1.0.2-SNAPSHOT").startLevel(START_LEVEL_SYSTEM_BUNDLES),
+
+ junitBundles(),
+ frameworkStartLevel(START_LEVEL_TEST_BUNDLE),
+ felix());
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ assertNotNull("No bundle context?!", m_context);
+ }
+
+ /**
+ * Waits for a service to become available in certain time interval.
+ * @param serviceName
+ * @return
+ * @throws Exception
+ */
+ protected <T> T awaitService(String serviceName) throws Exception {
+ ServiceTracker tracker = new ServiceTracker(m_context, serviceName, null);
+ tracker.open();
+ T result;
+ try {
+ result = (T) tracker.waitForService(DEFAULT_TIMEOUT);
+ }
+ finally {
+ tracker.close();
+ }
+ return result;
+ }
+
+ /**
+ * Obtains a service without waiting for it to become available.
+ * @param serviceName
+ * @return
+ * @throws Exception
+ */
+ protected <T> T getService(String serviceName) throws Exception {
+ ServiceTracker tracker = new ServiceTracker(m_context, serviceName, null);
+ tracker.open();
+ T result;
+ try {
+ result = (T) tracker.getService();
+ }
+ finally {
+ tracker.close();
+ }
+ return result;
+ }
+
+ /**
+ * @param bsn
+ * @return
+ */
+ protected Bundle findBundle(String bsn) {
+ for (Bundle bundle : m_context.getBundles()) {
+ if (bsn.equals(bundle.getSymbolicName())) {
+ return bundle;
+ }
+ }
+ return null;
+ }
+}
diff --git a/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/FileStoreInitializationTest.java b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/FileStoreInitializationTest.java
new file mode 100644
index 0000000..bfb8529
--- /dev/null
+++ b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/FileStoreInitializationTest.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.felix.useradmin.itest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.felix.useradmin.RoleRepositoryStore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.useradmin.Role;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@RunWith(JUnit4TestRunner.class)
+public class FileStoreInitializationTest extends BaseIntegrationTest {
+
+ /**
+ * Provides a mock file store that does nothing but track the number of
+ * times the {@link #initialize()} and {@link #close()} methods are called.
+ */
+ public static class MockRoleRepositoryStore implements RoleRepositoryStore {
+
+ final AtomicInteger m_initCount = new AtomicInteger(0);
+ final AtomicInteger m_closeCount = new AtomicInteger(0);
+
+ @Override
+ public boolean addRole(Role role) throws IOException {
+ return false;
+ }
+
+ @Override
+ public void close() throws IOException {
+ m_closeCount.incrementAndGet();
+ }
+
+ @Override
+ public Role[] getAllRoles() throws IOException {
+ return null;
+ }
+
+ @Override
+ public Role getRoleByName(String roleName) throws IOException {
+ return null;
+ }
+
+ @Override
+ public void initialize() throws IOException {
+ m_initCount.incrementAndGet();
+ }
+
+ @Override
+ public boolean removeRole(Role role) throws IOException {
+ return false;
+ }
+ }
+
+ /**
+ * Tests that initialization and closing of the repository store is
+ * performed correctly.
+ */
+ @Test
+ public void testStoreIsInitializedAndClosedProperlyOk() throws Exception {
+ final String serviceName = RoleRepositoryStore.class.getName();
+ final MockRoleRepositoryStore mockStore = new MockRoleRepositoryStore();
+
+ // Stop the file store...
+ Bundle fileStoreBundle = findBundle(ORG_APACHE_FELIX_USERADMIN_FILESTORE);
+ assertNotNull(fileStoreBundle);
+ fileStoreBundle.stop();
+
+ // Manually register our mock store...
+ ServiceRegistration serviceReg = m_context.registerService(serviceName, mockStore, null);
+
+ // Wait until it becomes available...
+ awaitService(serviceName);
+
+ assertEquals(1, mockStore.m_initCount.get());
+ assertEquals(0, mockStore.m_closeCount.get());
+
+ serviceReg.unregister();
+
+ Thread.sleep(100); // sleep a tiny bit to allow service to be properly unregistered...
+
+ assertEquals(1, mockStore.m_initCount.get());
+ assertEquals(1, mockStore.m_closeCount.get());
+
+ // Re-register the service again...
+ serviceReg = m_context.registerService(serviceName, mockStore, null);
+
+ assertEquals(2, mockStore.m_initCount.get());
+ assertEquals(1, mockStore.m_closeCount.get());
+
+ // Stop & start the UserAdmin bundle to verify the initialization is
+ // still only performed once...
+ Bundle userAdminBundle = findBundle(ORG_APACHE_FELIX_USERADMIN);
+ assertNotNull(userAdminBundle);
+ userAdminBundle.stop();
+
+ Thread.sleep(100); // sleep a tiny bit to allow service to be properly unregistered...
+
+ userAdminBundle.start();
+
+ assertEquals(3, mockStore.m_initCount.get());
+ assertEquals(2, mockStore.m_closeCount.get());
+ }
+}
diff --git a/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/UserAdminIntegrationTest.java b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/UserAdminIntegrationTest.java
new file mode 100644
index 0000000..4dd5db4
--- /dev/null
+++ b/useradmin/itest/src/test/java/org/apache/felix/useradmin/itest/UserAdminIntegrationTest.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.felix.useradmin.itest;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.Bundle;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Main integration test for the user admin service.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@RunWith(JUnit4TestRunner.class)
+public class UserAdminIntegrationTest extends BaseIntegrationTest {
+
+ /**
+ * Tests that stopping a filled store and starting it again will cause it to
+ * properly restore its state.
+ */
+ @Test
+ public void testFelix3735_StopRunningStoreRetainsDataOk() throws Exception {
+ final String userName = "testUser";
+ final String groupName = "testGroup";
+
+ UserAdmin userAdmin = awaitService(UserAdmin.class.getName());
+
+ // Fill the user admin with some data...
+ User testUser = (User) userAdmin.createRole(userName, Role.USER);
+ testUser.getProperties().put("key", "value");
+
+ Group testGroup = (Group) userAdmin.createRole(groupName, Role.GROUP);
+ testGroup.addMember(testUser);
+
+ // Stop the file store...
+ Bundle fileStoreBundle = findBundle(ORG_APACHE_FELIX_USERADMIN_FILESTORE);
+ assertNotNull(fileStoreBundle);
+ fileStoreBundle.stop();
+
+ // retrieve the useradmin again...
+ userAdmin = awaitService(UserAdmin.class.getName());
+
+ // Verify the user + group are gone (no store available)...
+ assertNull(userAdmin.getRole(userName));
+ assertNull(userAdmin.getRole(groupName));
+
+ // Start the file store...
+ fileStoreBundle.start();
+
+ // Verify the user + group are gone (no store available)...
+ User readUser = (User) userAdmin.getRole(userName);
+ assertNotNull(readUser);
+ assertEquals(userName, readUser.getName());
+ assertEquals("value", readUser.getProperties().get("key"));
+
+ Group readGroup = (Group) userAdmin.getRole(groupName);
+ assertNotNull(readGroup);
+ assertEquals(groupName, readGroup.getName());
+ assertEquals(1, readGroup.getMembers().length);
+ assertEquals(readUser, readGroup.getMembers()[0]);
+ }
+
+ /**
+ * Tests that starting the file store <em>after</em> the user admin service
+ * is started will cause it to be properly initialized.
+ */
+ @Test
+ public void testFelix3735_StartStoreAfterUserAdminInitializesOk() throws Exception {
+ final String userName = "anotherTestUser";
+ final String groupName = "anotherTestGroup";
+
+ UserAdmin userAdmin = awaitService(UserAdmin.class.getName());
+
+ // Fill the user admin with some data...
+ User testUser = (User) userAdmin.createRole(userName, Role.USER);
+ testUser.getProperties().put("key", "value");
+
+ Group testGroup = (Group) userAdmin.createRole(groupName, Role.GROUP);
+ testGroup.addMember(testUser);
+
+ // Stop the file store...
+ Bundle fileStoreBundle = findBundle(ORG_APACHE_FELIX_USERADMIN_FILESTORE);
+ assertNotNull(fileStoreBundle);
+ fileStoreBundle.stop();
+
+ Bundle userAdminBundle = findBundle(ORG_APACHE_FELIX_USERADMIN);
+ assertNotNull(userAdminBundle);
+ userAdminBundle.stop();
+
+ // Obtain user admin service again; shouldn't be available...
+ userAdmin = getService(UserAdmin.class.getName());
+ assertNull(userAdmin);
+
+ userAdminBundle.start();
+
+ // Obtain user admin service again; should be available now...
+ userAdmin = awaitService(UserAdmin.class.getName());
+ assertNotNull(userAdmin);
+
+ // Verify the user + group are gone (no store available)...
+ assertNull(userAdmin.getRole(userName));
+ assertNull(userAdmin.getRole(groupName));
+
+ // Start the file store...
+ fileStoreBundle.start();
+
+ // Verify the user + group are gone (no store available)...
+ User readUser = (User) userAdmin.getRole(userName);
+ assertNotNull(readUser);
+ assertEquals(userName, readUser.getName());
+ assertEquals("value", readUser.getProperties().get("key"));
+
+ Group readGroup = (Group) userAdmin.getRole(groupName);
+ assertNotNull(readGroup);
+ assertEquals(groupName, readGroup.getName());
+ assertEquals(1, readGroup.getMembers().length);
+ assertEquals(readUser, readGroup.getMembers()[0]);
+ }
+}
diff --git a/useradmin/itest/src/test/resources/logback.xml b/useradmin/itest/src/test/resources/logback.xml
new file mode 100644
index 0000000..fa644da
--- /dev/null
+++ b/useradmin/itest/src/test/resources/logback.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <root level="WARN">
+ <appender-ref ref="STDOUT" />
+ </root>
+
+ <logger name="org.ops4j" level="WARN" />
+</configuration>