You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by re...@apache.org on 2015/11/28 15:13:46 UTC

[3/7] git commit: updated refs/heads/master to 2ae3e0c

Fix event UUIDS missing on event bus

The fixing of CLOUDSTACK-8816 introduced a regression that removed the
first class entities in the event bus description property. This is
because everything was changed to use the Class as a key... Everything
but the populateFirstClassEntities method in ActionEventUtils.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/7d44e90c
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/7d44e90c
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/7d44e90c

Branch: refs/heads/master
Commit: 7d44e90c8df13146918c66cebdbb2573e1dec4ce
Parents: ad2bcc0
Author: jeff <je...@greenqloud.com>
Authored: Mon Nov 23 17:15:57 2015 +0000
Committer: jeff <je...@greenqloud.com>
Committed: Thu Nov 26 11:19:57 2015 +0000

----------------------------------------------------------------------
 .../src/com/cloud/event/ActionEventUtils.java   |   3 +-
 .../com/cloud/event/ActionEventUtilsTest.java   | 213 +++++++++++++++++++
 2 files changed, 214 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7d44e90c/server/src/com/cloud/event/ActionEventUtils.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/event/ActionEventUtils.java b/server/src/com/cloud/event/ActionEventUtils.java
index 0ca41cc..b1dd8fd 100644
--- a/server/src/com/cloud/event/ActionEventUtils.java
+++ b/server/src/com/cloud/event/ActionEventUtils.java
@@ -293,8 +293,7 @@ public class ActionEventUtils {
 
         for(Map.Entry<Object, Object> entry : contextMap.entrySet()){
             try{
-                Object key = entry.getKey();
-                Class<?> clz = Class.forName((String)key);
+                Class<?> clz = (Class<?>)entry.getKey();
                 if(clz != null && Identity.class.isAssignableFrom(clz)){
                     String uuid = getEntityUuid(clz, entry.getValue());
                     eventDescription.put(ReflectUtil.getEntityName(clz), uuid);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7d44e90c/server/test/com/cloud/event/ActionEventUtilsTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/event/ActionEventUtilsTest.java b/server/test/com/cloud/event/ActionEventUtilsTest.java
new file mode 100644
index 0000000..a7fcf53
--- /dev/null
+++ b/server/test/com/cloud/event/ActionEventUtilsTest.java
@@ -0,0 +1,213 @@
+package com.cloud.event;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.framework.events.Event;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.events.EventBus;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+
+import com.cloud.configuration.Config;
+import com.cloud.event.dao.EventDao;
+import com.cloud.network.IpAddress;
+import com.cloud.projects.dao.ProjectDao;
+import com.cloud.user.AccountVO;
+import com.cloud.user.User;
+import com.cloud.user.UserVO;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.user.dao.UserDao;
+import com.cloud.utils.component.ComponentContext;
+import com.cloud.utils.db.EntityManager;
+import com.cloud.vm.VirtualMachine;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(ComponentContext.class)
+public class ActionEventUtilsTest {
+    //Predictable constants used throughout this test.
+    public static final long EVENT_ID = 1;
+    public static final long USER_ID = 1;
+    public static final long ACCOUNT_ID = 1;
+
+    //Keep track of the static field values between tests.
+    //A horrid abuse of reflection required due to the strange
+    //static/inject pattern found in ActionEventUtils.
+    protected Map<String, Object> staticFieldValues = new HashMap<>();
+
+    //List of events published on the event bus. Handled via a mocked method.
+    //Cleared on every run.
+    protected List<Event> publishedEvents = new ArrayList<>();
+
+    //Mock fields. These are injected into ActionEventUtils by the setup() method.
+    @Mock
+    protected EventDao eventDao;
+
+    @Mock
+    protected AccountDao accountDao;
+
+    @Mock
+    protected UserDao userDao;
+
+    @Mock
+    protected ProjectDao projectDao;
+
+    @Mock
+    protected EntityManager entityMgr;
+
+    @Mock
+    protected ConfigurationDao configDao;
+
+    @Mock
+    protected EventBus eventBus;
+
+    /**
+     * This setup method injects the mocked beans into the ActionEventUtils class.
+     * Because ActionEventUtils has static methods, we must also remember these fields
+     * and restore them later, as otherwise strange behavior can result in other unit
+     * tests due to the way the JVM handles static fields.
+     * @throws Exception
+     */
+    @Before
+    public void setup() throws Exception {
+        publishedEvents = new ArrayList<>();
+        staticFieldValues = new HashMap<>();
+        setupCommonMocks();
+
+        ActionEventUtils utils = new ActionEventUtils();
+
+        for (Field field : ActionEventUtils.class.getDeclaredFields()) {
+            if (field.getAnnotation(Inject.class) != null) {
+                field.setAccessible(true);
+
+                try {
+                    //Inject the mocked field from this class into the ActionEventUtils
+                    //and keep track of its original value.
+                    Field mockField = this.getClass().getDeclaredField(field.getName());
+                    field.set(utils, mockField.get(this));
+                    Field staticField = ActionEventUtils.class.getDeclaredField("s_" + field.getName());
+                    staticFieldValues.put(field.getName(), staticField.get(null));
+                }
+                catch (Exception e) {
+                    // ignore missing fields
+                }
+            }
+        }
+
+        utils.init();
+    }
+
+    /**
+     * Set up the common specialized mocks that are needed to make the ActionEventUtils class behave in a
+     * predictable way. This method only mocks things that are common to all the tests. Each individual test
+     * also mocks some other methods (e.g. find user/account) by itself.
+     */
+    public void setupCommonMocks() throws Exception {
+        //Some basic mocks.
+        Mockito.when(configDao.getValue(Config.PublishActionEvent.key())).thenReturn("true");
+        PowerMockito.mockStatic(ComponentContext.class);
+        Mockito.when(ComponentContext.getComponent(EventBus.class)).thenReturn(eventBus);
+
+        //Needed for persist to actually set an ID that can be returned from the ActionEventUtils
+        //methods.
+        Mockito.when(eventDao.persist(Mockito.any(EventVO.class))).thenAnswer(new Answer<EventVO>() {
+            @Override
+            public EventVO answer(InvocationOnMock invocation) throws Throwable {
+                EventVO event = (EventVO)invocation.getArguments()[0];
+                Field id = event.getClass().getDeclaredField("id");
+                id.setAccessible(true);
+                id.set(event, EVENT_ID);
+                return event;
+            }
+        });
+
+        //Needed to record events published on the bus.
+        Mockito.doAnswer(new Answer<Void>() {
+            @Override public Void answer(InvocationOnMock invocation) throws Throwable {
+                Event event = (Event)invocation.getArguments()[0];
+                publishedEvents.add(event);
+                return null;
+            }
+
+        }).when(eventBus).publish(Mockito.any(Event.class));
+    }
+
+    /**
+     * This teardown method restores the ActionEventUtils static field values to their original values,
+     * keeping the mocked mess inside this class.
+     */
+    @After
+    public void teardown() {
+        ActionEventUtils utils = new ActionEventUtils();
+
+        for (String fieldName : staticFieldValues.keySet()) {
+            try {
+                Field field = ActionEventUtils.class.getDeclaredField(fieldName);
+                field.setAccessible(true);
+                field.set(utils, staticFieldValues.get(fieldName));
+            }
+            catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        utils.init();
+    }
+
+    @Test
+    public void testPopulateFirstClassEntities() {
+        AccountVO account = new AccountVO("testaccount", 1L, "networkdomain", (short) 0, "uuid");
+        account.setId(ACCOUNT_ID);
+        UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone",
+                UUID.randomUUID().toString(), User.Source.UNKNOWN);
+
+        Mockito.when(accountDao.findById(ACCOUNT_ID)).thenReturn(account);
+        Mockito.when(userDao.findById(USER_ID)).thenReturn(user);
+
+        CallContext.register(user, account);
+
+        //Inject some entity UUIDs into the call context
+        String instanceUuid = UUID.randomUUID().toString();
+        String ipUuid = UUID.randomUUID().toString();
+        CallContext.current().putContextParameter(VirtualMachine.class, instanceUuid);
+        CallContext.current().putContextParameter(IpAddress.class, ipUuid);
+
+        ActionEventUtils.onActionEvent(USER_ID, ACCOUNT_ID, account.getDomainId(), "StaticNat", "Test event");
+
+        //Assertions
+        Assert.assertNotEquals(publishedEvents.size(), 0);
+        Assert.assertEquals(publishedEvents.size(), 1);
+
+        Event event = publishedEvents.get(0);
+        Assert.assertNotNull(event.getDescription());
+
+        JsonObject json = new JsonParser().parse(event.getDescription()).getAsJsonObject();
+
+        Assert.assertTrue(json.has("VirtualMachine"));
+        Assert.assertTrue(json.has("IpAddress"));
+        Assert.assertEquals(json.get("VirtualMachine").getAsString(), instanceUuid);
+        Assert.assertEquals(json.get("IpAddress").getAsString(), ipUuid);
+
+        CallContext.unregister();
+    }
+}