/*
 * Copyright 2015-present Open Networking Foundation
 *
 * 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.onosproject.net.intent.impl.compiler;

import com.google.common.collect.ImmutableSet;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.onlab.util.Bandwidth;
import org.onosproject.TestApplicationId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.FilteredConnectPoint;
import org.onosproject.net.Link;
import org.onosproject.net.NetTestTools;
import org.onosproject.net.PortNumber;
import org.onosproject.net.ResourceGroup;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.intent.AbstractIntentTest;
import org.onosproject.net.intent.Constraint;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentTestsMocks;
import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.LinkCollectionIntent;
import org.onosproject.net.intent.PointToPointIntent;
import org.onosproject.net.intent.constraint.BandwidthConstraint;
import org.onosproject.net.intent.impl.PathNotFoundException;
import org.onosproject.net.resource.ContinuousResource;
import org.onosproject.net.resource.MockResourceService;
import org.onosproject.net.resource.ResourceAllocation;
import org.onosproject.net.resource.ResourceService;
import org.onosproject.net.resource.Resources;

import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.onosproject.net.intent.LinksHaveEntryWithSourceDestinationPairMatcher.linksHasPath;

/**
 * Unit tests for the HostToHost intent compiler.
 */
public class PointToPointIntentCompilerTest extends AbstractIntentTest {

    private static final ApplicationId APPID = new TestApplicationId("foo");

    private static final String S1 = "s1";
    private static final String S2 = "s2";
    private static final String S3 = "s3";
    private static final String S4 = "s4";
    private static final String S5 = "s5";
    private static final String S6 = "s6";
    private static final String S7 = "s7";
    private static final String S8 = "s8";

    private static final DeviceId DID_1 = DeviceId.deviceId("of:" + S1);
    private static final DeviceId DID_2 = DeviceId.deviceId("of:" + S2);
    private static final DeviceId DID_3 = DeviceId.deviceId("of:" + S3);
    private static final DeviceId DID_8 = DeviceId.deviceId("of:" + S8);

    private static final PortNumber PORT_1 = PortNumber.portNumber(1);
    private static final PortNumber PORT_2 =  PortNumber.portNumber(2);

    private  static final double BPS_TO_RESERVE = 100.0;

    private static final ContinuousResource RESOURCE_SW1_P1 =
            Resources.continuous(DID_1, PORT_1, Bandwidth.class)
                     .resource(BPS_TO_RESERVE);
    private static final ContinuousResource RESOURCE_SW1_P2 =
            Resources.continuous(DID_1, PORT_2, Bandwidth.class)
                    .resource(BPS_TO_RESERVE);
    private static final ContinuousResource RESOURCE_SW2_P1 =
            Resources.continuous(DID_2, PORT_1, Bandwidth.class)
                    .resource(BPS_TO_RESERVE);
    private static final ContinuousResource RESOURCE_SW2_P2 =
            Resources.continuous(DID_2, PORT_2, Bandwidth.class)
                    .resource(BPS_TO_RESERVE);
    private static final ContinuousResource RESOURCE_SW3_P1 =
            Resources.continuous(DID_3, PORT_1, Bandwidth.class)
                    .resource(BPS_TO_RESERVE);
    private static final ContinuousResource RESOURCE_SW3_P2 =
            Resources.continuous(DID_3, PORT_2, Bandwidth.class)
                    .resource(BPS_TO_RESERVE);

    private TrafficSelector selector = new IntentTestsMocks.MockSelector();
    private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();

    /**
     * Creates a PointToPoint intent based on ingress and egress device Ids.
     *
     * @param ingress the ingress connect point
     * @param egress the egress connect point
     * @return PointToPointIntent for the two devices
     */
    private PointToPointIntent makeIntent(ConnectPoint ingress, ConnectPoint egress) {
        return PointToPointIntent.builder()
                .appId(APPID)
                .selector(selector)
                .treatment(treatment)
                .filteredIngressPoint(new FilteredConnectPoint(ingress))
                .filteredEgressPoint(new FilteredConnectPoint(egress))
                .build();
    }

