SLIDER-324. Exports should be attributed to individual master components rather 
than only one master component


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

Branch: refs/heads/feature/SLIDER-151_REST_API
Commit: 2a25ab9192bc96a2f6f4409f9eea916e94c9484c
Parents: bc9561d
Author: Sumit Mohanty <smoha...@hortonworks.com>
Authored: Fri Aug 15 17:18:52 2014 -0700
Committer: Sumit Mohanty <smoha...@hortonworks.com>
Committed: Fri Aug 15 17:18:52 2014 -0700

----------------------------------------------------------------------
 app-packages/storm/metainfo.xml                 |   4 +-
 .../providers/agent/AgentProviderService.java   | 216 +++++++++++--------
 .../application/metadata/MetainfoParser.java    |   8 +-
 .../agent/TestAgentProviderService.java         |  34 ++-
 .../metadata/MetainfoParserTest.java            |  59 -----
 .../metadata/TestMetainfoParser.java            |  63 ++++++
 6 files changed, 221 insertions(+), 163 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/2a25ab91/app-packages/storm/metainfo.xml
----------------------------------------------------------------------
diff --git a/app-packages/storm/metainfo.xml b/app-packages/storm/metainfo.xml
index d9004ad..dbe8549 100644
--- a/app-packages/storm/metainfo.xml
+++ b/app-packages/storm/metainfo.xml
@@ -45,7 +45,7 @@
             
<value>http://${site.global.ganglia_server_host}/ganglia?c=${site.global.ganglia_server_id}</value>
           </export>
           <export>
-            <name>nimbus.url</name>
+            <name>nimbus.host_port</name>
             
<value>http://${NIMBUS_HOST}:${site.storm-site.nimbus.thrift.port}</value>
           </export>
         </exports>
@@ -82,7 +82,7 @@
         <name>NIMBUS</name>
         <category>MASTER</category>
         <autoStartOnFailure>true</autoStartOnFailure>
-        
<appExports>QuickLinks-nimbus.url,QuickLinks-ganglia.ui,QuickLinks-app.metrics</appExports>
+        
<appExports>QuickLinks-nimbus.host_port,QuickLinks-ganglia.ui,QuickLinks-app.metrics</appExports>
         <commandScript>
           <script>scripts/nimbus.py</script>
           <scriptType>PYTHON</scriptType>

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/2a25ab91/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
 
b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
index 91bc0a6..842f4f6 100644
--- 
a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
+++ 
b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
@@ -56,6 +56,7 @@ import org.apache.slider.providers.ProviderRole;
 import org.apache.slider.providers.ProviderUtils;
 import org.apache.slider.providers.agent.application.metadata.Application;
 import org.apache.slider.providers.agent.application.metadata.Component;
+import org.apache.slider.providers.agent.application.metadata.ComponentExport;
 import org.apache.slider.providers.agent.application.metadata.Export;
 import org.apache.slider.providers.agent.application.metadata.ExportGroup;
 import org.apache.slider.providers.agent.application.metadata.Metainfo;
@@ -137,6 +138,8 @@ public class AgentProviderService extends 
AbstractProviderService implements
       new ConcurrentHashMap<String, ComponentInstanceState>();
   private final Map<String, Map<String, String>> componentInstanceData =
       new ConcurrentHashMap<String, Map<String, String>>();
+  private final Map<String, Map<String, String>> exportGroups =
+      new ConcurrentHashMap<String, Map<String, String>>();
   private final Map<String, Map<String, String>> allocatedPorts =
       new ConcurrentHashMap<String, Map<String, String>>();
   private final Map<String, String> workFolders =
@@ -451,22 +454,8 @@ public class AgentProviderService extends 
AbstractProviderService implements
     Boolean isMaster = isMaster(roleName);
     ComponentInstanceState componentStatus = getComponentStatuses().get(label);
     componentStatus.heartbeat(System.currentTimeMillis());
