/* * Copyright (c) 2016 Cisco and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.fd.honeycomb.v3po.translate.v3po.vpp; import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; import com.google.common.base.Optional; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import io.fd.honeycomb.v3po.translate.MappingContext; import io.fd.honeycomb.v3po.translate.ModificationCache; import io.fd.honeycomb.v3po.translate.impl.write.CompositeRootWriter; import io.fd.honeycomb.v3po.translate.util.write.DelegatingWriterRegistry; import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; import io.fd.honeycomb.v3po.translate.write.WriteContext; import io.fd.honeycomb.v3po.translate.write.Writer; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomainsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.openvpp.jvpp.VppInvocationException; import org.openvpp.jvpp.dto.BridgeDomainAddDel; import org.openvpp.jvpp.dto.BridgeDomainAddDelReply; import org.openvpp.jvpp.future.FutureJVpp; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.ExecutionException; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; public class VppTest { private static final byte ADD_OR_UPDATE_BD = 1; private static final byte ZERO = 0; @Mock private FutureJVpp api; @Mock private WriteContext ctx; @Mock private MappingContext mappingContext; private DelegatingWriterRegistry rootRegistry; private CompositeRootWriter vppWriter; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); NamingContext bdContext = new NamingContext("generatedBdName", "test-instance"); final ModificationCache toBeReturned = new ModificationCache(); doReturn(toBeReturned).when(ctx).getModificationCache(); doReturn(mappingContext).when(ctx).getMappingContext(); vppWriter = VppUtils.getVppWriter(api, bdContext); rootRegistry = new DelegatingWriterRegistry( Collections.>singletonList(vppWriter)); } private BridgeDomains getBridgeDomains(String... name) { final List bdmns = Lists.newArrayList(); for (String s : name) { bdmns.add(new BridgeDomainBuilder() .setName(s) .setArpTermination(false) .setFlood(true) .setForward(false) .setLearn(true) .build()); } return new BridgeDomainsBuilder() .setBridgeDomain(bdmns) .build(); } private void whenBridgeDomainAddDelThen(final int retval) throws ExecutionException, VppInvocationException, InterruptedException { final CompletionStage replyCS = mock(CompletionStage.class); final CompletableFuture replyFuture = mock(CompletableFuture.class); when(replyCS.toCompletableFuture()).thenReturn(replyFuture); final BridgeDomainAddDelReply reply = new BridgeDomainAddDelReply(); when(replyFuture.get()).thenReturn(reply); when(api.bridgeDomainAddDel(any(BridgeDomainAddDel.class))).thenReturn(replyCS); } private void verifyBridgeDomainAddDel(final BridgeDomain bd, final int bdId) throws VppInvocationException { final byte arpTerm = BridgeDomainTestUtils.booleanToByte(bd.isArpTermination()); final byte flood = BridgeDomainTestUtils.booleanToByte(bd.isFlood()); final byte forward = BridgeDomainTestUtils.booleanToByte(bd.isForward()); final byte learn = BridgeDomainTestUtils.booleanToByte(bd.isLearn()); final byte uuf = BridgeDomainTestUtils.booleanToByte(bd.isUnknownUnicastFlood()); // TODO adding equals methods for jvpp DTOs would make ArgumentCaptor usage obsolete ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(BridgeDomainAddDel.class); verify(api).bridgeDomainAddDel(argumentCaptor.capture()); final BridgeDomainAddDel actual = argumentCaptor.getValue(); assertEquals(arpTerm, actual.arpTerm); assertEquals(flood, actual.flood); assertEquals(forward, actual.forward); assertEquals(learn, actual.learn); assertEquals(uuf, actual.uuFlood); assertEquals(ADD_OR_UPDATE_BD, actual.isAdd); assertEquals(bdId, actual.bdId); } private void verifyBridgeDomainDeleteWasInvoked(final int bdId) throws VppInvocationException { ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(BridgeDomainAddDel.class); verify(api).bridgeDomainAddDel(argumentCaptor.capture()); final BridgeDomainAddDel actual = argumentCaptor.getValue(); assertEquals(bdId, actual.bdId); assertEquals(ZERO, actual.arpTerm); assertEquals(ZERO, actual.flood); assertEquals(ZERO, actual.forward); assertEquals(ZERO, actual.learn); assertEquals(ZERO, actual.uuFlood); assertEquals(ZERO, actual.isAdd); } @Test public void writeVppUsingRootRegistry() throws Exception { final int bdId = 1; final BridgeDomains bdn1 = getBridgeDomains("bdn1"); whenBridgeDomainAddDelThen(0); doReturn(Optional .absent()).when(mappingContext).read(getMappingIid("bdn1", "test-instance").firstIdentifierOf(Mappings.class)); rootRegistry.update( InstanceIdentifier.create(Vpp.class), null, new VppBuilder().setBridgeDomains(bdn1).build(), ctx); verifyBridgeDomainAddDel(Iterators.getOnlyElement(bdn1.getBridgeDomain().iterator()), bdId); } @Test public void writeVppUsingVppWriter() throws Exception { final int bdId = 1; final BridgeDomains bdn1 = getBridgeDomains("bdn1"); whenBridgeDomainAddDelThen(0); doReturn(Optional .absent()).when(mappingContext).read(getMappingIid("bdn1", "test-instance").firstIdentifierOf(Mappings.class)); vppWriter.update(InstanceIdentifier.create(Vpp.class), null, new VppBuilder().setBridgeDomains(bdn1).build(), ctx); verifyBridgeDomainAddDel(Iterators.getOnlyElement(bdn1.getBridgeDomain().iterator()), bdId); verify(mappingContext).put(getMappingIid("bdn1", "test-instance"), getMapping("bdn1", 1).get()); } @Test public void writeVppFromRoot() throws Exception { final BridgeDomains bdn1 = getBridgeDomains("bdn1"); final int bdId = 1; final Vpp vpp = new VppBuilder().setBridgeDomains(bdn1).build(); doReturn(Optional .absent()).when(mappingContext).read(getMappingIid("bdn1", "test-instance").firstIdentifierOf(Mappings.class)); whenBridgeDomainAddDelThen(0); rootRegistry.update(Collections.emptyMap(), Collections., DataObject>singletonMap(InstanceIdentifier.create(Vpp.class), vpp), ctx); verifyBridgeDomainAddDel(Iterators.getOnlyElement(bdn1.getBridgeDomain().iterator()), bdId); } @Test public void deleteVpp() throws Exception { final String bdName = "bdn1"; final BridgeDomains bdn1 = getBridgeDomains(bdName); final int bdId = 1; whenBridgeDomainAddDelThen(0); doReturn(getMapping(bdName, bdId)).when(mappingContext).read(getMappingIid(bdName, "test-instance")); rootRegistry.update( InstanceIdentifier.create(Vpp.class), new VppBuilder().setBridgeDomains(bdn1).build(), null, ctx); verifyBridgeDomainDeleteWasInvoked(bdId); } @Test public void updateVppNoActualChange() throws Exception { rootRegistry.update( InstanceIdentifier.create(Vpp.class), new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(), new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(), ctx); verifyZeroInteractions(api); } @Test public void writeUpdate() throws Exception { final String bdName = "bdn1"; final int bdn1Id = 1; doReturn(getMapping(bdName, bdn1Id)).when(mappingContext).read(getMappingIid(bdName, "test-instance")); final BridgeDomains domainsBefore = getBridgeDomains(bdName); final BridgeDomain bdn1Before = domainsBefore.getBridgeDomain().get(0); final BridgeDomain bdn1After = new BridgeDomainBuilder(bdn1Before).setFlood(!bdn1Before.isFlood()).build(); final BridgeDomains domainsAfter = new BridgeDomainsBuilder() .setBridgeDomain(Collections.singletonList(bdn1After)) .build(); whenBridgeDomainAddDelThen(0); rootRegistry.update( InstanceIdentifier.create(Vpp.class), new VppBuilder().setBridgeDomains(domainsBefore).build(), new VppBuilder().setBridgeDomains(domainsAfter).build(), ctx); // bdn1 is created with negated flood value verifyBridgeDomainAddDel(bdn1After, bdn1Id); } // TODO test unkeyed list // TODO test update of a child without dedicated writer }