    /**
     * Creates a PointToPoint intent based on ingress and egress deviceIds and
     * constraints.
     *
     * @param ingress         the ingress connect point
     * @param egress          the egress connect point
     * @param constraints     constraints
     * @return the PointToPointIntent connecting the two connect points with
     * constraints
     */
    private PointToPointIntent makeIntent(ConnectPoint ingress,
                                          ConnectPoint egress,
                                          List<Constraint> constraints) {
        return PointToPointIntent.builder()
                .appId(APPID)
                .selector(selector)
                .treatment(treatment)
                .filteredIngressPoint(new FilteredConnectPoint(ingress))
                .filteredEgressPoint(new FilteredConnectPoint(egress))
                .constraints(constraints)
                .build();
    }

    /**
     * Creates a PointToPoint intent based on ingress and egress deviceIds,
     * constraints and a resource group.
     *
     * @param ingress         the ingress connect point
     * @param egress          the egress connect point
     * @param constraints     constraints
     * @param resourceGroup   the resource group
     * @return the PointToPointIntent connecting the two connect points with
     * constraints
     */
    private PointToPointIntent makeIntent(ConnectPoint ingress,
                                          ConnectPoint egress,
                                          List<Constraint> constraints,
                                          ResourceGroup resourceGroup) {
        return PointToPointIntent.builder()
                .appId(APPID)
                .resourceGroup(resourceGroup)
                .selector(selector)
                .treatment(treatment)
                .filteredIngressPoint(new FilteredConnectPoint(ingress))
                .filteredEgressPoint(new FilteredConnectPoint(egress))
                .constraints(constraints)
                .build();
    }

    /**
     * Creates a PointToPoint intent based on an intent key, ingress and egress
     * deviceIds, constraints and a resource group.
     *
     * @param key             the intent key
     * @param ingress         the ingress connect point
     * @param egress          the egress connect point
     * @param constraints     constraints
     * @param resourceGroup   the resource group
     * @return the PointToPointIntent connecting the two connect points with
     * constraints
     */
    private PointToPointIntent makeIntent(Key key,
                                          ConnectPoint ingress,
                                          ConnectPoint egress,
                                          List<Constraint> constraints,
                                          ResourceGroup resourceGroup) {
        return PointToPointIntent.builder()
                .appId(APPID)
                .key(key)
                .resourceGroup(resourceGroup)
                .selector(selector)
                .treatment(treatment)
                .filteredIngressPoint(new FilteredConnectPoint(ingress))
                .filteredEgressPoint(new FilteredConnectPoint(egress))
                .constraints(constraints)
                .build();
    }

    /**
     * Creates a PointToPoint intent based on ingress and egress deviceIds
     * and a suggested path.
     * @param ingress           the ingress connect point
     * @param egress            the egress connect point
     * @param suggestedPath     the suggested path
     * @return the PointToPointIntent connecting the two connect points with
     * the suggested path (if available)
     */
    private PointToPointIntent makeIntentSuggestedPath(ConnectPoint ingress,
                                                       ConnectPoint egress,
                                                       List<Link> suggestedPath) {
        return PointToPointIntent.builder()
                .appId(APPID)
                .selector(selector)
                .treatment(treatment)
                .filteredIngressPoint(new FilteredConnectPoint(ingress))
                .filteredEgressPoint(new FilteredConnectPoint(egress))
                .suggestedPath(suggestedPath)
                .build();
    }

    /**
     * Creates a PointToPoint intent based on ingress and egress deviceIds and
     * constraints with a suggested path.
     *
     * @param ingress         the ingress connect point
     * @param egress          the egress connect point
     * @param suggestedPath   the suggested path
     * @param constraints     constraints
     * @return the PointToPointIntent connecting the two connect points with
     * constraints and a suggested path
     */
    private PointToPointIntent makeIntentSuggestedPath(ConnectPoint ingress,
                                          ConnectPoint egress,
                                          List<Link> suggestedPath,
                                          List<Constraint> constraints) {
        return PointToPointIntent.builder()
                .appId(APPID)
                .selector(selector)
                .treatment(treatment)
                .filteredIngressPoint(new FilteredConnectPoint(ingress))
                .filteredEgressPoint(new FilteredConnectPoint(egress))
                .constraints(constraints)
                .suggestedPath(suggestedPath)
                .build();
    }

    /**
     * Creates a compiler for HostToHost intents.
     *
     * @param hops string array describing the path hops to use when compiling
     * @return HostToHost intent compiler
     */
    private PointToPointIntentCompiler makeCompiler(String[] hops) {
        return makeCompiler(hops, null);
    }

