Statistics collection added 06/12606/2
authorMarian Adamjak <marian.adamjak@pantheon.sk>
Fri, 7 Nov 2014 13:17:10 +0000 (14:17 +0100)
committerMichal Polkorab <michal.polkorab@pantheon.sk>
Mon, 10 Nov 2014 15:03:42 +0000 (16:03 +0100)
 - added statistics counters and tests
 - collection configurable through configSubsystem

Change-Id: I0b292174789fbb39ff7abd25fec9b53b35ff7927
Signed-off-by: Marian Adamjak <marian.adamjak@pantheon.sk>
Signed-off-by: Michal Polkorab <michal.polkorab@pantheon.sk>
18 files changed:
openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/ConnectionConfiguration.java
openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/StatisticsConfiguration.java [new file with mode: 0644]
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoder.java
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFEncoder.java
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/connection/ChannelOutboundQueue.java
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/connection/ConnectionAdapterImpl.java
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/statistics/Counter.java
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/statistics/CounterEventTypes.java
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/statistics/StatisticsCounters.java
openflow-protocol-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/_switch/connection/provider/impl/rev140328/SwitchConnectionProviderModule.java
openflow-protocol-impl/src/main/yang/openflow-switch-connection-provider-impl.yang
openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoderStatisticsTest.java
openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoderTest.java
openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFEncoderStatisticsTest.java
openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/connection/ChannelOutboundQueueTest.java
openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/connection/ConnectionAdapterImplStatisticsTest.java
openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/connection/ConnectionConfigurationImpl.java
openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/statistics/StatisticsCountersTest.java

index 6a61b5857afa2b402c5d34233f5e8186d7e28d92..0ba121cca99e9263aedc42c180d01c7aa0415baa 100644 (file)
@@ -11,7 +11,6 @@ package org.opendaylight.openflowjava.protocol.api.connection;
 import java.net.InetAddress;
 
 import javax.net.ssl.SSLEngine;
-
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SwitchIdleEvent;
 
 /**
@@ -54,4 +53,8 @@ public interface ConnectionConfiguration {
      * @return thread numbers for TcpHandler's eventloopGroups
      */
     ThreadConfiguration getThreadConfiguration();
+    /**
+     * @return Statistics configuration
+     */
+    StatisticsConfiguration getStatisticsConfiguration();
 }
