Repository: ambari
Updated Branches:
  refs/heads/trunk a4e72f648 -> 95fb3a16c


AMBARI-16439 - Restarting Upgraded Component During a Paused Upgrade Downgrades 
Component To Old Version (jonathanhurley)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/95fb3a16
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/95fb3a16
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/95fb3a16

Branch: refs/heads/trunk
Commit: 95fb3a16cfaf542b5fe221cecaa3cbeb68528852
Parents: a4e72f6
Author: Jonathan Hurley <jhur...@hortonworks.com>
Authored: Tue May 10 19:34:32 2016 -0400
Committer: Jonathan Hurley <jhur...@hortonworks.com>
Committed: Wed May 11 13:42:38 2016 -0400

----------------------------------------------------------------------
 .../ambari/server/agent/ExecutionCommand.java   |  11 +-
 .../ambari/server/agent/HeartbeatProcessor.java |   5 +-
 .../AmbariManagementControllerImpl.java         |   9 +-
 .../listeners/upgrade/StackVersionListener.java |  13 +-
 .../org/apache/ambari/server/state/Cluster.java |  45 ++-
 .../server/state/cluster/ClusterImpl.java       |  73 ++---
 .../upgrade/StackVersionListenerTest.java       |  37 +++
 .../cluster/ClusterEffectiveVersionTest.java    | 283 +++++++++++++++++++
 8 files changed, 412 insertions(+), 64 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/95fb3a16/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
index 34a0918..bdb5fb1 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
@@ -374,6 +374,7 @@ public class ExecutionCommand extends AgentCommand {
     String COMMAND_RETRY_ENABLED = "command_retry_enabled";
     String AGENT_STACK_RETRY_ON_UNAVAILABILITY = 
"agent_stack_retry_on_unavailability";
     String AGENT_STACK_RETRY_COUNT = "agent_stack_retry_count";
+
     /**
      * Comma separated list of config-types whose tags have be refreshed
      * at runtime before being executed. If all config-type tags have to be
@@ -383,6 +384,7 @@ public class ExecutionCommand extends AgentCommand {
 
     String SERVICE_CHECK = "SERVICE_CHECK"; // TODO: is it standard command? 
maybe add it to RoleCommand enum?
     String CUSTOM_COMMAND = "custom_command";
+
     /**
      * The key indicating that the package_version string is available
      */
@@ -392,11 +394,14 @@ public class ExecutionCommand extends AgentCommand {
      * The key indicating that there is an un-finalized upgrade which is 
suspended.
      */
     String UPGRADE_SUSPENDED = "upgrade_suspended";
+
     /**
-     * When installing packages, optionally provide the row id the version is 
for in
-     * order to precisely match response data.
+     * When installing packages, optionally provide the row id the version is
+     * for in order to precisely match response data.
+     * <p/>
+     * The agent will return this value back in its response so the repository
+     * can be looked up and possibly have its version updated.
      */
     String REPO_VERSION_ID = "repository_version_id";
   }
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/95fb3a16/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java
index c587e9f..c6036c2 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java
@@ -39,6 +39,7 @@ import org.apache.ambari.server.ServiceNotFoundException;
 import org.apache.ambari.server.actionmanager.ActionManager;
 import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
+import org.apache.ambari.server.agent.ExecutionCommand.KeyNames;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.MaintenanceStateHelper;
 import org.apache.ambari.server.events.ActionFinalReportReceivedEvent;
@@ -664,7 +665,7 @@ public class HeartbeatProcessor extends AbstractService{
                 }
               }
 