    /**
     * Creates a compiler for PointToPoint intents with suggested paths.
     *
     * @param paths all the possible paths in the network
     * @return PointToPoint intent compiler
     */
    private PointToPointIntentCompiler makeCompilerSuggestedPath(String[][] paths) {
        final PointToPointIntentCompiler compiler = new PointToPointIntentCompiler();
        compiler.pathService = new IntentTestsMocks.MockMultiplePathService(paths);
        compiler.linkService = new IntentTestsMocks.MockLinkService(paths);
        return compiler;
    }

    /**
     * Creates a point to point intent compiler for suggested path case.
     *
     * @param paths             all the possible paths in the network
     * @param resourceService   service to use for resource allocation requests
     * @return point to point compiler
     */
    private PointToPointIntentCompiler makeCompilerSuggestedPath(String[][] paths,
                                                    ResourceService resourceService) {
        final PointToPointIntentCompiler compiler = new PointToPointIntentCompiler();
        compiler.pathService = new IntentTestsMocks.MockMultiplePathService(paths);
        compiler.linkService = new IntentTestsMocks.MockLinkService(paths);

        if (resourceService == null) {
            compiler.resourceService = new MockResourceService();
        } else {
            compiler.resourceService = resourceService;
        }

        return compiler;
    }

    /**
     * Creates a point to point intent compiler for a three switch linear
     * topology.
     *
     * @param resourceService service to use for resource allocation requests
     * @return point to point compiler
     */
    private PointToPointIntentCompiler makeCompiler(String[] hops,
                                                    ResourceService resourceService) {
        final PointToPointIntentCompiler compiler = new PointToPointIntentCompiler();
        compiler.pathService = new IntentTestsMocks.MockPathService(hops);

        if (resourceService == null) {
            compiler.resourceService = new MockResourceService();
        } else {
            compiler.resourceService = resourceService;
        }

        return compiler;
    }

    /**
     * Tests a pair of devices in an 8 hop path, forward direction.
     */
    @Test
    public void testForwardPathCompilation() {

        PointToPointIntent intent = makeIntent(new ConnectPoint(DID_1, PORT_1),
                                               new ConnectPoint(DID_8, PORT_1));

        String[] hops = {S1, S2, S3, S4, S5, S6, S7, S8};
        PointToPointIntentCompiler compiler = makeCompiler(hops);

        List<Intent> result = compiler.compile(intent, null);
        assertThat(result, is(Matchers.notNullValue()));
        assertThat(result, hasSize(1));
        Intent forwardResultIntent = result.get(0);
        assertThat(forwardResultIntent instanceof LinkCollectionIntent, is(true));

        if (forwardResultIntent instanceof LinkCollectionIntent) {
            LinkCollectionIntent forwardIntent = (LinkCollectionIntent) forwardResultIntent;
            FilteredConnectPoint ingressPoint = new FilteredConnectPoint(new ConnectPoint(DID_1, PORT_1));
            FilteredConnectPoint egressPoint = new FilteredConnectPoint(new ConnectPoint(DID_8, PORT_1));
            // 7 links for the hops, plus one default lnk on ingress and egress
            assertThat(forwardIntent.links(), hasSize(hops.length - 1));
            assertThat(forwardIntent.links(), linksHasPath(S1, S2));
            assertThat(forwardIntent.links(), linksHasPath(S2, S3));
            assertThat(forwardIntent.links(), linksHasPath(S3, S4));
            assertThat(forwardIntent.links(), linksHasPath(S4, S5));
            assertThat(forwardIntent.links(), linksHasPath(S5, S6));
            assertThat(forwardIntent.links(), linksHasPath(S6, S7));
            assertThat(forwardIntent.links(), linksHasPath(S7, S8));
            assertThat(forwardIntent.filteredIngressPoints(), is(ImmutableSet.of(ingressPoint)));
            assertThat(forwardIntent.filteredEgressPoints(), is(ImmutableSet.of(egressPoint)));
        }
        assertThat("key is inherited", forwardResultIntent.key(), is(intent.key()));
    }

