From: Joakim Törnqvist Date: Wed, 17 Jan 2024 14:35:08 +0000 (+0000) Subject: New Package dealing with device rollback X-Git-Tag: 9.0.0~42^2~1 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=transportpce.git;a=commitdiff_plain;h=0a5e92dab0c7a79e3c7b446802d4551e53f943dc New Package dealing with device rollback Add a new class (TransactionHistory) capable of keeping track of created interfaces (during a service creation process) and rolling them back. The DeleteService class handles the rollback process. Passing in a subscriber (DeleteSubscriber) capable of tracking the process and creating a result. Pseudo code example public Result rollbackExample( OpenRoadmInterfaceFactory openRoadmInterfaceFactory, OpenRoadmInterfaces openRoadmInterfaces, CrossConnect crossConnect ) { History transactionHistory = new TransactionHistory(); String supportingOchInterface = openRoadmInterfaceFactory .createOpenRoadmOchInterface(...); transactionHistory.add( new DeviceInterface(nodeId, supportingOchInterface) ); transactionHistory.addInterfaces( nodeId, supportingOchInterface.split("#") ); Result rollbackResult = new FailedRollbackResult(); Subscriber deleteSubscriber = new DeleteSubscriber(rollbackResult); transactionHistory.rollback( new DeleteService( crossConnect, openRoadmInterfaces, deleteSubscriber ) ); return rollbackResult.renderRollbackOutput(); } JIRA: TRNSPRTPCE-615 Change-Id: I723e42628e8de0b45ab9160b5b8c366497c0f550 Signed-off-by: Joakim Törnqvist --- diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/Connection.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/Connection.java new file mode 100644 index 000000000..ad04ae734 --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/Connection.java @@ -0,0 +1,74 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction; + +import java.util.List; +import java.util.Objects; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.Delete; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Connection transaction. + * + *

