Package org.apache.ace.agent.itest

Source Code of org.apache.ace.agent.itest.AgentUpdateTest

/*
* 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.ace.agent.itest;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.ace.agent.AgentConstants;
import org.apache.ace.agent.AgentControl;
import org.apache.ace.it.IntegrationTestBase;
import org.apache.ace.test.constants.TestConstants;
import org.apache.ace.test.utils.NetUtils;
import org.apache.felix.dm.Component;
import org.osgi.framework.Bundle;
import org.osgi.framework.Version;
import org.osgi.service.http.HttpService;

/**
* Tests updating the management agent. In fact it tests different failure paths first, and finally gets to update the
* agent. The tests it does are:
* <ul>
* <li>Try to update to a corrupt bundle (with some random garbage injected in the JAR file).</li>
* <li>Try to update to a bundle that does not resolve because of some impossible import package statement.</li>
* <li>Try to update to a bundle that does resolve, but does not start because of a non-existing bundle activator.</li>
* <li>Update to a new version of the agent (actually, it's the same bundle, but with a different version.</li>
* </ul>
*/
public class AgentUpdateTest extends IntegrationTestBase {
    private static class DummyAuditLogServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;

        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String pathInfo = req.getPathInfo();
            if ("/send".equals(pathInfo)) {
                resp.setStatus(HttpServletResponse.SC_OK);
            }
            else {
                resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
            }
        }
    }

    private static class DeploymentServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;

        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setStatus(HttpServletResponse.SC_OK);
        }
    }

    private static class AgentUpdateOBRServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
       
        private final String m_currentVersion;
        private final String m_nextVersion;

        private Phase m_phase;
        private CountDownLatch m_latch;
       
        public AgentUpdateOBRServlet(Version currentVersion) {
          m_currentVersion = currentVersion.toString();
          // Determine the next version we want to update to...
          m_nextVersion = new Version(currentVersion.getMajor(), currentVersion.getMinor(), currentVersion.getMicro() + 1).toString();
    }

        public synchronized CountDownLatch setPhase(Phase phase, CountDownLatch latch) {
            m_phase = phase;
            m_latch = latch;
            System.out.printf("Updating in phase: %s (from v%s to v%s)...%n", phase, m_currentVersion, m_nextVersion);
            return latch;
        }
       
        public Version getNextAgentVersion() {
          return new Version(m_nextVersion);
        }

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String path = req.getPathInfo();
            if ("/repository.xml".equals(path)) {
                PrintWriter w = resp.getWriter();
                w.println("<?xml version='1.0' encoding='utf-8'?><repository>");
                w.println(createResource("org.apache.ace.agent", m_currentVersion));
                w.println(createResource("org.apache.ace.agent", m_nextVersion));
                w.println("</repository>");
            }
            else {
              String currentAgentJAR = m_currentVersion + ".jar";
              String nextAgentJAR = m_nextVersion + ".jar";

                if (path.endsWith(currentAgentJAR)) {
                    write(getBundle(), m_currentVersion, resp.getOutputStream());
                }
                else if (path.endsWith(nextAgentJAR)) {
                    write(getBundle(), m_nextVersion, resp.getOutputStream());
                }
                else {
                    throw new Error("Statement should never be reached.");
                }
            }
        }

        protected void doHead(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            response.setContentType("text/plain");
            response.flushBuffer();
        }

        private InputStream getBundle() throws IOException {
            return new FileInputStream(new File("../org.apache.ace.agent/generated/org.apache.ace.agent.jar"));
        }

        private synchronized void write(InputStream object, String version, OutputStream outputStream) throws IOException {
            JarInputStream jis = new JarInputStream(object);
            Manifest manifest = jis.getManifest();
            manifest.getMainAttributes().put(new Attributes.Name("Bundle-Version"), version);
            if (m_phase == Phase.BUNDLE_DOES_NOT_START && m_nextVersion.equals(version)) {
                manifest.getMainAttributes().put(new Attributes.Name("Bundle-Activator"), "org.foo.NonExistingClass");
            }
            if (m_phase == Phase.BUNDLE_DOES_NOT_RESOLVE && m_nextVersion.equals(version)) {
                manifest.getMainAttributes().put(new Attributes.Name("Import-Package"), "org.foo.nonexistingpackage");
            }
            JarOutputStream jos = new JarOutputStream(outputStream, manifest);
            JarEntry entry;
            int length;
            byte[] buffer = new byte[4096];
            while ((entry = jis.getNextJarEntry()) != null) {
                jos.putNextEntry(entry);
                while ((length = jis.read(buffer)) != -1) {
                    jos.write(buffer, 0, length);
                    if (m_phase == Phase.CORRUPT_STREAM && m_nextVersion.equals(version)) {
                        jos.write("garbage".getBytes());
                    }
                }
                jos.closeEntry();
                jis.closeEntry();
            }
            jis.close();
            jos.close();
            if (m_phase == Phase.BUNDLE_WORKS && m_nextVersion.equals(version)) {
                m_latch.countDown();
            }
            if (m_phase != Phase.BUNDLE_WORKS && m_currentVersion.equals(version)) {
                m_latch.countDown();
            }
        }
    }

    private enum Phase {
        CORRUPT_STREAM, BUNDLE_DOES_NOT_RESOLVE, BUNDLE_DOES_NOT_START, BUNDLE_WORKS
    }

    private static String createResource(String bsn, String version) {
        return "<resource id='" + bsn + "/" + version + "' symbolicname='" + bsn + "' version='" + version + "' uri='" + bsn + "-" + version + ".jar'></resource>";
    }

    private volatile HttpService m_http;
    private volatile AgentUpdateOBRServlet m_servlet;

    public void testAgentUpdate() throws Exception {
        final int defaultTimeout = 150;

        CountDownLatch latch;

        latch = m_servlet.setPhase(Phase.CORRUPT_STREAM, new CountDownLatch(1));
        assertTrue("Timed out while recovering from update with broken stream.", latch.await(defaultTimeout, TimeUnit.SECONDS));

        latch = m_servlet.setPhase(Phase.BUNDLE_DOES_NOT_RESOLVE, new CountDownLatch(1));
        assertTrue("Timed out while recovering from update with agent that does not resolve.", latch.await(defaultTimeout, TimeUnit.SECONDS));

        latch = m_servlet.setPhase(Phase.BUNDLE_DOES_NOT_START, new CountDownLatch(1));
        assertTrue("Timed out while recovering from update with agent that does not start.", latch.await(defaultTimeout, TimeUnit.SECONDS));

        latch = m_servlet.setPhase(Phase.BUNDLE_WORKS, new CountDownLatch(1));
        assertTrue("Timed out while starting working bundle?!", latch.await(defaultTimeout, TimeUnit.SECONDS));

        int timeout = defaultTimeout;
        while (timeout-- > 0) {
            Version agentVersion = getCurrentAgentVersion();
            if (agentVersion.equals(m_servlet.getNextAgentVersion())) {
              return;
            }

            Thread.sleep(200);
        }
        fail("Timed out waiting for update with new agent.");
    }

    @Override
    protected void configureProvisionedServices() throws Exception {
        String serverURL = String.format("http://localhost:%d/", TestConstants.PORT);
        String obrURL = serverURL.concat("obr/");
        configure("org.apache.ace.deployment.servlet.agent",
            "org.apache.ace.server.servlet.endpoint", "/agent",
            "obr.url", obrURL,
            "authentication.enabled", "false");

        Map<String, String> props = new HashMap<String, String>();
        props.put(AgentConstants.CONFIG_DISCOVERY_SERVERURLS, serverURL);

        AgentControl agentControl = getService(AgentControl.class);
        agentControl.getConfigurationHandler().putAll(props);
    }

    @Override
    protected void configureAdditionalServices() throws Exception {
      // We need to know the *current* version of the agent, as we're trying to get it updated to a later version!
      Version currentAgentVersion = getCurrentAgentVersion();
     
        m_servlet = new AgentUpdateOBRServlet(currentAgentVersion);

        String url = String.format("http://localhost:%d/obr", TestConstants.PORT);
        NetUtils.waitForURL(url, 404, 10000);

        m_http.registerServlet("/obr", m_servlet, null, null);
        m_http.registerServlet("/auditlog", new DummyAuditLogServlet(), null, null);
        m_http.registerServlet("/deployment", new DeploymentServlet(), null, null);

        NetUtils.waitForURL(url, 200, 10000);
    }

    @Override
    protected void doTearDown() throws Exception {
        m_http.unregister("/obr");
        m_http.unregister("/auditlog");
    }

    @Override
    protected Component[] getDependencies() {
        return new Component[] {
            createComponent()
                .setImplementation(this)
                .add(createServiceDependency().setService(HttpService.class).setRequired(true))
        };
    }
   
    private Version getCurrentAgentVersion() {
      Bundle agent = null;
      for (Bundle bundle : m_bundleContext.getBundles()) {
        if ("org.apache.ace.agent".equals(bundle.getSymbolicName())) {
          agent = bundle;
          break;
        }
      }
      assertNotNull("Agent bundle not found?!", agent);
      return agent.getVersion();
    }
}
TOP

Related Classes of org.apache.ace.agent.itest.AgentUpdateTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.