-    // If no Master can explicitly publish then publish if its a master
-    // Otherwise, wait till the master that can publish is ready
-    if (isMaster &&
-        (canAnyMasterPublishConfig() == false || canPublishConfig(roleName))) {
-      publishConfigAndExportGroups(heartBeat, componentStatus);
-    } else {
-      // Ack that config has been reported
-      List<ComponentStatus> statuses = heartBeat.getComponentStatus();
-      if (statuses != null && !statuses.isEmpty()) {
-        ComponentStatus status = statuses.get(0);
-        if(status.getConfigs().size() > 0) {
-          log.info("Config got reported by {} but discarded as component {} 
cannot publish.", label, roleName);
-          componentStatus.setConfigReported(true);
-        }
-      }
-    }
+
+    publishConfigAndExportGroups(heartBeat, componentStatus, roleName);
 
     List<CommandReport> reports = heartBeat.getReports();
     if (reports != null && !reports.isEmpty()) {
@@ -513,6 +502,7 @@ public class AgentProviderService extends 
AbstractProviderService implements
           }
         }
       }
+
       // if there is no outstanding command then retrieve config
       if (isMaster && componentStatus.getState() == State.STARTED
           && command == Command.NOP) {
@@ -758,39 +748,60 @@ public class AgentProviderService extends 
AbstractProviderService implements
 
   /**
    * Process return status for component instances
+   *
    * @param heartBeat
    * @param componentStatus
    */
-  protected void publishConfigAndExportGroups(HeartBeat heartBeat, 
ComponentInstanceState componentStatus) {
+  protected void publishConfigAndExportGroups(
+      HeartBeat heartBeat, ComponentInstanceState componentStatus, String 
roleName) {
     List<ComponentStatus> statuses = heartBeat.getComponentStatus();
     if (statuses != null && !statuses.isEmpty()) {
       log.info("Processing {} status reports.", statuses.size());
-      Application application = getMetainfo().getApplication();
-      List<ExportGroup> exportGroups = application.getExportGroups();
-      boolean hasExportGroups = exportGroups != null && 
!exportGroups.isEmpty();
-      Set<String> exportedConfigs = new HashSet();
-      String exportedConfigsStr = application.getExportedConfigs();
-      boolean exportedAllConfigs = exportedConfigsStr == null || 
exportedConfigsStr.isEmpty();
-      if (application.getExportedConfigs() != null && 
application.getExportedConfigs().length() > 0) {
-        for (String exportedConfig : 
application.getExportedConfigs().split(",")) {
-          if (exportedConfig.trim().length() > 0) {
-            exportedConfigs.add(exportedConfig.trim());
-          }
-        }
-      }
-
       for (ComponentStatus status : statuses) {
         log.info("Status report: " + status.toString());
+
         if (status.getConfigs() != null) {
-          for (String key : status.getConfigs().keySet()) {
-            if ((!exportedAllConfigs && exportedConfigs.contains(key)) ||
-                exportedAllConfigs) {
-              Map<String, String> configs = status.getConfigs().get(key);
-              publishApplicationInstanceData(key, key, configs.entrySet());
+          Application application = getMetainfo().getApplication();
+
+          if (canAnyMasterPublishConfig() == false || 
canPublishConfig(roleName)) {
+            // If no Master can explicitly publish then publish if its a master
+            // Otherwise, wait till the master that can publish is ready
+
+            Set<String> exportedConfigs = new HashSet();
+            String exportedConfigsStr = application.getExportedConfigs();
+            boolean exportedAllConfigs = exportedConfigsStr == null || 
exportedConfigsStr.isEmpty();
+            if (!exportedAllConfigs) {
+              for (String exportedConfig : exportedConfigsStr.split(",")) {
+                if (exportedConfig.trim().length() > 0) {
+                  exportedConfigs.add(exportedConfig.trim());
+                }
+              }
+            }
+
+            for (String key : status.getConfigs().keySet()) {
+              if ((!exportedAllConfigs && exportedConfigs.contains(key)) ||
+                  exportedAllConfigs) {
+                Map<String, String> configs = status.getConfigs().get(key);
+                publishApplicationInstanceData(key, key, configs.entrySet());
+              }
             }
           }
 
-          if (hasExportGroups) {
+          List<ExportGroup> exportGroups = application.getExportGroups();
+          boolean hasExportGroups = exportGroups != null && 
!exportGroups.isEmpty();
+
+          Set<String> appExports = new HashSet();
+          String appExportsStr = 
getApplicationComponent(roleName).getAppExports();
+          boolean hasNoAppExports = appExportsStr == null || 
appExportsStr.isEmpty();
+          if (!hasNoAppExports) {
+            for (String appExport : appExportsStr.split(",")) {
+              if (appExport.trim().length() > 0) {
+                appExports.add(appExport.trim());
+              }
+            }
+          }
+
+          if (hasExportGroups && appExports.size() > 0) {
             String configKeyFormat = "${site.%s.%s}";
             String hostKeyFormat = "${%s_HOST}";
 
@@ -809,33 +820,63 @@ public class AgentProviderService extends 
AbstractProviderService implements
               }
             }
 
+            Set<String> modifiedGroups = new HashSet<String>();
             for (ExportGroup exportGroup : exportGroups) {
               List<Export> exports = exportGroup.getExports();
               if (exports != null && !exports.isEmpty()) {
                 String exportGroupName = exportGroup.getName();
-                Map<String, String> map = new HashMap<String, String>();
+                Map<String, String> map = getCurrentExports(exportGroupName);
                 for (Export export : exports) {
-                  String value = export.getValue();
-                  // replace host names
-                  for (String token : replaceTokens.keySet()) {
-                    if (value.contains(token)) {
-                      value = value.replace(token, replaceTokens.get(token));
+                  if (canBeExported(exportGroupName, export.getName(), 
appExports)) {
+                    String value = export.getValue();
+                    // replace host names
+                    for (String token : replaceTokens.keySet()) {
+                      if (value.contains(token)) {
+                        value = value.replace(token, replaceTokens.get(token));
+                      }
                     }
+                    map.put(export.getName(), value);
+                    log.info("Preparing to publish. Key {} and Value {}", 
export.getName(), value);
                   }
-                  map.put(export.getName(), value);
-                  log.info("Preparing to publish. Key {} and Value {}", 
export.getName(), value);
                 }
-                publishApplicationInstanceData(exportGroupName, 
exportGroupName, map.entrySet());
+                modifiedGroups.add(exportGroupName);
               }
             }
+            publishModifiedExportGroups(modifiedGroups);
           }
-          log.info("Received and stored config for {}", 
heartBeat.getHostname());
+
+          log.info("Received and processed config for {}", 
heartBeat.getHostname());
           componentStatus.setConfigReported(true);
+
         }
       }
     }
   }
 
+  private boolean canBeExported(String exportGroupName, String name, 
Set<String> appExports) {
+    return  appExports.contains(String.format("%s-%s", exportGroupName, name));
+  }
+
+  protected Map<String, String> getCurrentExports(String groupName) {
+    if(!this.exportGroups.containsKey(groupName)) {
+       synchronized (this.exportGroups) {
+         if(!this.exportGroups.containsKey(groupName)) {
+           this.exportGroups.put(groupName, new ConcurrentHashMap<String, 
String>());
+         }
+       }
+    }
+
+    return this.exportGroups.get(groupName);
+  }
+
+  private void publishModifiedExportGroups(Set<String> modifiedGroups) {
+    synchronized (this.exportGroups) {
+      for(String groupName : modifiedGroups) {
+        publishApplicationInstanceData(groupName, groupName, 
this.exportGroups.get(groupName).entrySet());
+      }
+    }
+  }
+
   /** Publish component instance specific data if the component demands it */
   protected void processAndPublishComponentSpecificData(Map<String, String> 
ports,
                                                         String containerId,
@@ -848,9 +889,9 @@ public class AgentProviderService extends 
AbstractProviderService implements
     Application application = getMetainfo().getApplication();
     for (Component component : application.getComponents()) {
       if (component.getName().equals(roleName)) {
-        if (component.getExports().size() > 0) {
+        if (component.getComponentExports().size() > 0) {
 
-          for (Export export : component.getExports()) {
+          for (ComponentExport export : component.getComponentExports()) {
             String templateToExport = export.getValue();
             for (String portName : ports.keySet()) {
               boolean publishData = false;
@@ -901,26 +942,37 @@ public class AgentProviderService extends 
AbstractProviderService implements
   }
 
   /**
-   * Extract script path from the application metainfo
-   *
+   * Return Component based on name
    * @param roleName
-   *
    * @return
    */
-  protected String getScriptPathFromMetainfo(String roleName) {
-    String scriptPath = null;
+  protected Component getApplicationComponent(String roleName) {
     Application application = getMetainfo().getApplication();
     if (application == null) {
       log.error("Malformed app definition: Expect application as the top level 
element for metainfo.xml");
-      return scriptPath;
-    }
-    for (Component component : application.getComponents()) {
-      if (component.getName().equals(roleName)) {
-        scriptPath = component.getCommandScript().getScript();
-        break;
+    } else {
+      for (Component component : application.getComponents()) {
+        if (component.getName().equals(roleName)) {
+          return component;
+        }
       }
     }
-    return scriptPath;
+    return null;
+  }
+
+  /**
+   * Extract script path from the application metainfo
+   *
+   * @param roleName
+   *
+   * @return
+   */
+  protected String getScriptPathFromMetainfo(String roleName) {
+    Component component = getApplicationComponent(roleName);
+    if (component != null) {
+      return component.getCommandScript().getScript();
+    }
+    return null;
   }
 
   /**
@@ -931,18 +983,10 @@ public class AgentProviderService extends 
AbstractProviderService implements
    * @return
    */
   protected boolean isMaster(String roleName) {
-    Application application = getMetainfo().getApplication();
-    if (application == null) {
-      log.error("Malformed app definition: Expect application as the top level 
element for metainfo.xml");
-    } else {
-      for (Component component : application.getComponents()) {
-        if (component.getName().equals(roleName)) {
-          if (component.getCategory().equals("MASTER")) {
-            return true;
-          } else {
-            return false;
-          }
-        }
+    Component component = getApplicationComponent(roleName);
+    if (component != null) {
+      if (component.getCategory().equals("MASTER")) {
+        return true;
       }
     }
     return false;
@@ -956,34 +1000,24 @@ public class AgentProviderService extends 
AbstractProviderService implements
    * @return
    */
   protected boolean canPublishConfig(String roleName) {
-    Application application = getMetainfo().getApplication();
-    if (application == null) {
-      log.error("Malformed app definition: Expect application as the top level 
element for metainfo.xml");
-    } else {
-      for (Component component : application.getComponents()) {
-        if (component.getName().equals(roleName)) {
-          return Boolean.TRUE.toString().equals(component.getPublishConfig());
-        }
-      }
+    Component component = getApplicationComponent(roleName);
+    if (component != null) {
+      return Boolean.TRUE.toString().equals(component.getPublishConfig());
     }
     return false;
   }
 
   /**
    * Checks if the role is marked auto-restart
+   *
    * @param roleName
+   *
    * @return
    */
   protected boolean isMarkedAutoRestart(String roleName) {
-    Application application = getMetainfo().getApplication();
-    if (application == null) {
-      log.error("Malformed app definition: Expect application as the top level 
element for metainfo.xml");
-    } else {
-      for (Component component : application.getComponents()) {
-        if (component.getName().equals(roleName)) {
-          return component.getRequiresAutoRestart();
-        }
-      }
+    Component component = getApplicationComponent(roleName);
+    if (component != null) {
+      return component.getRequiresAutoRestart();
     }
     return false;
   }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/2a25ab91/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java
 
b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java
index 4b91ff7..bc93d6f 100644
--- 
a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java
+++ 
b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java
@@ -61,10 +61,10 @@ public class MetainfoParser {
     digester.addBeanPropertySetter("*/component/maxInstanceCount");
     digester.addBeanPropertySetter("*/component/autoStartOnFailure");
     digester.addBeanPropertySetter("*/component/appExports");
-    digester.addObjectCreate("*/component/componentExport", 
ComponentExport.class);
-    digester.addBeanPropertySetter("*/component/componentExport/name");
-    digester.addBeanPropertySetter("*/component/componentExport/value");
-    digester.addSetNext("*/component/componentExport", "addComponentExport");
+    digester.addObjectCreate("*/componentExport", ComponentExport.class);
+    digester.addBeanPropertySetter("*/componentExport/name");
+    digester.addBeanPropertySetter("*/componentExport/value");
+    digester.addSetNext("*/componentExport", "addComponentExport");
     digester.addSetNext("*/component", "addComponent");
 
     digester.addObjectCreate("*/commandScript", CommandScript.class);

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/2a25ab91/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
 
b/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
index 1ea11a6..6ed950f 100644
--- 
a/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
+++ 
b/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
@@ -136,8 +136,18 @@ public class TestAgentProviderService {
                                                + "      </commandOrders>\n"
                                                + "      <components>\n"
                                                + "        <component>\n"
+                                               + "          
<name>HBASE_REST</name>\n"
+                                               + "          
<category>MASTER</category>\n"
+                                               + "          <commandScript>\n"
+                                               + "            
<script>scripts/hbase_rest.py</script>\n"
+                                               + "            
<scriptType>PYTHON</scriptType>\n"
+                                               + "            
<timeout>600</timeout>\n"
+                                               + "          </commandScript>\n"
+                                               + "        </component>\n"
+                                               + "        <component>\n"
                                                + "          
<name>HBASE_MASTER</name>\n"
                                                + "          
<category>MASTER</category>\n"
+                                               + "          
<publishConfig>true</publishConfig>\n"
                                                + "          
<autoStartOnFailure>true</autoStartOnFailure>\n"
                                                + "          
<appExports>QuickLinks-JMX_Endpoint,QuickLinks-Master_Status</appExports>\n"
                                                + "          
<minInstanceCount>1</minInstanceCount>\n"
@@ -166,7 +176,7 @@ public class TestAgentProviderService {
                                                + "              
<name>PropertyB</name>\n"
                                                + "              
<value>AConstant</value>\n"
                                                + "            
</componentExport>\n"
-                                               + "          
</componentExport>\n"
+                                               + "          
</componentExports>\n"
                                                + "        </component>\n"
                                                + "      </components>\n"
                                                + "      <osSpecifics>\n"
@@ -458,15 +468,15 @@ public class TestAgentProviderService {
     doReturn(metainfo).when(mockAps).getMetainfo();
     doReturn(roleClusterNodeMap).when(mockAps).getRoleClusterNodeMapping();
 
-    mockAps.publishConfigAndExportGroups(hb, componentStatus);
-    assert componentStatus.getConfigReported() == true;
+    mockAps.publishConfigAndExportGroups(hb, componentStatus, "HBASE_MASTER");
+    Assert.assertTrue(componentStatus.getConfigReported());
     ArgumentCaptor<Collection> entriesCaptor = ArgumentCaptor.
         forClass(Collection.class);
     Mockito.verify(mockAps, Mockito.times(3)).publishApplicationInstanceData(
         anyString(),
         anyString(),
         entriesCaptor.capture());
-    assert entriesCaptor.getAllValues().size() == 3;
+    Assert.assertEquals(3, entriesCaptor.getAllValues().size());
     for (Collection coll : entriesCaptor.getAllValues()) {
       Set<Map.Entry<String, String>> entrySet = (Set<Map.Entry<String, 
String>>) coll;
       for (Map.Entry entry : entrySet) {
@@ -476,6 +486,16 @@ public class TestAgentProviderService {
         }
       }
     }
+
+    Map<String, String> exports = mockAps.getCurrentExports("QuickLinks");
+    Assert.assertEquals(2, exports.size());
+    Assert.assertEquals(exports.get("JMX_Endpoint"), "http://HOST1:60012/jmx";);
+
+    mockAps.publishConfigAndExportGroups(hb, componentStatus, "HBASE_REST");
+    Mockito.verify(mockAps, Mockito.times(3)).publishApplicationInstanceData(
+        anyString(),
+        anyString(),
+        entriesCaptor.capture());
   }
 
   @Test
@@ -487,7 +507,7 @@ public class TestAgentProviderService {
     log.info("Service: " + application.toString());
     Assert.assertEquals(application.getName(), "HBASE");
     Assert.assertEquals(application.getExportedConfigs(), "hbase-site,global");
-    Assert.assertEquals(application.getComponents().size(), 2);
+    Assert.assertEquals(application.getComponents().size(), 3);
     List<Component> components = application.getComponents();
     int found = 0;
     for (Component component : components) {
@@ -596,9 +616,9 @@ public class TestAgentProviderService {
 
     Assert.assertTrue(mockAps.isMaster(role_hm));
     Assert.assertFalse(mockAps.isMaster(role_hrs));
-    Assert.assertFalse(mockAps.canPublishConfig(role_hm));
+    Assert.assertTrue(mockAps.canPublishConfig(role_hm));
     Assert.assertFalse(mockAps.canPublishConfig(role_hrs));
-    Assert.assertFalse(mockAps.canAnyMasterPublishConfig());
+    Assert.assertTrue(mockAps.canAnyMasterPublishConfig());
 
     Assert.assertTrue(mockAps2.isMaster(role_hm));
     Assert.assertFalse(mockAps2.isMaster(role_hrs));

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/2a25ab91/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/MetainfoParserTest.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/MetainfoParserTest.java
 
b/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/MetainfoParserTest.java
deleted file mode 100644
index 61c53df..0000000
--- 
a/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/MetainfoParserTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.slider.providers.agent.application.metadata;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- *
- */
-public class MetainfoParserTest {
-  protected static final Logger log =
-      LoggerFactory.getLogger(MetainfoParserTest.class);
-  public static final String METAINFO_XML =
-      "/org/apache/slider/providers/agent/application/metadata/metainfo.xml";
-
-  @Test
-  public void testParse() throws IOException {
-
-    InputStream resStream = this.getClass().getResourceAsStream(
-        METAINFO_XML);
-    MetainfoParser parser = new MetainfoParser();
-    Metainfo metainfo = parser.parse(resStream);
-    Assert.assertNotNull(metainfo);
-    Assert.assertNotNull(metainfo.getApplication());
-    Application application = metainfo.getApplication();
-    assert "STORM".equals(application.getName());
-    assert 5 == application.getComponents().size();
-    OSPackage pkg = application.getOSSpecifics().get(0).getPackages().get(0);
-    assert "tarball".equals(pkg.getType());
-    assert "files/apache-storm-0.9.1.2.1.1.0-237.tar.gz".equals(pkg.getName());
-    boolean found = false;
-    for (Component comp : application.getComponents()) {
-      if (comp != null && comp.getName().equals("NIMBUS")) {
-        found = true;
-      }
-    }
-    assert found;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/2a25ab91/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/TestMetainfoParser.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/TestMetainfoParser.java
 
b/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/TestMetainfoParser.java
new file mode 100644
index 0000000..98f0afb
--- /dev/null
+++ 
b/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/TestMetainfoParser.java
@@ -0,0 +1,63 @@
+/*
+ * 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.slider.providers.agent.application.metadata;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ *
+ */
+public class TestMetainfoParser {
+  protected static final Logger log =
+      LoggerFactory.getLogger(TestMetainfoParser.class);
+  public static final String METAINFO_XML =
+      "/org/apache/slider/providers/agent/application/metadata/metainfo.xml";
+
+  @Test
+  public void testParse() throws IOException {
+
+    InputStream resStream = this.getClass().getResourceAsStream(
+        METAINFO_XML);
+    MetainfoParser parser = new MetainfoParser();
+    Metainfo metainfo = parser.parse(resStream);
+    Assert.assertNotNull(metainfo);
+    Assert.assertNotNull(metainfo.getApplication());
+    Application application = metainfo.getApplication();
+    assert "STORM".equals(application.getName());
+    assert 5 == application.getComponents().size();
+    OSPackage pkg = application.getOSSpecifics().get(0).getPackages().get(0);
+    assert "tarball".equals(pkg.getType());
+    assert "files/apache-storm-0.9.1.2.1.1.0-237.tar.gz".equals(pkg.getName());
+    boolean found = false;
+    for (Component comp : application.getComponents()) {
+      if (comp != null && comp.getName().equals("NIMBUS")) {
+        found = true;
+        Assert.assertEquals(0, comp.getComponentExports().size());
+      }
+      if (comp != null && comp.getName().equals("SUPERVISOR")) {
+        Assert.assertEquals(1, comp.getComponentExports().size());
+      }
+    }
+    assert found;
+  }
+}

Reply via email to