+ * i.e. a class tracking a connection. + */ +public class Connection implements Transaction { + + private static final Logger LOG = LoggerFactory.getLogger(Connection.class); + private final String deviceId; + private final String connectionNumber; + private final boolean isOtn; + + public Connection(String deviceId, String connectionNumber, boolean isOtn) { + this.deviceId = deviceId; + this.connectionNumber = connectionNumber; + this.isOtn = isOtn; + } + + @Override + public boolean rollback(Delete delete) { + List supportingInterfaces = delete.deleteCrossConnect(deviceId, connectionNumber, isOtn); + + if (supportingInterfaces == null || supportingInterfaces.size() == 0) { + return false; + } + + LOG.info("Supporting interfaces {} affected by rollback on {} {}", + String.join(", ", supportingInterfaces), deviceId, connectionNumber); + + return true; + + } + + @Override + public String description() { + return String.format("Connection %s connection number %s isOtn %s", deviceId, + connectionNumber, isOtn); + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (!(object instanceof Connection)) { + return false; + } + Connection that = (Connection) object; + return isOtn == that.isOtn && Objects.equals(deviceId, that.deviceId) + && Objects.equals(connectionNumber, that.connectionNumber); + } + + @Override + public int hashCode() { + return Objects.hash(deviceId, connectionNumber, isOtn); + } +} diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/DeviceInterface.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/DeviceInterface.java new file mode 100644 index 000000000..8bcc2c161 --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/DeviceInterface.java @@ -0,0 +1,52 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction; + +import java.util.Objects; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.Delete; + +public class DeviceInterface implements Transaction { + + private final String nodeId; + + private final String interfaceId; + + public DeviceInterface(String nodeId, String interfaceId) { + this.nodeId = nodeId; + this.interfaceId = interfaceId; + } + + @Override + public boolean rollback(Delete delete) { + return delete.deleteInterface(nodeId, interfaceId); + } + + @Override + public String description() { + return String.format("Node: %s interface id: %s", nodeId, interfaceId); + } + + @Override + public int hashCode() { + return Objects.hash(nodeId, interfaceId); + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (!(object instanceof DeviceInterface)) { + return false; + } + DeviceInterface that = (DeviceInterface) object; + return Objects.equals(nodeId, that.nodeId) && Objects.equals(interfaceId, + that.interfaceId); + } +} \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/Transaction.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/Transaction.java new file mode 100644 index 000000000..d1300e37b --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/Transaction.java @@ -0,0 +1,29 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction; + +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.Delete; + +/** + * Any class wishing to keep track of transactions + * may implement this interface. + */ +public interface Transaction { + + /** + * Rollback this transaction. + */ + boolean rollback(Delete delete); + + String description(); + + int hashCode(); + + boolean equals(Object object); +} \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/Delete.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/Delete.java new file mode 100644 index 000000000..95fcdff3e --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/Delete.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction.delete; + +import java.util.List; + +/** + * A class capable of deleting service connections/interfaces + * may implement this interface. + */ +public interface Delete { + + /** + * Delete cross connection. + * Typically, deleted before interfaces. + */ + List deleteCrossConnect(String deviceId, String connectionNumber, boolean isOtn); + + /** + * Delete an interface. + * Typically, deleted after the cross connection. + */ + boolean deleteInterface(String nodeId, String interfaceId); +} \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/DeleteService.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/DeleteService.java new file mode 100644 index 000000000..62af4bf4a --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/DeleteService.java @@ -0,0 +1,66 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction.delete; + +import java.util.ArrayList; +import java.util.List; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.transportpce.common.crossconnect.CrossConnect; +import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaceException; +import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaces; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DeleteService implements Delete { + + private final CrossConnect crossConnect; + private final OpenRoadmInterfaces openRoadmInterfaces; + + private final Subscriber subscriber; + + private static final Logger LOG = LoggerFactory.getLogger(DeleteService.class); + + public DeleteService( + CrossConnect crossConnect, + OpenRoadmInterfaces openRoadmInterfaces, + Subscriber subscriber) { + this.crossConnect = crossConnect; + this.openRoadmInterfaces = openRoadmInterfaces; + this.subscriber = subscriber; + } + + @Override + public @NonNull List deleteCrossConnect(String deviceId, String connectionNumber, + boolean isOtn) { + List result = crossConnect.deleteCrossConnect(deviceId, connectionNumber, isOtn); + + if (result == null) { + subscriber.result(false, deviceId, connectionNumber); + return new ArrayList<>(); + } + + subscriber.result(true, deviceId, connectionNumber); + + return result; + } + + @Override + public boolean deleteInterface(String nodeId, String interfaceId) { + try { + openRoadmInterfaces.deleteInterface(nodeId, interfaceId); + + subscriber.result(true, nodeId, interfaceId); + return true; + } catch (OpenRoadmInterfaceException e) { + LOG.error("Failed rolling back {} {}", nodeId, interfaceId); + subscriber.result(false, nodeId, interfaceId); + return false; + } + } +} \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/DeleteSubscriber.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/DeleteSubscriber.java new file mode 100644 index 000000000..886b45979 --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/DeleteSubscriber.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction.delete; + +public class DeleteSubscriber implements Subscriber { + + private final Result result; + + public DeleteSubscriber(Result result) { + this.result = result; + } + + @Override + public void result(Boolean success, String nodeId, String interfaceId) { + + result.add(success, nodeId, interfaceId); + + } + +} \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/FailedRollbackResult.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/FailedRollbackResult.java new file mode 100644 index 000000000..5637879d6 --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/FailedRollbackResult.java @@ -0,0 +1,66 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction.delete; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.RendererRollbackOutput; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.RendererRollbackOutputBuilder; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.renderer.rollback.output.FailedToRollback; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.renderer.rollback.output.FailedToRollbackBuilder; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.renderer.rollback.output.FailedToRollbackKey; + +public class FailedRollbackResult implements Result { + + private final Map> failedRollback = Collections.synchronizedMap( + new HashMap<>()); + + @Override + public boolean add(boolean success, String nodeId, String interfaceId) { + + if (success) { + return false; + } + + if (!failedRollback.containsKey(nodeId)) { + failedRollback.put(nodeId, new LinkedHashSet<>()); + } + + return failedRollback.get(nodeId).add(interfaceId); + } + + @Override + public RendererRollbackOutput renderRollbackOutput() { + + Map failedToRollbackList = new HashMap<>(); + + for (Entry> entry : failedRollback.entrySet()) { + + FailedToRollback failedToRollack = new FailedToRollbackBuilder() + .withKey(new FailedToRollbackKey(entry.getKey())) + .setNodeId(entry.getKey()) + .setInterface(entry.getValue()) + .build(); + + failedToRollbackList.put(failedToRollack.key(), failedToRollack); + + } + + return new RendererRollbackOutputBuilder() + .setSuccess(failedRollback.isEmpty()) + .setFailedToRollback(failedToRollbackList) + .build(); + + } + +} \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/Result.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/Result.java new file mode 100644 index 000000000..fb77027cf --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/Result.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction.delete; + +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.RendererRollbackOutput; + +public interface Result { + + boolean add(boolean success, String nodeId, String interfaceId); + + RendererRollbackOutput renderRollbackOutput(); + +} \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/Subscriber.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/Subscriber.java new file mode 100644 index 000000000..8e83d16ca --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/delete/Subscriber.java @@ -0,0 +1,15 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction.delete; + +public interface Subscriber { + + void result(Boolean success, String nodeId, String interfaceId); + +} \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/history/History.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/history/History.java new file mode 100644 index 000000000..fd2646afe --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/history/History.java @@ -0,0 +1,76 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction.history; + +import java.util.List; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.Transaction; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.Delete; + +public interface History { + + /** + * Add transaction. + * + *

+ * Only accepts the transaction if this History + * object doesn't already contain the object. + * + * @return true if the transaction was added. + */ + boolean add(Transaction transaction); + + /** + * A list of transactions. + * + *

+ * Will only accept unique transactions. + * @return true if all transactions was added. false if one or more transactions was rejected. + */ + boolean add(List transactions); + + /** + * Add an array of interface transactions. + * + *

+ * Duplicate interface ids, null or empty strings + * are silently ignored. + * @return may return false + */ + boolean addInterfaces(String nodeId, String interfaceId); + + /** + * Add an array of interface transactions. + * + *

+ * Duplicate interface ids, null or empty strings + * are silently ignored. + * @return may return false + */ + boolean addInterfaces(String nodeId, String[] interfaceIds); + + /** + * Add a list of interface transactions. + * + *

+ * Duplicate interface ids, null or empty strings + * are silently ignored. + */ + boolean addInterfaces(String nodeId, List interfaceIds); + + /** + * Rollback all transactions. + * + *

+ * Typically, the transactions are rolled back in reverse + * order, but the implementing class may choose a different + * logic. + */ + boolean rollback(Delete delete); + +} \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/history/NonStickHistoryMemory.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/history/NonStickHistoryMemory.java new file mode 100644 index 000000000..71d8f74de --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/history/NonStickHistoryMemory.java @@ -0,0 +1,63 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction.history; + +import java.util.List; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.Transaction; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.Delete; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Goldfish implementation of the History interface. + * + *

