Repository: ambari
Updated Branches:
  refs/heads/trunk 4140cc78a -> 2b35c980c


AMBARI-18557. Create Component to Repo Version db associations (ncole)


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

Branch: refs/heads/trunk
Commit: 2b35c980c187b0b211c1b6cf875bc800a35b491a
Parents: 4140cc7
Author: Nate Cole <nc...@hortonworks.com>
Authored: Fri Oct 7 15:13:00 2016 -0400
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Thu Oct 13 17:11:31 2016 -0400

----------------------------------------------------------------------
 .../AmbariManagementControllerImpl.java         |   4 +-
 .../dao/ServiceComponentDesiredStateDAO.java    |  23 ++-
 .../ServiceComponentDesiredStateEntity.java     |  24 +++
 .../entities/ServiceComponentVersionEntity.java | 159 +++++++++++++++++++
 .../apache/ambari/server/stack/RepoUtil.java    |   3 +-
 .../state/repository/VersionDefinitionXml.java  |   4 +-
 .../server/upgrade/UpgradeCatalog250.java       |  37 +++++
 .../server/upgrade/UpgradeCatalog300.java       |   1 -
 .../main/resources/Ambari-DDL-Derby-CREATE.sql  |  15 +-
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |  14 +-
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |  12 ++
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |  14 +-
 .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql |  12 ++
 .../resources/Ambari-DDL-SQLServer-CREATE.sql   |  14 +-
 .../src/main/resources/META-INF/persistence.xml |   1 +
 .../server/state/ServiceComponentTest.java      | 140 ++++++++++++++--
 .../server/upgrade/UpgradeCatalog250Test.java   | 111 ++++++++++---
 .../server/upgrade/UpgradeCatalog300Test.java   |   2 -
 18 files changed, 543 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/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 ef4fc33..5d8f279 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
@@ -202,6 +202,7 @@ import org.slf4j.LoggerFactory;
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Multimap;
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
@@ -209,7 +210,6 @@ import com.google.inject.Inject;
 import com.google.inject.Injector;
 import com.google.inject.Singleton;
 import com.google.inject.persist.Transactional;
-import com.google.common.collect.ListMultimap;
 
 @Singleton
 public class AmbariManagementControllerImpl implements 