    /**
     * Tests a pair of devices in an 8 hop path, forward direction.
     */
    @Test
    public void testReversePathCompilation() {

        PointToPointIntent intent = makeIntent(new ConnectPoint(DID_8, PORT_1),
                                               new ConnectPoint(DID_1, PORT_1));

        String[] hops = {S1, S2, S3, S4, S5, S6, S7, S8};
        PointToPointIntentCompiler compiler = makeCompiler(hops);

        List<Intent> result = compiler.compile(intent, null);
        assertThat(result, is(Matchers.notNullValue()));
        assertThat(result, hasSize(1));
        Intent reverseResultIntent = result.get(0);
        assertThat(reverseResultIntent instanceof LinkCollectionIntent, is(true));

        if (reverseResultIntent instanceof LinkCollectionIntent) {
            LinkCollectionIntent reverseLinkCollectionIntent = (LinkCollectionIntent) reverseResultIntent;
            FilteredConnectPoint egressPoint = new FilteredConnectPoint(new ConnectPoint(DID_1, PORT_1));
            FilteredConnectPoint ingressPoint = new FilteredConnectPoint(new ConnectPoint(DID_8, PORT_1));
            assertThat(reverseLinkCollectionIntent.links(), hasSize(hops.length - 1));
            assertThat(reverseLinkCollectionIntent.links(), linksHasPath(S2, S1));
            assertThat(reverseLinkCollectionIntent.links(), linksHasPath(S3, S2));
            assertThat(reverseLinkCollectionIntent.links(), linksHasPath(S4, S3));
            assertThat(reverseLinkCollectionIntent.links(), linksHasPath(S5, S4));
            assertThat(reverseLinkCollectionIntent.links(), linksHasPath(S6, S5));
            assertThat(reverseLinkCollectionIntent.links(), linksHasPath(S7, S6));
            assertThat(reverseLinkCollectionIntent.links(), linksHasPath(S8, S7));
            assertThat(reverseLinkCollectionIntent.filteredIngressPoints(), is(ImmutableSet.of(ingressPoint)));
            assertThat(reverseLinkCollectionIntent.filteredEgressPoints(), is(ImmutableSet.of(egressPoint)));
        }
        assertThat("key is inherited", reverseResultIntent.key(), is(intent.key()));
    }

    /**
     * Tests the compilation of an intent which designates two different ports
     * on the same switch.
     */
    @Test
    public void testSameSwitchDifferentPortsIntentCompilation() {
        FilteredConnectPoint src =
                new FilteredConnectPoint(new ConnectPoint(DID_1, PORT_1));
        FilteredConnectPoint dst =
                new FilteredConnectPoint(new ConnectPoint(DID_1, PORT_2));

        PointToPointIntent intent = makeIntent(new ConnectPoint(DID_1, PORT_1),
                                               new ConnectPoint(DID_1, PORT_2));

        String[] hops = {S1};
        PointToPointIntentCompiler compiler = makeCompiler(hops);

        List<Intent> compiled = compiler.compile(intent, null);

        assertThat("key is inherited",
                   compiled.stream().map(Intent::key).collect(Collectors.toList()),
                   everyItem(is(intent.key())));

        assertThat(compiled, hasSize(1));
        assertThat(compiled.get(0), is(instanceOf(LinkCollectionIntent.class)));
        LinkCollectionIntent linkCollectionIntent = (LinkCollectionIntent) compiled.get(0);
        Set<Link> links = linkCollectionIntent.links();

        assertThat(links, hasSize(0));
        assertThat(linkCollectionIntent.filteredIngressPoints(), is(ImmutableSet.of(src)));
        assertThat(linkCollectionIntent.filteredEgressPoints(), is(ImmutableSet.of(dst)));
    }

    /**
     * Tests that requests with sufficient available bandwidth succeed.
     */
    @Test
    public void testBandwidthConstrainedIntentSuccess() {
        final double bpsTotal = 1000.0;
        final double bpsToReserve = 100.0;

        final ResourceService resourceService =
               MockResourceService.makeCustomBandwidthResourceService(bpsTotal);
        final List<Constraint> constraints =
                Collections.singletonList(new BandwidthConstraint(Bandwidth.bps(bpsToReserve)));

        final PointToPointIntent intent = makeIntent(new ConnectPoint(DID_1, PORT_1),
                                                     new ConnectPoint(DID_3, PORT_2),
                                                     constraints);

        String[] hops = {S1, S2, S3};
        final PointToPointIntentCompiler compiler = makeCompiler(hops,
                                                                 resourceService);

        final List<Intent> compiledIntents = compiler.compile(intent, null);

        assertThat(compiledIntents, Matchers.notNullValue());
        assertThat(compiledIntents, hasSize(1));

        assertThat("key is inherited",
                   compiledIntents.stream().map(Intent::key).collect(Collectors.toList()),
                   everyItem(is(intent.key())));

    }

