Author: ivol
Date: Tue Oct 19 09:57:11 2010
New Revision: 187
Log:
[AMDATU-107] Implemented tenant integration test as unit test
Added:
trunk/libraries/amdatu-utilities/src/main/java/org/amdatu/libraries/utilities/TestUtil.java
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantDAO.java
- copied, changed from r179,
/trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantDAO.java
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantImpl.java
- copied, changed from r179,
/trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantImpl.java
trunk/platform-bundles/tenant-service/src/test/
trunk/platform-bundles/tenant-service/src/test/java/
trunk/platform-bundles/tenant-service/src/test/java/org/
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/InMemoryTenantDAO.java
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/TenantManagementServiceTest.java
Modified:
trunk/integration-tests/pom.xml
trunk/platform-bundles/tenant-service/pom.xml
Modified: trunk/integration-tests/pom.xml
==============================================================================
--- trunk/integration-tests/pom.xml (original)
+++ trunk/integration-tests/pom.xml Tue Oct 19 09:57:11 2010
@@ -115,6 +115,7 @@
<plugin>
<groupId>org.apache.servicemix.tooling</groupId>
<artifactId>depends-maven-plugin</artifactId>
+ <version>1.2</version>
<executions>
<execution>
<phase>integration-test</phase>
@@ -129,6 +130,7 @@
<plugin>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>maven-paxexam-plugin</artifactId>
+ <version>1.2.0</version>
<executions>
<execution>
<phase>integration-test</phase>
@@ -136,12 +138,13 @@
<goals>
<goal>generate-config</goal>
</goals>
- </execution>
+ </execution>
</executions>
<configuration>
<options>
<platform>${target-framework}</platform>
</options>
+
</configuration>
</plugin>
@@ -165,7 +168,7 @@
<skip>true</skip>
</configuration>
</plugin>
-
+
</plugins>
</build>
</project>
Added:
trunk/libraries/amdatu-utilities/src/main/java/org/amdatu/libraries/utilities/TestUtil.java
==============================================================================
--- (empty file)
+++
trunk/libraries/amdatu-utilities/src/main/java/org/amdatu/libraries/utilities/TestUtil.java
Tue Oct 19 09:57:11 2010
@@ -0,0 +1,166 @@
+/*
+ * 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.amdatu.libraries.utilities;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/**
+ * Utility class that injects dependencies. Can be used to unit test service
implementations.
+ */
+public class TestUtil {
+ public static final String UNIT = "unit";
+ public static final String INTEGRATION = "integration";
+ public static final String SMOKE = "smoke";
+ public static final String PERFORMANCE = "performance";
+ public static final String UI = "ui";
+ public static final String BROKEN = "broken";
+ /**
+ * Configures an object to use a null object for the specified service
interface.
+ *
+ * @param object the object
+ * @param iface the service interface
+ */
+ public static <T> void configureObject(Object object, Class<T> iface) {
+ configureObject(object, iface, createNullObject(iface));
+ }
+
+ /**
+ * Creates a null object for a service interface.
+ *
+ * @param iface the service interface
+ * @return a null object
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T createNullObject(Class<T> iface) {
+ return (T) Proxy.newProxyInstance(iface.getClassLoader(), new Class[]
{ iface }, new NullObject());
+ }
+
+ /**
+ * Wraps the given handler in an adapter that will try to pass on received
invocations to the hander if that has
+ * an applicable methods else it defaults to a NullObject.
+ *
+ * @param iface the service interface
+ * @param handler the handler to pass invocations to.
+ * @return an adapter that will try to pass on received invocations to the
given handler
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T createMockObjectAdapter(Class<T> iface, final Object
handler) {
+ return (T) Proxy.newProxyInstance(iface.getClassLoader(), new Class[]
{ iface }, new NullObject() {
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
+ try {
+ Method bridge =
handler.getClass().getMethod(method.getName(), method.getParameterTypes());
+ bridge.setAccessible(true);
+ return bridge.invoke(handler, args);
+ }
+ catch (NoSuchMethodException ex) {
+ return super.invoke(proxy, method, args);
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getCause();
+ }
+ }
+ });
+ }
+
+ /**
+ * Configures an object to use a specific implementation for the specified
service interface.
+ *
+ * @param object the object
+ * @param iface the service interface
+ * @param instance the implementation
+ */
+ @SuppressWarnings("unchecked")
+ public static void configureObject(Object object, Class iface, Object
instance) {
+ Class serviceClazz = object.getClass();
+
+ while (serviceClazz != null) {
+ Field[] fields = serviceClazz.getDeclaredFields();
+ AccessibleObject.setAccessible(fields, true);
+ for (int j = 0; j < fields.length; j++) {
+ if (fields[j].getType().equals(iface)) {
+ try {
+ // synchronized makes sure the field is actually
written to immediately
+ synchronized (new Object()) {
+ fields[j].set(object, instance);
+ }
+ }
+ catch (Exception e) {
+ throw new IllegalStateException("Could not set field "
+ fields[j].getName() + " on " + object);
+ }
+ }
+ }
+ serviceClazz = serviceClazz.getSuperclass();
+ }
+ }
+
+ static class NullObject implements InvocationHandler {
+ private static final Boolean DEFAULT_BOOLEAN = Boolean.FALSE;
+
+ private static final Byte DEFAULT_BYTE = new Byte((byte) 0);
+
+ private static final Short DEFAULT_SHORT = new Short((short) 0);
+
+ private static final Integer DEFAULT_INT = new Integer(0);
+
+ private static final Long DEFAULT_LONG = new Long(0);
+
+ private static final Float DEFAULT_FLOAT = new Float(0.0f);
+
+ private static final Double DEFAULT_DOUBLE = new Double(0.0);
+
+ /**
+ * Invokes a method on this null object. The method will return a
default value without doing anything.
+ */
+ @SuppressWarnings("unchecked")
+ public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
+ Class returnType = method.getReturnType();
+ if (returnType.equals(Boolean.class) ||
returnType.equals(Boolean.TYPE)) {
+ return DEFAULT_BOOLEAN;
+ }
+ else if (returnType.equals(Byte.class) ||
returnType.equals(Byte.TYPE)) {
+ return DEFAULT_BYTE;
+ }
+ else if (returnType.equals(Short.class) ||
returnType.equals(Short.TYPE)) {
+ return DEFAULT_SHORT;
+ }
+ else if (returnType.equals(Integer.class) ||
returnType.equals(Integer.TYPE)) {
+ return DEFAULT_INT;
+ }
+ else if (returnType.equals(Long.class) ||
returnType.equals(Long.TYPE)) {
+ return DEFAULT_LONG;
+ }
+ else if (returnType.equals(Float.class) ||
returnType.equals(Float.TYPE)) {
+ return DEFAULT_FLOAT;
+ }
+ else if (returnType.equals(Double.class) ||
returnType.equals(Double.TYPE)) {
+ return DEFAULT_DOUBLE;
+ }
+ else {
+ return null;
+ }
+ }
+ }
+}
Modified: trunk/platform-bundles/tenant-service/pom.xml
==============================================================================
--- trunk/platform-bundles/tenant-service/pom.xml (original)
+++ trunk/platform-bundles/tenant-service/pom.xml Tue Oct 19 09:57:11 2010
@@ -18,7 +18,7 @@
<dependency>
<groupId>org.amdatu.platform</groupId>
<artifactId>cassandra-application</artifactId>
- <version>0.0.5-SNAPSHOT</version>
+ <version>${platform.version}</version>
<scope>provided</scope>
<type>bundle</type>
</dependency>
@@ -34,6 +34,13 @@
<scope>provided</scope>
<type>bundle</type>
</dependency>
+ <dependency>
+ <groupId>org.amdatu.libraries</groupId>
+ <artifactId>amdatu-utilities</artifactId>
+ <version>${platform.version}</version>
+ <scope>compile</scope>
+ <type>jar</type>
+ </dependency>
</dependencies>
<build>
Copied:
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantDAO.java
(from r179,
/trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantDAO.java)
==============================================================================
---
/trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantDAO.java
(original)
+++
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantDAO.java
Tue Oct 19 09:57:11 2010
@@ -19,6 +19,7 @@
import java.util.List;
+
/**
* Interface for the Tenant DAO. The DAO contains CRUD operations for tenants.
The DAO is decoupled from the Tenant
* Management service for unit testing purposes.
Copied:
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantImpl.java
(from r179,
/trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantImpl.java)
==============================================================================
---
/trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantImpl.java
(original)
+++
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantImpl.java
Tue Oct 19 09:57:11 2010
@@ -20,6 +20,7 @@
import java.util.Map;
+
public class TenantImpl implements Tenant {
// The id of the tenant
private String m_id;
Added:
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/InMemoryTenantDAO.java
==============================================================================
--- (empty file)
+++
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/InMemoryTenantDAO.java
Tue Oct 19 09:57:11 2010
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.test.unit;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.amdatu.platform.tenant.Tenant;
+import org.amdatu.platform.tenant.TenantDAO;
+import org.amdatu.platform.tenant.TenantException;
+import org.amdatu.platform.tenant.TenantImpl;
+
+/**
+ * This service provided an in-memory implementation of the TenantDAO, used
for unit testing.
+ * @author ivol
+ */
+public class InMemoryTenantDAO implements TenantDAO {
+ // list of in-moemory tenants
+ private List<Tenant> m_tenants = new ArrayList<Tenant>();
+
+ /**
+ * @see TenantDAO#create(String, String)
+ */
+ public Tenant create(String id, String name) throws TenantException {
+ try {
+ read(id);
+ }
+ catch (TenantException e) {
+ TenantImpl tenant = new TenantImpl(id, name, new HashMap<String,
String>());
+ m_tenants.add(tenant);
+ return copy(tenant);
+ }
+ throw new TenantException("Tenant with id " + id + " already exists");
+ }
+
+ /**
+ * @see TenantDAO#readAll()
+ */
+ public List<Tenant> readAll() throws TenantException {
+ List<Tenant> tenantCopy = new ArrayList<Tenant>();
+ for (Tenant tenant : m_tenants) {
+ tenantCopy.add(copy(tenant));
+ }
+ return tenantCopy;
+ }
+
+ /**
+ * @see TenantDAO#read(String)
+ */
+ public Tenant read(String id) throws TenantException {
+ for (Tenant tenant : m_tenants) {
+ if (id.equals(tenant.getId())) {
+ return tenant;
+ }
+ }
+ throw new TenantException("Tenant with id '" + id + "' does not
exist");
+ }
+
+ /**
+ * @see TenantDAO#update(Tenant)
+ */
+ public void update(Tenant tenant) throws TenantException {
+ Tenant t = read(tenant.getId());
+ t.setName(tenant.getName());
+ }
+
+ /**
+ * @see TenantDAO#delete(Tenant)
+ */
+ public void delete(Tenant tenant) throws TenantException {
+ for (Tenant t : m_tenants) {
+ if (tenant.getId().equals(t.getId())) {
+ m_tenants.remove(tenant);
+ return;
+ }
+ }
+ throw new TenantException("Tenant with id '" + tenant.getId() + "'
could not be removed");
+ }
+
+ /**
+ * Copies a tenant.
+ * @param tenant The tenant to copy
+ * @return the copied tenant
+ */
+ private Tenant copy(Tenant tenant) {
+ return new TenantImpl(tenant.getId(), tenant.getName(),
tenant.getProperties());
+ }
+}
Added:
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/TenantManagementServiceTest.java
==============================================================================
--- (empty file)
+++
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/TenantManagementServiceTest.java
Tue Oct 19 09:57:11 2010
@@ -0,0 +1,116 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.test.unit;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.Assert;
+
+import org.amdatu.libraries.utilities.TestUtil;
+import org.amdatu.platform.tenant.Tenant;
+import org.amdatu.platform.tenant.TenantDAO;
+import org.amdatu.platform.tenant.TenantException;
+import org.amdatu.platform.tenant.TenantManagementService;
+import org.amdatu.platform.tenant.service.TenantManagementServiceImpl;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+/**
+ * This class provides a Unit test for testing the Tenant Management Service.
+ * @author ivol
+ */
+public class TenantManagementServiceTest {
+ /**
+ * Run the unit test.
+ */
+ @Test
+ public void run() {
+ // Instantiate the Tenant management service to test
+ TenantDAO tenantDAO = new InMemoryTenantDAO();
+ TenantManagementService tenantService = new
TenantManagementServiceImpl();
+ TestUtil.configureObject(tenantService, LogService.class,
TestUtil.createNullObject(LogService.class));
+ TestUtil.configureObject(tenantService, TenantDAO.class, tenantDAO);
+ TestUtil.configureObject(tenantService, DependencyManager.class, new
DependencyManager(TestUtil.createNullObject(BundleContext.class)));
+
+ try {
+ // Verify that there are no tenants available right now
+ Tenant[] allTenants = tenantService.getAllTenants();
+ Assert
+ .assertTrue("There are already tenants present in the storage",
+ tenantService.getAllTenants().length == 0);
+
+ // Create and update a tenant and verify that it has been added
+ int tenantCount = allTenants.length;
+ Tenant tenant =
tenantService.createTentant("org.amdatu.test.integration.tests.testtenant",
"TEST");
+ tenantService.updateTenant(tenant);
+ Assert.assertTrue("Added and updated 1 tenant, but the Tenant
service now holds "
+ + tenantService.getAllTenants().length + " tenants, expected:
" + (tenantCount + 1), tenantService
+ .getAllTenants().length == tenantCount + 1);
+
+ // Try to add a tenant with the same id, this should throw an
exception
+ try {
+
tenantService.createTentant("org.amdatu.test.integration.tests.testtenant",
"sdfsdfd");
+ Assert.assertTrue("Tenant with the same id could be created
twice", false);
+ }
+ catch (TenantException e) {
+ }
+
+ // Delete the tenant and check if it has been removed
+ tenantService.deleteTenant(tenant);
+ Assert.assertTrue(tenantService.getAllTenants().length ==
tenantCount);
+
+ // Create and update three tenants
+ Tenant tenant1 =
tenantService.createTentant("org.amdatu.test.integration.tests.testtenant.1",
"TEST 1");
+ Tenant tenant2 =
tenantService.createTentant("org.amdatu.test.integration.tests.testtenant.2",
"TEST 2");
+ Tenant tenant3 =
tenantService.createTentant("org.amdatu.test.integration.tests.testtenant.3",
"TEST 3");
+ tenant1.getProperties().put("hostname", "localhost");
+ tenant2.getProperties().put("hostname", "localhost");
+ tenant3.getProperties().put("hostname", "amdatu.org");
+ tenantService.updateTenant(tenant1);
+ tenantService.updateTenant(tenant2);
+ tenantService.updateTenant(tenant3);
+
+ // Check if the filter works correct
+ Map<String, String> filter = new HashMap<String, String>();
+ filter.put("hostname", "localhost");
+ Assert.assertTrue(tenantService.getTenants(filter).length == 2);
+ filter.put("hostname", "amdatu.org");
+ Assert.assertTrue(tenantService.getTenants(filter).length == 1);
+
+ // Delete the tenants, now all tenants should be removed
+ tenantService.deleteTenant(tenant1);
+ tenantService.deleteTenant(tenant2);
+ tenantService.deleteTenant(tenant3);
+ Assert.assertTrue(tenantService.getAllTenants().length == 0);
+
+ // What happens if I remove a tenant that was already removed?
This should throw an exception
+ try {
+ tenantService.deleteTenant(tenant);
+ Assert.fail("Tenant with the same id could be deleted twice");
+ }
+ catch (TenantException e) {
+ }
+ }
+ catch (TenantException e) {
+ Assert.fail("An error has occurred: " + e.toString());
+ e.printStackTrace();
+ }
+ }
+}