AmbariManagementController {
@@ -2355,7 +2355,7 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
     
execCmd.setAvailableServicesFromServiceInfoMap(ambariMetaInfo.getServices(stackId.getStackName(),
 stackId.getStackVersion()));
 
     if ((execCmd != null) && 
(execCmd.getConfigurationTags().containsKey("cluster-env"))) {
-      LOG.info("AmbariManagementControllerImpl.createHostAction: created 
ExecutionCommand for host {}, role {}, roleCommand {}, and command ID {}, with 
cluster-env tags {}",
+      LOG.debug("AmbariManagementControllerImpl.createHostAction: created 
ExecutionCommand for host {}, role {}, roleCommand {}, and command ID {}, with 
cluster-env tags {}",
         execCmd.getHostname(), execCmd.getRole(), execCmd.getRoleCommand(), 
execCmd.getCommandId(), 
execCmd.getConfigurationTags().get("cluster-env").get("tag"));
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java
index cdaa6f0..987e44f 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ServiceComponentDesiredStateDAO.java
@@ -28,6 +28,7 @@ import javax.persistence.TypedQuery;
 import org.apache.ambari.server.orm.RequiresSession;
 import 
org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity;
 import org.apache.ambari.server.orm.entities.ServiceComponentHistoryEntity;
+import org.apache.ambari.server.orm.entities.ServiceComponentVersionEntity;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -175,7 +176,27 @@ public class ServiceComponentDesiredStateDAO {
     query.setParameter("serviceName", serviceName);
     query.setParameter("componentName", componentName);
 
-    ServiceComponentDesiredStateEntity entity = null;
     return daoUtils.selectList(query);
   }
+
+  /**
+   * @param clusterId     the cluster id
+   * @param serviceName   the service name
+   * @param componentName the component name
+   * @return the list of repository versions for a component
+   */
+  @RequiresSession
+  public List<ServiceComponentVersionEntity> findVersions(long clusterId, 
String serviceName,
+      String componentName) {
+    EntityManager entityManager = entityManagerProvider.get();
+    TypedQuery<ServiceComponentVersionEntity> query = 
entityManager.createNamedQuery(
+        "ServiceComponentVersionEntity.findByComponent", 
ServiceComponentVersionEntity.class);
+
+    query.setParameter("clusterId", clusterId);
+    query.setParameter("serviceName", serviceName);
+    query.setParameter("componentName", componentName);
+
+    return daoUtils.selectList(query);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java
index 61c053d..9b93517 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java
@@ -117,6 +117,9 @@ public class ServiceComponentDesiredStateEntity {
       cascade = { CascadeType.ALL })
   private Collection<ServiceComponentHistoryEntity> serviceComponentHistory;
 
+  @OneToMany(mappedBy = "m_serviceComponentDesiredStateEntity", cascade = { 
CascadeType.ALL })
+  private Collection<ServiceComponentVersionEntity> serviceComponentVersion;
+
   public Long getId() {
     return id;
   }
@@ -195,6 +198,27 @@ public class ServiceComponentDesiredStateEntity {
     return serviceComponentHistory;
   }
 
+
+  /**
+   * @param versionEntry the version to add
+   */
+  public void addVersion(ServiceComponentVersionEntity versionEntry) {
+    if (null == serviceComponentVersion) {
+      serviceComponentVersion = new ArrayList<>();
+    }
+
+    serviceComponentVersion.add(versionEntry);
+    versionEntry.setServiceComponentDesiredState(this);
+  }
+
+  /**
+   * @return the collection of versions for the component
+   */
+  public Collection<ServiceComponentVersionEntity> getVersions() {
+    return serviceComponentVersion;
+  }
+
+
   public boolean isRecoveryEnabled() {
     return recoveryEnabled != 0;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentVersionEntity.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentVersionEntity.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentVersionEntity.java
new file mode 100644
index 0000000..5085d18
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentVersionEntity.java
@@ -0,0 +1,159 @@
+/**
+ * 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.orm.entities;
+
+import java.util.Objects;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import org.apache.ambari.server.state.RepositoryVersionState;
+
+/**
+ * The {@link ServiceComponentVersionEntity} class is used to represent the
+ * association of a component and repository version.
+ */
+@Entity
+@Table(name = "servicecomponent_version")
+@TableGenerator(
+    name = "servicecomponent_version_id_generator",
+    table = "ambari_sequences",
+    pkColumnName = "sequence_name",
+    valueColumnName = "sequence_value",
+    pkColumnValue = "servicecomponent_version_id_seq",
+    initialValue = 0)
+@NamedQueries({ @NamedQuery(
+    name = "ServiceComponentVersionEntity.findByComponent",
+    query = "SELECT version FROM ServiceComponentVersionEntity version WHERE 
version.m_serviceComponentDesiredStateEntity.clusterId = :clusterId AND 
version.m_serviceComponentDesiredStateEntity.serviceName = :serviceName AND 
version.m_serviceComponentDesiredStateEntity.componentName = :componentName") })
+public class ServiceComponentVersionEntity {
+
+  @Id
+  @GeneratedValue(
+      strategy = GenerationType.TABLE,
+      generator = "servicecomponent_version_id_generator")
+  @Column(name = "id", nullable = false, updatable = false)
+  private long m_id;
+
+  @ManyToOne(optional = false, cascade = { CascadeType.MERGE })
+  @JoinColumn(name = "component_id", referencedColumnName = "id", nullable = 
false)
+  private ServiceComponentDesiredStateEntity 
m_serviceComponentDesiredStateEntity;
+
+  @ManyToOne
+  @JoinColumn(name = "repo_version_id", referencedColumnName = 
"repo_version_id", nullable = false)
+  private RepositoryVersionEntity m_repositoryVersion;
+
+  @Column(name = "state", nullable = false, insertable = true, updatable = 
true)
+  @Enumerated(value = EnumType.STRING)
+  private RepositoryVersionState m_state = RepositoryVersionState.CURRENT;
+
+  @Column(name = "user_name", nullable = false, insertable=true, 
updatable=true)
+  private String userName;
+
+
+  /**
+   * @return the associated component
+   */
+  public ServiceComponentDesiredStateEntity getServiceComponentDesiredState() {
+    return m_serviceComponentDesiredStateEntity;
+  }
+
+  /**
+   * @param serviceComponentDesiredStateEntity  the associated component (not 
{@code null})
+   */
+  public void 
setServiceComponentDesiredState(ServiceComponentDesiredStateEntity 
serviceComponentDesiredStateEntity) {
+    m_serviceComponentDesiredStateEntity = serviceComponentDesiredStateEntity;
+  }
+
+  /**
+   * @param repositoryVersion the repository
+   */
+  public void setRepositoryVersion(RepositoryVersionEntity repositoryVersion) {
+    m_repositoryVersion = repositoryVersion;
+  }
+
+  /**
+   * @return the id
+   */
+  public long getId() {
+    return m_id;
+  }
+
+  /**
+   * @return the state of the repository
+   */
+  public RepositoryVersionState getState() {
+    return m_state;
+  }
+
+  /**
+   * @param state the state of the repository
+   */
+  public void setState(RepositoryVersionState state) {
+    m_state = state;
+  }
+
+  /**
+   * @return the user name
+   */
+  public String getUserName() {
+    return userName;
+  }
+
+  /**
+   * @param name  the user name
+   */
+  public void setUserName(String name) {
+    userName = name;
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(m_id, m_repositoryVersion, 
m_serviceComponentDesiredStateEntity, m_state);
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) {
+      return true;
+    }
+
+    if (obj == null || getClass() != obj.getClass()) {
+      return false;
+    }
+
+    final ServiceComponentVersionEntity other = 
(ServiceComponentVersionEntity) obj;
+
+    return Objects.equals(m_id, other.m_id)
+        && Objects.equals(m_repositoryVersion, other.m_repositoryVersion)
+        && Objects.equals(m_serviceComponentDesiredStateEntity, 
other.m_serviceComponentDesiredStateEntity)
+        && Objects.equals(m_state, other.m_state);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java
index 56ad95d..1380f93 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java
@@ -23,6 +23,7 @@ import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+
 import javax.annotation.Nullable;
 
 import org.apache.ambari.server.AmbariException;
@@ -152,7 +153,7 @@ public class RepoUtil {
         }
       }
     }
-    LOG.info("Found {} service repos: {}", 
serviceRepoIds.size(),Iterables.toString(serviceRepoIds));
+    LOG.debug("Found {} service repos: {}", 
serviceRepoIds.size(),Iterables.toString(serviceRepoIds));
     return serviceRepos;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
index 6d5f23e..69399d6 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
@@ -120,7 +120,7 @@ public class VersionDefinitionXml {
    * collection is either the subset of the manifest, or the manifest itself 
if no services
    * are specified as "available".
    */
-  public Collection<AvailableService> getAvailableServices(StackInfo stack) {
+  public synchronized Collection<AvailableService> 
getAvailableServices(StackInfo stack) {
     if (null == m_availableMap) {
       Map<String, ManifestService> manifests = buildManifest();
       m_availableMap = new HashMap<>();
@@ -155,7 +155,7 @@ public class VersionDefinitionXml {
    * @param stack the stack for which to get the information
    * @return the list of {@code ManifestServiceInfo} instances for each 
service in the stack
    */
-  public List<ManifestServiceInfo> getStackServices(StackInfo stack) {
+  public synchronized List<ManifestServiceInfo> getStackServices(StackInfo 
stack) {
 
     if (null != m_manifest) {
       return m_manifest;

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog250.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog250.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog250.java
index 091c6d9..34331ee 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog250.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog250.java
@@ -27,6 +27,7 @@ import java.util.Map;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.orm.DBAccessor.DBColumnInfo;
 import org.apache.ambari.server.orm.dao.DaoUtils;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
@@ -48,6 +49,12 @@ public class UpgradeCatalog250 extends 
AbstractUpgradeCatalog {
   private static final String KAFKA_BROKER = "kafka-broker";
   private static final String KAFKA_TIMELINE_METRICS_HOST = 
"kafka.timeline.metrics.host";
 
+  public static final String COMPONENT_TABLE = "servicecomponentdesiredstate";
+  public static final String COMPONENT_VERSION_TABLE = 
"servicecomponent_version";
+  public static final String COMPONENT_VERSION_PK = "PK_sc_version";
+  public static final String COMPONENT_VERSION_FK_COMPONENT = 
"FK_scv_component_id";
+  public static final String COMPONENT_VERSION_FK_REPO_VERSION = 
"FK_scv_repo_version_id";
+
   /**
    * Logger.
    */
@@ -96,6 +103,7 @@ public class UpgradeCatalog250 extends 
AbstractUpgradeCatalog {
   @Override
   protected void executeDDLUpdates() throws AmbariException, SQLException {
     updateHostVersionTable();
+    createComponentVersionTable();
   }
 
   /**
@@ -211,5 +219,34 @@ public class UpgradeCatalog250 extends 
AbstractUpgradeCatalog {
       }
     }
   }
+
+  /**
+   * Creates the servicecomponent_version table
+   * @throws SQLException
+   */
+  private void createComponentVersionTable() throws SQLException {
+
+    List<DBColumnInfo> columns = new ArrayList<>();
+
+    // Add extension link table
+    LOG.info("Creating {} table", COMPONENT_VERSION_TABLE);
+
+    columns.add(new DBColumnInfo("id", Long.class, null, null, false));
+    columns.add(new DBColumnInfo("component_id", Long.class, null, null, 
false));
+    columns.add(new DBColumnInfo("repo_version_id", Long.class, null, null, 
false));
+    columns.add(new DBColumnInfo("state", String.class, 32, null, false));
+    columns.add(new DBColumnInfo("user_name", String.class, 255, null, false));
+    dbAccessor.createTable(COMPONENT_VERSION_TABLE, columns, (String[]) null);
+
+    dbAccessor.addPKConstraint(COMPONENT_VERSION_TABLE, COMPONENT_VERSION_PK, 
"id");
+
+    dbAccessor.addFKConstraint(COMPONENT_VERSION_TABLE, 
COMPONENT_VERSION_FK_COMPONENT, "component_id",
+        COMPONENT_TABLE, "id", false);
+
+    dbAccessor.addFKConstraint(COMPONENT_VERSION_TABLE, 
COMPONENT_VERSION_FK_REPO_VERSION, "repo_version_id",
+        "repo_version", "repo_version_id", false);
+
+    addSequence("servicecomponent_version_id_seq", 0L, false);
+  }
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java
index 64c98b7..4f90ef3 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java
@@ -122,5 +122,4 @@ public class UpgradeCatalog300 extends 
AbstractUpgradeCatalog {
 
   }
 
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql 
b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
index c2c965d..4b64955 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
@@ -872,6 +872,17 @@ CREATE TABLE servicecomponent_history(
   CONSTRAINT FK_sc_history_to_stack_id FOREIGN KEY (to_stack_id) REFERENCES 
stack (stack_id)
 );
 
+CREATE TABLE servicecomponent_version(
+  id BIGINT NOT NULL,
+  component_id BIGINT NOT NULL,
+  repo_version_id BIGINT NOT NULL,
+  state VARCHAR(32) NOT NULL,
+  user_name VARCHAR(255) NOT NULL,
+  CONSTRAINT PK_sc_version PRIMARY KEY (id),
+  CONSTRAINT FK_scv_component_id FOREIGN KEY (component_id) REFERENCES 
servicecomponentdesiredstate (id),
+  CONSTRAINT FK_scv_repo_version_id FOREIGN KEY (repo_version_id) REFERENCES 
repo_version (repo_version_id)
+);
+
 CREATE TABLE ambari_operation_history(
   id BIGINT NOT NULL,
   from_version VARCHAR(255) NOT NULL,
@@ -1142,7 +1153,9 @@ INSERT INTO ambari_sequences (sequence_name, 
sequence_value)
   union all
   select 'remote_cluster_id_seq', 0 FROM SYSIBM.SYSDUMMY1
   union all
-  select 'remote_cluster_service_id_seq', 0 FROM SYSIBM.SYSDUMMY1;
+  select 'remote_cluster_service_id_seq', 0 FROM SYSIBM.SYSDUMMY1
+  union all
+  select 'servicecomponent_version_id_seq', 0 FROM SYSIBM.SYSDUMMY1;
 
 
 INSERT INTO adminresourcetype (resource_type_id, resource_type_name)

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql 
b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index f28cdc9..15a84cd 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -879,6 +879,17 @@ CREATE TABLE servicecomponent_history(
   CONSTRAINT FK_sc_history_to_stack_id FOREIGN KEY (to_stack_id) REFERENCES 
stack (stack_id)
 );
 
+CREATE TABLE servicecomponent_version(
+  id BIGINT NOT NULL,
+  component_id BIGINT NOT NULL,
+  repo_version_id BIGINT NOT NULL,
+  state VARCHAR(32) NOT NULL,
+  user_name VARCHAR(255) NOT NULL,
+  CONSTRAINT PK_sc_version PRIMARY KEY (id),
+  CONSTRAINT FK_scv_component_id FOREIGN KEY (component_id) REFERENCES 
servicecomponentdesiredstate (id),
+  CONSTRAINT FK_scv_repo_version_id FOREIGN KEY (repo_version_id) REFERENCES 
repo_version (repo_version_id)
+);
+
 CREATE TABLE ambari_operation_history(
   id BIGINT NOT NULL,
   from_version VARCHAR(255) NOT NULL,
@@ -1097,7 +1108,8 @@ INSERT INTO ambari_sequences(sequence_name, 
sequence_value) VALUES
   ('blueprint_setting_id_seq', 0),
   ('ambari_operation_history_id_seq', 0),
   ('remote_cluster_id_seq', 0),
-  ('remote_cluster_service_id_seq', 0);
+  ('remote_cluster_service_id_seq', 0),
+  ('servicecomponent_version_id_seq', 0);
 
 INSERT INTO adminresourcetype (resource_type_id, resource_type_name) VALUES
   (1, 'AMBARI'),

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql 
b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
index 49f3e2f..6c3c036 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -869,6 +869,17 @@ CREATE TABLE servicecomponent_history(
   CONSTRAINT FK_sc_history_to_stack_id FOREIGN KEY (to_stack_id) REFERENCES 
stack (stack_id)
 );
 
+CREATE TABLE servicecomponent_version(
+  id NUMBER(19) NOT NULL,
+  component_id NUMBER(19) NOT NULL,
+  repo_version_id NUMBER(19) NOT NULL,
+  state VARCHAR2(32) NOT NULL,
+  user_name VARCHAR2(255) NOT NULL,
+  CONSTRAINT PK_sc_version PRIMARY KEY (id),
+  CONSTRAINT FK_scv_component_id FOREIGN KEY (component_id) REFERENCES 
servicecomponentdesiredstate (id),
+  CONSTRAINT FK_scv_repo_version_id FOREIGN KEY (repo_version_id) REFERENCES 
repo_version (repo_version_id)
+);
+
 CREATE TABLE ambari_operation_history(
   id NUMBER(19) NOT NULL,
   from_version VARCHAR2(255) NOT NULL,
@@ -1088,6 +1099,7 @@ INSERT INTO ambari_sequences(sequence_name, 
sequence_value) values ('blueprint_s
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values 
('ambari_operation_history_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values 
('remote_cluster_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values 
('remote_cluster_service_id_seq', 0);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values 
('servicecomponent_version_id_seq', 0);
 
 INSERT INTO metainfo("metainfo_key", "metainfo_value") values ('version', 
'${ambariSchemaVersion}');
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql 
b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index 7aa52ef..570b684 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -871,6 +871,17 @@ CREATE TABLE servicecomponent_history(
   CONSTRAINT FK_sc_history_to_stack_id FOREIGN KEY (to_stack_id) REFERENCES 
stack (stack_id)
 );
 
+CREATE TABLE servicecomponent_version(
+  id BIGINT NOT NULL,
+  component_id BIGINT NOT NULL,
+  repo_version_id BIGINT NOT NULL,
+  state VARCHAR(32) NOT NULL,
+  user_name VARCHAR(255) NOT NULL,
+  CONSTRAINT PK_sc_version PRIMARY KEY (id),
+  CONSTRAINT FK_scv_component_id FOREIGN KEY (component_id) REFERENCES 
servicecomponentdesiredstate (id),
+  CONSTRAINT FK_scv_repo_version_id FOREIGN KEY (repo_version_id) REFERENCES 
repo_version (repo_version_id)
+);
+
 CREATE TABLE ambari_operation_history(
   id BIGINT NOT NULL,
   from_version VARCHAR(255) NOT NULL,
@@ -1088,7 +1099,8 @@ INSERT INTO ambari_sequences (sequence_name, 
sequence_value) VALUES
   ('blueprint_setting_id_seq', 0),
   ('ambari_operation_history_id_seq', 0),
   ('remote_cluster_id_seq', 0),
-  ('remote_cluster_service_id_seq', 0);
+  ('remote_cluster_service_id_seq', 0),
+  ('servicecomponent_version_id_seq', 0);
 
 INSERT INTO adminresourcetype (resource_type_id, resource_type_name) VALUES
   (1, 'AMBARI'),

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql 
b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
index 0c95471..170e430 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
@@ -868,6 +868,17 @@ CREATE TABLE servicecomponent_history(
   CONSTRAINT FK_sc_history_to_stack_id FOREIGN KEY (to_stack_id) REFERENCES 
stack (stack_id)
 );
 
+CREATE TABLE servicecomponent_version(
+  id NUMERIC(19) NOT NULL,
+  component_id NUMERIC(19) NOT NULL,
+  repo_version_id NUMERIC(19) NOT NULL,
+  state VARCHAR(32) NOT NULL,
+  user_name VARCHAR(255) NOT NULL,
+  CONSTRAINT PK_sc_version PRIMARY KEY (id),
+  CONSTRAINT FK_scv_component_id FOREIGN KEY (component_id) REFERENCES 
servicecomponentdesiredstate (id),
+  CONSTRAINT FK_scv_repo_version_id FOREIGN KEY (repo_version_id) REFERENCES 
repo_version (repo_version_id)
+);
+
 CREATE TABLE ambari_operation_history(
   id NUMERIC(19) NOT NULL,
   from_version VARCHAR(255) NOT NULL,
@@ -1087,6 +1098,7 @@ INSERT INTO ambari_sequences(sequence_name, 
sequence_value) values ('blueprint_s
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values 
('ambari_operation_history_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values 
('remote_cluster_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values 
('remote_cluster_service_id_seq', 0);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values 
('servicecomponent_version_id_seq', 0);
 
 insert into adminresourcetype (resource_type_id, resource_type_name)
   select 1, 'AMBARI'

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql 
b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
index 631b5c4..1501143 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
@@ -889,6 +889,17 @@ CREATE TABLE servicecomponent_history(
   CONSTRAINT FK_sc_history_to_stack_id FOREIGN KEY (to_stack_id) REFERENCES 
stack (stack_id)
 );
 
+CREATE TABLE servicecomponent_version(
+  id BIGINT NOT NULL,
+  component_id BIGINT NOT NULL,
+  repo_version_id BIGINT NOT NULL,
+  state VARCHAR(32) NOT NULL,
+  user_name VARCHAR(255) NOT NULL,
+  CONSTRAINT PK_sc_version PRIMARY KEY (id),
+  CONSTRAINT FK_scv_component_id FOREIGN KEY (component_id) REFERENCES 
servicecomponentdesiredstate (id),
+  CONSTRAINT FK_scv_repo_version_id FOREIGN KEY (repo_version_id) REFERENCES 
repo_version (repo_version_id)
+);
+
 CREATE TABLE ambari_operation_history(
   id BIGINT NOT NULL,
   from_version VARCHAR(255) NOT NULL,
@@ -1112,7 +1123,8 @@ BEGIN TRANSACTION
     ('blueprint_setting_id_seq', 0),
     ('ambari_operation_history_id_seq', 0),
     ('remote_cluster_id_seq', 0),
-    ('remote_cluster_service_id_seq', 0);
+    ('remote_cluster_service_id_seq', 0),
+    ('servicecomponent_version_id_seq', 0);
 
   insert into adminresourcetype (resource_type_id, resource_type_name)
   values

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/main/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/META-INF/persistence.xml 
b/ambari-server/src/main/resources/META-INF/persistence.xml
index 2bc3282..0375650 100644
--- a/ambari-server/src/main/resources/META-INF/persistence.xml
+++ b/ambari-server/src/main/resources/META-INF/persistence.xml
@@ -67,6 +67,7 @@
     
<class>org.apache.ambari.server.orm.entities.RoleSuccessCriteriaEntity</class>
     
<class>org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity</class>
     
<class>org.apache.ambari.server.orm.entities.ServiceComponentHistoryEntity</class>
+    
<class>org.apache.ambari.server.orm.entities.ServiceComponentVersionEntity</class>
     <class>org.apache.ambari.server.orm.entities.ServiceConfigEntity</class>
     
<class>org.apache.ambari.server.orm.entities.ServiceDesiredStateEntity</class>
     <class>org.apache.ambari.server.orm.entities.StackEntity</class>

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceComponentTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceComponentTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceComponentTest.java
index b043da1..0bf21f9 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceComponentTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceComponentTest.java
@@ -18,10 +18,14 @@
 
 package org.apache.ambari.server.state;
 
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.persist.PersistService;
-import junit.framework.Assert;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.ServiceComponentResponse;
@@ -31,14 +35,17 @@ import org.apache.ambari.server.orm.OrmTestHelper;
 import org.apache.ambari.server.orm.dao.HostComponentDesiredStateDAO;
 import org.apache.ambari.server.orm.dao.HostComponentStateDAO;
 import org.apache.ambari.server.orm.dao.HostDAO;
+import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.dao.ServiceComponentDesiredStateDAO;
 import org.apache.ambari.server.orm.dao.UpgradeDAO;
 import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity;
 import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntityPK;
 import org.apache.ambari.server.orm.entities.HostComponentStateEntity;
 import org.apache.ambari.server.orm.entities.HostEntity;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import 
org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity;
 import org.apache.ambari.server.orm.entities.ServiceComponentHistoryEntity;
+import org.apache.ambari.server.orm.entities.ServiceComponentVersionEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
 import org.apache.ambari.server.state.stack.upgrade.Direction;
 import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
@@ -46,13 +53,11 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.persist.PersistService;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
+import junit.framework.Assert;
 
 public class ServiceComponentTest {
 
@@ -510,6 +515,7 @@ public class ServiceComponentTest {
     ServiceComponentDesiredStateEntity serviceComponentDesiredStateEntity = 
serviceComponentDesiredStateDAO.findByName(
         cluster.getClusterId(), serviceName, componentName);
 
+
     Assert.assertNotNull(serviceComponentDesiredStateEntity);
 
     UpgradeEntity upgradeEntity = createUpgradeEntity("2.2.0.0", "2.2.0.1");
@@ -551,6 +557,119 @@ public class ServiceComponentTest {
     assertEquals(0, componentHistoryList.size());
   }
 
+  @Test
+  public void testVersionCreation() throws Exception {
+    ServiceComponentDesiredStateDAO serviceComponentDesiredStateDAO = 
injector.getInstance(
+        ServiceComponentDesiredStateDAO.class);
+
+    String componentName = "NAMENODE";
+    ServiceComponent component = serviceComponentFactory.createNew(service, 
componentName);
+    service.addServiceComponent(component);
+    component.persist();
+
+    ServiceComponent sc = service.getServiceComponent(componentName);
+    Assert.assertNotNull(sc);
+
+    sc.setDesiredState(State.INSTALLED);
+    Assert.assertEquals(State.INSTALLED, sc.getDesiredState());
+
+    sc.setDesiredStackVersion(new StackId("HDP-2.2.0"));
+    StackId stackId = sc.getDesiredStackVersion();
+    Assert.assertEquals(new StackId("HDP", "2.2.0"), stackId);
+
+    Assert.assertEquals("HDP-2.2.0", sc.getDesiredStackVersion().getStackId());
+
+    ServiceComponentDesiredStateEntity serviceComponentDesiredStateEntity = 
serviceComponentDesiredStateDAO.findByName(
+        cluster.getClusterId(), serviceName, componentName);
+
+    Assert.assertNotNull(serviceComponentDesiredStateEntity);
+
+    RepositoryVersionEntity rve = new RepositoryVersionEntity(
+        serviceComponentDesiredStateEntity.getDesiredStack(), "HDP-2.2.0", 
"2.2.0.1-1111", "[]");
+
+    RepositoryVersionDAO repositoryDAO = 
injector.getInstance(RepositoryVersionDAO.class);
+    repositoryDAO.create(rve);
+
+    ServiceComponentVersionEntity version = new 
ServiceComponentVersionEntity();
+    version.setState(RepositoryVersionState.CURRENT);
+    version.setRepositoryVersion(rve);
+    version.setUserName("user");
+    serviceComponentDesiredStateEntity.addVersion(version);
+
+    serviceComponentDesiredStateEntity = serviceComponentDesiredStateDAO.merge(
+        serviceComponentDesiredStateEntity);
+
+    serviceComponentDesiredStateEntity = 
serviceComponentDesiredStateDAO.findByName(
+        cluster.getClusterId(), serviceName, componentName);
+
+    assertEquals(1, serviceComponentDesiredStateEntity.getVersions().size());
+    ServiceComponentVersionEntity persistedVersion = 
serviceComponentDesiredStateEntity.getVersions().iterator().next();
+
+    assertEquals(RepositoryVersionState.CURRENT, persistedVersion.getState());
+  }
+
+  @Test
+  public void testVersionRemoval() throws Exception {
+    ServiceComponentDesiredStateDAO serviceComponentDesiredStateDAO = 
injector.getInstance(
+        ServiceComponentDesiredStateDAO.class);
+
+    String componentName = "NAMENODE";
+    ServiceComponent component = serviceComponentFactory.createNew(service, 
componentName);
+    service.addServiceComponent(component);
+    component.persist();
+
+    ServiceComponent sc = service.getServiceComponent(componentName);
+    Assert.assertNotNull(sc);
+
+    sc.setDesiredState(State.INSTALLED);
+    Assert.assertEquals(State.INSTALLED, sc.getDesiredState());
+
+    sc.setDesiredStackVersion(new StackId("HDP-2.2.0"));
+    StackId stackId = sc.getDesiredStackVersion();
+    Assert.assertEquals(new StackId("HDP", "2.2.0"), stackId);
+
+    Assert.assertEquals("HDP-2.2.0", sc.getDesiredStackVersion().getStackId());
+
+    ServiceComponentDesiredStateEntity serviceComponentDesiredStateEntity = 
serviceComponentDesiredStateDAO.findByName(
+        cluster.getClusterId(), serviceName, componentName);
+
+    Assert.assertNotNull(serviceComponentDesiredStateEntity);
+
+    RepositoryVersionEntity rve = new RepositoryVersionEntity(
+        serviceComponentDesiredStateEntity.getDesiredStack(), "HDP-2.2.0", 
"2.2.0.1-1111", "[]");
+
+    RepositoryVersionDAO repositoryDAO = 
injector.getInstance(RepositoryVersionDAO.class);
+    repositoryDAO.create(rve);
+
+    ServiceComponentVersionEntity version = new 
ServiceComponentVersionEntity();
+    version.setState(RepositoryVersionState.CURRENT);
+    version.setRepositoryVersion(rve);
+    version.setUserName("user");
+    serviceComponentDesiredStateEntity.addVersion(version);
+
+    serviceComponentDesiredStateEntity = serviceComponentDesiredStateDAO.merge(
+        serviceComponentDesiredStateEntity);
+
+    serviceComponentDesiredStateEntity = 
serviceComponentDesiredStateDAO.findByName(
+        cluster.getClusterId(), serviceName, componentName);
+
+    assertEquals(1, serviceComponentDesiredStateEntity.getVersions().size());
+    ServiceComponentVersionEntity persistedVersion = 
serviceComponentDesiredStateEntity.getVersions().iterator().next();
+
+    assertEquals(RepositoryVersionState.CURRENT, persistedVersion.getState());
+
+    sc.delete();
+
+    serviceComponentDesiredStateEntity = 
serviceComponentDesiredStateDAO.findByName(
+        cluster.getClusterId(), serviceName, componentName);
+    Assert.assertNull(serviceComponentDesiredStateEntity);
+
+
+    // verify versions are gone, too
+    List<ServiceComponentVersionEntity> list = 
serviceComponentDesiredStateDAO.findVersions(cluster.getClusterId(), 
serviceName, componentName);
+    assertEquals(0, list.size());
+  }
+
   /**
    * Creates an upgrade entity, asserting it was created correctly.
    *
@@ -574,4 +693,5 @@ public class ServiceComponentTest {
     assertEquals(1, upgrades.size());
     return upgradeEntity;
   }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog250Test.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog250Test.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog250Test.java
index 9f34bcc..d3586c3 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog250Test.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog250Test.java
@@ -18,13 +18,37 @@
 
 package org.apache.ambari.server.upgrade;
 
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.anyString;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.createMockBuilder;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.createStrictMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.newCapture;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import javax.persistence.EntityManager;
 
-import com.google.common.collect.Maps;
-import com.google.gson.Gson;
-import junit.framework.Assert;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.ActionManager;
+import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.AmbariManagementControllerImpl;
 import org.apache.ambari.server.controller.KerberosHelper;
@@ -47,32 +71,15 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.common.collect.Maps;
+import com.google.gson.Gson;
 import com.google.inject.Binder;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Module;
 import com.google.inject.Provider;
 
-import java.lang.reflect.Method;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.anyString;
-import static org.easymock.EasyMock.createMockBuilder;
-import static org.easymock.EasyMock.capture;
-import static org.easymock.EasyMock.createNiceMock;
-import static org.easymock.EasyMock.createStrictMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.newCapture;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
-import static org.easymock.EasyMock.verify;
-import static org.junit.Assert.assertTrue;
+import junit.framework.Assert;
 
 /**
  * {@link UpgradeCatalog250} unit tests.
@@ -99,10 +106,37 @@ public class UpgradeCatalog250Test {
   public void testExecuteDDLUpdates() throws Exception {
     final DBAccessor dbAccessor = createNiceMock(DBAccessor.class);
 
+    Configuration configuration = createNiceMock(Configuration.class);
+    Connection connection = createNiceMock(Connection.class);
+    Statement statement = createNiceMock(Statement.class);
+    ResultSet resultSet = createNiceMock(ResultSet.class);
+
+
+    // !!! setup capture for host_version
     dbAccessor.addUniqueConstraint("host_version", "UQ_host_repo", 
"repo_version_id", "host_id");
     expectLastCall().once();
 
-    replay(dbAccessor);
+    // !!! setup capture for servicecomponent_version
+    Capture<List<DBAccessor.DBColumnInfo>> capturedComponentVersionColumns = 
newCapture();
+
+    dbAccessor.createTable(eq(UpgradeCatalog250.COMPONENT_VERSION_TABLE), 
capture(capturedComponentVersionColumns),
+        eq((String[]) null));
+
+    dbAccessor.addPKConstraint(eq(UpgradeCatalog250.COMPONENT_VERSION_TABLE),
+        eq(UpgradeCatalog250.COMPONENT_VERSION_PK), eq("id"));
+    dbAccessor.addFKConstraint(eq(UpgradeCatalog250.COMPONENT_VERSION_TABLE),
+        eq(UpgradeCatalog250.COMPONENT_VERSION_FK_COMPONENT), 
eq("component_id"),
+        eq(UpgradeCatalog250.COMPONENT_TABLE), eq("id"), eq(false));
+    dbAccessor.addFKConstraint(eq(UpgradeCatalog250.COMPONENT_VERSION_TABLE),
+        eq(UpgradeCatalog250.COMPONENT_VERSION_FK_REPO_VERSION), 
eq("repo_version_id"),
+        eq("repo_version"), eq("repo_version_id"), eq(false));
+
+
+    expect(dbAccessor.getConnection()).andReturn(connection);
+    expect(connection.createStatement()).andReturn(statement);
+    
expect(statement.executeQuery(anyObject(String.class))).andReturn(resultSet);
+
+    replay(dbAccessor, configuration, connection, statement, resultSet);
 
     Module module = new Module() {
       @Override
@@ -118,6 +152,35 @@ public class UpgradeCatalog250Test {
     upgradeCatalog250.executeDDLUpdates();
 
     verify(dbAccessor);
+
+    // !!! check the captured for host_version
+    // (no checks)
+
+    // !!! check the captured for servicecomponent_version
+    Map<String, DBAccessor.DBColumnInfo> expected = new HashMap<>();
+    expected.put("id", new DBAccessor.DBColumnInfo("id", Long.class, null, 
null, false));
+    expected.put("component_id", new DBAccessor.DBColumnInfo("component_id", 
Long.class, null, null, false));
+    expected.put("repo_version_id", new 
DBAccessor.DBColumnInfo("repo_version_id", Long.class, null, null, false));
+    expected.put("state", new DBAccessor.DBColumnInfo("state", String.class, 
32, null, false));
+    expected.put("user_name", new DBAccessor.DBColumnInfo("user_name", 
String.class, 255, null, false));
+
+    List<DBAccessor.DBColumnInfo> captured = 
capturedComponentVersionColumns.getValue();
+    Assert.assertEquals(5, captured.size());
+
+    for (DBAccessor.DBColumnInfo column : captured) {
+      DBAccessor.DBColumnInfo expectedColumn = 
expected.remove(column.getName());
+
+      Assert.assertNotNull(expectedColumn);
+      Assert.assertEquals(expectedColumn.getDefaultValue(), 
column.getDefaultValue());
+      Assert.assertEquals(expectedColumn.getName(), column.getName());
+      Assert.assertEquals(expectedColumn.getLength(), column.getLength());
+      Assert.assertEquals(expectedColumn.getType(), column.getType());
+      Assert.assertEquals(expectedColumn.getClass(), column.getClass());
+    }
+
+    // did we get them all?
+    Assert.assertEquals(0, expected.size());
+
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/ambari/blob/2b35c980/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java
index dcb1fdd..d7979e8 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java
@@ -47,8 +47,6 @@ public class UpgradeCatalog300Test {
     upgradeCatalog300.executeDMLUpdates();
 
     verify(upgradeCatalog300);
-
-
   }
 
 }

Reply via email to