    /**
     * Tests that requests with insufficient available bandwidth fail.
     */
    @Test
    public void testBandwidthConstrainedIntentFailure() {
        final double bpsTotal = 10.0;

        final ResourceService resourceService =
                MockResourceService.makeCustomBandwidthResourceService(bpsTotal);
        final List<Constraint> constraints =
                Collections.singletonList(new BandwidthConstraint(Bandwidth.bps(BPS_TO_RESERVE)));

        try {
            final PointToPointIntent intent = makeIntent(new ConnectPoint(DID_1, PORT_1),
                                                         new ConnectPoint(DID_3, PORT_2),
                                                         constraints);

            String[] hops = {S1, S2, S3};
            final PointToPointIntentCompiler compiler = makeCompiler(hops,
                                                                     resourceService);

            compiler.compile(intent, null);

            fail("Point to Point compilation with insufficient bandwidth does "
                    + "not throw exception.");
        } catch (PathNotFoundException noPath) {
            assertThat(noPath.getMessage(), containsString("No path"));
        }
    }

    /**
     * Tests if bandwidth resources get allocated correctly. An intent with a
     * key only is submitted.
     */
    @Test
    public void testBandwidthConstrainedIntentAllocation() {
        final double bpsTotal = 1000.0;

        String[] hops = {S1, S2, S3};

        final ResourceService resourceService =
                MockResourceService.makeCustomBandwidthResourceService(bpsTotal);
        final List<Constraint> constraints =
                Collections.singletonList(new BandwidthConstraint(Bandwidth.bps(BPS_TO_RESERVE)));

        final PointToPointIntent intent = makeIntent(new ConnectPoint(DID_1, PORT_1),
                                                     new ConnectPoint(DID_3, PORT_2),
                                                     constraints);

        PointToPointIntentCompiler compiler = makeCompiler(hops, resourceService);

        compiler.compile(intent, null);

        Key intentKey = intent.key();

        ResourceAllocation rAOne = new ResourceAllocation(RESOURCE_SW1_P1, intentKey);
        ResourceAllocation rATwo = new ResourceAllocation(RESOURCE_SW1_P2, intentKey);
        ResourceAllocation rAThree = new ResourceAllocation(RESOURCE_SW2_P1, intentKey);
        ResourceAllocation rAFour = new ResourceAllocation(RESOURCE_SW2_P2, intentKey);
        ResourceAllocation rAFive = new ResourceAllocation(RESOURCE_SW3_P1, intentKey);
        ResourceAllocation rASix = new ResourceAllocation(RESOURCE_SW3_P2, intentKey);

        Set<ResourceAllocation> expectedresourceAllocations =
                ImmutableSet.of(rAOne, rATwo, rAThree, rAFour, rAFive, rASix);

        Set<ResourceAllocation> resourceAllocations =
                ImmutableSet.copyOf(resourceService.getResourceAllocations(intentKey));

        assertThat(resourceAllocations, hasSize(6));
        assertEquals(expectedresourceAllocations, resourceAllocations);
    }

