bug 6579 handling back to back tx updates 41/48741/5
authorK.V Suneelu Verma <k.v.suneelu.verma@ericsson.com>
Mon, 28 Nov 2016 14:14:50 +0000 (19:44 +0530)
committersuneel verma <k.v.suneelu.verma@ericsson.com>
Mon, 12 Dec 2016 08:37:39 +0000 (08:37 +0000)
Added the following utility methods in operational state and device info
isKeyPartOfCurrentTx indicates this key is also part of the same tx
isKeyInTransit indicates this key is part of prev tx to device

Before inserting any key into any table
check if this key or its dependent keys are part of prev transaction

Change-Id: I87699c244b7feee27d2c95178dfe5727f4148cdb
Signed-off-by: K.V Suneelu Verma <k.v.suneelu.verma@ericsson.com>
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionInstance.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepConnectionManager.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDeviceInfo.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundUtil.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/HwvtepOperationalState.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/DataChangeListenerTestBase.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepOperationalStateTest.java [new file with mode: 0644]

index 43ca350f3bd238952abf9aab22b07070f9600c58..cec5fc852243b21da8ad2847d3f409ac92614d1e 100644 (file)
@@ -17,6 +17,7 @@ import java.util.concurrent.ExecutionException;
 
 import javax.annotation.Nonnull;
 
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
 import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactCommand;
@@ -67,14 +68,16 @@ public class HwvtepConnectionInstance {
     private EntityOwnershipCandidateRegistration deviceOwnershipCandidateRegistration;
     private HwvtepGlobalAugmentation initialCreatedData = null;
     private HwvtepDeviceInfo deviceInfo;
+    private DataBroker dataBroker;
 
     HwvtepConnectionInstance (ConnectionInfo key, OvsdbClient client,
-                              InstanceIdentifier<Node> iid, TransactionInvoker txInvoker) {
+                              InstanceIdentifier<Node> iid, TransactionInvoker txInvoker, DataBroker dataBroker) {
         this.connectionInfo = key;
         this.client = client;
         this.instanceIdentifier = iid;
         this.txInvoker = txInvoker;
-        this.deviceInfo = new HwvtepDeviceInfo();
+        this.deviceInfo = new HwvtepDeviceInfo(this);
+        this.dataBroker = dataBroker;
     }
 
     public void transact(TransactCommand command) {
@@ -155,6 +158,10 @@ public class HwvtepConnectionInstance {
          */
     }
 
+    public DataBroker getDataBroker() {
+        return dataBroker;
+    }
+
     public ListenableFuture<List<String>> getDatabases() {
         return client.getDatabases();
     }
index 79b84a4ac5fafcc220c544de98d7cc7b3dc17a6b..b40a7367cc691544c9741d1a5add0fc9fe33bc05 100644 (file)
@@ -215,7 +215,7 @@ public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoClo
         }
 
         hwvtepConnectionInstance = new HwvtepConnectionInstance(key, externalClient, getInstanceIdentifier(key),
-                txInvoker);
+                txInvoker, db);
         hwvtepConnectionInstance.createTransactInvokers();
         return hwvtepConnectionInstance;
     }
index 6ac4a94dc2d446935ba811e97285f04bafe57535..d4dba02b05ad072d6c0e4b27bd1da3f4aa030d3f 100644 (file)
@@ -8,13 +8,18 @@
 
 package org.opendaylight.ovsdb.hwvtepsouthbound;
 
-import java.util.HashMap;
-import java.util.Map;
-
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalLocator;
 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /*
  * HwvtepDeviceInfo is used to store some of the table entries received
@@ -35,12 +40,55 @@ import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
  *
  */
 public class HwvtepDeviceInfo {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HwvtepDeviceInfo.class);