\ No newline at end of file
diff --git a/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/StatisticsConfiguration.java b/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/StatisticsConfiguration.java
new file mode 100644 (file)
index 0000000..68cfa43
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.openflowjava.protocol.api.connection;
+
+/**
+ * @author madamjak
+ *
+ */
+public interface StatisticsConfiguration {
+    Boolean getStatisticsCollect();
+    Integer getLogReportDelay();
+}
index 0ccd295536c260c4617fdc99a808506da20b226d..386caa3442c85b7469f913644146c00db9a9390b 100644 (file)
@@ -41,6 +41,7 @@ public class OFDecoder extends MessageToMessageDecoder<VersionMessageWrapper> {
     @Override
     protected void decode(ChannelHandlerContext ctx, VersionMessageWrapper msg,
             List<Object> out) throws Exception {
+        statisticsCounter.incrementCounter(CounterEventTypes.US_RECEIVED_IN_OFJAVA);
         if (LOGGER.isDebugEnabled()) {
             LOGGER.debug("VersionMessageWrapper received");
             LOGGER.debug("<< " + ByteBufUtils.byteBufToHexString(msg.getMessageBuffer()));
index 6caf1bdf395b39499dedfc9395d1cefe8143df78..5a739497c3703a7dbfb2416520f351a57323a1bb 100644 (file)
@@ -17,6 +17,7 @@ import org.opendaylight.openflowjava.protocol.impl.core.connection.MessageListen
 import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory;
 import org.opendaylight.openflowjava.statistics.CounterEventTypes;
 import org.opendaylight.openflowjava.statistics.StatisticsCounters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowModInput;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,6 +44,9 @@ public class OFEncoder extends MessageToByteEncoder<MessageListenerWrapper> {
         LOGGER.trace("Encoding");
         try {
             serializationFactory.messageToBuffer(wrapper.getMsg().getVersion(), out, wrapper.getMsg());
+            if(wrapper.getMsg() instanceof FlowModInput){
+                statisticsCounters.incrementCounter(CounterEventTypes.DS_FLOW_MODS_SENT);
+            }
             statisticsCounters.incrementCounter(CounterEventTypes.DS_ENCODE_SUCCESS);
         } catch(Exception e) {
             LOGGER.warn("Message serialization failed ", e);
index 47d694d32f075e4e4033e8b06bfbb7d66815bf88..7a43db626923b06a0057d068ff64d2dbe065925f 100644 (file)
@@ -129,7 +129,7 @@ final class ChannelOutboundQueue extends ChannelInboundHandlerAdapter {
             return true;
         }
 
-        LOG.trace("Message queue is full");
+        LOG.debug("Message queue is full");
         return false;
     }
 
@@ -165,6 +165,7 @@ final class ChannelOutboundQueue extends ChannelInboundHandlerAdapter {
      * uncontended.
      */
     private synchronized void flush() {
+
         final long start = System.nanoTime();
         final long deadline = start + maxWorkTime;
 
index e35c6064a9536defefd2507e247121e571943701..7f1c09713517f8d453e2765a50349cc92966ca1c 100644 (file)
@@ -162,6 +162,7 @@ public class ConnectionAdapterImpl implements ConnectionFacade {
 
     @Override
     public Future<RpcResult<Void>> flowMod(final FlowModInput input) {
+        statisticsCounters.incrementCounter(CounterEventTypes.DS_FLOW_MODS_ENTERED);
         return sendToSwitchFuture(input, "flow-mod sending failed");
     }
 
index 7c539eff86928165cd8acd87def9da7bac2ebdb1..9d7ddc77e50fe194948f2126e81c5c12d31b84ce 100644 (file)
@@ -9,7 +9,6 @@
 package org.opendaylight.openflowjava.statistics;\r
 \r
 import java.util.concurrent.atomic.AtomicLong;\r
-\r
 /**\r
  * Counts statistics\r
  * \r
@@ -36,6 +35,8 @@ public class Counter {
     }\r
 \r
     /**\r
+     * return the last read value of counter. This value can be set during the reading of current counter value, \r
+     *      for detail see method getCounterValue(boolean modifyLastReadValue).\r
      * @return the counterLastReadValue\r
      */\r
     public long getCounterLastReadValue() {\r
@@ -43,8 +44,8 @@ public class Counter {
     }\r
 \r
     /**\r
-     * get current counter value and rewrite CounterLastReadValue by current value\r
-     * @return\r
+     * get current value of counter and rewrite CounterLastReadValue by current value\r
+     * @return  the current value of counter\r
      */\r
     public long getCounterValue() {\r
         return getCounterValue(true);\r
@@ -55,7 +56,7 @@ public class Counter {
      * @param modifyLastReadValue\r
      *      true - CounterLastReadValue will be rewritten by current CounterValue\r
      *      false - no change CounterLastReadValue\r
-     * @return\r
+     * @return the current value of counter\r
      */\r
     public long getCounterValue(boolean modifyLastReadValue) {\r
         if(modifyLastReadValue){\r
@@ -74,6 +75,8 @@ public class Counter {
 \r
     @Override\r
     public String toString() {\r
-        return "Current value: " + counterValue + " Previous read value: " + counterLastReadValue;\r
+        long cntPrevVal = getCounterLastReadValue();\r
+        long cntCurValue = getCounterValue();\r
+        return String.format("+%d | %d",cntCurValue-cntPrevVal,cntCurValue);\r
     }\r
 }
\ No newline at end of file
index be39a7bb049e4c7743d863f9d07c5957492991ff..0dd7faad41adb44eeb361d66ef68478b91918c71 100644 (file)
@@ -9,15 +9,45 @@
 package org.opendaylight.openflowjava.statistics;\r
 \r
 /**\r
+ * Enumeration of events to be counted with StatisticsCounters\r
  * @author madamjak\r
  *\r
  */\r
 public enum CounterEventTypes {\r
+    /**\r
+     * enter message to OFJ and pass to downstream\r
+     */\r
     DS_ENTERED_OFJAVA,\r
+    /**\r
+     * flow-mod is entered\r
+     */\r
+    DS_FLOW_MODS_ENTERED,\r
+    /**\r
+     * encode message successfully\r
+     */\r
     DS_ENCODE_SUCCESS,\r
+    /**\r
+     * fail encode message\r
+     */\r
     DS_ENCODE_FAIL,\r
+    /**\r
+     * flow-mod encoded and sent to downstream\r
+     */\r
+    DS_FLOW_MODS_SENT,\r
+    /**\r
+     * receive message and pass to upstream\r
+     */\r
     US_RECEIVED_IN_OFJAVA,\r
+    /**\r
+     * decode message successfully\r
+     */\r
     US_DECODE_SUCCESS,\r
+    /**\r
+     * fail decode message\r
+     */\r
     US_DECODE_FAIL,\r
+    /**\r
+     * pass message to consumer (end of upstream)\r
+     */\r
     US_MESSAGE_PASS;\r
 }
\ No newline at end of file
index 5b666e997ad7fbd22cf938c135efb07a4d45f4cb..34f072b0839abbc6664625957d5b689d51854b6b 100644 (file)
 package org.opendaylight.openflowjava.statistics;
 
 import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
+ * Singleton class to hold and process counters
  * @author madamjak
  *
  */
 public final class StatisticsCounters {
 
+    /**
+     * Default delay between two writings into log (milliseconds)
+     */
+    public static final int DEFAULT_LOG_REPORT_PERIOD = 10000;
+    /**
+     * Minimal delay between two writings into log (milliseconds)
+     */
+    public static final int MINIMAL_LOG_REPORT_PERIOD = 500;
     private static StatisticsCounters instanceHolder;
     private static final Logger LOGGER = LoggerFactory.getLogger(StatisticsCounters.class);
 
-    private final Counter cntDSEncodeFail;
-    private final Counter cntDSEncodeSuccess;
-    private final Counter cntDSEnteredOFJava;
-    private final Counter cntUSDecodeFail;
-    private final Counter cntUSDecodeSuccess;
-    private final Counter cntUSMessagePass;
-    private final Counter cntUSReceivedOFJava;
-    //private Map<CounterEventTypes,Counter> countersMap;
-
-    public static StatisticsCounters  getInstance(){
-        if (instanceHolder == null){
+    private Timer logReporter;
+    private int logReportPeriod;
+    private boolean runLogReport;
+    private Map<CounterEventTypes, Counter> countersMap;
+    private boolean runCounting;
+    // array to hold enabled counter types
+    private CounterEventTypes[] enabledCounters = {
+                    CounterEventTypes.DS_ENCODE_FAIL, 
+                    CounterEventTypes.DS_ENCODE_SUCCESS,
+                    CounterEventTypes.DS_ENTERED_OFJAVA,
+                    CounterEventTypes.DS_FLOW_MODS_ENTERED,
+                    CounterEventTypes.DS_FLOW_MODS_SENT,
+                    CounterEventTypes.US_DECODE_FAIL, 
+                    CounterEventTypes.US_DECODE_SUCCESS, 
+                    CounterEventTypes.US_MESSAGE_PASS, 
+                    CounterEventTypes.US_RECEIVED_IN_OFJAVA};
+
+    /**
+     * Get instance of statistics counters, first created object does not start counting and log reporting
+     * @return an instance
+     */
+    public synchronized static StatisticsCounters getInstance() {
+        if (instanceHolder == null) {
             instanceHolder = new StatisticsCounters();
         }
         return instanceHolder;
     }
 
     private StatisticsCounters() {
-        cntDSEncodeFail = new Counter();
-        cntDSEncodeSuccess = new Counter();
-        cntDSEnteredOFJava = new Counter();
-        cntUSDecodeFail = new Counter();
-        cntUSDecodeSuccess = new Counter();
-        cntUSMessagePass = new Counter();
-        cntUSReceivedOFJava = new Counter();
-        LOGGER.debug("StaticsCounters (without Map) has been created");
-//        countersMap = new ConcurrentHashMap<>();
-//        countersMap.put(CounterEventTypes.DS_ENCODE_FAIL, new Counter());
-//        countersMap.put(CounterEventTypes.DS_ENCODE_SUCCESS, new Counter());
-//        countersMap.put(CounterEventTypes.DS_ENTERED_OFJAVA, new Counter());
-//        countersMap.put(CounterEventTypes.US_DECODE_FAIL, new Counter());
-//        countersMap.put(CounterEventTypes.US_DECODE_SUCCESS, new Counter());
-//        countersMap.put(CounterEventTypes.US_MESSAGE_PASS, new Counter());
-//        countersMap.put(CounterEventTypes.US_RECEIVED_IN_OFJAVA, new Counter());
-//        LOGGER.debug("StaticsCounters (with Map) has been created");
-    }
-
-    /**
-     * Get given counter
-     * @param counterEventKey - key to identify counter
-     * @return
-     */
-    public Counter getCounter(CounterEventTypes counterEventKey){
-        if(counterEventKey == null){
-            throw new IllegalArgumentException("counterEventKey can not be null");
+        countersMap = new ConcurrentHashMap<>();
+        for(CounterEventTypes cet : enabledCounters){
+            countersMap.put(cet, new Counter());
+        }
+        runCounting = false;
+        this.logReportPeriod = -1;
+        this.runLogReport = false;
+        LOGGER.debug("StaticsCounters has been created");
+    }
+
+    /**
+     * Start counting
+     * @param resetCounters - true = statistics counters will be reset before start counting
+     * @param reportToLogs - true = statistics counters will periodically write to log
+     * @param logReportDelay - delay between two writings into logs in milliseconds (for details see startLogReport(int logReportDelay))
+     */
+    public void startCounting(boolean resetCounters, boolean reportToLogs, int logReportDelay){
+        if (runCounting) {
+            return;
+        }
+        LOGGER.debug("Start counting...");
+        if(reportToLogs){
+            startLogReport(logReportDelay);
+        }
+        if(resetCounters){
+            resetCounters();
+        }
+        runCounting = true;
+    }
+
+    /**
+     * Start counting (counters are set to 0 before start counting)
+     * @param reportToLogs - true = statistics counters will periodically write to log
+     * @param logReportDelay - delay between two writings into logs in milliseconds (for details see startLogReport(int logReportDelay))
+     */
+    public void startCounting(boolean reportToLogs, int logReportDelay){
+        if (runCounting) {
+            return;
+        }
+        startCounting(true,reportToLogs,logReportDelay);
+    }
+
+    /**
+     * Stop counting, values in counters are untouched, log reporter is stopped
+     */
+    public void stopCounting(){
+        runCounting = false;
+        LOGGER.debug("Stop counting...");
+        stopLogReport();
+    }
+
+    /**
+     * Give an information if counting is running
+     * @return true, if counting is running, otherwise false
+     */
+    public boolean isRunCounting(){
+        return runCounting;
+    }
+
+    /**
+     * Start write statistics into logs, if writing is run calling has no effect. 
+     * If method is called without previous setting of report delay than DEFAULT_LOG_REPORT_PERIOD will be used.
+     */
+    public void startLogReport(){
+        if(runLogReport){
+            return;
+        }
+        if(this.logReportPeriod <= 0){
+            this.logReportPeriod = DEFAULT_LOG_REPORT_PERIOD;
+        }
+        if(this.logReportPeriod <= MINIMAL_LOG_REPORT_PERIOD){
+            this.logReportPeriod = MINIMAL_LOG_REPORT_PERIOD;
+        }
+        logReporter = new Timer("SC_Timer");
+        logReporter.schedule(new LogReporterTask(this), this.logReportPeriod,this.logReportPeriod);
+        runLogReport = true;
+        LOGGER.debug("Statistics log reporter has been scheduled with period {} ms", this.logReportPeriod);
+    }
+
+    /**
+     * Start write statistics into logs with given delay between writings, if writing is run calling has no effect.
+     * @param logReportDelay - delay between two writings into logs (milliseconds). 
+     *            It is mandatory if reportToLogs is true, value have to be greater than 0 (zero)
+     *            If value is smaller than MINIMAL_LOG_REPORT_PERIOD, the value MINIMAL_LOG_REPORT_PERIOD will be used.
+     * @exception IllegalArgumentException if logReportDelay is not greater than 0 (zero)
+     */
+    public void startLogReport(int logReportDelay){
+        if(runLogReport){
+            return;
+        }
+        if(logReportDelay <= 0){
+            throw new IllegalArgumentException("logReportPeriod have to bee greater than 0 zero");
         }
-        switch (counterEventKey){
-            case DS_ENCODE_FAIL:
-                return cntDSEncodeFail;
-            case DS_ENCODE_SUCCESS:
-                return cntDSEncodeSuccess;
-            case DS_ENTERED_OFJAVA:
-                return cntDSEnteredOFJava;
-            case US_DECODE_FAIL:
-                return cntUSDecodeFail;
-            case US_DECODE_SUCCESS:
-                return cntUSDecodeSuccess;
-            case US_MESSAGE_PASS:
-                return cntUSMessagePass;
-            case US_RECEIVED_IN_OFJAVA:
-                return cntUSReceivedOFJava;
-            default:
-                throw new IllegalArgumentException("unknown counterEventKey");
+        if(logReportDelay < MINIMAL_LOG_REPORT_PERIOD){
+            this.logReportPeriod = MINIMAL_LOG_REPORT_PERIOD;
+        } else {
+            this.logReportPeriod = logReportDelay;
         }
-//        return countersMap.get(counterEventKey);
+        startLogReport();
+    }
+
+    /**
+     * Stop  write statistics into logs, counting does not stop
+     */
+    public void stopLogReport(){
+        if(runLogReport){
+            if(logReporter != null){
+                logReporter.cancel();
+                LOGGER.debug("Statistics log reporter has been canceled");
+            }
+            runLogReport = false;
+        }
+    }
+
+    /**
+     * Give an information if log reporter is running (statistics are write into logs).
+     * @return true if log reporter writes statistics into log, otherwise false
+     */
+    public boolean isRunLogReport(){
+        return runLogReport;
+    }
+
+    /**
+     * @return the current delay between two writings into logs
+     */
+    public int getLogReportPeriod() {
+        return logReportPeriod;
+    }
+
+    /**
+     * @return the enabled counters
+     */
+    protected CounterEventTypes[] getEnabledCounters() {
+        return enabledCounters;
+    }
+    /**
+     * @return the countersMap
+     */
+    protected Map<CounterEventTypes, Counter> getCountersMap() {
+        return countersMap;
+    }
+
+    /**
+     * Give an information if is given counter is enabled
+     * @param counterEventKey
+     * @return true if counter has been Enabled, otherwise false
+     */
+    public boolean isCounterEnabled(CounterEventTypes counterEventKey){
+        if (counterEventKey == null) {
+            return false;
+        }
+        return countersMap.containsKey(counterEventKey);
+    }
+
+    /**
+     * Get counter by counter event type
+     * @param counterEventKey key to identify counter (can not be null)
+     * @return - Counter object or null if counter has not been enabled
+     * @exception - IllegalArgumentException if counterEventKey is null
+     */
+    public Counter getCounter(CounterEventTypes counterEventKey) {
+        if (counterEventKey == null) {
+            throw new IllegalArgumentException("counterEventKey can not be null");
+        }
+        return countersMap.get(counterEventKey);
     }
 
     /**
      * Increment value of given counter
-     * @param counterEventKey - key to identify counter
-     * @return
+     * @param counterEventKey key to identify counter
      */
-    public void incrementCounter(CounterEventTypes counterEventKey){
-        getCounter(counterEventKey).incrementCounter();
+    public void incrementCounter(CounterEventTypes counterEventKey) {
+        if(runCounting){
+            if (isCounterEnabled(counterEventKey)){
+                countersMap.get(counterEventKey).incrementCounter();
+            }
+        }
     }
 
     /**
      * Set values of all counter to 0 (zero)
      */
-    public void resetCounters(){
-        cntDSEncodeFail.reset(); ;
-        cntDSEncodeSuccess.reset();
-        cntDSEnteredOFJava.reset();
-        cntUSDecodeFail.reset();
-        cntUSDecodeSuccess.reset();
-        cntUSMessagePass.reset();
-        cntUSReceivedOFJava.reset();
-//        countersMap.get(CounterEventTypes.DS_ENCODE_FAIL).reset();
-//        countersMap.get(CounterEventTypes.DS_ENCODE_SUCCESS).reset();
-//        countersMap.get(CounterEventTypes.DS_ENTERED_OFJAVA).reset();
-//        countersMap.get(CounterEventTypes.US_DECODE_FAIL).reset();
-//        countersMap.get(CounterEventTypes.US_DECODE_SUCCESS).reset();
-//        countersMap.get(CounterEventTypes.US_MESSAGE_PASS).reset();
-//        countersMap.get(CounterEventTypes.US_RECEIVED_IN_OFJAVA).reset();
+    public void resetCounters() {
+        for(CounterEventTypes cet : enabledCounters){
+            countersMap.get(cet).reset();
+        }
         LOGGER.debug("StaticsCounters has been reset");
     }
+
+    /**
+     * internal class to process logReporter
+     * @author madamjak
+     *
+     */
+    private static class LogReporterTask extends TimerTask {
+        private static final Logger LOG = LoggerFactory.getLogger(LogReporterTask.class);
+
+        private StatisticsCounters sc;
+        public LogReporterTask(StatisticsCounters sc) {
+            this.sc = sc;
+        }
+
+        @Override
+        public void run() {
+                for(CounterEventTypes cet : sc.getEnabledCounters()){
+                    LOG.debug(cet.toString() + ": " + sc.getCountersMap().get(cet).toString());
+                }
+        }
+    }
 }
index 95674fec6cc821c08d6551883d4b605b3233f8bf..d64941083860214cbba9a50d8179bfc0bf130936 100644 (file)
@@ -13,9 +13,11 @@ import java.net.InetAddress;
 import java.net.UnknownHostException;
 
 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionConfiguration;
+import org.opendaylight.openflowjava.protocol.api.connection.StatisticsConfiguration;
 import org.opendaylight.openflowjava.protocol.api.connection.ThreadConfiguration;
 import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;
 import org.opendaylight.openflowjava.protocol.impl.core.SwitchConnectionProviderImpl;
+import org.opendaylight.openflowjava.statistics.StatisticsCounters;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.TransportProtocol;
@@ -61,15 +63,18 @@ public final class SwitchConnectionProviderModule extends org.opendaylight.yang.
     public java.lang.AutoCloseable createInstance() {
         LOG.info("SwitchConnectionProvider started.");
         SwitchConnectionProviderImpl switchConnectionProviderImpl = new SwitchConnectionProviderImpl();
+        StatisticsCounters sc = StatisticsCounters.getInstance();
         try {
             ConnectionConfiguration connConfiguration = createConnectionConfiguration();
             switchConnectionProviderImpl.setConfiguration(connConfiguration);
+            startStatistics(sc, connConfiguration.getStatisticsConfiguration());
         } catch (UnknownHostException e) {
             throw new IllegalArgumentException(e.getMessage(), e);
         }
         return switchConnectionProviderImpl;
     }
 
+    
     /**
      * @return instance configuration object
      * @throws UnknownHostException 
@@ -81,6 +86,7 @@ public final class SwitchConnectionProviderModule extends org.opendaylight.yang.
         final Tls tlsConfig = getTls();
         final Threads threads = getThreads();
         final TransportProtocol transportProtocol = getTransportProtocol();
+        final Statistics statistics = getStatistics();
         
         return new ConnectionConfiguration() {
             @Override
@@ -166,6 +172,31 @@ public final class SwitchConnectionProviderModule extends org.opendaylight.yang.
                     }
                 };
             }
+            @Override
+            public StatisticsConfiguration getStatisticsConfiguration(){
+               return new StatisticsConfiguration() {
+                @Override
+                public Boolean getStatisticsCollect() {
+                    if(statistics == null){
+                        return false;
+                    }
+                    if (statistics.getStatisticsCollect() == null){
+                        return false;
+                    }
+                    return statistics.getStatisticsCollect();
+                }
+                @Override
+                public Integer getLogReportDelay() {
+                    if(statistics == null){
+                        return -1;
+                    }
+                    if(statistics.getLogReportDelay() == null){
+                        return -1;
+                    };
+                    return statistics.getLogReportDelay();
+                }
+            };
+            }
         };
     }
 
@@ -191,6 +222,37 @@ public final class SwitchConnectionProviderModule extends org.opendaylight.yang.
         }
     }
 
+    /**
+     * Configure and start Statistics Counters by configuration parameters. 
+     *      No operations is performed if:
+     *      - statisticsConfig is null
+     *      - sc is null
+     *      - sc is not null and if counting is running
+     * @param sc - statistic counter to configure and start
+     * @param statisticsConfig - configuration parameters
+     */
+    private static void startStatistics(StatisticsCounters sc, StatisticsConfiguration statisticsConfig){
+        if(statisticsConfig == null){
+            return;
+        }
+        if(sc == null || sc.isRunCounting()){
+            return;
+        }
+        Boolean toCollectStats = statisticsConfig.getStatisticsCollect();
+        Integer logDelay = statisticsConfig.getLogReportDelay();
+        if(toCollectStats != null && toCollectStats.booleanValue()){
+            int logPeriod = -1;
+            if(logDelay != null){
+                logPeriod = logDelay.intValue();
+            }
+            if(logPeriod >0){
+                sc.startCounting(true, logPeriod);
+            } else {
+                sc.startCounting(false, 0);
+            }
+        }
+    }
+    
     /**
      * @param value
      * @return
index 6afd5c60a1b8aeea650e75b83c6fcee391f6267e..4ca3188622ff2ef96c596364b6cd40746e100886 100644 (file)
@@ -92,6 +92,16 @@ module openflow-switch-connection-provider-impl {
                     type uint16;
                 }
             }
+            container statistics {
+                leaf statistics-collect {
+                    description "Toggle of collecting statistics";
+                    type boolean;
+                }
+                leaf log-report-delay {
+                    description "Delay between statistics logs";
+                    type uint16;
+                }
+            }
         }
     }
 }
\ No newline at end of file
index 9462de15e7441048034f1e3970fff94b068a880c..4dd3f53b1c14a4b362ae041ca72421ac2a491528 100644 (file)
@@ -27,84 +27,115 @@ import org.opendaylight.openflowjava.statistics.CounterEventTypes;
 import org.opendaylight.openflowjava.statistics.StatisticsCounters;
 import org.opendaylight.openflowjava.util.ByteBufUtils;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
+ * Test to count decoder events (counters US_DECODE_SUCCESS, US_DECODE_FAIL and
+ * US_RECEIVED_IN_OFJAVA have to be enabled)
+ * 
  * @author madamjak
  *
  */
 public class OFDecoderStatisticsTest {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(OFEncoderStatisticsTest.class);
+    @Mock ChannelHandlerContext mockChHndlrCtx;
+    @Mock DeserializationFactory mockDeserializationFactory;
+    @Mock DataObject mockDataObject;
 
-    @Mock ChannelHandlerContext mockChHndlrCtx ;
-    @Mock DeserializationFactory mockDeserializationFactory ;
-    @Mock DataObject mockDataObject ;
-
-    private OFDecoder ofDecoder ;
+    private OFDecoder ofDecoder;
     private ByteBuf writeObj;
     private VersionMessageWrapper inMsg;
     private List<Object> outList;
     private StatisticsCounters statCounters;
 
     /**
-     * Sets up test environment
-     * 
+     * Sets up test environment Start counting and reset counters before each
+     * test
      */
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        ofDecoder = new OFDecoder() ;
-        ofDecoder.setDeserializationFactory( mockDeserializationFactory ) ;
+        ofDecoder = new OFDecoder();
+        ofDecoder.setDeserializationFactory(mockDeserializationFactory);
         outList = new ArrayList<>();
         statCounters = StatisticsCounters.getInstance();
-        statCounters.resetCounters();
+        statCounters.startCounting(true, false, 0);
     }
 
+    /**
+     * Stop counting after each test
+     */
     @After
-    public void tierDown(){
-        statCounters.resetCounters();
+    public void tierDown() {
+        statCounters.stopCounting();
     }
 
+    /**
+     * Test decode success counter
+     */
     @Test
-    public void testDecodeSuccesfullCounter() throws InterruptedException {
+    public void testDecodeSuccesfullCounter() {
+        if (!statCounters.isCounterEnabled(CounterEventTypes.US_DECODE_SUCCESS)) {
+            Assert.fail("Counter " + CounterEventTypes.US_DECODE_SUCCESS + " is not enable");
+        }
+        if (!statCounters.isCounterEnabled(CounterEventTypes.US_DECODE_FAIL)) {
+            Assert.fail("Counter " + CounterEventTypes.US_DECODE_FAIL + " is not enable");
+        }
+        if (!statCounters
+                .isCounterEnabled(CounterEventTypes.US_RECEIVED_IN_OFJAVA)) {
+            Assert.fail("Counter " + CounterEventTypes.US_RECEIVED_IN_OFJAVA + " is not enable");
+        }
         int count = 4;
-        when(mockDeserializationFactory.deserialize( any(ByteBuf.class), anyShort() )).thenReturn(mockDataObject);
+        when(mockDeserializationFactory.deserialize(any(ByteBuf.class),anyShort())).thenReturn(mockDataObject);
         try {
-            for(int i = 0; i<count; i++){
+            for (int i = 0; i < count; i++) {
                 writeObj = ByteBufUtils.hexStringToByteBuf("16 03 01 00");
-                inMsg = new VersionMessageWrapper( (short)8, writeObj );
+                inMsg = new VersionMessageWrapper((short) 8, writeObj);
                 ofDecoder.decode(mockChHndlrCtx, inMsg, outList);
             }
         } catch (Exception e) {
             Assert.fail();
         }
-        LOGGER.debug("Waiting to event queue process");
-        Assert.assertEquals("Wrong - bad counter value for OFEncoder encode succesfully ", count, statCounters.getCounter(CounterEventTypes.US_DECODE_SUCCESS).getCounterValue());
+        Assert.assertEquals("Wrong - bad counter value for OFEncoder encode succesfully ",
+                count,statCounters.getCounter(CounterEventTypes.US_DECODE_SUCCESS).getCounterValue());
+        Assert.assertEquals(
+                "Wrong - different between RECEIVED_IN_OFJAVA and (US_DECODE_SUCCESS + US_DECODE_FAIL)",
+                statCounters.getCounter(CounterEventTypes.US_RECEIVED_IN_OFJAVA).getCounterValue(),
+                statCounters.getCounter(CounterEventTypes.US_DECODE_SUCCESS).getCounterValue() 
+                + statCounters.getCounter(CounterEventTypes.US_DECODE_FAIL).getCounterValue());
     }
 
     /**
-     * @throws InterruptedException 
-     * 
+     * Test fail decode counter
      */
     @Test
-    public void testDecodeFailCounter() throws InterruptedException {
+    public void testDecodeFailCounter() {
+        if (!statCounters.isCounterEnabled(CounterEventTypes.US_DECODE_SUCCESS)) {
+            Assert.fail("Counter " + CounterEventTypes.US_DECODE_SUCCESS + " is not enable");
+        }
+        if (!statCounters.isCounterEnabled(CounterEventTypes.US_DECODE_FAIL)) {
+            Assert.fail("Counter " + CounterEventTypes.US_DECODE_FAIL + " is not enable");
+        }
+        if (!statCounters.isCounterEnabled(CounterEventTypes.US_RECEIVED_IN_OFJAVA)) {
+            Assert.fail("Counter " + CounterEventTypes.US_RECEIVED_IN_OFJAVA + " is not enable");
+        }
         int count = 2;
-        when(mockDeserializationFactory.deserialize( any(ByteBuf.class), anyShort() ))
-        .thenThrow(new IllegalArgumentException()) ;
+        when( mockDeserializationFactory.deserialize(any(ByteBuf.class),anyShort())).thenThrow(new IllegalArgumentException());
         try {
-            for(int i = 0; i<count; i++){
+            for (int i = 0; i < count; i++) {
                 writeObj = ByteBufUtils.hexStringToByteBuf("16 03 01 00");
-                inMsg = new VersionMessageWrapper( (short)8, writeObj );
+                inMsg = new VersionMessageWrapper((short) 8, writeObj);
                 ofDecoder.decode(mockChHndlrCtx, inMsg, outList);
             }
         } catch (Exception e) {
-            System.out.println("a");
             Assert.fail();
         }
-        LOGGER.debug("Waiting to event queue process");
-        Assert.assertEquals("Wrong - bad counter value for OFEncoder encode succesfully ", count, statCounters.getCounter(CounterEventTypes.US_DECODE_FAIL).getCounterValue());
-
+        Assert.assertEquals(
+                "Wrong - bad counter value for OFEncoder encode succesfully ",
+                count, statCounters.getCounter(CounterEventTypes.US_DECODE_FAIL).getCounterValue());
+        Assert.assertEquals(
+                "Wrong - different between RECEIVED_IN_OFJAVA and (US_DECODE_SUCCESS + US_DECODE_FAIL)",
+                statCounters.getCounter(CounterEventTypes.US_RECEIVED_IN_OFJAVA).getCounterValue(),
+                statCounters.getCounter(CounterEventTypes.US_DECODE_SUCCESS).getCounterValue()
+                + statCounters.getCounter(CounterEventTypes.US_DECODE_FAIL).getCounterValue());
     }
 }
index 4c2789f16ba60969a03a867e85ee5387bd1dd637..af8a0102e8fe4a2d0d28b7ff03e3a9753ddbf19b 100644 (file)
@@ -84,7 +84,6 @@ public class OFDecoderTest {
         try {
             ofDecoder.decode(mockChHndlrCtx, inMsg, outList);
         } catch (Exception e) {
-            System.out.println("a");
             Assert.fail();
         }
 
index 7c803ad4ec138a4f3bcf763e6cd7d68b9c3e0383..46aa2f45b113bb110619a416d35a2cca5161cfb8 100644 (file)
@@ -27,19 +27,17 @@ import org.opendaylight.openflowjava.protocol.impl.core.connection.MessageListen
 import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory;
 import org.opendaylight.openflowjava.statistics.CounterEventTypes;
 import org.opendaylight.openflowjava.statistics.StatisticsCounters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowModInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
+ * Test counters for encoding (at least DS_ENCODE_SUCCESS, DS_ENCODE_FAIL and DS_FLOW_MODS_SENT counters have to be enabled)
  * @author madamjak
  *
  */
 public class OFEncoderStatisticsTest {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(OFEncoderStatisticsTest.class);
-
     @Mock ChannelHandlerContext mockChHndlrCtx ;
     @Mock SerializationFactory mockSerializationFactory ;
     @Mock MessageListenerWrapper wrapper;
@@ -47,26 +45,40 @@ public class OFEncoderStatisticsTest {
     @Mock ByteBuf mockOut ;
     @Mock Future<Void> future;
     @Mock GenericFutureListener<Future<Void>> listener;
+    @Mock FlowModInput mockFlowModInput;
 
     private StatisticsCounters statCounters;
     private OFEncoder ofEncoder;
 
+    /**
+     * Initialize tests, start and reset counters before each test
+     */
     @Before
-    public void initTest(){
+    public void initTlest(){
         MockitoAnnotations.initMocks(this);
         ofEncoder = new OFEncoder() ;
         ofEncoder.setSerializationFactory(mockSerializationFactory) ;
         statCounters = StatisticsCounters.getInstance();
-        statCounters.resetCounters();
+        statCounters.startCounting(true,false, 0);
     }
 
+    /**
+     * Stop counting after each test
+     */
     @After
     public void tierDown(){
-        statCounters.resetCounters();
+        statCounters.stopCounting();
     }
 
+    /**
+     * Test counting of success encode (counter DS_ENCODE_SUCCESS has to be enabled)
+     */
     @Test
-    public void testEncodeSuccessCounter() throws InterruptedException{
+    public void testEncodeSuccessCounter() {
+        CounterEventTypes cet = CounterEventTypes.DS_ENCODE_SUCCESS;
+        if(! statCounters.isCounterEnabled(cet)){
+            Assert.fail("Counter " + cet + " is not enabled.");
+        }
         int count = 4;
         when(mockOut.readableBytes()).thenReturn(1);
         when(wrapper.getMsg()).thenReturn(mockMsg);
@@ -78,12 +90,41 @@ public class OFEncoderStatisticsTest {
         } catch (Exception e) {
             Assert.fail();
         }
-        LOGGER.debug("Waiting to event queue process");
-        Assert.assertEquals("Wrong - bad counter value for OFEncoder encode succesfully ", count, statCounters.getCounter(CounterEventTypes.DS_ENCODE_SUCCESS).getCounterValue());
+        Assert.assertEquals("Wrong - bad counter value for OFEncoder encode succesfully ", count, statCounters.getCounter(cet).getCounterValue());
     }
 
+    /**
+     * Test counting of flow-mod sent (counter DS_FLOW_MODS_SENT has to be enabled)
+     */
     @Test
-    public void testEncodeEncodeFailCounter() throws InterruptedException {
+    public void testFlowModSentCounter() {
+        CounterEventTypes cet = CounterEventTypes.DS_FLOW_MODS_SENT;
+        if(! statCounters.isCounterEnabled(cet)){
+            Assert.fail("Counter " + cet + " is not enabled.");
+        }
+        int count = 4;
+        when(mockOut.readableBytes()).thenReturn(1);
+        when(wrapper.getMsg()).thenReturn(mockFlowModInput);
+        when(wrapper.getMsg().getVersion()).thenReturn((short) EncodeConstants.OF13_VERSION_ID);
+        try {
+            for(int i = 0; i< count; i++){
+                ofEncoder.encode(mockChHndlrCtx, wrapper, mockOut);
+            }
+        } catch (Exception e) {
+            Assert.fail();
+        }
+        Assert.assertEquals("Wrong - bad counter value for OFEncoder flow-mod sent", count, statCounters.getCounter(cet).getCounterValue());
+    }
+    /**
+     * Test counting of encode fail (counter DS_ENCODE_FAIL has to be enabled)
+     */
+
+    @Test
+    public void testEncodeEncodeFailCounter() {
+        CounterEventTypes cet = CounterEventTypes.DS_ENCODE_FAIL;
+        if(! statCounters.isCounterEnabled(cet)){
+            Assert.fail("Counter " + cet + " is not enabled.");
+        }
         int count = 2;
         when(wrapper.getMsg()).thenReturn(mockMsg);
         when(wrapper.getListener()).thenReturn(listener);
@@ -96,7 +137,6 @@ public class OFEncoderStatisticsTest {
         } catch (Exception e) {
             Assert.fail();
         }
-        LOGGER.debug("Waiting to event queue process");
-        Assert.assertEquals("Wrong - bad counter value for OFEncoder fail encode", count, statCounters.getCounter(CounterEventTypes.DS_ENCODE_FAIL).getCounterValue());
+        Assert.assertEquals("Wrong - bad counter value for OFEncoder fail encode", count, statCounters.getCounter(cet).getCounterValue());
     }
 }
index dd9f404344279381e40cf0b7b608b02732baa3e4..cf50b62693cf56104ae4ccd93d73b531e9ff6e9f 100644 (file)
@@ -46,7 +46,8 @@ public class ChannelOutboundQueueTest {
     @Test\r
     public void testEnqueue() {\r
         ChannelOutboundQueue queue = new ChannelOutboundQueue(channel, 1, null);\r
-        boolean enqueued = queue.enqueue(new SimpleRpcListener("INPUT", "Failed to send INPUT"));\r
+        boolean enqueued;\r
+        enqueued = queue.enqueue(new SimpleRpcListener("INPUT", "Failed to send INPUT"));\r
         Assert.assertTrue("Enqueue problem", enqueued);\r
         enqueued = queue.enqueue(new SimpleRpcListener("INPUT", "Failed to send INPUT"));\r
         Assert.assertFalse("Enqueue problem", enqueued);\r
index 49cadf483b6de230152cad9246903061abf409c5..8429afdef1bca8d5feb384d1bf56c8e49279a73b 100644 (file)
@@ -9,19 +9,16 @@ package org.opendaylight.openflowjava.protocol.impl.core.connection;
 
 import static org.mockito.Mockito.when;
 import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelOutboundHandlerAdapter;
 import io.netty.channel.ChannelPipeline;
-import io.netty.channel.ChannelPromise;
 import io.netty.channel.embedded.EmbeddedChannel;
 import io.netty.channel.socket.SocketChannel;
 
 import java.net.InetSocketAddress;
 import java.util.concurrent.TimeUnit;
 
-import junit.framework.Assert;
-
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -48,7 +45,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MeterModInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReplyMessageBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartRequestInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OpenflowProtocolListener;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketInMessageBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketOutInput;
@@ -60,8 +56,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.TableModInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SystemNotificationsListener;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
@@ -69,11 +63,12 @@ import com.google.common.cache.RemovalListener;
 import com.google.common.cache.RemovalNotification;
 
 /**
+ * Test counters in ConnectionAdapter (at least DS_ENTERED_OFJAVA, DS_FLOW_MODS_ENTERED and US_MESSAGE_PASS counters have to be enabled)
  * @author madamjak
  *
  */
 public class ConnectionAdapterImplStatisticsTest {
-    private static final Logger LOGGER = LoggerFactory.getLogger(StatisticsCounters.class);
+
     private static final int RPC_RESPONSE_EXPIRATION = 1;
     private static final RemovalListener<RpcResponseKey, ResponseExpectedRpcListener<?>> REMOVAL_LISTENER =
             new RemovalListener<RpcResponseKey, ResponseExpectedRpcListener<?>>() {
@@ -83,10 +78,9 @@ public class ConnectionAdapterImplStatisticsTest {
             notification.getValue().discard();
         }
     };
-    
+
     @Mock SystemNotificationsListener systemListener;
     @Mock ConnectionReadyListener readyListener;
-    //@Mock Cache<RpcResponseKey, ResponseExpectedRpcListener<?>> mockCache;
     @Mock ChannelFuture channelFuture;
     @Mock OpenflowProtocolListener messageListener;
     @Mock SocketChannel channel;
@@ -110,104 +104,101 @@ public class ConnectionAdapterImplStatisticsTest {
     @Mock TableModInput tableModInput;
     @Mock GetAsyncInput getAsyncInput;
     @Mock SetAsyncInput setAsyncInput;
-    
+
     private ConnectionAdapterImpl adapter;
     private Cache<RpcResponseKey, ResponseExpectedRpcListener<?>> cache;
     private StatisticsCounters statCounters;
+
     /**
      * Initialize mocks
+     * Start counting and reset counters before each test
      */
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         statCounters = StatisticsCounters.getInstance();
-        statCounters.resetCounters();
+        statCounters.startCounting(true,false, 0);
     }
+
     /**
      * Disconnect adapter
+     * Stop counting after each test
      */
     @After
     public void tierDown(){
         if (adapter != null && adapter.isAlive()) {
             adapter.disconnect();
         }
-        statCounters.resetCounters();
+        statCounters.stopCounting();
     }
+
     /**
-     * Test statistic counter for all rpc calls 
-     * @throws InterruptedException 
+     * Test statistic counter for all rpc calls (counters DS_ENTERED_OFJAVA and DS_FLOW_MODS_ENTERED have to be enabled)
      */
     @Test
-    public void testEnterOFJavaCounter() throws InterruptedException {
+    public void testEnterOFJavaCounter() {
+        if(!statCounters.isCounterEnabled(CounterEventTypes.DS_ENTERED_OFJAVA)){
+            Assert.fail("Counter " + CounterEventTypes.DS_ENTERED_OFJAVA + " is not enabled");
+        }
+        if(!statCounters.isCounterEnabled(CounterEventTypes.DS_FLOW_MODS_ENTERED)){
+            Assert.fail("Counter " + CounterEventTypes.DS_FLOW_MODS_ENTERED + " is not enabled");
+        }
         EmbeddedChannel embChannel = new EmbeddedChannel(new EmbededChannelHandler());
         adapter = new ConnectionAdapterImpl(embChannel,InetSocketAddress.createUnresolved("localhost", 9876));
         cache = CacheBuilder.newBuilder().concurrencyLevel(1).expireAfterWrite(RPC_RESPONSE_EXPIRATION, TimeUnit.MINUTES)
                 .removalListener(REMOVAL_LISTENER).build();
         adapter.setResponseCache(cache);
-        // -- barrier
         adapter.barrier(barrierInput);
         embChannel.runPendingTasks();
-        // -- echo
         adapter.echo(echoInput);
         embChannel.runPendingTasks();
-        // -- echoReply
         adapter.echoReply(echoReplyInput);
         embChannel.runPendingTasks();
-        // -- experimenter
         adapter.experimenter(experimenterInput);
         embChannel.runPendingTasks();
-        // -- flowMod
         adapter.flowMod(flowModInput);
         embChannel.runPendingTasks();
-        // -- getConfig
         adapter.getConfig(getConfigInput);
         embChannel.runPendingTasks();
-        // -- getFeatures
         adapter.getFeatures(getFeaturesInput);
         embChannel.runPendingTasks();
-        // -- getQueueConfig
         adapter.getQueueConfig(getQueueConfigInput);
         embChannel.runPendingTasks();
-        // -- groupMod
         adapter.groupMod(groupModInput);
         embChannel.runPendingTasks();
-        // -- hello
         adapter.hello(helloInput);
         embChannel.runPendingTasks();
-        // -- meterMod
         adapter.meterMod(meterModInput);
         embChannel.runPendingTasks();
-        // -- packetOut
         adapter.packetOut(packetOutInput);
         embChannel.runPendingTasks();
-        // -- multipartRequest
         adapter.multipartRequest(multipartRequestInput);
         embChannel.runPendingTasks();
-        // -- portMod
         adapter.portMod(portModInput);
         embChannel.runPendingTasks();
-        // -- roleRequest
         adapter.roleRequest(roleRequestInput);
         embChannel.runPendingTasks();
-        // -- setConfig
         adapter.setConfig(setConfigInput);
         embChannel.runPendingTasks();
-        // -- tableMod
         adapter.tableMod(tableModInput);
         embChannel.runPendingTasks();
-        // -- getAsync
         adapter.getAsync(getAsyncInput);
         embChannel.runPendingTasks();
-        // -- setAsync
         adapter.setAsync(setAsyncInput);
         embChannel.runPendingTasks();
-        LOGGER.debug("Waiting to Event Queue process");
         Assert.assertEquals("Wrong - bad counter value for ConnectionAdapterImpl rpc methods", 19, statCounters.getCounter(CounterEventTypes.DS_ENTERED_OFJAVA).getCounterValue());
+        Assert.assertEquals("Wrong - bad counter value for ConnectionAdapterImpl flow-mod entered", 1, statCounters.getCounter(CounterEventTypes.DS_FLOW_MODS_ENTERED).getCounterValue());
         adapter.disconnect();
     }
 
+    /**
+     * Test counter for pass messages to consumer (counter US_MESSAGE_PASS has to be enabled)
+     */
     @Test
-    public void testMessagePassCounter() throws InterruptedException {
+    public void testMessagePassCounter() {
+        if(!statCounters.isCounterEnabled(CounterEventTypes.US_MESSAGE_PASS)){
+            Assert.fail("Counter " + CounterEventTypes.US_MESSAGE_PASS + " is not enabled");
+        }
         when(channel.pipeline()).thenReturn(pipeline);
         adapter = new ConnectionAdapterImpl(channel, InetSocketAddress.createUnresolved("10.0.0.1", 6653));
         adapter.setMessageListener(messageListener);
@@ -235,26 +226,16 @@ public class ConnectionAdapterImplStatisticsTest {
         adapter.consume(message);
         message = new EchoRequestMessageBuilder().build();
         adapter.consume(message);
-        LOGGER.debug("Waiting to Event Queue process");
         Assert.assertEquals("Wrong - bad counter value for ConnectionAdapterImpl consume method", 9, statCounters.getCounter(CounterEventTypes.US_MESSAGE_PASS).getCounterValue());
         adapter.disconnect();
     }
-    
+
     /**
-     * Channel Handler for testing
+     * Empty channel Handler for testing
      * @author madamjak
      *
      */
     private class EmbededChannelHandler extends ChannelOutboundHandlerAdapter {
-        @Override
-        public void write(ChannelHandlerContext ctx, Object msg,
-                ChannelPromise promise) throws Exception {
-            OfHeader responseOfCall = null;
-            if(msg instanceof MessageListenerWrapper){
-                MessageListenerWrapper listener = (MessageListenerWrapper) msg;
-                OfHeader ofHeader = listener.getMsg();
-                responseOfCall = ofHeader;
-            }
-        }
+        // no operation need to test
     }
 }
index a66e9768df7f789cc0d493c854d5cc731a3c85f8..ec947e9aa5114d426ecc5b8e54ea352616f81045 100644 (file)
@@ -11,9 +11,11 @@ package org.opendaylight.openflowjava.protocol.impl.core.connection;
 import java.net.InetAddress;
 
 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionConfiguration;
+import org.opendaylight.openflowjava.protocol.api.connection.StatisticsConfiguration;
 import org.opendaylight.openflowjava.protocol.api.connection.ThreadConfiguration;
 import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.TransportProtocol;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow._switch.connection.provider.impl.rev140328.modules.module.configuration.openflow._switch.connection.provider.impl.Statistics;
 
 /**
  * @author michal.polkorab
@@ -28,6 +30,7 @@ public class ConnectionConfigurationImpl implements ConnectionConfiguration {
     private long switchIdleTimeout;
     private ThreadConfiguration threadConfig;
     private TransportProtocol protocol;
+    private Statistics statistics;
 
     /**
      * Creates {@link ConnectionConfigurationImpl}
@@ -93,4 +96,10 @@ public class ConnectionConfigurationImpl implements ConnectionConfiguration {
     public void setThreadConfiguration(ThreadConfiguration threadConfig) {
         this.threadConfig = threadConfig;
     }
+
+    @Override
+    public StatisticsConfiguration getStatisticsConfiguration() {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }
\ No newline at end of file
index 9f064d5f5c93d3e8b1af842257d4cc73b04a5d43..1bb549b6fedb5f9b1efbc478ae51ecb716aac7a9 100644 (file)
@@ -15,6 +15,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
+ * General tests for StatisticsCounters class 
  * @author madamjak
  *
  */
@@ -23,62 +24,115 @@ public class StatisticsCountersTest {
     private static final Logger LOGGER = LoggerFactory.getLogger(StatisticsCounters.class);
     private StatisticsCounters statCounters;
 
+    /**
+     * Initialize StatisticsCounters before each test, reset counters
+     */
     @Before
     public void initTest(){
         statCounters = StatisticsCounters.getInstance();
-        statCounters.resetCounters();
+        statCounters.startCounting(true,false, 0);
     }
 
+    /**
+     * Stop counting after each test
+     */
     @After
     public void tierDown(){
-        statCounters.resetCounters();
+        statCounters.stopCounting();
     }
 
+    /**
+     * Basic test of increment and reset counters
+     */
     @Test
-    public void testCounterAll() throws InterruptedException{
+    public void testCounterAll() {
         int testCount = 4;
-        incrementCounter(CounterEventTypes.DS_ENTERED_OFJAVA,testCount);
-        incrementCounter(CounterEventTypes.DS_ENCODE_SUCCESS,testCount);
-        incrementCounter(CounterEventTypes.DS_ENCODE_FAIL,testCount);
-        incrementCounter(CounterEventTypes.US_DECODE_FAIL,testCount);
-        incrementCounter(CounterEventTypes.US_DECODE_SUCCESS,testCount);
-        incrementCounter(CounterEventTypes.US_MESSAGE_PASS,testCount);
-        incrementCounter(CounterEventTypes.US_RECEIVED_IN_OFJAVA,testCount);
-        LOGGER.debug("Waiting to process event queue");
-        Assert.assertEquals("Wrong - bad counter value " + CounterEventTypes.DS_ENTERED_OFJAVA, testCount, statCounters.getCounter(CounterEventTypes.DS_ENTERED_OFJAVA).getCounterValue());
-        Assert.assertEquals("Wrong - bad counter value " + CounterEventTypes.DS_ENCODE_SUCCESS, testCount, statCounters.getCounter(CounterEventTypes.DS_ENCODE_SUCCESS).getCounterValue());
-        Assert.assertEquals("Wrong - bad counter value " + CounterEventTypes.DS_ENCODE_FAIL, testCount, statCounters.getCounter(CounterEventTypes.DS_ENCODE_FAIL).getCounterValue());
-        Assert.assertEquals("Wrong - bad counter value " + CounterEventTypes.US_DECODE_FAIL, testCount, statCounters.getCounter(CounterEventTypes.US_DECODE_FAIL).getCounterValue());
-        Assert.assertEquals("Wrong - bad counter value " + CounterEventTypes.US_DECODE_SUCCESS, testCount, statCounters.getCounter(CounterEventTypes.US_DECODE_SUCCESS).getCounterValue());
-        Assert.assertEquals("Wrong - bad counter value " + CounterEventTypes.US_MESSAGE_PASS, testCount, statCounters.getCounter(CounterEventTypes.US_MESSAGE_PASS).getCounterValue());
-        Assert.assertEquals("Wrong - bad counter value " + CounterEventTypes.US_RECEIVED_IN_OFJAVA, testCount, statCounters.getCounter(CounterEventTypes.US_RECEIVED_IN_OFJAVA).getCounterValue());
+        for(CounterEventTypes cet : CounterEventTypes.values()){
+            if(statCounters.isCounterEnabled(cet)){
+                incrementCounter(cet,testCount);
+                Assert.assertEquals("Wrong - bad counter value " + cet, testCount, statCounters.getCounter(cet).getCounterValue());
+            } else {
+                Assert.assertNull("Wrong - not enabled counter give not null value", statCounters.getCounter(cet));
+            }
+            
+        }
         statCounters.resetCounters();
-        Assert.assertEquals("Wrong - bad counter value after reset " + CounterEventTypes.DS_ENTERED_OFJAVA, 0, statCounters.getCounter(CounterEventTypes.DS_ENTERED_OFJAVA).getCounterValue());
-        Assert.assertEquals("Wrong - bad counter value after reset " + CounterEventTypes.DS_ENCODE_SUCCESS, 0, statCounters.getCounter(CounterEventTypes.DS_ENCODE_SUCCESS).getCounterValue());
-        Assert.assertEquals("Wrong - bad counter value after reset " + CounterEventTypes.DS_ENCODE_FAIL, 0, statCounters.getCounter(CounterEventTypes.DS_ENCODE_FAIL).getCounterValue());
-        Assert.assertEquals("Wrong - bad counter value after reset " + CounterEventTypes.US_DECODE_FAIL, 0, statCounters.getCounter(CounterEventTypes.US_DECODE_FAIL).getCounterValue());
-        Assert.assertEquals("Wrong - bad counter value after reset " + CounterEventTypes.US_DECODE_SUCCESS, 0, statCounters.getCounter(CounterEventTypes.US_DECODE_SUCCESS).getCounterValue());
-        Assert.assertEquals("Wrong - bad counter value after reset " + CounterEventTypes.US_MESSAGE_PASS, 0, statCounters.getCounter(CounterEventTypes.US_MESSAGE_PASS).getCounterValue());
-        Assert.assertEquals("Wrong - bad counter value after reset " + CounterEventTypes.US_RECEIVED_IN_OFJAVA, 0, statCounters.getCounter(CounterEventTypes.US_RECEIVED_IN_OFJAVA).getCounterValue());
+        for(CounterEventTypes cet : CounterEventTypes.values()){
+            if(statCounters.isCounterEnabled(cet)){
+                Assert.assertEquals("Wrong - bad counter value after reset " + cet, 0, statCounters.getCounter(cet).getCounterValue());
+            }
+        }
     }
 
+    /**
+     * Test to store current and last read value of counter (at least one counter has to be enabled)
+     */
     @Test
-    public void testCounterLastRead() throws InterruptedException{
+    public void testCounterLastRead() {
         int testCount = 4;
-        incrementCounter(CounterEventTypes.DS_ENTERED_OFJAVA,testCount);
-        LOGGER.debug("Waiting to process event queue");
-        Assert.assertEquals("Wrong - bad last read value.", 0,statCounters.getCounter(CounterEventTypes.DS_ENTERED_OFJAVA).getCounterLastReadValue());
-        Assert.assertEquals("Wrong - bad value", 4,statCounters.getCounter(CounterEventTypes.DS_ENTERED_OFJAVA).getCounterValue(false));
-        Assert.assertEquals("Wrong - bad last read value.", 0,statCounters.getCounter(CounterEventTypes.DS_ENTERED_OFJAVA).getCounterLastReadValue());
-        Assert.assertEquals("Wrong - bad last read value.", 4,statCounters.getCounter(CounterEventTypes.DS_ENTERED_OFJAVA).getCounterValue());
-        Assert.assertEquals("Wrong - bad last read value.", 4,statCounters.getCounter(CounterEventTypes.DS_ENTERED_OFJAVA).getCounterLastReadValue());
-        incrementCounter(CounterEventTypes.DS_ENTERED_OFJAVA,testCount);
+        CounterEventTypes firstEnabledCET = null;
+        for(CounterEventTypes  cet : CounterEventTypes.values()){
+            if(statCounters.isCounterEnabled(cet)){
+                firstEnabledCET = cet;
+                break;
+            }
+        }
+        if(firstEnabledCET == null){
+            Assert.fail("No counter is enabled");
+        }
+        incrementCounter(firstEnabledCET,testCount);
         LOGGER.debug("Waiting to process event queue");
-        Assert.assertEquals("Wrong - bad last read value.", 4,statCounters.getCounter(CounterEventTypes.DS_ENTERED_OFJAVA).getCounterLastReadValue());
-        Assert.assertEquals("Wrong - bad last read value.", 8,statCounters.getCounter(CounterEventTypes.DS_ENTERED_OFJAVA).getCounterValue());
+        Assert.assertEquals("Wrong - bad last read value.", 0,statCounters.getCounter(firstEnabledCET).getCounterLastReadValue());
+        Assert.assertEquals("Wrong - bad value", testCount,statCounters.getCounter(firstEnabledCET).getCounterValue(false));
+        Assert.assertEquals("Wrong - bad last read value.", 0,statCounters.getCounter(firstEnabledCET).getCounterLastReadValue());
+        Assert.assertEquals("Wrong - bad last read value.", testCount,statCounters.getCounter(firstEnabledCET).getCounterValue());
+        Assert.assertEquals("Wrong - bad last read value.", testCount,statCounters.getCounter(firstEnabledCET).getCounterLastReadValue());
+        incrementCounter(firstEnabledCET,testCount);
+        Assert.assertEquals("Wrong - bad last read value.", testCount,statCounters.getCounter(firstEnabledCET).getCounterLastReadValue());
+        Assert.assertEquals("Wrong - bad last read value.", 2*testCount,statCounters.getCounter(firstEnabledCET).getCounterValue());
+    }
+
+    /**
+     * Test start and stop log reporter
+     */
+    @Test
+    public void testStartStopLogReporter(){
+        int testDelay = 10000;
+        statCounters.startLogReport(testDelay);
+        Assert.assertTrue("Wrong - logRepoter is not running", statCounters.isRunLogReport());
+        Assert.assertEquals("Wrong - bad logReportPeriod", testDelay, statCounters.getLogReportPeriod());
+        statCounters.startLogReport();
+        Assert.assertTrue("Wrong - logRepoter is not running", statCounters.isRunLogReport());
+        Assert.assertEquals("Wrong - bad logReportPeriod", testDelay, statCounters.getLogReportPeriod());
+        statCounters.stopLogReport();
+        Assert.assertFalse("Wrong - logRepoter is running", statCounters.isRunLogReport());
+        statCounters.startLogReport(statCounters.MINIMAL_LOG_REPORT_PERIOD / 2);
+        Assert.assertTrue("Wrong - logRepoter is not running", statCounters.isRunLogReport());
+        Assert.assertEquals("Wrong - bad logReportPeriod", statCounters.MINIMAL_LOG_REPORT_PERIOD, statCounters.getLogReportPeriod());
+        statCounters.stopCounting();
+        Assert.assertFalse("Wrong - logRepoter is running", statCounters.isRunLogReport());
+    }
+
+    /**
+     * Test start log report with bad logReportDealy
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testLogReportBadPeriod(){
+        statCounters.startLogReport(-1);
+    }
+
+    /**
+     * Test to get counter with null key
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetCounterbyNull(){
+        statCounters.getCounter(null);
     }
 
     private void incrementCounter(CounterEventTypes cet, int count){
+        if(!statCounters.isCounterEnabled(cet)){
+            return;
+        }
         for(int i = 0; i< count; i++){
             statCounters.incrementCounter(cet);
         }