    /**
     * Tests if bandwidth resources get allocated correctly using the resource
     * group. An intent with a resource group is submitted.
     */
    @Test
    public void testRGBandwidthConstrainedIntentAllocation() {
        final double bpsTotal = 1000.0;

        ResourceGroup resourceGroup = ResourceGroup.of(100);

        String[] hops = {S1, S2, S3};

        final ResourceService resourceService =
                MockResourceService.makeCustomBandwidthResourceService(bpsTotal);
        final List<Constraint> constraints =
                Collections.singletonList(new BandwidthConstraint(Bandwidth.bps(BPS_TO_RESERVE)));

        final PointToPointIntent intent = makeIntent(new ConnectPoint(DID_1, PORT_1),
                                                     new ConnectPoint(DID_3, PORT_2),
                                                     constraints,
                                                     resourceGroup);

        PointToPointIntentCompiler compiler = makeCompiler(hops, resourceService);

        compiler.compile(intent, null);

        ResourceAllocation rAOne = new ResourceAllocation(RESOURCE_SW1_P1, resourceGroup);
        ResourceAllocation rATwo = new ResourceAllocation(RESOURCE_SW1_P2, resourceGroup);
        ResourceAllocation rAThree = new ResourceAllocation(RESOURCE_SW2_P1, resourceGroup);
        ResourceAllocation rAFour = new ResourceAllocation(RESOURCE_SW2_P2, resourceGroup);
        ResourceAllocation rAFive = new ResourceAllocation(RESOURCE_SW3_P1, resourceGroup);
        ResourceAllocation rASix = new ResourceAllocation(RESOURCE_SW3_P2, resourceGroup);

        Set<ResourceAllocation> expectedresourceAllocations =
                ImmutableSet.of(rAOne, rATwo, rAThree, rAFour, rAFive, rASix);

        Set<ResourceAllocation> resourceAllocations =
                ImmutableSet.copyOf(resourceService.getResourceAllocations(resourceGroup));

        assertThat(resourceAllocations, hasSize(6));
        assertEquals(expectedresourceAllocations, resourceAllocations);
    }

    /**
     * Tests that bandwidth resources don't get allocated twice if the intent
     * is submitted twice.
     */
    @Test
    public void testTwoBandwidthConstrainedIntentAllocation() {
        final double bpsTotal = 1000.0;

        String[] hops = {S1, S2, S3};

        final ResourceService resourceService =
                MockResourceService.makeCustomBandwidthResourceService(bpsTotal);
        final List<Constraint> constraints =
                Collections.singletonList(new BandwidthConstraint(Bandwidth.bps(BPS_TO_RESERVE)));

        final PointToPointIntent intent = makeIntent(new ConnectPoint(DID_1, PORT_1),
                                                     new ConnectPoint(DID_3, PORT_2),
                                                     constraints);

        PointToPointIntentCompiler compiler = makeCompiler(hops, resourceService);

        compiler.compile(intent, null);

        // Resubmit the same intent
        compiler.compile(intent, null);

        Key intentKey = intent.key();

        ResourceAllocation rAOne = new ResourceAllocation(RESOURCE_SW1_P1, intentKey);
        ResourceAllocation rATwo = new ResourceAllocation(RESOURCE_SW1_P2, intentKey);
        ResourceAllocation rAThree = new ResourceAllocation(RESOURCE_SW2_P1, intentKey);
        ResourceAllocation rAFour = new ResourceAllocation(RESOURCE_SW2_P2, intentKey);
        ResourceAllocation rAFive = new ResourceAllocation(RESOURCE_SW3_P1, intentKey);
        ResourceAllocation rASix = new ResourceAllocation(RESOURCE_SW3_P2, intentKey);

        Set<ResourceAllocation> expectedresourceAllocations =
                ImmutableSet.of(rAOne, rATwo, rAThree, rAFour, rAFive, rASix);

        Set<ResourceAllocation> resourceAllocations =
                ImmutableSet.copyOf(resourceService.getResourceAllocations(intentKey));

        assertThat(resourceAllocations, hasSize(6));
        assertEquals(expectedresourceAllocations, resourceAllocations);
    }

