[ONOS-7003] Policer implementation

Changes:
- Introduce trafficcontrol package
- Add policer
- Add policer id
- Add policing resource
- Add token bucket
- Add unit tests

Change-Id: I70065d58d3df7033e67a81943ebf60187c33c3e2
diff --git a/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerIdTest.java b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerIdTest.java
new file mode 100644
index 0000000..883f40d
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerIdTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2017-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.behaviour.trafficcontrol;
+
+import com.google.common.base.Strings;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.onlab.junit.ImmutableClassChecker;
+
+import java.net.URI;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Test class for PolicerId.
+ */
+public class PolicerIdTest {
+
+    // Test scheme
+    private static final String FOO_SCHEME = "foo";
+    // OpenFlow scheme
+    private static final String OF_SCHEME = "of";
+    // Some test ids
+    private static final Short ONE = 1;
+    private static final Short TWO = 15;
+    private static final String A = "A";
+    private static final String LA = "a";
+
+    /**
+     * Test policer id creation from URI.
+     */
+    @Test
+    public void testfromUriCreation() {
+        // Create URI representing the id
+        URI uriOne = URI.create(OF_SCHEME + ":" + Integer.toHexString(ONE));
+        // Create policer id
+        PolicerId one = PolicerId.policerId(uriOne);
+        // Verify proper creation
+        assertThat(one, notNullValue());
+        assertThat(one.id(), is(uriOne.toString().toLowerCase()));
+        assertThat(one.uri(), is(uriOne));
+    }
+
+    /**
+     * Test policer id creation from string.
+     */
+    @Test
+    public void testfromStringCreation() {
+        // Create String representing the id
+        String stringTwo = OF_SCHEME + ":" + Integer.toHexString(TWO);
+        // Create policer id
+        PolicerId two = PolicerId.policerId(stringTwo);
+        // Verify proper creation
+        assertThat(two, notNullValue());
+        assertThat(two.id(), is(stringTwo));
+        assertThat(two.uri(), is(URI.create(stringTwo)));
+    }
+
+    /**
+     * Exception expected to raise when creating a wrong policer id.
+     */
+    @Rule
+    public ExpectedException exceptionWrongId = ExpectedException.none();
+
+    /**
+     * Test wrong creation of a policer id.
+     */
+    @Test
+    public void testWrongCreation() {
+        // Build not allowed string
+        String wrongString = Strings.repeat("x", 1025);
+        // Define expected exception
+        exceptionWrongId.expect(IllegalArgumentException.class);
+        // Create policer id
+        PolicerId.policerId(wrongString);
+    }
+
+    /**
+     * Test equality between policer ids.
+     */
+    @Test
+    public void testEquality() {
+        // Create URI representing the id one
+        URI uriOne = URI.create(OF_SCHEME + ":" + Integer.toHexString(ONE));
+        // Create String representing the id one
+        String stringOne = OF_SCHEME + ":" + Integer.toHexString(ONE);
+        // Create String representing the id two
+        String stringTwo = OF_SCHEME + ":" + Integer.toHexString(TWO);
+        // Create String representing the id A
+        String stringA = FOO_SCHEME + ":" + A;
+        // Create String representing the id LA
+        String stringLA = FOO_SCHEME + ":" + LA;
+        // Create policer id one
+        PolicerId one = PolicerId.policerId(uriOne);
+        // Create policer id one
+        PolicerId copyOfOne = PolicerId.policerId(stringOne);
+        // Verify equality
+        assertEquals(one, copyOfOne);
+        // Create a different policer id
+        PolicerId two = PolicerId.policerId(stringTwo);
+        // Verify not equals
+        assertNotEquals(two, one);
+        assertNotEquals(two, copyOfOne);
+        // Create policer id A
+        PolicerId a = PolicerId.policerId(A);
+        // Create policer id LA
+        PolicerId la = PolicerId.policerId(LA);
+        // Verify not equals
+        assertNotEquals(a, la);
+    }
+
+    /**
+     * Tests immutability of PolicerId.
+     */
+    @Test
+    public void testImmutability() {
+        ImmutableClassChecker.assertThatClassIsImmutable(PolicerId.class);
+    }
+
+}
diff --git a/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerTest.java b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerTest.java
new file mode 100644
index 0000000..142f962
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicerTest.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2017-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.behaviour.trafficcontrol;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.*;
+import static org.onosproject.net.behaviour.trafficcontrol.Policer.Unit.KB_PER_SEC;
+import static org.onosproject.net.behaviour.trafficcontrol.Policer.Unit.MB_PER_SEC;
+import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DROP;
+import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DSCP_CLASS;
+import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DSCP_PRECEDENCE;
+
+/**
+ * Test class for policer implementation.
+ */
+public class PolicerTest {
+
+    // Fake Application Id
+    private static final ApplicationId FOO_APP_ID = new TestApplicationId("foo");
+    // Connect points
+    private static final String SDID1 = "of:00000000000001";
+    private static final DeviceId DID1 = DeviceId.deviceId(SDID1);
+    // OpenFlow scheme
+    private static final String OF_SCHEME = "of";
+    // Policers identifiers
+    private static final String SID1 = OF_SCHEME + ":" + Integer.toHexString(1);
+    private static final PolicerId ID1 = PolicerId.policerId(SID1);
+    private static final String SID2 = OF_SCHEME + ":" + Integer.toHexString(2);
+    private static final PolicerId ID2 = PolicerId.policerId(SID2);
+    private static final String SID3 = OF_SCHEME + ":" + Integer.toHexString(3);
+    private static final PolicerId ID3 = PolicerId.policerId(SID3);
+    private static final String SID4 = OF_SCHEME + ":" + Integer.toHexString(4);
+    private static final PolicerId ID4 = PolicerId.policerId(SID4);
+    private static final String SID5 = OF_SCHEME + ":" + Integer.toHexString(5);
+    private static final PolicerId ID5 = PolicerId.policerId(SID5);
+    private static final String SID6 = OF_SCHEME + ":" + Integer.toHexString(6);
+    private static final PolicerId ID6 = PolicerId.policerId(SID6);
+    private static final String SID7 = OF_SCHEME + ":" + Integer.toHexString(7);
+    private static final PolicerId ID7 = PolicerId.policerId(SID7);
+    private static final String SID8 = OF_SCHEME + ":" + Integer.toHexString(8);
+    private static final PolicerId ID8 = PolicerId.policerId(SID8);
+    private static final String SID9 = OF_SCHEME + ":" + Integer.toHexString(9);
+    private static final PolicerId ID9 = PolicerId.policerId(SID9);
+
+    /**
+     * Test block traffic policer.
+     */
+    @Test
+    public void testBlockCreation() {
+        // Create a block traffic token bucket
+        TokenBucket tokenBucket = DefaultTokenBucket.builder()
+                .withBurstSize(0)
+                .withAction(DROP)
+                .build();
+        // Create a policer with above token bucket
+        Policer policer = DefaultPolicer.builder()
+                .forDeviceId(DID1)
+                .fromApp(FOO_APP_ID)
+                .withId(ID1)
+                .withTokenBuckets(ImmutableList.of(tokenBucket))
+                .build();
+        // Assert on device id
+        assertThat(policer.deviceId(), is(DID1));
+        // Assert on app id
+        assertThat(policer.applicationId(), is(FOO_APP_ID));
+        // Assert on policer id
+        assertThat(policer.policerId(), is(ID1));
+        // It is not color aware
+        assertFalse(policer.isColorAware());
+        // Unit is Mbps
+        assertThat(policer.unit(), is(MB_PER_SEC));
+        // One token bucket
+        assertThat(policer.tokenBuckets().size(), is(1));
+        // One token bucket equals to tokenBucket
+        assertTrue(policer.tokenBuckets().contains(tokenBucket));
+    }
+
+    /**
+     * Test simple drop policer.
+     */
+    @Test
+    public void testDropCreation() {
+        // Create a drop traffic token bucket at 1MB/s
+        TokenBucket tokenBucket = DefaultTokenBucket.builder()
+                .withRate(1)
+                .withAction(DROP)
+                .build();
+        // Create a policer with above token bucket
+        Policer policer = DefaultPolicer.builder()
+                .forDeviceId(DID1)
+                .fromApp(FOO_APP_ID)
+                .withId(ID2)
+                .withTokenBuckets(ImmutableList.of(tokenBucket))
+                .build();
+        // Assert on device id
+        assertThat(policer.deviceId(), is(DID1));
+        // Assert on app id
+        assertThat(policer.applicationId(), is(FOO_APP_ID));
+        // Assert on policer id
+        assertThat(policer.policerId(), is(ID2));
+        // It is not color aware
+        assertFalse(policer.isColorAware());
+        // Unit is Mbps
+        assertThat(policer.unit(), is(MB_PER_SEC));
+        // One token bucket
+        assertThat(policer.tokenBuckets().size(), is(1));
+        // One token bucket equals to tokenBucket
+        assertTrue(policer.tokenBuckets().contains(tokenBucket));
+    }
+
+    /**
+     * Test simple mark policer.
+     */
+    @Test
+    public void testMarkCreation() {
+        // Create a drop traffic token bucket at 1MB/s
+        TokenBucket tokenBucket = DefaultTokenBucket.builder()
+                .withRate(1)
+                .withAction(DSCP_PRECEDENCE)
+                .withDscp((short) 2)
+                .build();
+        // Create a policer with above token bucket
+        Policer policer = DefaultPolicer.builder()
+                .forDeviceId(DID1)
+                .fromApp(FOO_APP_ID)
+                .withId(ID3)
+                .withTokenBuckets(ImmutableList.of(tokenBucket))
+                .build();
+        // Assert on device id
+        assertThat(policer.deviceId(), is(DID1));
+        // Assert on app id
+        assertThat(policer.applicationId(), is(FOO_APP_ID));
+        // Assert on policer id
+        assertThat(policer.policerId(), is(ID3));
+        // It is not color aware
+        assertFalse(policer.isColorAware());
+        // Unit is Mbps
+        assertThat(policer.unit(), is(MB_PER_SEC));
+        // One token bucket
+        assertThat(policer.tokenBuckets().size(), is(1));
+        // One token bucket equals to tokenBucket
+        assertTrue(policer.tokenBuckets().contains(tokenBucket));
+    }
+
+    /**
+     * Test single rate three colors scenario (RFC 2697).
+     */
+    @Test
+    public void testSingleRateThreeColors() {
+        // Create token bucket for committed rate
+        TokenBucket crTokenBucket = DefaultTokenBucket.builder()
+                .withRate(1)
+                .withAction(DSCP_PRECEDENCE)
+                .withDscp((short) 2)
+                .build();
+        // Create token bucket for excess rate
+        TokenBucket erTokenBucket = DefaultTokenBucket.builder()
+                .withRate(1)
+                .withBurstSize(4 * 1500)
+                .withAction(DROP)
+                .build();
+        // Create a policer with above token buckets
+        Policer policer = DefaultPolicer.builder()
+                .forDeviceId(DID1)
+                .fromApp(FOO_APP_ID)
+                .withId(ID4)
+                // The order is important
+                .withTokenBuckets(ImmutableList.of(crTokenBucket, erTokenBucket))
+                .build();
+        // Assert on device id
+        assertThat(policer.deviceId(), is(DID1));
+        // Assert on app id
+        assertThat(policer.applicationId(), is(FOO_APP_ID));
+        // Assert on policer id
+        assertThat(policer.policerId(), is(ID4));
+        // It is not color aware
+        assertFalse(policer.isColorAware());
+        // Unit is Mbps
+        assertThat(policer.unit(), is(MB_PER_SEC));
+        // Two token buckets
+        assertThat(policer.tokenBuckets().size(), is(2));
+        // One token bucket equals to crTokenBucket
+        assertTrue(policer.tokenBuckets().contains(crTokenBucket));
+        // One token bucket equals to erTokenBucket
+        assertTrue(policer.tokenBuckets().contains(erTokenBucket));
+    }
+
+    /**
+     * Test two rates three colors scenario (RFC 2698 and P4 meter).
+     */
+    @Test
+    public void testTwoRatesThreeColors() {
+        // Create token bucket for peak rate at 10Mb/s
+        TokenBucket prTokenBucket = DefaultTokenBucket.builder()
+                // (10 * 1000)/8 ---> 1250KB/s
+                .withRate(1250)
+                .withBurstSize(10 * 1500)
+                .withAction(DROP)
+                .build();
+        // Create token bucket for committed rate at 1Mb/s
+        TokenBucket crTokenBucket = DefaultTokenBucket.builder()
+                // (1 * 1000)/8 ---> 125KB/s
+                .withRate(125)
+                .withAction(DSCP_CLASS)
+                .withDscp((short) 10)
+                .build();
+        // Create a policer with above token buckets
+        Policer policer = DefaultPolicer.builder()
+                .forDeviceId(DID1)
+                .fromApp(FOO_APP_ID)
+                .withId(ID5)
+                .withUnit(KB_PER_SEC)
+                // The order is important
+                .withTokenBuckets(ImmutableList.of(prTokenBucket, crTokenBucket))
+                .build();
+        // Assert on device id
+        assertThat(policer.deviceId(), is(DID1));
+        // Assert on app id
+        assertThat(policer.applicationId(), is(FOO_APP_ID));
+        // Assert on policer id
+        assertThat(policer.policerId(), is(ID5));
+        // It is not color aware
+        assertFalse(policer.isColorAware());
+        // Unit is Mbps
+        assertThat(policer.unit(), is(KB_PER_SEC));
+        // Two token buckets
+        assertThat(policer.tokenBuckets().size(), is(2));
+        // One token bucket equals to prTokenBucket
+        assertTrue(policer.tokenBuckets().contains(prTokenBucket));
+        // One token bucket equals to crTokenBucket
+        assertTrue(policer.tokenBuckets().contains(crTokenBucket));
+    }
+
+    /**
+     * Exception expected to raise when creating a policer with null params.
+     */
+    @Rule
+    public ExpectedException exceptionNullParam = ExpectedException.none();
+
+    /**
+     * Test creation with null parameters.
+     */
+    @Test
+    public void testNullParam() {
+        // Define expected exception
+        exceptionNullParam.expect(NullPointerException.class);
+        // Invalid policer, device id is not defined
+        DefaultPolicer.builder()
+                .fromApp(FOO_APP_ID)
+                .withId(ID6)
+                .build();
+    }
+
+    /**
+     * Exception expected to raise when creating a policer without token buckets.
+     */
+    @Rule
+    public ExpectedException exceptionNoTokenBuckets = ExpectedException.none();
+
+    /**
+     * Test creation without token buckets.
+     */
+    @Test
+    public void testNoTokenBuckets() {
+        // Define expected exception
+        exceptionNoTokenBuckets.expect(IllegalArgumentException.class);
+        // Invalid policer, no token buckets
+        DefaultPolicer.builder()
+                .fromApp(FOO_APP_ID)
+                .withId(ID7)
+                .forDeviceId(DID1)
+                .withTokenBuckets(ImmutableList.of())
+                .build();
+    }
+
+    /**
+     * Test equality between policers.
+     */
+    @Test
+    public void testEqualilty() {
+        // Create a block traffic token bucket
+        TokenBucket blockTokenBucket = DefaultTokenBucket.builder()
+                .withBurstSize(0)
+                .withAction(DROP)
+                .build();
+        // Create a mark traffic token bucket
+        TokenBucket markTokenBucket = DefaultTokenBucket.builder()
+                .withBurstSize(0)
+                .withAction(DSCP_CLASS)
+                .withDscp((short) 10)
+                .build();
+        // Create first policer
+        Policer policerOne = DefaultPolicer.builder()
+                .forDeviceId(DID1)
+                .fromApp(FOO_APP_ID)
+                .withId(ID8)
+                .withTokenBuckets(ImmutableList.of(blockTokenBucket))
+                .build();
+        // Create second policer
+        Policer policerTwo = DefaultPolicer.builder()
+                .forDeviceId(DID1)
+                .fromApp(FOO_APP_ID)
+                .withId(ID9)
+                .withTokenBuckets(ImmutableList.of(markTokenBucket))
+                .build();
+        // Create third policer copy of one
+        // Create first policer
+        Policer policerThree = DefaultPolicer.builder()
+                .forDeviceId(DID1)
+                .fromApp(FOO_APP_ID)
+                .withId(ID8)
+                .withTokenBuckets(ImmutableList.of(blockTokenBucket))
+                .build();
+        // One and Three are equal
+        assertEquals(policerOne, policerThree);
+        // Two is different due to the different id
+        assertNotEquals(policerOne, policerTwo);
+        assertNotEquals(policerThree, policerTwo);
+    }
+
+}
diff --git a/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicingResourceTest.java b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicingResourceTest.java
new file mode 100644
index 0000000..7f6d1f9
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/PolicingResourceTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017-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.behaviour.trafficcontrol;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.onlab.junit.ImmutableClassChecker;
+import org.onosproject.net.ConnectPoint;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.*;
+
+/**
+ * Test class for PolicingResource.
+ */
+public class PolicingResourceTest {
+
+    // Connectpoints
+    private static final String SCP1 = "of:00000000000001/1";
+    private static final String SCP2 = "of:00000000000001/2";
+    private static final ConnectPoint CP1 = ConnectPoint.deviceConnectPoint(SCP1);
+    private static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint(SCP2);
+    // OpenFlow scheme
+    private static final String OF_SCHEME = "of";
+    // Policer identifier
+    private static final String SID = OF_SCHEME + ":" + Integer.toHexString(1);
+    private static final PolicerId PID = PolicerId.policerId(SID);
+
+    /**
+     * Test policing resource creation.
+     */
+    @Test
+    public void testCreation() {
+        // Create a new policing resource
+        PolicingResource policingResource = new PolicingResource(PID, CP1);
+        // Verify proper creation
+        assertThat(policingResource, notNullValue());
+        assertThat(policingResource.policerId(), is(PID));
+        assertThat(policingResource.connectPoint(), is(CP1));
+    }
+
+    /**
+     * Exception expected to raise when creating policing resource with null id.
+     */
+    @Rule
+    public ExpectedException exceptionNullId = ExpectedException.none();
+
+    /**
+     * Test wrong creation of a policing resource.
+     */
+    @Test
+    public void testNullIdCreation() {
+        // Define expected exception
+        exceptionNullId.expect(NullPointerException.class);
+        // Create wrong policing resource
+        new PolicingResource(null, CP1);
+    }
+
+    /**
+     * Test equality between policing resources.
+     */
+    @Test
+    public void testEqualilty() {
+        // Create two identical resources
+        PolicingResource one = new PolicingResource(PID, CP1);
+        PolicingResource copyOfOne = new PolicingResource(PID, CP1);
+        // Verify equality
+        assertEquals(one, copyOfOne);
+        // Create a different resource
+        PolicingResource two = new PolicingResource(PID, CP2);
+        // Verify not equals
+        assertNotEquals(two, one);
+        assertNotEquals(two, copyOfOne);
+    }
+
+    /**
+     * Tests immutability of PolicingResource.
+     */
+    @Test
+    public void testImmutability() {
+        ImmutableClassChecker.assertThatClassIsImmutable(PolicingResource.class);
+    }
+
+}
diff --git a/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucketTest.java b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucketTest.java
new file mode 100644
index 0000000..7deedda
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/TokenBucketTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2017-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.behaviour.trafficcontrol;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.*;
+import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DROP;
+import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DSCP_CLASS;
+import static org.onosproject.net.behaviour.trafficcontrol.TokenBucket.Action.DSCP_PRECEDENCE;
+
+/**
+ * Test class for TokenBucket.
+ */
+public class TokenBucketTest {
+
+    // Test rate
+    private static final long RATE = 1;
+    // Test dscp drop precedence
+    private static final short DSCP_PREC = 2;
+    // Test dscp class
+    private static final short DSCP_CL = 250;
+    // Test wrong dscp
+    private static final short WRONG_DSCP = -1;
+
+    /**
+     * Test creation of a drop token bucket.
+     */
+    @Test
+    public void testDropCreation() {
+        // Create a drop token bucket
+        TokenBucket drop = DefaultTokenBucket.builder()
+                .withRate(RATE)
+                .withAction(DROP)
+                .build();
+        // Not null
+        assertThat(drop, notNullValue());
+        // Rate should be equal to RATE
+        assertThat(drop.rate(), is(RATE));
+        // Burst size should be equal to 2xMTU
+        assertThat(drop.burstSize(), is(2 * 1500L));
+        // Action should be drop
+        assertThat(drop.action(), is(DROP));
+    }
+
+    /**
+     * Test creation of a dscp precedence token bucket.
+     */
+    @Test
+    public void testDscpPrecCreation() {
+        // Create a dscp precedence token bucket
+        TokenBucket drop = DefaultTokenBucket.builder()
+                .withRate(RATE)
+                .withAction(DSCP_PRECEDENCE)
+                .withBurstSize(6 * 1500)
+                .withDscp(DSCP_PREC)
+                .build();
+        // Not null
+        assertThat(drop, notNullValue());
+        // Rate should be equal to RATE
+        assertThat(drop.rate(), is(RATE));
+        // Burst size should be equal to 6xMTU
+        assertThat(drop.burstSize(), is(6 * 1500L));
+        // Action should increase dscp drop precedence
+        assertThat(drop.action(), is(DSCP_PRECEDENCE));
+        // Dcsp drop precedence should be increased of 2
+        assertThat(drop.dscp(), is(DSCP_PREC));
+    }
+
+    /**
+     * Test creation of a dscp class token bucket.
+     */
+    @Test
+    public void testDscpClassCreation() {
+        // Create a dscp class token bucket
+        TokenBucket drop = DefaultTokenBucket.builder()
+                .withRate(RATE)
+                .withAction(DSCP_CLASS)
+                .withDscp(DSCP_CL)
+                .build();
+        // Not null
+        assertThat(drop, notNullValue());
+        // Rate should be equal to RATE
+        assertThat(drop.rate(), is(RATE));
+        // Burst size should be equal to 2xMTU
+        assertThat(drop.burstSize(), is(2 * 1500L));
+        // Action should be drop
+        assertThat(drop.action(), is(DSCP_CLASS));
+        // Dcsp drop precedence should be increased of 2
+        assertThat(drop.dscp(), is(DSCP_CL));
+    }
+
+    /**
+     * Exception expected to raise when creating a token bucket with null action.
+     */
+    @Rule
+    public ExpectedException exceptionNullAction = ExpectedException.none();
+
+    /**
+     * Test creation of a token bucket with null action.
+     */
+    @Test
+    public void testNullActionCreation() {
+        // Define expected exception
+        exceptionNullAction.expect(NullPointerException.class);
+        // Create a token bucket without action
+        TokenBucket drop = DefaultTokenBucket.builder()
+                .withRate(RATE)
+                .build();
+    }
+
+    /**
+     * Exception expected to raise when creating a token bucket with wrong dscp.
+     */
+    @Rule
+    public ExpectedException exceptionWrongDscp = ExpectedException.none();
+
+    /**
+     * Test creation of a token bucket with wrong dscp.
+     */
+    @Test
+    public void testWrongDscpCreation() {
+        // Define expected exception
+        exceptionWrongDscp.expect(IllegalArgumentException.class);
+        // Create a token bucket with wrong dscp
+        TokenBucket drop = DefaultTokenBucket.builder()
+                .withRate(RATE)
+                .withAction(DSCP_PRECEDENCE)
+                .withDscp(WRONG_DSCP)
+                .build();
+    }
+
+    /**
+     * Test equality between policer ids.
+     */
+    @Test
+    public void testEqualilty() {
+        // Create a drop token bucket
+        TokenBucket drop = DefaultTokenBucket.builder()
+                .withRate(RATE)
+                .withAction(DROP)
+                .build();
+        // Create a mark token bucket
+        TokenBucket mark = DefaultTokenBucket.builder()
+                .withRate(RATE)
+                .withAction(DSCP_PRECEDENCE)
+                .withDscp(DSCP_PREC)
+                .build();
+        // Create a copy of the drop token bucket
+        TokenBucket copyDrop = DefaultTokenBucket.builder()
+                .withRate(RATE)
+                .withAction(DROP)
+                .build();
+        // Verify equality
+        assertEquals(drop, copyDrop);
+        // Verify not equals
+        assertNotEquals(mark, drop);
+        assertNotEquals(mark, copyDrop);
+    }
+
+}
diff --git a/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/package-info.java b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/package-info.java
new file mode 100644
index 0000000..63c5f92
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/behaviour/trafficcontrol/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-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.
+ */
+
+/**
+ * Test class for traffic control behaviors and related classes.
+ */
+package org.onosproject.net.behaviour.trafficcontrol;