/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ambari.server.state; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import org.apache.ambari.server.state.stack.ServiceMetainfoXml; import org.junit.Test; import com.google.common.collect.Lists; /** * ServiceInfo tests. */ public class ServiceInfoTest { @Test public void testIsRestartRequiredAfterRackChange() throws Exception { String serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>RESTART</name>\n" + " <displayName>RESTART</displayName>\n" + " <comment>Apache Hadoop Distributed File System</comment>\n" + " <version>2.1.0.2.0</version>\n" + " <restartRequiredAfterRackChange>true</restartRequiredAfterRackChange>\n" + " </service>\n" + " <service>\n" + " <name>NO_RESTART</name>\n" + " <displayName>NO_RESTART</displayName>\n" + " <comment>Apache Hadoop Distributed File System</comment>\n" + " <version>2.1.0.2.0</version>\n" + " <restartRequiredAfterRackChange>false</restartRequiredAfterRackChange>\n" + " </service>\n" + " <service>\n" + " <name>DEFAULT_RESTART</name>\n" + " <displayName>DEFAULT_RESTART</displayName>\n" + " <comment>Apache Hadoop Distributed File System</comment>\n" + " <version>2.1.0.2.0</version>\n" + " </service>\n" + " <service>\n" + " <name>HCFS_SERVICE</name>\n" + " <displayName>HCFS_SERVICE</displayName>\n" + " <comment>Hadoop Compatible File System</comment>\n" + " <version>2.1.1.0</version>\n" + " <serviceType>HCFS</serviceType>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml); assertTrue(serviceInfoMap.get("RESTART").isRestartRequiredAfterRackChange()); assertFalse(serviceInfoMap.get("NO_RESTART").isRestartRequiredAfterRackChange()); assertNull(serviceInfoMap.get("DEFAULT_RESTART").isRestartRequiredAfterRackChange()); assertEquals(serviceInfoMap.get("HCFS_SERVICE").getServiceType(),"HCFS"); } @Test public void testCustomMetricsWidgetsFiles() throws Exception { String serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>CUSTOM</name>\n" + " <displayName>CUSTOM</displayName>\n" + " <metricsFileName>CUSTOM_metrics.json</metricsFileName>\n" + " <widgetsFileName>CUSTOM_widgets.json</widgetsFileName>\n" + " </service>\n" + " <service>\n" + " <name>DEFAULT</name>\n" + " <displayName>DEFAULT</displayName>\n" + " <comment>Apache Hadoop Distributed File System</comment>\n" + " <version>2.1.0.2.0</version>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml); assertEquals("CUSTOM_metrics.json", serviceInfoMap.get("CUSTOM").getMetricsFileName()); assertEquals("CUSTOM_widgets.json", serviceInfoMap.get("CUSTOM").getWidgetsFileName()); assertEquals("metrics.json", serviceInfoMap.get("DEFAULT").getMetricsFileName()); assertEquals("widgets.json", serviceInfoMap.get("DEFAULT").getWidgetsFileName()); } @Test public void testSelectionField() throws Exception { String serviceInfoXmlDeprecated = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>DEPRECATED</name>\n" + " <selection>DEPRECATED</selection>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; Map<String, ServiceInfo> serviceInfoMapDeprecated = getServiceInfo(serviceInfoXmlDeprecated); ServiceInfo deprecated = serviceInfoMapDeprecated.get("DEPRECATED"); assertEquals(deprecated.getSelection(), ServiceInfo.Selection.DEPRECATED); assertFalse(deprecated.isSelectionEmpty()); String serviceInfoXmlDefault = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>DEFAULT</name>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; Map<String, ServiceInfo> serviceInfoMapDefault = getServiceInfo(serviceInfoXmlDefault); ServiceInfo defaultSi = serviceInfoMapDefault.get("DEFAULT"); assertEquals(defaultSi.getSelection(), ServiceInfo.Selection.DEFAULT); assertTrue(defaultSi.isSelectionEmpty()); } /** * Tests the presence and absence of the credential-store block. * @throws Exception */ @Test public void testCredentialStoreFields() throws Exception { /* * <credential-store> supported and enabled. */ String serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>RANGER</name>\n" + " <credential-store>\n" + " <supported>true</supported>\n" + " <enabled>true</enabled>\n" + " <required>true</required>\n" + " </credential-store>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml); ServiceInfo service = serviceInfoMap.get("RANGER"); assertTrue(service.isCredentialStoreSupported()); assertTrue(service.isCredentialStoreEnabled()); assertTrue(service.isCredentialStoreRequired()); /* * <credential-store> supported but not enabled. */ serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>HIVE</name>\n" + " <credential-store>\n" + " <supported>true</supported>\n" + " <enabled>false</enabled>\n" + " <required>false</required>\n" + " </credential-store>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; serviceInfoMap = getServiceInfo(serviceInfoXml); service = serviceInfoMap.get("HIVE"); assertTrue(service.isCredentialStoreSupported()); assertFalse(service.isCredentialStoreEnabled()); assertFalse(service.isCredentialStoreRequired()); /* * <credential-store> is missing */ serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>AMBARI_METRICS</name>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; serviceInfoMap = getServiceInfo(serviceInfoXml); service = serviceInfoMap.get("AMBARI_METRICS"); assertFalse(service.isCredentialStoreSupported()); assertFalse(service.isCredentialStoreEnabled()); /* * <credential-store><enabled> is missing. Invalid * scenario. So both values should be false. */ serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>HBASE</name>\n" + " <credential-store>\n" + " <supported>true</supported>\n" + " </credential-store>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; serviceInfoMap = getServiceInfo(serviceInfoXml); service = serviceInfoMap.get("HBASE"); assertTrue(service.isCredentialStoreSupported()); assertFalse(service.isCredentialStoreEnabled()); } @Test public void testCredentialStoreInfoValidity() throws Exception { // Valid: Supported->True, Enabled->False String serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>RANGER</name>\n" + " <credential-store>\n" + " <supported>true</supported>\n" + " <enabled>false</enabled>\n" + " </credential-store>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml); ServiceInfo serviceInfo = serviceInfoMap.get("RANGER"); assertTrue(serviceInfo.isValid()); // Valid: Supported->True, Enabled->True serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>RANGER</name>\n" + " <credential-store>\n" + " <supported>true</supported>\n" + " <enabled>true</enabled>\n" + " </credential-store>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; serviceInfoMap = getServiceInfo(serviceInfoXml); serviceInfo = serviceInfoMap.get("RANGER"); assertTrue(serviceInfo.isValid()); // Valid: Supported->False, Enabled->False serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>RANGER</name>\n" + " <credential-store>\n" + " <supported>false</supported>\n" + " <enabled>false</enabled>\n" + " </credential-store>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; serviceInfoMap = getServiceInfo(serviceInfoXml); serviceInfo = serviceInfoMap.get("RANGER"); assertTrue(serviceInfo.isValid()); // Valid: credential-store not specified serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>RANGER</name>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; serviceInfoMap = getServiceInfo(serviceInfoXml); serviceInfo = serviceInfoMap.get("RANGER"); assertTrue(serviceInfo.isValid()); // Specified but invalid // Invalid: Supported->False, Enabled->True serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>RANGER</name>\n" + " <credential-store>\n" + " <supported>false</supported>\n" + " <enabled>true</enabled>\n" + " </credential-store>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; serviceInfoMap = getServiceInfo(serviceInfoXml); serviceInfo = serviceInfoMap.get("RANGER"); assertFalse("Credential store is enabled for a service that does not support it", serviceInfo.isValid()); // Invalid: Supported->Unspecified, Enabled->Unspecified serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>RANGER</name>\n" + " <credential-store>\n" + " </credential-store>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; serviceInfoMap = getServiceInfo(serviceInfoXml); serviceInfo = serviceInfoMap.get("RANGER"); assertFalse("Credential store details not specified", serviceInfo.isValid()); // Invalid: Supported->Specified, Enabled->Unspecified serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>RANGER</name>\n" + " <credential-store>\n" + " <supported>true</supported>\n" + " </credential-store>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; serviceInfoMap = getServiceInfo(serviceInfoXml); serviceInfo = serviceInfoMap.get("RANGER"); assertFalse("Credential store enabled not specified", serviceInfo.isValid()); // Invalid: Supported->Unspecified, Enabled->Specified serviceInfoXml = "<metainfo>\n" + " <schemaVersion>2.0</schemaVersion>\n" + " <services>\n" + " <service>\n" + " <name>RANGER</name>\n" + " <credential-store>\n" + " <enabled>true</enabled>\n" + " </credential-store>\n" + " </service>\n" + " </services>\n" + "</metainfo>\n"; serviceInfoMap = getServiceInfo(serviceInfoXml); serviceInfo = serviceInfoMap.get("RANGER"); assertFalse("Credential store supported not specified", serviceInfo.isValid()); } @Test public void testSetRestartRequiredAfterRackChange() throws Exception { ServiceInfo serviceInfo = new ServiceInfo(); serviceInfo.setRestartRequiredAfterRackChange(true); assertTrue(serviceInfo.isRestartRequiredAfterRackChange()); serviceInfo.setRestartRequiredAfterRackChange(false); assertFalse(serviceInfo.isRestartRequiredAfterRackChange()); } @Test public void testServiceProperties() throws Exception { String serviceInfoXml = "<metainfo>" + " <schemaVersion>2.0</schemaVersion>" + " <services>" + " <service>" + " <name>WITH_PROPS</name>" + " <displayName>WITH_PROPS</displayName>" + " <properties>" + " <property>" + " <name>PROP1</name>" + " <value>VAL1</value>" + " </property>" + " <property>" + " <name>PROP2</name>" + " <value>VAL2</value>" + " </property>" + " </properties>" + " </service>" + " </services>" + "</metainfo>"; Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml); Map<String, String> serviceProperties = serviceInfoMap.get("WITH_PROPS").getServiceProperties(); assertTrue(serviceProperties.containsKey("PROP1")); assertEquals("VAL1", serviceProperties.get("PROP1")); assertTrue(serviceProperties.containsKey("PROP2")); assertEquals("VAL2", serviceProperties.get("PROP2")); } @Test public void testDefaultVisibilityServiceProperties() throws Exception { // Given String serviceInfoXml = "<metainfo>" + " <schemaVersion>2.0</schemaVersion>" + " <services>" + " <service>" + " <name>WITH_PROPS</name>" + " <displayName>WITH_PROPS</displayName>" + " <properties>" + " <property>" + " <name>PROP1</name>" + " <value>VAL1</value>" + " </property>" + " <property>" + " <name>PROP2</name>" + " <value>VAL2</value>" + " </property>" + " </properties>" + " </service>" + " </services>" + "</metainfo>"; // When Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml); // Then Map<String, String> serviceProperties = serviceInfoMap.get("WITH_PROPS").getServiceProperties(); assertTrue("true".equals(serviceProperties.get(ServiceInfo.DEFAULT_SERVICE_INSTALLABLE_PROPERTY.getKey()))); assertTrue("true".equals(serviceProperties.get(ServiceInfo.DEFAULT_SERVICE_MANAGED_PROPERTY.getKey()))); assertTrue("true".equals(serviceProperties.get(ServiceInfo.DEFAULT_SERVICE_MONITORED_PROPERTY.getKey()))); } @Test public void testVisibilityServicePropertyOverride() throws Exception { // Given String serviceInfoXml = "<metainfo>" + " <schemaVersion>2.0</schemaVersion>" + " <services>" + " <service>" + " <name>WITH_PROPS</name>" + " <displayName>WITH_PROPS</displayName>" + " <properties>" + " <property>" + " <name>PROP1</name>" + " <value>VAL1</value>" + " </property>" + " <property>" + " <name>PROP2</name>" + " <value>VAL2</value>" + " </property>" + " <property>" + " <name>managed</name>" + " <value>false</value>" + " </property>" + " </properties>" + " </service>" + " </services>" + "</metainfo>"; // When Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml); // Then Map<String, String> serviceProperties = serviceInfoMap.get("WITH_PROPS").getServiceProperties(); assertTrue("true".equals(serviceProperties.get(ServiceInfo.DEFAULT_SERVICE_INSTALLABLE_PROPERTY.getKey()))); assertTrue("false".equals(serviceProperties.get(ServiceInfo.DEFAULT_SERVICE_MANAGED_PROPERTY.getKey()))); assertTrue("true".equals(serviceProperties.get(ServiceInfo.DEFAULT_SERVICE_MONITORED_PROPERTY.getKey()))); } @Test public void testDuplicateServicePropertyValidationAfterXmlDeserialization() throws Exception { // Given String serviceInfoXml = "<metainfo>" + " <schemaVersion>2.0</schemaVersion>" + " <services>" + " <service>" + " <version>1.0</version>" + " <name>WITH_DUPLICATE_PROPS</name>" + " <displayName>WITH_PROPS</displayName>" + " <properties>" + " <property>" + " <name>PROP1</name>" + " <value>VAL1</value>" + " </property>" + " <property>" + " <name>PROP1</name>" + " <value>VAL2</value>" + " </property>" + " <property>" + " <name>managed</name>" + " <value>false</value>" + " </property>" + " </properties>" + " </service>" + " </services>" + "</metainfo>"; // When Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml); ServiceInfo serviceInfo = serviceInfoMap.get("WITH_DUPLICATE_PROPS"); // Then assertFalse("Service info should be in invalid state due to duplicate service property names !", serviceInfo.isValid()); assertTrue("Service info error collection should contain the name of the duplicate service property !", serviceInfo.getErrors().contains("Duplicate service property with name 'PROP1' found in " + serviceInfo.getName() + ":" + serviceInfo.getVersion() + " service definition !")); } @Test public void testDuplicateServicePropertyValidationAfterSet() { // Given ServicePropertyInfo p1 = new ServicePropertyInfo(); p1.setName("PROP1"); p1.setValue("V1"); ServicePropertyInfo p2 = new ServicePropertyInfo(); p2.setName("PROP1"); p2.setValue("V2"); List<ServicePropertyInfo> servicePropertyList = Lists.newArrayList(p1, p2); ServiceInfo serviceInfo = new ServiceInfo(); serviceInfo.setName("TEST_NAME"); serviceInfo.setVersion("TEST_VERSION"); serviceInfo.setServicePropertyList(servicePropertyList); // Then assertFalse("Service info should be in invalid state due to duplicate service property names !", serviceInfo.isValid()); assertTrue("Service info error collection should contain the name of the duplicate service property !", serviceInfo.getErrors().contains("Duplicate service property with name 'PROP1' found in " + serviceInfo.getName() + ":" + serviceInfo.getVersion() + " service definition !")); } @Test public void testMultiplePimaryLogsValidationAfterXmlDeserialization() throws Exception { // Given String serviceInfoXml = "<metainfo>" + " <schemaVersion>2.0</schemaVersion>" + " <services>" + " <service>" + " <version>1.0</version>" + " <name>WITH_MULTIPLE_PRIMARY_LOGS</name>" + " <displayName>WITH_MULTIPLE_PRIMARY_LOGS</displayName>" + " <properties>" + " <property>" + " <name>managed</name>" + " <value>false</value>" + " </property>" + " </properties>" + " <components> " + " <component> " + " <name>COMPONENT_WITH_MULTIPLE_PRIMARY_LOG</name> " + " <displayName>COMPONENT_WITH_MULTIPLE_PRIMARY_LOG</displayName> " + " <category>MASTER</category> " + " <cardinality>0-1</cardinality> " + " <versionAdvertised>true</versionAdvertised> " + " <logs> " + " <log> " + " <logId>log1</logId> " + " <primary>true</primary> " + " </log> " + " <log> " + " <logId>log2</logId> " + " <primary>true</primary> " + " </log> " + " </logs> " + " </component> " + " </components> " + " </service>" + " </services>" + "</metainfo>"; // When Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml); ServiceInfo serviceInfo = serviceInfoMap.get("WITH_MULTIPLE_PRIMARY_LOGS"); // Then assertFalse("Service info should be in invalid state due to multiple primary logs at one of it's components!", serviceInfo.isValid()); assertTrue("Service info error collection should contain the name of the component with the multiple primary logs!", serviceInfo.getErrors().contains("More than one primary log exists for the component COMPONENT_WITH_MULTIPLE_PRIMARY_LOG")); } @Test public void testSetServicePropertiesAfterPropertyListSet() { // Given ServicePropertyInfo p1 = new ServicePropertyInfo(); p1.setName("PROP1"); p1.setValue("V1"); ServicePropertyInfo p2 = new ServicePropertyInfo(); p2.setName("PROP2"); p2.setValue("V2"); List<ServicePropertyInfo> servicePropertyList = Lists.newArrayList(p1, p2); ServiceInfo serviceInfo = new ServiceInfo(); serviceInfo.setName("TEST_NAME"); serviceInfo.setVersion("TEST_VERSION"); serviceInfo.setServicePropertyList(servicePropertyList); // When Map<String, String> serviceProperties = serviceInfo.getServiceProperties(); // Then assertTrue(serviceProperties.containsKey("PROP1")); assertEquals("V1", serviceProperties.get("PROP1")); assertTrue(serviceProperties.containsKey("PROP2")); assertEquals("V2", serviceProperties.get("PROP2")); assertTrue("true".equals(serviceProperties.get(ServiceInfo.DEFAULT_SERVICE_INSTALLABLE_PROPERTY.getKey()))); assertTrue("true".equals(serviceProperties.get(ServiceInfo.DEFAULT_SERVICE_MANAGED_PROPERTY.getKey()))); assertTrue("true".equals(serviceProperties.get(ServiceInfo.DEFAULT_SERVICE_MONITORED_PROPERTY.getKey()))); } @Test public void testSupportDeleteViaUI() throws Exception { //Explicitly set to true String serviceInfoXml = "<metainfo>" + " <schemaVersion>2.0</schemaVersion>" + " <services>" + " <service>" + " <name>HDFS</name>" + " <displayName>HDFS</displayName>" + " <supportDeleteViaUI>true</supportDeleteViaUI>" + " </service>" + " </services>" + "</metainfo>"; Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml); assertTrue(serviceInfoMap.get("HDFS").isSupportDeleteViaUI()); //Explicitly set to false serviceInfoXml = "<metainfo>" + " <schemaVersion>2.0</schemaVersion>" + " <services>" + " <service>" + " <name>HDFS</name>" + " <displayName>HDFS</displayName>" + " <supportDeleteViaUI>false</supportDeleteViaUI>" + " </service>" + " </services>" + "</metainfo>"; serviceInfoMap = getServiceInfo(serviceInfoXml); assertFalse(serviceInfoMap.get("HDFS").isSupportDeleteViaUI()); //Default to true serviceInfoXml = "<metainfo>" + " <schemaVersion>2.0</schemaVersion>" + " <services>" + " <service>" + " <name>HDFS</name>" + " <displayName>HDFS</displayName>" + " </service>" + " </services>" + "</metainfo>"; serviceInfoMap = getServiceInfo(serviceInfoXml); assertTrue(serviceInfoMap.get("HDFS").isSupportDeleteViaUI()); } public static Map<String, ServiceInfo> getServiceInfo(String xml) throws JAXBException { InputStream configStream = new ByteArrayInputStream(xml.getBytes()); JAXBContext jaxbContext = JAXBContext.newInstance(ServiceMetainfoXml.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); ServiceMetainfoXml serviceMetainfoXml = (ServiceMetainfoXml) unmarshaller.unmarshal(configStream); Map<String, ServiceInfo> serviceInfoMap = new HashMap<>(); for (ServiceInfo serviceInfo : serviceMetainfoXml.getServices()) { serviceInfoMap.put(serviceInfo.getName(), serviceInfo); } return serviceInfoMap; } }