    /**
     * Tests if bandwidth resources get allocated correctly using groups.
     * An intent asks to allocate bandwidth using the intent key as a reference.
     * Then, the intent is submitted with the same key and a group set.
     * Previous allocations should be released and new resources should be
     * allocated using the group.
     */
    @Test
    public void testKeyRGBandwidthConstrainedIntentAllocation() {
        final double bpsTotal = 1000.0;

        String[] hops = {S1, S2, S3};

        final ResourceService resourceService =
                MockResourceService.makeCustomBandwidthResourceService(bpsTotal);
        final List<Constraint> constraints =
                Collections.singletonList(new BandwidthConstraint(Bandwidth.bps(BPS_TO_RESERVE)));

        final PointToPointIntent intent = makeIntent(new ConnectPoint(DID_1, PORT_1),
                                                     new ConnectPoint(DID_3, PORT_2),
                                                     constraints);

        PointToPointIntentCompiler compiler = makeCompiler(hops, resourceService);

        compiler.compile(intent, null);

        Key intentKey = intent.key();

        ResourceGroup resourceGroup = ResourceGroup.of(100);

        final PointToPointIntent newIntent = makeIntent(intentKey,
                                                        new ConnectPoint(DID_1, PORT_1),
                                                        new ConnectPoint(DID_3, PORT_2),
                                                        constraints,
                                                        resourceGroup);

        compiler.compile(newIntent, null);

        ResourceAllocation rAOne = new ResourceAllocation(RESOURCE_SW1_P1, resourceGroup);
        ResourceAllocation rATwo = new ResourceAllocation(RESOURCE_SW1_P2, resourceGroup);
        ResourceAllocation rAThree = new ResourceAllocation(RESOURCE_SW2_P1, resourceGroup);
        ResourceAllocation rAFour = new ResourceAllocation(RESOURCE_SW2_P2, resourceGroup);
        ResourceAllocation rAFive = new ResourceAllocation(RESOURCE_SW3_P1, resourceGroup);
        ResourceAllocation rASix = new ResourceAllocation(RESOURCE_SW3_P2, resourceGroup);

        Set<ResourceAllocation> expectedresourceAllocations =
                ImmutableSet.of(rAOne, rATwo, rAThree, rAFour, rAFive, rASix);

        Set<ResourceAllocation> resourceAllocations =
                ImmutableSet.copyOf(resourceService.getResourceAllocations(resourceGroup));

        assertThat(resourceAllocations, hasSize(6));
        assertEquals(expectedresourceAllocations, resourceAllocations);
    }

    /**
     * Test if a suggested path is correctly applied.
     */
    @Test
    public void testSuggestedPath() {
        String[] suggestedPathHops = {S1, S3, S4, S5, S6, S8};
        List<Link> suggestedPath = NetTestTools.createPath(suggestedPathHops).links();

        PointToPointIntent intent = makeIntentSuggestedPath(new ConnectPoint(DID_1, PORT_1),
                                                            new ConnectPoint(DID_8, PORT_2),
                                                            suggestedPath);

        String[][] paths = {{S1, S2, S8}, suggestedPathHops};
        PointToPointIntentCompiler compiler = makeCompilerSuggestedPath(paths);

        List<Intent> result = compiler.compile(intent, null);
        assertThat(result, is(Matchers.notNullValue()));
        assertThat(result, hasSize(1));
        Intent resultIntent = result.get(0);
        assertThat(resultIntent instanceof LinkCollectionIntent, is(true));

        if (resultIntent instanceof LinkCollectionIntent) {
            LinkCollectionIntent resultLinkIntent = (LinkCollectionIntent) resultIntent;
            FilteredConnectPoint ingressPoint = new FilteredConnectPoint(new ConnectPoint(DID_1, PORT_1));
            FilteredConnectPoint egressPoint = new FilteredConnectPoint(new ConnectPoint(DID_8, PORT_2));
            // 5 links for the hops, plus one default link on ingress and egress
            assertThat(resultLinkIntent.links(), hasSize(suggestedPathHops.length - 1));
            assertThat(resultLinkIntent.links(), linksHasPath(S1, S3));
            assertThat(resultLinkIntent.links(), linksHasPath(S3, S4));
            assertThat(resultLinkIntent.links(), linksHasPath(S4, S5));
            assertThat(resultLinkIntent.links(), linksHasPath(S5, S6));
            assertThat(resultLinkIntent.links(), linksHasPath(S6, S8));
            assertThat(resultLinkIntent.filteredIngressPoints(), is(ImmutableSet.of(ingressPoint)));
            assertThat(resultLinkIntent.filteredEgressPoints(), is(ImmutableSet.of(egressPoint)));
        }
        assertThat("key is inherited", resultIntent.key(), is(intent.key()));
    }