-              this.heartbeatMonitor.getAgentRequests()
+              heartbeatMonitor.getAgentRequests()
                   .setExecutionDetailsRequest(hostname, componentName, 
status.getSendExecCmdDet());
             } else {
               // TODO: What should be done otherwise?
@@ -738,7 +739,7 @@ public class HeartbeatProcessor extends AbstractService{
     @SerializedName("direction")
     private Direction upgradeDirection = null;
 
-    @SerializedName("repository_version_id")
+    @SerializedName(KeyNames.REPO_VERSION_ID)
     private Long repositoryVersionId;
 
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/95fb3a16/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 6dbceba..7884d02 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -2207,16 +2207,19 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
     hostParams.put(REPO_INFO, repoInfo);
     hostParams.putAll(getRcaParameters());
 
+    // use the effective cluster version here since this command might happen
+    // in the context of an upgrade and we should send the repo ID which 
matches
+    // the version being send down
     RepositoryVersionEntity repoVersion = null;
-    if (null != cluster.getCurrentClusterVersion()) {
-      repoVersion = cluster.getCurrentClusterVersion().getRepositoryVersion();
+    ClusterVersionEntity effectiveClusterVersion = 
cluster.getEffectiveClusterVersion();
+    if (null != effectiveClusterVersion) {
+      repoVersion = effectiveClusterVersion.getRepositoryVersion();
     } else {
       List<ClusterVersionEntity> list = 
clusterVersionDAO.findByClusterAndState(cluster.getClusterName(),
           RepositoryVersionState.INIT);
       if (1 == list.size()) {
         repoVersion = list.get(0).getRepositoryVersion();
       }
-
     }
 
     if (null != repoVersion) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/95fb3a16/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListener.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListener.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListener.java
index b14e9e5..d9599cc 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListener.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListener.java
@@ -92,14 +92,19 @@ public class StackVersionListener {
 
     m_stackVersionLock.lock();
 
-    if (null != event.getRepositoryVersionId()) {
+    // if the cluster is upgrading, there's no need to update the repo version 
-
+    // it better be right
+    if (null != event.getRepositoryVersionId() && null == 
cluster.getUpgradeInProgress()) {
       // !!! make sure the repo_version record actually has the same version.
       // This is NOT true when installing a cluster using a public repo where 
the
       // exact version is not known in advance.
       RepositoryVersionEntity rve = 
repositoryVersionDAO.findByPK(event.getRepositoryVersionId());
-      if (null != rve && !rve.getVersion().equals(newVersion)) {
-        rve.setVersion(newVersion);
-        repositoryVersionDAO.merge(rve);
+      if (null != rve) {
+        String currentRepoVersion = rve.getVersion();
+        if (!StringUtils.equals(currentRepoVersion, newVersion)) {
+          rve.setVersion(newVersion);
+          repositoryVersionDAO.merge(rve);
+        }
       }
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/95fb3a16/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java 
b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
index cf2c9aa..303b043 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
@@ -138,9 +138,28 @@ public interface Cluster {
   ClusterVersionEntity getCurrentClusterVersion();
 
   /**
-   * If no RU/EU is in progress, get the ClusterVersionEntity object whose 
state is CURRENT.
-   * If RU/EU is in progress, based on the direction and desired stack, 
determine which version to use.
-   * @return Cluster Version entity to use.
+   * Gets the current stack version associated with the cluster.
+   * <ul>
+   * <li>if there is no upgrade in progress then get the
+   * {@link ClusterVersionEntity} object whose state is
+   * {@link RepositoryVersionState#CURRENT}.
+   * <li>If an upgrade is in progress then based on the direction and the
+   * desired stack determine which version to use. Assuming upgrading from HDP
+   * 2.2.0.0-1 to 2.3.0.0-2:
+   * <ul>
+   * <li>RU Upgrade: 2.3.0.0-2 (desired stack id)
+   * <li>RU Downgrade: 2.2.0.0-1 (desired stack id)
+   * <li>EU Upgrade: while stopping services and before changing desired stack,
+   * use 2.2.0.0-1, after, use 2.3.0.0-2
+   * <li>EU Downgrade: while stopping services and before changing desired
+   * stack, use 2.3.0.0-2, after, use 2.2.0.0-1
+   * </ul>
+   * </ul>
+   *
+   * This method must take into account both a running and a suspended upgrade.
+   *
+   * @return the effective cluster stack version given the current upgrading
+   *         conditions of the cluster.
    */
   ClusterVersionEntity getEffectiveClusterVersion() throws AmbariException;
 
@@ -672,10 +691,24 @@ public interface Cluster {
   boolean isUpgradeSuspended();
 
   /**
+   * Gets an {@link UpgradeEntity} if there is an upgrade in progress or an
+   * upgrade that has been suspended. This will first check
+   * {@link #getUpgradeEntity()} and return that if it is not {@code null}.
+   * Otherwise, this will perform a search for the most recent 
upgrade/downgrade
+   * which has not been completed.
+   *
+   * @return an upgrade which will either be in progress or suspended, or
+   *         {@code null} if none.
+   */
+  UpgradeEntity getUpgradeInProgress();
+
+  /**
    * Returns the name of the service that the passed config type belongs to.
-   * @param configType the config type to look up the service by
-   * @return returns the name of the service that the config type belongs to 
if there is any
-   *         otherwise returns null.
+   *
+   * @param configType
+   *          the config type to look up the service by
+   * @return returns the name of the service that the config type belongs to if
+   *         there is any otherwise returns null.
    */
   String getServiceByConfigType(String configType);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/95fb3a16/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index cd0812b..85ca2c7 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@ -322,9 +322,6 @@ public class ClusterImpl implements Cluster {
       loadServiceConfigTypes();
     }
 
-    // Load any active stack upgrades.
-    loadStackUpgrade();
-
     loadServices();
 
     // register to receive stuff
@@ -349,24 +346,6 @@ public class ClusterImpl implements Cluster {
   }
 
   /**
-   * When a cluster is first loaded, determine if it has a stack upgrade in 
progress.
-   */
-  private void loadStackUpgrade() {
-    clusterGlobalLock.writeLock().lock();
-
-    try {
-      UpgradeEntity activeUpgrade = getUpgradeInProgress();
-      if (activeUpgrade != null) {
-        setUpgradeEntity(activeUpgrade);
-      }
-    } catch (AmbariException e) {
-      LOG.error("Unable to load active stack upgrade. Error: " + 
e.getMessage());
-    } finally {
-      clusterGlobalLock.writeLock().unlock();
-    }
-  }
-
-  /**
    * Construct config type to service name mapping
    * @throws AmbariException when stack or its part not found
    */
@@ -1189,17 +1168,27 @@ public class ClusterImpl implements Cluster {
   }
 
   /**
-   * Get any stack upgrade currently in progress.
-   * @return
+   * {@inheritDoc}
    */
-  private UpgradeEntity getUpgradeInProgress() {
+  @Override
+  public UpgradeEntity getUpgradeInProgress() {
+    // first check for an upgrade that's actively running
+    UpgradeEntity upgradeInProgress = getUpgradeEntity();
+    if (null != upgradeInProgress) {
+      return upgradeInProgress;
+    }
+
+    // perform a search for any upgrade which shoudl also return upgrades which
+    // are suspended
     UpgradeEntity mostRecentUpgrade = 
upgradeDAO.findLastUpgradeOrDowngradeForCluster(getClusterId());
     if (mostRecentUpgrade != null) {
-      List<HostRoleStatus> UNFINISHED_STATUSES = new ArrayList();
+      List<HostRoleStatus> UNFINISHED_STATUSES = new ArrayList<>();
       UNFINISHED_STATUSES.add(HostRoleStatus.PENDING);
       UNFINISHED_STATUSES.add(HostRoleStatus.ABORTED);
 
-      List<HostRoleCommandEntity> commands = 
hostRoleCommandDAO.findByRequestIdAndStatuses(mostRecentUpgrade.getRequestId(), 
UNFINISHED_STATUSES);
+      List<HostRoleCommandEntity> commands = 
hostRoleCommandDAO.findByRequestIdAndStatuses(
+          mostRecentUpgrade.getRequestId(), UNFINISHED_STATUSES);
+
       if (!commands.isEmpty()) {
         return mostRecentUpgrade;
       }
@@ -1208,39 +1197,32 @@ public class ClusterImpl implements Cluster {
     return null;
   }
 
+
   /**
-   * If no RU/EU is in progress, get the ClusterVersionEntity object whose 
state is CURRENT.
-   * If RU/EU is in progress, based on the direction and desired stack, 
determine which version to use.
-   * Assuming upgrading from HDP 2.2.0.0-1 to 2.3.0.0-2, then
-   * RU Upgrade: 2.3.0.0-2 (desired stack id)
-   * RU Downgrade: 2.2.0.0-1 (desired stack id)
-   * EU Upgrade: while stopping services and before changing desired stack, 
use 2.2.0.0-1, after, use 2.3.0.0-2
-   * EU Downgrade: while stopping services and before changing desired stack, 
use 2.3.0.0-2, after, use 2.2.0.0-1
-   * @return
+   * {@inheritDoc}
    */
   @Override
   public ClusterVersionEntity getEffectiveClusterVersion() throws 
AmbariException {
-    // This is not reliable. Need to find the last upgrade request.
-    UpgradeEntity upgradeInProgress = getUpgradeEntity();
-    if (upgradeInProgress == null) {
+    UpgradeEntity upgradeEntity = getUpgradeInProgress();
+    if (upgradeEntity == null) {
       return getCurrentClusterVersion();
     }
 
     String effectiveVersion = null;
-    switch (upgradeInProgress.getUpgradeType()) {
+    switch (upgradeEntity.getUpgradeType()) {
       case NON_ROLLING:
-        if (upgradeInProgress.getDirection() == Direction.UPGRADE) {
-          boolean pastChangingStack = 
isNonRollingUpgradePastUpgradingStack(upgradeInProgress);
-          effectiveVersion = pastChangingStack ? 
upgradeInProgress.getToVersion() : upgradeInProgress.getFromVersion();
+        if (upgradeEntity.getDirection() == Direction.UPGRADE) {
+          boolean pastChangingStack = 
isNonRollingUpgradePastUpgradingStack(upgradeEntity);
+          effectiveVersion = pastChangingStack ? upgradeEntity.getToVersion() 
: upgradeEntity.getFromVersion();
         } else {
           // Should be the lower value during a Downgrade.
-          effectiveVersion = upgradeInProgress.getToVersion();
+          effectiveVersion = upgradeEntity.getToVersion();
         }
         break;
       case ROLLING:
       default:
         // Version will be higher on upgrade and lower on downgrade directions.
-        effectiveVersion = upgradeInProgress.getToVersion();
+        effectiveVersion = upgradeEntity.getToVersion();
         break;
     }
 
@@ -1255,6 +1237,7 @@ public class ClusterImpl implements Cluster {
         return clusterVersionEntity;
       }
     }
+
     return null;
   }
 
@@ -1305,9 +1288,7 @@ public class ClusterImpl implements Cluster {
       throw new AmbariException("Could not find current stack version of 
cluster " + getClusterName());
     }
 
-    final Set<RepositoryVersionState> validStates = new 
HashSet<RepositoryVersionState>(){{
-      add(RepositoryVersionState.CURRENT);
-    }};
+    final Set<RepositoryVersionState> validStates = 
Sets.newHashSet(RepositoryVersionState.CURRENT);
 
     if (!validStates.contains(desiredState)) {
       throw new AmbariException("The state must be one of [" + 
StringUtils.join(validStates, ", ") + "]");

http://git-wip-us.apache.org/repos/asf/ambari/blob/95fb3a16/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListenerTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListenerTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListenerTest.java
index 3a8b396..6177e6b 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListenerTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/StackVersionListenerTest.java
@@ -37,6 +37,8 @@ import org.easymock.EasyMockSupport;
 import org.junit.Before;
 import org.junit.Test;
 
+import junit.framework.Assert;
+
 /**
  * StackVersionListener tests.
  */
@@ -258,6 +260,41 @@ public class StackVersionListenerTest extends 
EasyMockSupport {
     verifyAll();
   }
 
+  /**
+   * Tests that the {@link RepositoryVersionEntity} is not updated if there is
+   * an upgrade, even if the repo ID is passed back and the versions don't
+   * match.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testRepositoryVersionNotSetDuringUpgrade() throws Exception {
+    // this call will make it seem like there is an upgrade in progress
+    
expect(cluster.getUpgradeInProgress()).andReturn(createNiceMock(UpgradeEntity.class));
+
+    // create the DAO - nothing will be called on it, so make it strict
+    RepositoryVersionDAO dao = createStrictMock(RepositoryVersionDAO.class);
+
+    replayAll();
+
+    // !!! avoid injector for test class
+    StackVersionListener listener = new StackVersionListener(publisher);
+
+    Field field = 
StackVersionListener.class.getDeclaredField("repositoryVersionDAO");
+    field.setAccessible(true);
+    field.set(listener, dao);
+
+    HostComponentVersionAdvertisedEvent event = new 
HostComponentVersionAdvertisedEvent(cluster,
+        sch, VALID_NEW_VERSION, 1L);
+
+    // make sure that a repo ID will come back
+    Assert.assertNotNull(event.getRepositoryVersionId());
+
+    listener.onAmbariEvent(event);
+
+    verifyAll();
+  }
+
   private void sendEventAndVerify(String newVersion) {
     HostComponentVersionAdvertisedEvent event = new 
HostComponentVersionAdvertisedEvent(cluster, sch, newVersion);
     StackVersionListener listener = new StackVersionListener(publisher);

http://git-wip-us.apache.org/repos/asf/ambari/blob/95fb3a16/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterEffectiveVersionTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterEffectiveVersionTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterEffectiveVersionTest.java
new file mode 100644
index 0000000..2aaa2cf
--- /dev/null
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterEffectiveVersionTest.java
@@ -0,0 +1,283 @@
+/**
+ * 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.ambari.server.state.cluster;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+
+import org.apache.ambari.server.actionmanager.ActionManager;
+import org.apache.ambari.server.actionmanager.RequestFactory;
+import org.apache.ambari.server.actionmanager.StageFactory;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.AbstractRootServiceResponseFactory;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.controller.spi.ClusterController;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
+import org.apache.ambari.server.orm.DBAccessor;
+import org.apache.ambari.server.orm.dao.ClusterDAO;
+import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
+import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
+import org.apache.ambari.server.orm.entities.ClusterEntity;
+import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
+import org.apache.ambari.server.orm.entities.ClusterVersionEntity;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
+import org.apache.ambari.server.orm.entities.StackEntity;
+import org.apache.ambari.server.orm.entities.UpgradeEntity;
+import org.apache.ambari.server.scheduler.ExecutionScheduler;
+import org.apache.ambari.server.security.authorization.Users;
+import org.apache.ambari.server.stack.StackManagerFactory;
+import org.apache.ambari.server.stageplanner.RoleGraphFactory;
+import org.apache.ambari.server.stageplanner.RoleGraphFactoryImpl;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.ConfigFactory;
+import org.apache.ambari.server.state.ServiceComponentFactory;
+import org.apache.ambari.server.state.ServiceComponentHostFactory;
+import org.apache.ambari.server.state.ServiceFactory;
+import org.apache.ambari.server.state.ServiceInfo;
+import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
+import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
+import org.apache.ambari.server.state.stack.OsFamily;
+import org.apache.ambari.server.state.stack.upgrade.Direction;
+import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
+import org.easymock.EasyMock;
+import org.easymock.EasyMockSupport;
+import org.eclipse.jetty.server.SessionManager;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+import com.google.common.collect.Lists;
+import com.google.inject.Binder;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+
+import junit.framework.Assert;
+
+/**
+ * Tests that cluster effective version is calcualted correctly during 
upgrades.
+ */
+@RunWith(value = PowerMockRunner.class)
+@PrepareForTest({ ClusterImpl.class })
+public class ClusterEffectiveVersionTest extends EasyMockSupport {
+
+  private Injector m_injector;
+  private ClusterEntity m_clusterEntity;
+  private Cluster m_cluster;
+
+  /**
+   * @throws Exception
+   */
+  @Before
+  public void setup() throws Exception {
+    m_injector = Guice.createInjector(new MockModule());
+    m_clusterEntity = createNiceMock(ClusterEntity.class);
+
+    expectClusterEntityMocks();
+
+    AmbariEventPublisher eventPublisher = 
createNiceMock(AmbariEventPublisher.class);
+
+    replayAll();
+
+    m_cluster = new ClusterImpl(m_clusterEntity, m_injector, eventPublisher);
+
+    verifyAll();
+  }
+
+  /**
+   * Tests that {@link Cluster#getEffectiveClusterVersion()} returns the
+   * "current" version when there is no upgrade in progress.
+   */
+  @Test
+  public void testEffectiveVersionWithNoUpgrade() throws Exception {
+    Cluster clusterSpy = Mockito.spy(m_cluster);
+
+    Mockito.doReturn(null).when(clusterSpy).getUpgradeInProgress();
+
+    ClusterVersionEntity currentClusterVersion = new ClusterVersionEntity();
+    
Mockito.doReturn(currentClusterVersion).when(clusterSpy).getCurrentClusterVersion();
+
+    ClusterVersionEntity effectiveVersion = 
clusterSpy.getEffectiveClusterVersion();
+    Assert.assertEquals(currentClusterVersion, effectiveVersion);
+  }
+
+  /**
+   * Tests that {@link Cluster#getEffectiveClusterVersion()} returns the target
+   * version in an active rolling upgrade.
+   */
+  @Test
+  public void testEffectiveVersionWithActiveRollingUpgrade() throws Exception {
+    resetAll();
+    expectClusterEntityMocks();
+
+    Cluster clusterSpy = Mockito.spy(m_cluster);
+
+    UpgradeEntity upgradeEntity = createNiceMock(UpgradeEntity.class);
+    
EasyMock.expect(upgradeEntity.getUpgradeType()).andReturn(UpgradeType.ROLLING).atLeastOnce();
+    
EasyMock.expect(upgradeEntity.getFromVersion()).andReturn("2.3.0.0-1234").anyTimes();
+    
EasyMock.expect(upgradeEntity.getToVersion()).andReturn("2.4.0.0-1234").atLeastOnce();
+
+    RepositoryVersionEntity repositoryVersionEntity = 
createNiceMock(RepositoryVersionEntity.class);
+    
EasyMock.expect(repositoryVersionEntity.getVersion()).andReturn("2.4.0.0-1234").atLeastOnce();
+
+    ClusterVersionEntity clusterVersionUpgradingTo = 
createNiceMock(ClusterVersionEntity.class);
+    
EasyMock.expect(clusterVersionUpgradingTo.getRepositoryVersion()).andReturn(
+        repositoryVersionEntity).atLeastOnce();
+
+    List<ClusterVersionEntity> clusterVersionEntities = 
Lists.newArrayList(clusterVersionUpgradingTo);
+    
EasyMock.expect(m_clusterEntity.getClusterVersionEntities()).andReturn(clusterVersionEntities).atLeastOnce();
+
+    replayAll();
+
+    Mockito.doReturn(upgradeEntity).when(clusterSpy).getUpgradeInProgress();
+
+    // this shouldn't be returned since there is an upgrade in progress
+    ClusterVersionEntity currentClusterVersion = new ClusterVersionEntity();
+    
Mockito.doReturn(currentClusterVersion).when(clusterSpy).getCurrentClusterVersion();
+
+    ClusterVersionEntity effectiveVersion = 
clusterSpy.getEffectiveClusterVersion();
+    Assert.assertEquals(clusterVersionUpgradingTo, effectiveVersion);
+
+    verifyAll();
+  }
+
+  /**
+   * Tests that {@link Cluster#getEffectiveClusterVersion()} returns the target
+   * version in an active rolling upgrade.
+   */
+  @Test
+  public void testEffectiveVersionWithActiveExpressDowngrade() throws 
Exception {
+    resetAll();
+    expectClusterEntityMocks();
+
+    Cluster clusterSpy = Mockito.spy(m_cluster);
+
+    // from/to are switched on downgrade
+    UpgradeEntity upgradeEntity = createNiceMock(UpgradeEntity.class);
+    
EasyMock.expect(upgradeEntity.getUpgradeType()).andReturn(UpgradeType.NON_ROLLING).atLeastOnce();
+    
EasyMock.expect(upgradeEntity.getToVersion()).andReturn("2.3.0.0-1234").atLeastOnce();
+    
EasyMock.expect(upgradeEntity.getFromVersion()).andReturn("2.4.0.0-1234").anyTimes();
+    
EasyMock.expect(upgradeEntity.getDirection()).andReturn(Direction.DOWNGRADE).atLeastOnce();
+
+    RepositoryVersionEntity repositoryVersionEntity = 
createNiceMock(RepositoryVersionEntity.class);
+    
EasyMock.expect(repositoryVersionEntity.getVersion()).andReturn("2.3.0.0-1234").atLeastOnce();
+
+    ClusterVersionEntity clusterVersionUpgradingTo = 
createNiceMock(ClusterVersionEntity.class);
+    
EasyMock.expect(clusterVersionUpgradingTo.getRepositoryVersion()).andReturn(
+        repositoryVersionEntity).atLeastOnce();
+
+    List<ClusterVersionEntity> clusterVersionEntities = 
Lists.newArrayList(clusterVersionUpgradingTo);
+    
EasyMock.expect(m_clusterEntity.getClusterVersionEntities()).andReturn(clusterVersionEntities).atLeastOnce();
+
+    replayAll();
+
+    Mockito.doReturn(upgradeEntity).when(clusterSpy).getUpgradeInProgress();
+
+    // this shouldn't be returned since there is an upgrade in progress
+    ClusterVersionEntity currentClusterVersion = new ClusterVersionEntity();
+    
Mockito.doReturn(currentClusterVersion).when(clusterSpy).getCurrentClusterVersion();
+
+    ClusterVersionEntity effectiveVersion = 
clusterSpy.getEffectiveClusterVersion();
+    Assert.assertEquals(clusterVersionUpgradingTo, effectiveVersion);
+
+    verifyAll();
+  }
+
+  /**
+   * Sets the expectations on the {@link ClusterEntity} mock.
+   */
+  private void expectClusterEntityMocks() {
+    ClusterDAO clusterDAO = m_injector.getInstance(ClusterDAO.class);
+    StackEntity stackEntity = createNiceMock(StackEntity.class);
+
+    
EasyMock.expect(clusterDAO.findById(1L)).andReturn(m_clusterEntity).anyTimes();
+
+    EasyMock.expect(stackEntity.getStackId()).andReturn(1L).anyTimes();
+    EasyMock.expect(stackEntity.getStackName()).andReturn("HDP").anyTimes();
+    EasyMock.expect(stackEntity.getStackVersion()).andReturn("2.3").anyTimes();
+
+    EasyMock.expect(m_clusterEntity.getClusterId()).andReturn(1L).anyTimes();
+    
EasyMock.expect(m_clusterEntity.getClusterName()).andReturn("c1").anyTimes();
+    
EasyMock.expect(m_clusterEntity.getDesiredStack()).andReturn(stackEntity).anyTimes();
+    EasyMock.expect(m_clusterEntity.getClusterServiceEntities()).andReturn(
+        new ArrayList<ClusterServiceEntity>()).anyTimes();
+    EasyMock.expect(m_clusterEntity.getClusterConfigEntities()).andReturn(
+        new ArrayList<ClusterConfigEntity>()).anyTimes();
+  }
+
+  /**
+  *
+  */
+  private class MockModule implements Module {
+    /**
+    *
+    */
+    @Override
+    public void configure(Binder binder) {
+      
binder.bind(Clusters.class).toInstance(EasyMock.createNiceMock(Clusters.class));
+      
binder.bind(OsFamily.class).toInstance(EasyMock.createNiceMock(OsFamily.class));
+      
binder.bind(DBAccessor.class).toInstance(EasyMock.createNiceMock(DBAccessor.class));
+      
binder.bind(EntityManager.class).toInstance(EasyMock.createNiceMock(EntityManager.class));
+      
binder.bind(ActionManager.class).toInstance(EasyMock.createNiceMock(ActionManager.class));
+      
binder.bind(HostRoleCommandDAO.class).toInstance(EasyMock.createNiceMock(HostRoleCommandDAO.class));
+      
binder.bind(AmbariManagementController.class).toInstance(EasyMock.createNiceMock(AmbariManagementController.class));
+      
binder.bind(ClusterController.class).toInstance(EasyMock.createNiceMock(ClusterController.class));
+      
binder.bind(StackManagerFactory.class).toInstance(EasyMock.createNiceMock(StackManagerFactory.class));
+      
binder.bind(SessionManager.class).toInstance(EasyMock.createNiceMock(SessionManager.class));
+      
binder.bind(RequestExecutionFactory.class).toInstance(EasyMock.createNiceMock(RequestExecutionFactory.class));
+      
binder.bind(ExecutionScheduler.class).toInstance(EasyMock.createNiceMock(ExecutionScheduler.class));
+      
binder.bind(RequestFactory.class).toInstance(EasyMock.createNiceMock(RequestFactory.class));
+      
binder.bind(StageFactory.class).toInstance(EasyMock.createNiceMock(StageFactory.class));
+      
binder.bind(RoleGraphFactory.class).toInstance(EasyMock.createNiceMock(RoleGraphFactoryImpl.class));
+      
binder.bind(AbstractRootServiceResponseFactory.class).toInstance(EasyMock.createNiceMock(AbstractRootServiceResponseFactory.class));
+      
binder.bind(ConfigFactory.class).toInstance(EasyMock.createNiceMock(ConfigFactory.class));
+      
binder.bind(ConfigGroupFactory.class).toInstance(EasyMock.createNiceMock(ConfigGroupFactory.class));
+      
binder.bind(ServiceFactory.class).toInstance(EasyMock.createNiceMock(ServiceFactory.class));
+      
binder.bind(ServiceComponentFactory.class).toInstance(EasyMock.createNiceMock(ServiceComponentFactory.class));
+      
binder.bind(ServiceComponentHostFactory.class).toInstance(EasyMock.createNiceMock(ServiceComponentHostFactory.class));
+      
binder.bind(PasswordEncoder.class).toInstance(EasyMock.createNiceMock(PasswordEncoder.class));
+      
binder.bind(KerberosHelper.class).toInstance(EasyMock.createNiceMock(KerberosHelper.class));
+      
binder.bind(Users.class).toInstance(EasyMock.createNiceMock(Users.class));
+
+
+      try {
+        AmbariMetaInfo ambariMetaInfo = 
EasyMock.createNiceMock(AmbariMetaInfo.class);
+        EasyMock.expect(
+            ambariMetaInfo.getServices(EasyMock.anyString(), 
EasyMock.anyString())).andReturn(
+                new HashMap<String, ServiceInfo>());
+
+        EasyMock.replay(ambariMetaInfo);
+
+        binder.bind(AmbariMetaInfo.class).toInstance(ambariMetaInfo);
+      } catch (Exception exception) {
+        Assert.fail(exception.toString());
+      }
+
+      
binder.bind(ClusterDAO.class).toInstance(createNiceMock(ClusterDAO.class));
+    }
+  }
+}

Reply via email to