Repository: ambari Updated Branches: refs/heads/branch-2.5 48fcbb886 -> eb982a0eb
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/eb982a0e Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/eb982a0e Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/eb982a0e Branch: refs/heads/branch-2.5 Commit: eb982a0eb3232669360d81fc7429ddec81a91719 Parents: 48fcbb8 Author: Nate Cole <[email protected]> Authored: Thu Oct 13 18:00:12 2016 -0400 Committer: Nate Cole <[email protected]> Committed: Thu Oct 13 18:00:40 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 | 40 +++++ .../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 ++++++++++--- 16 files changed, 546 insertions(+), 44 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/eb982a0e/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 cd02223..873462f 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 @@ -201,6 +201,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; @@ -208,7 +209,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 { @@ -2333,7 +2333,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/eb982a0e/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/eb982a0e/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/eb982a0e/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/eb982a0e/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 07b845a..e60fd85 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 javax.xml.bind.JAXBException; @@ -153,7 +154,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/eb982a0e/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/eb982a0e/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 185bd58..3809c0c 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; @@ -45,6 +46,15 @@ public class UpgradeCatalog250 extends AbstractUpgradeCatalog { protected static final String HOST_VERSION_TABLE = "host_version"; private static final String AMS_ENV = "ams-env"; + 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. */ @@ -93,6 +103,7 @@ public class UpgradeCatalog250 extends AbstractUpgradeCatalog { @Override protected void executeDDLUpdates() throws AmbariException, SQLException { updateHostVersionTable(); + createComponentVersionTable(); } /** @@ -183,5 +194,34 @@ public class UpgradeCatalog250 extends AbstractUpgradeCatalog { addRoleAuthorization("AMBARI.RUN_CUSTOM_COMMAND", "Perform custom administrative actions", Collections.singletonList("AMBARI.ADMINISTRATOR:AMBARI")); } + + /** + * 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/eb982a0e/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/eb982a0e/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/eb982a0e/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/eb982a0e/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/eb982a0e/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/eb982a0e/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/eb982a0e/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/eb982a0e/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/eb982a0e/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 7b6c3ad..1ea42b2 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