+
+    public enum DeviceDataStatus {
+        IN_TRANSIT,
+        UNAVAILABLE,
+        AVAILABLE
+    }
+
+    public static class DeviceData {
+        private final InstanceIdentifier key;
+        private final UUID uuid;
+        private final Object data;
+        private final DeviceDataStatus status;
+
+        public DeviceData(InstanceIdentifier key, UUID uuid, Object data, DeviceDataStatus status) {
+            this.data = data;
+            this.key = key;
+            this.status = status;
+            this.uuid = uuid;
+        }
+
+        public Object getData() {
+            return data;
+        }
+
+        public DeviceDataStatus getStatus() {
+            return status;
+        }
+
+        public UUID getUuid() {
+            return uuid;
+        }
+    }
+
+    //TODO remove this
     private Map<UUID, LogicalSwitch> logicalSwitches = null;
     private Map<UUID, PhysicalSwitch> physicalSwitches = null;
     private Map<UUID, PhysicalLocator> physicalLocators = null;
     private Map<UUID, UUID> mapTunnelToPhysicalSwitch = null;
 
-    public HwvtepDeviceInfo() {
+    private HwvtepConnectionInstance connectionInstance;
+
+    private Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> configKeyVsData = new ConcurrentHashMap<>();
+    private Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> opKeyVsData = new ConcurrentHashMap<>();
+    private Map<Class<? extends Identifiable>, Map<UUID, Object>> uuidVsData = new ConcurrentHashMap<>();
+
+    public HwvtepDeviceInfo(HwvtepConnectionInstance hwvtepConnectionInstance) {
+        this.connectionInstance = hwvtepConnectionInstance;
         this.logicalSwitches = new HashMap<>();
         this.physicalSwitches = new HashMap<>();
         this.physicalLocators = new HashMap<>();
@@ -111,4 +159,56 @@ public class HwvtepDeviceInfo {
         return mapTunnelToPhysicalSwitch;
     }
 
+    public boolean isKeyInTransit(Class<? extends Identifiable> cls, InstanceIdentifier key) {
+        DeviceData deviceData = HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
+        return deviceData != null && DeviceDataStatus.IN_TRANSIT == deviceData.status;
+    }
+
+    public boolean isConfigDataAvailable(Class<? extends Identifiable> cls, InstanceIdentifier key) {
+        return HwvtepSouthboundUtil.getData(configKeyVsData, cls, key) != null;
+    }
+
+    public void updateConfigData(Class<? extends Identifiable> cls, InstanceIdentifier key, Object data) {
+        HwvtepSouthboundUtil.updateData(configKeyVsData, cls, key,
+                new DeviceData(key, null, data, DeviceDataStatus.AVAILABLE));
+    }
+
+    public void clearConfigData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
+        HwvtepSouthboundUtil.clearData(configKeyVsData, cls, key);
+    }
+
+    public void markKeyAsInTransit(Class<? extends Identifiable> cls, InstanceIdentifier key) {
+        HwvtepSouthboundUtil.updateData(opKeyVsData, cls, key,
+                new DeviceData(key, null, null, DeviceDataStatus.IN_TRANSIT));
+    }
+
+    public void updateDeviceOpData(Class<? extends Identifiable> cls, InstanceIdentifier key, UUID uuid, Object data) {
+        HwvtepSouthboundUtil.updateData(opKeyVsData, cls, key,
+                new DeviceData(key, uuid, data, DeviceDataStatus.AVAILABLE));
+        HwvtepSouthboundUtil.updateData(uuidVsData, cls, uuid, data);
+    }
+
+    public void clearDeviceOpData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
+        DeviceData deviceData = HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
+        if (deviceData != null && deviceData.uuid != null) {
+            HwvtepSouthboundUtil.clearData(uuidVsData, cls, deviceData.uuid);
+        }
+        HwvtepSouthboundUtil.clearData(opKeyVsData, cls, key);
+    }
+
+    public Object getDeviceOpData(Class<? extends Identifiable> cls, UUID uuid) {
+        return HwvtepSouthboundUtil.getData(uuidVsData, cls, uuid);
+    }
+
+    public DeviceData getDeviceOpData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
+        return HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
+    }
+
+    public UUID getUUID(Class<? extends Identifiable> cls, InstanceIdentifier key) {
+        DeviceData data = HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
+        if (data != null) {
+            return data.uuid;
+        }
+        return null;
+    }
 }