    /**
     * Test that if a suggested path isn't available it applies another available path.
     */
    @Test
    public void testSuggestedPathNotAvailable() {
        String[] suggestedPathHops = {S1, S3, S8};
        String[] shortestPath = {S1, S2, S8};
        List<Link> suggestedPath = NetTestTools.createPath(suggestedPathHops).links();

        PointToPointIntent intent = makeIntentSuggestedPath(new ConnectPoint(DID_1, PORT_1),
                                                            new ConnectPoint(DID_8, PORT_2),
                                                            suggestedPath);

        String[][] path = {shortestPath};
        PointToPointIntentCompiler compiler = makeCompilerSuggestedPath(path);

        List<Intent> result = compiler.compile(intent, null);
        assertThat(result, is(Matchers.notNullValue()));
        assertThat(result, hasSize(1));
        Intent resultIntent = result.get(0);
        assertThat(resultIntent instanceof LinkCollectionIntent, is(true));

        if (resultIntent instanceof LinkCollectionIntent) {
            LinkCollectionIntent resultLinkIntent = (LinkCollectionIntent) resultIntent;
            FilteredConnectPoint ingressPoint = new FilteredConnectPoint(new ConnectPoint(DID_1, PORT_1));
            FilteredConnectPoint egressPoint = new FilteredConnectPoint(new ConnectPoint(DID_8, PORT_2));
            // 5 links for the hops, plus one default link on ingress and egress
            assertThat(resultLinkIntent.links(), hasSize(shortestPath.length - 1));
            assertThat(resultLinkIntent.links(), linksHasPath(S1, S2));
            assertThat(resultLinkIntent.links(), linksHasPath(S2, S8));
            assertThat(resultLinkIntent.filteredIngressPoints(), is(ImmutableSet.of(ingressPoint)));
            assertThat(resultLinkIntent.filteredEgressPoints(), is(ImmutableSet.of(egressPoint)));
        }
        assertThat("key is inherited", resultIntent.key(), is(intent.key()));
    }

    /**
     * Tests that requests with suggested path
     * and with sufficient available bandwidth succeed.
     */
    @Test
    public void testSuggestedPathBandwidthConstrainedIntentSuccess() {
        final double bpsTotal = 1000.0;
        final double bpsToReserve = 100.0;

        final ResourceService resourceService =
                MockResourceService.makeCustomBandwidthResourceService(bpsTotal);
        final List<Constraint> constraints =
                Collections.singletonList(new BandwidthConstraint(Bandwidth.bps(bpsToReserve)));

        String[] suggestedPathHops = {S1, S4, S5, S3};
        List<Link> suggestedPath = NetTestTools.createPath(suggestedPathHops).links();

        final PointToPointIntent intent = makeIntentSuggestedPath(
                new ConnectPoint(DID_1, PORT_1),
                new ConnectPoint(DID_3, PORT_2),
                suggestedPath,
                constraints);

        String[][] hops = {{S1, S2, S3}, suggestedPathHops};
        final PointToPointIntentCompiler compiler = makeCompilerSuggestedPath(hops,
                                                                 resourceService);

        final List<Intent> compiledIntents = compiler.compile(intent, null);

        assertThat(compiledIntents, Matchers.notNullValue());
        assertThat(compiledIntents, hasSize(1));

        assertThat("key is inherited",
                   compiledIntents.stream().map(Intent::key).collect(Collectors.toList()),
                   everyItem(is(intent.key())));

    }

    /**
     * Tests that requests with insufficient available bandwidth fail.
     */
    @Test
    public void testSuggestedPathBandwidthConstrainedIntentFailure() {
        final double bpsTotal = 10.0;

        final ResourceService resourceService =
                MockResourceService.makeCustomBandwidthResourceService(bpsTotal);
        final List<Constraint> constraints =
                Collections.singletonList(new BandwidthConstraint(Bandwidth.bps(BPS_TO_RESERVE)));

        String[] suggestedPathHops = {S1, S4, S5, S3};
        List<Link> suggestedPath = NetTestTools.createPath(suggestedPathHops).links();

        try {
            final PointToPointIntent intent = makeIntentSuggestedPath(
                    new ConnectPoint(DID_1, PORT_1),
                    new ConnectPoint(DID_3, PORT_2),
                    suggestedPath,
                    constraints);

            String[][] paths = {{S1, S2, S3}, suggestedPathHops};
            final PointToPointIntentCompiler compiler = makeCompilerSuggestedPath(paths,
                                                                     resourceService);

            compiler.compile(intent, null);

            fail("Point to Point compilation with insufficient bandwidth does "
                         + "not throw exception.");
        } catch (PathNotFoundException noPath) {
            assertThat(noPath.getMessage(), containsString("No path"));
        }
    }
}
