2ee3b2689559c1560ec2c6addc5e92e5eaf1d656
[odlparent.git] / bundles-test / src / main / java / org / opendaylight / odlparent / bundlestest / TestBundleDiag.java
1 /*
2  * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.odlparent.bundlestest;
9
10 import static java.util.concurrent.TimeUnit.MILLISECONDS;
11 import static java.util.concurrent.TimeUnit.SECONDS;
12 import static org.junit.Assert.fail;
13
14 import java.util.concurrent.TimeUnit;
15 import org.apache.karaf.bundle.core.BundleService;
16 import org.awaitility.Awaitility;
17 import org.awaitility.core.ConditionTimeoutException;
18 import org.osgi.framework.Bundle;
19 import org.osgi.framework.BundleContext;
20 import org.osgi.framework.InvalidSyntaxException;
21 import org.osgi.framework.ServiceReference;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 /**
26  * Utility to verify bundle diagnostic state from OSGi integration tests.
27  *
28  * @author Michael Vorburger.ch
29  */
30 public class TestBundleDiag {
31
32     private static final Logger LOG = LoggerFactory.getLogger(TestBundleDiag.class);
33
34     private final BundleContext bundleContext;
35     private final BundleService bundleService;
36
37     public TestBundleDiag(BundleContext bundleContext, BundleService bundleService) {
38         this.bundleContext = bundleContext;
39         this.bundleService = bundleService;
40     }
41
42     /**
43      * Does the equivalent of the "diag" CLI command, and fails the test if anything incl. bundle wiring is NOK.
44      *
45      * <p>The implementation is based on Karaf's BundleService, and not the BundleStateService,
46      * because each Karaf supported DI system (such as Blueprint and Declarative Services, see String constants
47      * in BundleStateService), will have a separate BundleStateService.  The BundleService however will
48      * contain the combined status of all BundleStateServices.
49      *
50      * @author Michael Vorburger, based on guidance from Christian Schneider
51      */
52     public void checkBundleDiagInfos(long timeout, TimeUnit timeoutUnit) {
53         try {
54             Awaitility.await("checkBundleDiagInfos")
55                 .pollDelay(0, MILLISECONDS)
56                 .pollInterval(1, SECONDS)
57                 .atMost(timeout, timeoutUnit)
58                     .conditionEvaluationListener(
59                         condition -> LOG.info("checkBundleDiagInfos: Elapsed time {}s, remaining time {}s, {}",
60                             condition.getElapsedTimeInMS() / 1000, condition.getRemainingTimeInMS() / 1000,
61                             ((BundleDiagInfos) condition.getValue()).getFullDiagnosticText()))
62                     .until(() -> getBundleDiagInfos(), new BundleServiceSummaryMatcher());
63
64             // If we're here then either BundleServiceSummaryMatcher quit because of Active, Failure or Stopping..
65             BundleDiagInfos bundleInfos = getBundleDiagInfos();
66             SystemState systemState = bundleInfos.getSystemState();
67             if (systemState.equals(SystemState.Failure) || systemState.equals(SystemState.Stopping)) {
68                 LOG.error("diag failure; BundleService reports bundle(s) which failed or are already stopping"
69                         + " (details in following INFO and ERROR log messages...)");
70                 logBundleDiagInfos(bundleInfos);
71                 fail(bundleInfos.getFullDiagnosticText());
72
73             } else {
74                 // Inform the developer of the green SystemState.Active
75                 LOG.info(bundleInfos.getFullDiagnosticText());
76             }
77
78         } catch (ConditionTimeoutException e) {
79             // If this happens then it got stuck waiting in SystemState.Booting,
80             // typically due to bundles still in BundleState GracePeriod or Waiting
81             LOG.error("diag failure; BundleService reports bundle(s) which are still not active"
82                     + " (details in following INFO and ERROR log messages...)");
83             BundleDiagInfos bundleInfos = getBundleDiagInfos();
84             logBundleDiagInfos(bundleInfos);
85             throw e; // fail the test!
86         }
87     }
88
89     private void logBundleDiagInfos(BundleDiagInfos bundleInfos) {
90         try {
91             logOSGiServices();
92         } catch (IllegalStateException e) {
93             LOG.warn("logOSGiServices() failed (never mind); too late during shutdown already?", e);
94         }
95         for (String okBundleStateInfo : bundleInfos.getOkBundleStateInfoTexts()) {
96             LOG.info(okBundleStateInfo);
97         }
98         for (String whitelistedBundleStateInfo : bundleInfos.getWhitelistedBundleStateInfoTexts()) {
99             LOG.warn(whitelistedBundleStateInfo);
100         }
101         for (String nokBundleStateInfo : bundleInfos.getNokBundleStateInfoTexts()) {
102             LOG.error(nokBundleStateInfo);
103         }
104     }
105
106     private BundleDiagInfos getBundleDiagInfos() {
107         return BundleDiagInfos.forContext(bundleContext, bundleService);
108     }
109
110     private void logOSGiServices() {
111         ServiceReferenceUtil util = new ServiceReferenceUtil();
112         LOG.info("Now going to log all known services, to help diagnose root cause of "
113                 + "diag failure BundleService reported bundle(s) which are not active");
114         try {
115             for (ServiceReference<?> serviceRef : bundleContext.getAllServiceReferences(null, null)) {
116                 Bundle bundle = serviceRef.getBundle();
117                 // serviceRef.getBundle() can return null if the bundle was destroyed
118                 if (bundle != null) {
119                     LOG.info("{} defines OSGi Service {} used by {}", bundle.getSymbolicName(),
120                             util.getProperties(serviceRef), util.getUsingBundleSymbolicNames(serviceRef));
121                 } else {
122                     LOG.trace("skipping reporting service reference as the underlying bundle is null");
123                 }
124             }
125         } catch (InvalidSyntaxException e) {
126             LOG.error("logOSGiServices() failed due to InvalidSyntaxException", e);
127         }
128     }
129
130 }