+ * This implementation simply doesn't track anything. + * Most useful for backwards compatibility reasons. + */ +public class NonStickHistoryMemory implements History { + + private static final Logger LOG = LoggerFactory.getLogger(NonStickHistoryMemory.class); + + @Override + public boolean add(Transaction transaction) { + LOG.warn("Transaction history disabled. Ignoring '{}'.", transaction.description()); + return false; + } + + @Override + public boolean add(List transactions) { + LOG.warn("Transaction history disabled. No rollback executed."); + return false; + } + + @Override + public boolean addInterfaces(String nodeId, String interfaceId) { + LOG.warn("Transaction history disabled."); + return false; + } + + @Override + public boolean addInterfaces(String nodeId, String[] interfaceIds) { + LOG.warn("Transaction history disabled."); + return false; + } + + @Override + public boolean addInterfaces(String nodeId, List interfaceIds) { + LOG.warn("Transaction history disabled."); + return false; + } + + @Override + public boolean rollback(Delete delete) { + LOG.warn("Transaction history disabled. No rollback executed."); + return false; + } +} \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/history/TransactionHistory.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/history/TransactionHistory.java new file mode 100644 index 000000000..a1565fc88 --- /dev/null +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/history/TransactionHistory.java @@ -0,0 +1,115 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction.history; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.DeviceInterface; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.Transaction; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.Delete; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A class keeping track of transaction history. + * + *