index 033bf73efe360fd918a0ecf31d8681e388e38ed1..f6300ec9c371d7b31c488a89aee8b49ef8e1cc8e 100644 (file)
@@ -8,6 +8,9 @@
 
 package org.opendaylight.ovsdb.hwvtepsouthbound;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
@@ -19,16 +22,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hw
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalSwitchAttributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.CheckedFuture;
-
-import java.util.concurrent.ExecutionException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 public class HwvtepSouthboundUtil {
 
@@ -137,4 +138,47 @@ public class HwvtepSouthboundUtil {
     public static void schemaMismatchLog(String column, String table, SchemaVersionMismatchException ex) {
         LOG.debug(SCHEMA_VERSION_MISMATCH, column, table, "hw_vtep", ex.getMessage());
     }
+
+    public static <KeyType, D> void updateData(Map<Class<? extends Identifiable>, Map<KeyType, D>> map,
+                                               Class<? extends Identifiable> cls, KeyType key, D data) {
+        if (key == null) {
+            return;
+        }
+        if (!map.containsKey(cls)) {
+            map.put(cls, new ConcurrentHashMap<>());
+        }
+        map.get(cls).put(key, data);
+    }
+
+    public static <KeyType, D> D getData(Map<Class<? extends Identifiable>, Map<KeyType, D>> map,
+                                         Class<? extends Identifiable> cls, KeyType key) {
+        if (key == null) {
+            return null;
+        }
+        if (map.containsKey(cls)) {
+            return map.get(cls).get(key);
+        }
+        return null;
+    }
+
+    public static <KeyType, D> boolean containsKey(Map<Class<? extends Identifiable>, Map<KeyType, D>> map,
+                                                   Class<? extends Identifiable> cls, KeyType key) {
+        if (key == null) {
+            return false;
+        }
+        if (map.containsKey(cls)) {
+            return map.get(cls).containsKey(key);
+        }
+        return false;
+    }
+
+    public static <KeyType, D> void clearData(Map<Class<? extends Identifiable>, Map<KeyType, D>> map,
+                                              Class<? extends Identifiable> cls, KeyType key) {
+        if (key == null) {
+            return;
+        }
+        if (map.containsKey(cls)) {
+            map.get(cls).remove(key);
+        }
+    }
 }
index 3153cab15bd4aae0c032d9b739867841314fe5fc..efecef985d66dfc4b8912550575eea8ed7bc2fe2 100644 (file)
@@ -8,16 +8,14 @@
 
 package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
 
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo;
 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
@@ -42,19 +40,32 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hw
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelsKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 //TODO: need to be optimized, get entry by iid not name
 public class HwvtepOperationalState {
+
     private static final Logger LOG = LoggerFactory.getLogger(HwvtepOperationalState.class);
+
     private Map<InstanceIdentifier<Node>, Node> operationalNodes = new HashMap<>();
     private ReadWriteTransaction transaction;
     HashMap<InstanceIdentifier<TerminationPoint>, UUID> inflightLocators = Maps.newHashMap();
+    private HwvtepDeviceInfo deviceInfo;
+    private HwvtepConnectionInstance connectionInstance;
+    private Map<Class<? extends Identifiable>, Map<InstanceIdentifier, UUID>> currentTxUUIDs = new ConcurrentHashMap<>();
+    private Map<Class<? extends Identifiable>, Map<InstanceIdentifier, Boolean>> currentTxDeletedKeys = new ConcurrentHashMap<>();
 
     public HwvtepOperationalState(DataBroker db, Collection<DataTreeModification<Node>> changes) {
         Map<InstanceIdentifier<Node>, Node> nodeCreateOrUpdate =
@@ -93,7 +104,17 @@ public class HwvtepOperationalState {
         }
     }
 
-    private Optional<Node> getGlobalNode(InstanceIdentifier<?> iid) {
+    public HwvtepOperationalState(HwvtepConnectionInstance connectionInstance) {
+        this.connectionInstance = connectionInstance;
+        this.deviceInfo = connectionInstance.getDeviceInfo();
+        transaction = connectionInstance.getDataBroker().newReadWriteTransaction();
+        Optional<Node> readNode = HwvtepSouthboundUtil.readNode(transaction, connectionInstance.getInstanceIdentifier());
+        if (readNode.isPresent()) {
+            operationalNodes.put(connectionInstance.getInstanceIdentifier(), readNode.get());
+        }
+    }
+
+    public Optional<Node> getGlobalNode(InstanceIdentifier<?> iid) {
         InstanceIdentifier<Node> nodeIid = iid.firstIdentifierOf(Node.class);
         return Optional.fromNullable(operationalNodes.get(nodeIid));
     }
@@ -173,7 +194,7 @@ public class HwvtepOperationalState {
             List<TerminationPoint> tpList = nodeOptional.get();
             for (TerminationPoint tp : tpList) {
                 HwvtepPhysicalPortAugmentation hppAugmentation = tp.getAugmentation(HwvtepPhysicalPortAugmentation.class);
-                if (hppAugmentation.getHwvtepNodeName().equals(hwvtepNodeName)) {
+                if (hppAugmentation != null && hppAugmentation.getHwvtepNodeName().equals(hwvtepNodeName)) {
                     return Optional.fromNullable(hppAugmentation);
                 }
             }
@@ -189,7 +210,7 @@ public class HwvtepOperationalState {
             List<TerminationPoint> tpList = nodeOptional.get();
             for (TerminationPoint tp : tpList) {
                 HwvtepPhysicalLocatorAugmentation hppAugmentation = tp.getAugmentation(HwvtepPhysicalLocatorAugmentation.class);
-                if (hppAugmentation.getDstIp().equals(dstIp)
+                if (hppAugmentation != null && hppAugmentation.getDstIp().equals(dstIp)
                         && hppAugmentation.getEncapsulationType().equals(encapType)) {
                     return Optional.fromNullable(hppAugmentation);
                 }
@@ -308,4 +329,37 @@ public class HwvtepOperationalState {
     public UUID getPhysicalLocatorInFlight(InstanceIdentifier<TerminationPoint> iid) {
         return inflightLocators.get(iid);
     }
+
+    public HwvtepConnectionInstance getConnectionInstance() {
+        return connectionInstance;
+    }
+
+    public HwvtepDeviceInfo getDeviceInfo() {
+        return deviceInfo;
+    }
+
+    public void updateCurrentTxData(Class<? extends Identifiable> cls, InstanceIdentifier key, UUID uuid) {
+        HwvtepSouthboundUtil.updateData(currentTxUUIDs, cls, key, uuid);
+        deviceInfo.markKeyAsInTransit(cls, key);
+    }
+
+    public void updateCurrentTxDeleteData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
+        HwvtepSouthboundUtil.updateData(currentTxDeletedKeys, cls, key, Boolean.TRUE);
+    }
+
+    public UUID getUUIDFromCurrentTx(Class<? extends Identifiable> cls, InstanceIdentifier key) {
+        return HwvtepSouthboundUtil.getData(currentTxUUIDs, cls, key);
+    }
+
+    public boolean isKeyPartOfCurrentTx(Class<? extends Identifiable> cls, InstanceIdentifier key) {
+        return HwvtepSouthboundUtil.containsKey(currentTxUUIDs, cls, key);
+    }
+
+    public Set<InstanceIdentifier> getDeletedKeysInCurrentTx(Class<? extends Identifiable> cls) {
+        if (currentTxDeletedKeys.containsKey(cls)) {
+            return currentTxDeletedKeys.get(cls).keySet();
+        }
+        return Collections.EMPTY_SET;
+    }
+
 }
index ae0a87c8bce8a31babd44eea75355dc4a0ce5b41..576f7002392aa742ea1cf8ef546e0e2a75c4322c 100644 (file)
@@ -97,16 +97,16 @@ public class DataChangeListenerTestBase extends AbstractDataBrokerTest {
          *  topology.rev131021.node.attributes.SupportingNode$StreamWriter: frozen class (cannot edit)
          */
         if (dataBroker == null) {
-            dataBroker = getDataBroker();
+            dataBroker = super.getDataBroker();
         }
         entityOwnershipService = mock(EntityOwnershipService.class);
+        nodeUuid = java.util.UUID.randomUUID().toString();
+        nodeIid = createInstanceIdentifier(nodeUuid);
         loadSchema();
         mockConnectionInstance();
         mockConnectionManager();
         mockOperations();
 
-        nodeUuid = java.util.UUID.randomUUID().toString();
-        nodeIid = createInstanceIdentifier(nodeUuid);
         addNode(OPERATIONAL);
         addNode(CONFIGURATION);
         hwvtepDataChangeListener = new HwvtepDataChangeListener(dataBroker, hwvtepConnectionManager);
@@ -151,12 +151,14 @@ public class DataChangeListenerTestBase extends AbstractDataBrokerTest {
         connectionInstance = PowerMockito.mock(HwvtepConnectionInstance.class, Mockito.CALLS_REAL_METHODS);
         field(HwvtepConnectionInstance.class, "instanceIdentifier").set(connectionInstance, nodeIid);
         field(HwvtepConnectionInstance.class, "txInvoker").set(connectionInstance, transactionInvoker);
-        field(HwvtepConnectionInstance.class, "deviceInfo").set(connectionInstance, new HwvtepDeviceInfo());
+        field(HwvtepConnectionInstance.class, "deviceInfo").set(connectionInstance, new HwvtepDeviceInfo(connectionInstance));
         field(HwvtepConnectionInstance.class, "client").set(connectionInstance, ovsdbClient);
         when(connectionInstance.getConnectionInfo()).thenReturn(connectionInfo);
         when(connectionInstance.getConnectionInfo().getRemoteAddress()).thenReturn(mock(InetAddress.class));
         when(connectionInstance.getInstanceIdentifier()).thenReturn(nodeIid);
         doReturn(listenableDbSchema).when(connectionInstance).getSchema(anyString());
+        when(connectionInstance.getDataBroker()).thenReturn(dataBroker);
+        when(connectionInstance.getInstanceIdentifier()).thenReturn(nodeIid);
         connectionInstance.createTransactInvokers();
     }
 
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepOperationalStateTest.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepOperationalStateTest.java
new file mode 100644 (file)
index 0000000..77ad5c4
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.HwvtepOperationalState;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.operations.Operations;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitchesKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.when;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({HwvtepConnectionInstance.class, HwvtepConnectionManager.class, Operations.class})
+public class HwvtepOperationalStateTest extends DataChangeListenerTestBase {
+
+    UUID uuid = new UUID("ls0");
+
+    @Test
+    public void testUpdateCurrentTxData() throws Exception {
+        InstanceIdentifier<LogicalSwitches> lsIid = nodeIid.augmentation(HwvtepGlobalAugmentation.class).
+                child(LogicalSwitches.class, new LogicalSwitchesKey(new HwvtepNodeName("ls0")));
+
+        HwvtepOperationalState opState = new HwvtepOperationalState(connectionInstance);
+
+        UUID resultUuid = opState.getUUIDFromCurrentTx(LogicalSwitches.class, lsIid);
+        assertNull(resultUuid);
+
+        opState.updateCurrentTxData(LogicalSwitches.class, lsIid, uuid);
+        resultUuid = opState.getUUIDFromCurrentTx(LogicalSwitches.class, lsIid);
+        assertEquals(uuid, resultUuid);
+
+        boolean result = opState.getDeviceInfo().isKeyInTransit(LogicalSwitches.class, lsIid);
+        assertTrue(result);
+
+        opState.getDeviceInfo().updateDeviceOpData(LogicalSwitches.class, lsIid, uuid, lsIid);
+        result = opState.getDeviceInfo().isKeyInTransit(LogicalSwitches.class, lsIid);
+        assertFalse(result);
+
+        result = opState.getDeviceInfo().isConfigDataAvailable(LogicalSwitches.class, lsIid);
+        assertFalse(result);
+
+        opState.getDeviceInfo().updateConfigData(LogicalSwitches.class, lsIid, null);
+        result = opState.getDeviceInfo().isConfigDataAvailable(LogicalSwitches.class, lsIid);
+        assertTrue(result);
+    }
+}