org.midonet.brain.services.vxgw.VxLanFailoverTest.java Source code

Java tutorial

Introduction

Here is the source code for org.midonet.brain.services.vxgw.VxLanFailoverTest.java

Source

/*
 * Copyright 2014 Midokura SARL
 *
 * 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 org.midonet.brain.services.vxgw;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

import com.google.inject.Guice;
import com.google.inject.Injector;

import mockit.Expectations;
import mockit.Mocked;
import mockit.integration.junit4.JMockit;

import org.apache.commons.configuration.HierarchicalConfiguration;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import rx.Observable;
import rx.Subscription;

import org.midonet.brain.BrainTestUtils;
import org.midonet.brain.configuration.MidoBrainConfig;
import org.midonet.brain.southbound.vtep.VtepBroker;
import org.midonet.brain.southbound.vtep.VtepDataClient;
import org.midonet.brain.southbound.vtep.VtepDataClientFactory;
import org.midonet.brain.southbound.vtep.VtepException;
import org.midonet.cluster.DataClient;
import org.midonet.cluster.data.TunnelZone;
import org.midonet.cluster.data.VTEP;
import org.midonet.midolman.serialization.SerializationException;
import org.midonet.midolman.state.Directory;
import org.midonet.midolman.state.StateAccessException;
import org.midonet.midolman.state.ZookeeperConnectionWatcher;
import org.midonet.packets.IPv4Addr;
import org.midonet.util.functors.Callback;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

@RunWith(JMockit.class)
public class VxLanFailoverTest {
    private static final byte[] VTEP_MGMT_IP = { (byte) 192, (byte) 168 };
    private static final int VTEP_MGMT_PORT = 6632;

    private DataClient midoClient;
    private ZookeeperConnectionWatcher zkConnWatcher;

    private static final Subscription emptySubscription = Observable.empty().subscribe();

    @Mocked
    private VtepDataClient vtepClient;
    @Mocked
    private VtepDataClientFactory vtepDataClientFactory;
    @Mocked
    private MidoBrainConfig config;

    @Before
    public void setup() throws Exception {
        HierarchicalConfiguration config = new HierarchicalConfiguration();
        BrainTestUtils.fillTestConfig(config);
        Injector injector = Guice.createInjector(BrainTestUtils.modules(config));

        Directory directory = injector.getInstance(Directory.class);
        BrainTestUtils.setupZkTestDirectory(directory);

        midoClient = injector.getInstance(DataClient.class);
        zkConnWatcher = new ZookeeperConnectionWatcher();
    }

    @Test
    public void testFailoverOneVtep(@Mocked final VtepBroker vtepBroker) throws Exception {

        UUID tzId = createTunnelZone(1);
        IPv4Addr vtepId = createVtep(1, tzId);

        new Expectations() {
            {
                vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any);
                result = vtepClient;
                times = 1;

                VtepBroker vB1 = new VtepBroker(vtepClient);
                times = 1;
                vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any);
                result = emptySubscription;
                times = 1;
                vB1.observableUpdates();
                result = Observable.empty();
                times = 1;
                vtepClient.getTunnelIp();
                times = 1;

                vtepClient.disconnect((UUID) any, true);
                times = 1;

                vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any);
                result = vtepClient;
                times = 1;

                VtepBroker vB2 = new VtepBroker(vtepClient);
                times = 1;
                vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any);
                result = emptySubscription;
                times = 1;
                vB2.observableUpdates();
                result = Observable.empty();
                times = 1;
                vtepClient.getTunnelIp();
                times = 1;

                vtepClient.disconnect((UUID) any, true);
                times = 1;
            }
        };

        VxLanGatewayService srv1 = createService();
        VxLanGatewayService srv2 = createService();

        // Service 1 should be the owner of the VTEP.
        srv1.startAsync().awaitRunning();
        assertEquals(srv1.getOwnedVteps().size(), 1);
        assertTrue(srv1.getOwnedVteps().contains(vtepId));

        // Service 2 should not be the owner of the VTEP.
        srv2.startAsync().awaitRunning();
        assertEquals(srv2.getOwnedVteps().size(), 0);

        // Service 2 should be the owner of the VTEP.
        srv1.stopAsync().awaitTerminated();
        assertEquals(srv1.getOwnedVteps().size(), 0);
        assertEquals(srv2.getOwnedVteps().size(), 1);
        assertTrue(srv2.getOwnedVteps().contains(vtepId));

        // Service 2 should not be the owner of the VTEP.
        srv2.stopAsync().awaitTerminated();
        assertEquals(srv2.getOwnedVteps().size(), 0);
    }

    @Test
    public void testFailoverThreeVteps(@Mocked final VtepBroker vtepBroker) throws Exception {

        UUID tzId = createTunnelZone(1);
        IPv4Addr vtepId1 = createVtep(1, tzId);
        IPv4Addr vtepId2 = createVtep(2, tzId);
        IPv4Addr vtepId3 = createVtep(3, tzId);

        new Expectations() {
            {
                vtepDataClientFactory.connect((IPv4Addr) any, VTEP_MGMT_PORT, (UUID) any);
                result = vtepClient;
                times = 1;

                VtepBroker vB1_1 = new VtepBroker(vtepClient);
                times = 1;
                vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any);
                result = emptySubscription;
                times = 1;
                vB1_1.observableUpdates();
                result = Observable.empty();
                times = 1;
                vtepClient.getTunnelIp();
                times = 1;

                vtepDataClientFactory.connect((IPv4Addr) any, VTEP_MGMT_PORT, (UUID) any);
                result = vtepClient;
                times = 1;

                VtepBroker vB1_2 = new VtepBroker(vtepClient);
                times = 1;
                vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any);
                result = emptySubscription;
                times = 1;
                vB1_2.observableUpdates();
                result = Observable.empty();
                times = 1;
                vtepClient.getTunnelIp();
                times = 1;

                vtepDataClientFactory.connect((IPv4Addr) any, VTEP_MGMT_PORT, (UUID) any);
                result = vtepClient;
                times = 1;

                VtepBroker vB1_3 = new VtepBroker(vtepClient);
                times = 1;
                vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any);
                result = emptySubscription;
                times = 1;
                vB1_3.observableUpdates();
                result = Observable.empty();
                times = 1;
                vtepClient.getTunnelIp();
                times = 1;

                vtepClient.disconnect((UUID) any, true);
                times = 1;

                vtepDataClientFactory.connect((IPv4Addr) any, VTEP_MGMT_PORT, (UUID) any);
                result = vtepClient;
                times = 1;

                VtepBroker vB2_1 = new VtepBroker(vtepClient);
                times = 1;
                vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any);
                result = emptySubscription;
                times = 1;
                vB2_1.observableUpdates();
                result = Observable.empty();
                times = 1;
                vtepClient.getTunnelIp();
                times = 1;

                vtepClient.disconnect((UUID) any, true);
                times = 1;

                vtepDataClientFactory.connect((IPv4Addr) any, VTEP_MGMT_PORT, (UUID) any);
                result = vtepClient;
                times = 1;

                VtepBroker vB2_2 = new VtepBroker(vtepClient);
                times = 1;
                vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any);
                result = emptySubscription;
                times = 1;
                vB2_2.observableUpdates();
                result = Observable.empty();
                times = 1;
                vtepClient.getTunnelIp();
                times = 1;

                vtepClient.disconnect((UUID) any, true);
                times = 1;

                vtepDataClientFactory.connect((IPv4Addr) any, VTEP_MGMT_PORT, (UUID) any);
                result = vtepClient;
                times = 1;

                VtepBroker vB2_3 = new VtepBroker(vtepClient);
                times = 1;
                vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any);
                result = emptySubscription;
                times = 1;
                vB2_3.observableUpdates();
                result = Observable.empty();
                times = 1;
                vtepClient.getTunnelIp();
                times = 1;

                vtepClient.disconnect((UUID) any, true);
                times = 3;
            }
        };

        VxLanGatewayService srv1 = createService();
        VxLanGatewayService srv2 = createService();

        // Service 1 should be the owner of the VTEP.
        srv1.startAsync().awaitRunning();
        assertEquals(srv1.getOwnedVteps().size(), 3);
        assertTrue(srv1.getOwnedVteps().contains(vtepId1));
        assertTrue(srv1.getOwnedVteps().contains(vtepId2));
        assertTrue(srv1.getOwnedVteps().contains(vtepId3));

        // Service 2 should not be the owner of the VTEP.
        srv2.startAsync().awaitRunning();
        assertEquals(srv2.getOwnedVteps().size(), 0);

        // Service 2 should be the owner of the VTEP.
        srv1.stopAsync().awaitTerminated();
        assertEquals(srv1.getOwnedVteps().size(), 0);
        assertEquals(srv2.getOwnedVteps().size(), 3);
        assertTrue(srv2.getOwnedVteps().contains(vtepId1));
        assertTrue(srv2.getOwnedVteps().contains(vtepId2));
        assertTrue(srv2.getOwnedVteps().contains(vtepId3));

        // Service 2 should not be the owner of the VTEP.
        srv2.stopAsync().awaitTerminated();
        assertEquals(srv2.getOwnedVteps().size(), 0);
    }

    @Test
    public void testFailoverConcurrent(@Mocked final VtepBroker vtepBroker) throws Exception {

        UUID tzId = createTunnelZone(1);

        new Expectations() {
            {
                vtepDataClientFactory.connect(getVtepAddress(1), VTEP_MGMT_PORT, (UUID) any);
                result = vtepClient;
                times = 1;

                VtepBroker vB1 = new VtepBroker(vtepClient);
                times = 1;
                vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any);
                result = emptySubscription;
                times = 1;
                vB1.observableUpdates();
                result = Observable.empty();
                times = 1;
                vtepClient.getTunnelIp();
                times = 1;

                vtepDataClientFactory.connect(getVtepAddress(2), VTEP_MGMT_PORT, (UUID) any);
                result = vtepClient;
                times = 1;

                VtepBroker vB2 = new VtepBroker(vtepClient);
                times = 1;
                vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any);
                result = emptySubscription;
                times = 1;
                vB2.observableUpdates();
                result = Observable.empty();
                times = 1;
                vtepClient.getTunnelIp();
                times = 1;

                vtepDataClientFactory.connect(getVtepAddress(3), VTEP_MGMT_PORT, (UUID) any);
                result = vtepClient;
                times = 1;

                VtepBroker vB3 = new VtepBroker(vtepClient);
                times = 1;
                vtepClient.onConnected((Callback<VtepDataClient, VtepException>) any);
                result = emptySubscription;
                times = 1;
                vB3.observableUpdates();
                result = Observable.empty();
                times = 1;
                vtepClient.getTunnelIp();
                times = 1;

                vtepClient.disconnect((UUID) any, true);
                times = 3;
            }
        };

        VxLanGatewayService srv1 = createService();
        VxLanGatewayService srv2 = createService();
        VxLanGatewayService srv3 = createService();

        srv1.startAsync().awaitRunning();
        srv2.startAsync().awaitRunning();
        srv3.startAsync().awaitRunning();

        IPv4Addr vtepId1 = createVtep(1, tzId);
        assertEquals(getVteps(srv1, srv2, srv3).size(), 1);
        assertTrue(getVteps(srv1, srv2, srv3).contains(vtepId1));
        IPv4Addr vtepId2 = createVtep(2, tzId);
        assertEquals(getVteps(srv1, srv2, srv3).size(), 2);
        assertTrue(getVteps(srv1, srv2, srv3).contains(vtepId1));
        assertTrue(getVteps(srv1, srv2, srv3).contains(vtepId2));
        IPv4Addr vtepId3 = createVtep(3, tzId);
        assertEquals(getVteps(srv1, srv2, srv3).size(), 3);
        assertTrue(getVteps(srv1, srv2, srv3).contains(vtepId1));
        assertTrue(getVteps(srv1, srv2, srv3).contains(vtepId2));
        assertTrue(getVteps(srv1, srv2, srv3).contains(vtepId3));

        midoClient.vtepDelete(vtepId1);
        assertEquals(getVteps(srv1, srv2, srv3).size(), 2);
        assertFalse(getVteps(srv1, srv2, srv3).contains(vtepId1));
        midoClient.vtepDelete(vtepId2);
        assertEquals(getVteps(srv1, srv2, srv3).size(), 1);
        assertFalse(getVteps(srv1, srv2, srv3).contains(vtepId2));
        midoClient.vtepDelete(vtepId3);
        assertTrue(getVteps(srv1, srv2, srv3).isEmpty());

        srv1.stopAsync().awaitTerminated();
        srv2.stopAsync().awaitTerminated();
        srv3.stopAsync().awaitTerminated();
    }

    public VxLanGatewayService createService() {
        return new VxLanGatewayService(midoClient, vtepDataClientFactory, zkConnWatcher, config);
    }

    public UUID createTunnelZone(int index) throws StateAccessException, SerializationException {

        // Create the tunnel zone.
        TunnelZone tzone = new TunnelZone();
        tzone.setName("TunnelZone-" + index);
        tzone.setType(TunnelZone.Type.vtep);
        return midoClient.tunnelZonesCreate(tzone);
    }

    public IPv4Addr createVtep(int index, UUID tzoneId) throws StateAccessException, SerializationException {

        // Create the VTEP.
        VTEP vtep = new VTEP();
        vtep.setId(getVtepAddress(index));
        vtep.setMgmtPort(VTEP_MGMT_PORT);
        vtep.setTunnelZone(tzoneId);
        midoClient.vtepCreate(vtep);

        return vtep.getId();
    }

    public static IPv4Addr getVtepAddress(int value) {
        return IPv4Addr.apply(new byte[] { VTEP_MGMT_IP[0], VTEP_MGMT_IP[1], (byte) ((value >> 8) & 0xFF),
                (byte) (value & 0xFF) });
    }

    public static Set<IPv4Addr> getVteps(VxLanGatewayService... services) {
        Set<IPv4Addr> vteps = new HashSet<>();

        for (VxLanGatewayService service : services) {
            for (IPv4Addr vtep : service.getOwnedVteps()) {
                boolean result = vteps.add(vtep);
                assertTrue(result);
            }
        }

        return vteps;
    }
}