+ * A transaction can be something like an interface or a roadm connection, that may need to be + * rolled back in the future. + */ +public class TransactionHistory implements History { + + private static final Logger LOG = LoggerFactory.getLogger(TransactionHistory.class); + Set transactionHistory = Collections.synchronizedSet(new LinkedHashSet<>()); + + @Override + public boolean add(Transaction transaction) { + + boolean result = transactionHistory.add(transaction); + + if (result) { + LOG.info("Adding {}", transaction.description()); + } else { + LOG.warn("Transaction {} not added.", transaction.description()); + } + + return result; + } + + @Override + public boolean add(List transactions) { + Set results = new HashSet<>(transactions.size()); + + for (Transaction transaction : transactions) { + results.add(add(transaction)); + } + + return results.stream().allMatch(i -> (i.equals(Boolean.TRUE))); + } + + @Override + public boolean addInterfaces(String nodeId, String interfaceId) { + return addInterfaces(nodeId, Collections.singletonList(interfaceId)); + } + + @Override + public boolean addInterfaces(String nodeId, String[] interfaceIds) { + + return addInterfaces(nodeId, Arrays.asList(interfaceIds)); + + } + + @Override + public boolean addInterfaces(String nodeId, List interfaceIds) { + + Set results = new HashSet<>(); + Set unique = new LinkedHashSet<>(); + + for (String interfaceId : interfaceIds) { + if (interfaceId != null && !interfaceId.trim().isEmpty()) { + unique.add(interfaceId.trim()); + } + } + + for (String interfaceId : unique) { + results.add(this.add(new DeviceInterface(nodeId, interfaceId))); + } + + return results.stream().allMatch(i -> (i.equals(Boolean.TRUE))); + + } + + @Override + public boolean rollback(Delete delete) { + + LOG.info("History contains {} items. Rolling them back in reverse order.", + transactionHistory.size()); + + List reverse = new ArrayList<>(transactionHistory); + + Collections.reverse(reverse); + + boolean success = true; + + for (Transaction transaction : reverse) { + LOG.info("Rolling back {}", transaction.description()); + if (!transaction.rollback(delete)) { + success = false; + } + } + + return success; + + } +} \ No newline at end of file diff --git a/renderer/src/test/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/ConnectionTest.java b/renderer/src/test/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/ConnectionTest.java new file mode 100644 index 000000000..a3ba1e7cb --- /dev/null +++ b/renderer/src/test/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/ConnectionTest.java @@ -0,0 +1,86 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction; + +import java.util.ArrayList; +import java.util.List; +import org.junit.Assert; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.Delete; + +class ConnectionTest { + + @Test + void rollback() { + Delete delete = Mockito.mock(Delete.class); + Mockito.when(delete.deleteCrossConnect("ROADM-A", "DEG1", false)) + .thenReturn(List.of("Interface1")); + + Connection n1 = new Connection("ROADM-A", "DEG1", false); + + Assert.assertTrue(n1.rollback(delete)); + + Mockito.verify(delete, Mockito.times(1)) + .deleteCrossConnect("ROADM-A", "DEG1", false); + } + + @Test + void testTwoObjectsWithSameInformationIsEqual() { + Connection n1 = new Connection("ROADM-A", "DEG1", false); + Connection n2 = new Connection("ROADM-A", "DEG1", false); + + Assert.assertTrue(n1.equals(n2)); + } + + @Test + void testTwoObjectsWithDifferentInformationIsNotEqual() { + Connection n1 = new Connection("ROADM-A", "DEG1", true); + Connection n2 = new Connection("ROADM-A", "DEG1", false); + + Assert.assertFalse(n1.equals(n2)); + } + + @Test + void testTwoDifferentRoadmNodesAreNotEqual() { + Connection n1 = new Connection("ROADM-A", "DEG1", false); + Connection n2 = new Connection("ROADM-B", "DEG1", false); + + Assert.assertFalse(n1.equals(n2)); + } + + + @Test + void deleteReturnNull() { + Delete delete = Mockito.mock(Delete.class); + Mockito.when(delete.deleteCrossConnect("ROADM-A", "DEG1", false)) + .thenReturn(null); + + Connection n1 = new Connection("ROADM-A", "DEG1", false); + + Assert.assertFalse(n1.rollback(delete)); + + Mockito.verify(delete, Mockito.times(1)) + .deleteCrossConnect("ROADM-A", "DEG1", false); + } + + @Test + void deleteReturnEmptyList() { + Delete delete = Mockito.mock(Delete.class); + Mockito.when(delete.deleteCrossConnect("ROADM-A", "DEG1", false)) + .thenReturn(new ArrayList<>()); + + Connection n1 = new Connection("ROADM-A", "DEG1", false); + + Assert.assertFalse(n1.rollback(delete)); + + Mockito.verify(delete, Mockito.times(1)) + .deleteCrossConnect("ROADM-A", "DEG1", false); + } +} \ No newline at end of file diff --git a/renderer/src/test/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/DeviceInterfaceTest.java b/renderer/src/test/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/DeviceInterfaceTest.java new file mode 100644 index 000000000..d0481ae67 --- /dev/null +++ b/renderer/src/test/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/DeviceInterfaceTest.java @@ -0,0 +1,44 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction; + +import org.junit.Assert; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.Delete; + +class DeviceInterfaceTest { + + @Test + void rollback() { + Delete delete = Mockito.mock(Delete.class); + Mockito.when(delete.deleteInterface("ROADM-A", "DEG1")).thenReturn(true); + + DeviceInterface n1 = new DeviceInterface("ROADM-A", "DEG1"); + Assert.assertTrue(n1.rollback(delete)); + + Mockito.verify(delete, Mockito.times(1)).deleteInterface("ROADM-A", "DEG1"); + } + + @Test + void testTwoInterfacesAreEqual() { + DeviceInterface n1 = new DeviceInterface("ROADM-A", "DEG1"); + DeviceInterface n2 = new DeviceInterface("ROADM-A", "DEG1"); + + Assert.assertTrue(n1.equals(n2)); + } + + @Test + void testTwoInterfacesAreNotEqual() { + DeviceInterface n1 = new DeviceInterface("ROADM-A", "DEG1"); + DeviceInterface n2 = new DeviceInterface("ROADM-B", "DEG1"); + + Assert.assertFalse(n1.equals(n2)); + } +} \ No newline at end of file diff --git a/renderer/src/test/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/history/TransactionHistoryTest.java b/renderer/src/test/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/history/TransactionHistoryTest.java new file mode 100644 index 000000000..0adf41801 --- /dev/null +++ b/renderer/src/test/java/org/opendaylight/transportpce/renderer/provisiondevice/transaction/history/TransactionHistoryTest.java @@ -0,0 +1,143 @@ +/* + * Copyright © 2024 Smartoptics 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.transportpce.renderer.provisiondevice.transaction.history; + +import java.util.List; +import org.junit.Assert; +import org.junit.jupiter.api.Test; +import org.mockito.InOrder; +import org.mockito.Mockito; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.DeviceInterface; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.Transaction; +import org.opendaylight.transportpce.renderer.provisiondevice.transaction.delete.Delete; + +class TransactionHistoryTest { + + @Test + void add() { + Transaction transaction = Mockito.mock(Transaction.class); + History history = new TransactionHistory(); + + Assert.assertTrue(history.add(transaction)); + } + + @Test + void testDuplicateTransactionIsIgnored() { + + Transaction t1 = new DeviceInterface("ROADM-A", "DEG1"); + Transaction t2 = new DeviceInterface("ROADM-A", "DEG1"); + + History history = new TransactionHistory(); + + history.add(t1); + Assert.assertFalse(history.add(t2)); + } + + @Test + void testAddCollectionOfUniqueTransactions() { + Transaction t1 = new DeviceInterface("ROADM-A", "DEG1"); + Transaction t2 = new DeviceInterface("ROADM-A", "DEG2"); + + List transactions = List.of(t1, t2); + + History history = new TransactionHistory(); + + Assert.assertTrue(history.add(transactions)); + } + + @Test + void testAddCollectionOfDuplicateTransactions() { + Transaction t1 = new DeviceInterface("ROADM-A", "DEG1"); + Transaction t2 = new DeviceInterface("ROADM-A", "DEG1"); + + List transactions = List.of(t1, t2); + + History history = new TransactionHistory(); + + Assert.assertFalse(history.add(transactions)); + } + + @Test + void testAddUniqueStringOfInterfaceIds() { + String nodeId = "ROADM-A"; + String[] interfaces = new String[]{"DEG1", "DEG2"}; + + History history = new TransactionHistory(); + + Assert.assertTrue(history.addInterfaces(nodeId, interfaces)); + } + + @Test + void testAddDuplicateStringOfInterfaceIds() { + String nodeId = "ROADM-A"; + String[] interfaces = new String[]{"DEG1", "DEG1"}; + + History history = new TransactionHistory(); + + Assert.assertTrue(history.addInterfaces(nodeId, interfaces)); + + } + + @Test + void testAddDuplicateListOfInterfaceIds() { + String nodeId = "ROADM-A"; + List interfaces = List.of("DEG1", "DEG1"); + + History history = new TransactionHistory(); + + Assert.assertTrue(history.addInterfaces(nodeId, interfaces)); + + } + + @Test + void rollbackOneInterface() { + + String nodeId = "ROADM-A"; + List interfaces = List.of("DEG1", "DEG1"); + + History history = new TransactionHistory(); + history.addInterfaces(nodeId, interfaces); + + Delete delete = Mockito.mock(Delete.class); + Mockito.when(delete.deleteInterface("ROADM-A", "DEG1")).thenReturn(true); + + Assert.assertTrue(history.rollback(delete)); + + //Although the same interface was added twice, we only rollback once. + Mockito.verify(delete, Mockito.times(1)) + .deleteInterface("ROADM-A", "DEG1"); + } + + @Test + void rollbackTwoInterfacesInReverseOrderTheyWereAdded() { + + String nodeId = "ROADM-A"; + + //Note DEG1 is added before DEG2 + List interfaces = List.of("DEG1", "DEG2"); + + History history = new TransactionHistory(); + history.addInterfaces(nodeId, interfaces); + + Delete delete = Mockito.mock(Delete.class); + Mockito.when(delete.deleteInterface("ROADM-A", "DEG1")).thenReturn(true); + Mockito.when(delete.deleteInterface("ROADM-A", "DEG2")).thenReturn(true); + + Assert.assertTrue(history.rollback(delete)); + + //The rollback occurs in the reverse order. + // i.e. DEG2 before DEG1. + InOrder inOrder = Mockito.inOrder(delete); + inOrder.verify(delete, Mockito.times(1)) + .deleteInterface("ROADM-A", "DEG2"); + inOrder.verify(delete, Mockito.times(1)) + .deleteInterface("ROADM-A", "DEG1"); + + } +} \ No newline at end of file