summaryrefslogtreecommitdiffstats
path: root/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IpPrefixTest.java
blob: 052a4cbb43ad129656add8f07f6b2b874f7e3ab3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
.. This work is licensed under a Creative Commons Attribution 4.0 International License.
.. http://creativecommons.org/licenses/by/4.0

Troubleshooting
===============

This section gives some guidelines about how to troubleshoot the test cases
owned by Functest.

**IMPORTANT**: As in the previous section, the steps defined below must be
executed inside the Functest Docker container and after sourcing the OpenStack
credentials::

    . $creds

or::

    source /home/opnfv/functest/conf/openstack.creds

VIM
---

This section covers the test cases related to the VIM (healthcheck, vping_ssh,
vping_userdata, tempest_smoke_serial, tempest_full_parallel, rally_sanity,
rally_full).

vPing common
^^^^^^^^^^^^
For both vPing test cases (**vPing_ssh**, and **vPing_userdata**), the first steps are
similar:

    * Create Glance image
    * Create Network
    * Create Security Group
    * Create Instances

After these actions, the test cases differ and will be explained in their
respective section.

These test cases can be run inside the container, using new Functest CLI as follows::

    $ functest testcase run vping_ssh
    $ functest testcase run vping_userdata

The Functest CLI is designed to route a call to the corresponding internal
python scripts, located in paths:
*$REPOS_DIR/functest/functest/opnfv_tests/openstack/vping/vping_ssh.py* and
*$REPOS_DIR/functest/functest/opnfv_tests/openstack/vping/vping_userdata.py*

Notes:

  #. There is one difference, between the Functest CLI based test case
     execution compared to the earlier used Bash shell script, which is
     relevant to point out in troubleshooting scenarios:

         The Functest CLI does **not yet** support the option to suppress
         clean-up of the generated OpenStack resources, following the execution
         of a test case.

     Explanation: After finishing the test execution, the corresponding
     script will remove, by default, all created resources in OpenStack
     (image, instances, network and security group). When troubleshooting,
     it is advisable sometimes to keep those resources in case the test
     fails and a manual testing is needed.

     It is actually still possible to invoke test execution, with suppression
     of OpenStack resource cleanup, however this requires invocation of a
     **specific Python script:** 'run_tests'.
     The `OPNFV Functest Developer Guide`_ provides guidance on the use of that
     Python script in such troubleshooting cases.

Some of the common errors that can appear in this test case are::

    vPing_ssh- ERROR - There has been a problem when creating the neutron network....

This means that there has been some problems with Neutron, even before creating the
instances. Try to create manually a Neutron network and a Subnet to see if that works.
The debug messages will also help to see when it failed (subnet and router creation).
Example of Neutron commands (using 10.6.0.0/24 range for example)::

    neutron net-create net-test
    neutron subnet-create --name subnet-test --allocation-pool start=10.6.0.2,end=10.6.0.100 \
    --gateway 10.6.0.254 net-test 10.6.0.0/24
    neutron router-create test_router
    neutron router-interface-add <ROUTER_ID> test_subnet
    neutron router-gateway-set <ROUTER_ID> <EXT_NET_NAME>

Another related error can occur while creating the Security Groups for the instances::

    vPing_ssh- ERROR - Failed to create the security group...

In this case, proceed to create it manually. These are some hints::

    neutron security-group-create sg-test
    neutron security-group-rule-create sg-test --direction ingress --protocol icmp \
    --remote-ip-prefix 0.0.0.0/0
    neutron security-group-rule-create sg-test --direction ingress --ethertype IPv4 \
    --protocol tcp --port-range-min 80 --port-range-max 80 --remote-ip-prefix 0.0.0.0/0
    neutron security-group-rule-create sg-test --direction egress --ethertype IPv4 \
    --protocol tcp --port-range-min 80 --port-range-max 80 --remote-ip-prefix 0.0.0.0/0

The next step is to create the instances. The image used is located in
*/home/opnfv/functest/data/cirros-0.3.5-x86_64-disk.img* and a Glance image is created
with the name **functest-vping**. If booting the instances fails (i.e. the status
is not **ACTIVE**), you can check why it failed by doing::

    nova list
    nova show <INSTANCE_ID>

It might show some messages about the booting failure. To try that manually::

    nova boot --flavor m1.small --image functest-vping --nic net-id=<NET_ID> nova-test

This will spawn a VM using the network created previously manually.
In all the OPNFV tested scenarios from CI, it never has been a problem with the
previous actions. Further possible problems are explained in the following sections.


vPing_SSH
^^^^^^^^^
This test case creates a floating IP on the external network and assigns it to
the second instance **opnfv-vping-2**. The purpose of this is to establish
a SSH connection to that instance and SCP a script that will ping the first
instance. This script is located in the repository under
*$REPOS_DIR/functest/functest/opnfv_tests/openstack/vping/ping.sh* and takes an IP as
a parameter. When the SCP is completed, the test will do an SSH call to that script
inside the second instance. Some problems can happen here::

    vPing_ssh- ERROR - Cannot establish connection to IP xxx.xxx.xxx.xxx. Aborting

If this is displayed, stop the test or wait for it to finish, if you have used
the special method of test invocation with specific supression of OpenStack
resource clean-up, as explained earler. It means that the Container can not
reach the Public/External IP assigned to the instance **opnfv-vping-2**. There
are many possible reasons, and they really depend on the chosen scenario. For
most of the ODL-L3 and ONOS scenarios this has been noticed and it is a known
limitation.

First, make sure that the instance **opnfv-vping-2** succeeded to get an IP
from the DHCP agent. It can be checked by doing::

    nova console-log opnfv-vping-2

If the message *Sending discover* and *No lease, failing* is shown, it probably
means that the Neutron dhcp-agent failed to assign an IP or even that it was not
responding. At this point it does not make sense to try to ping the floating IP.

If the instance got an IP properly, try to ping manually the VM from the container::

    nova list
    <grab the public IP>
    ping <public IP>

If the ping does not return anything, try to ping from the Host where the Docker
container is running. If that solves the problem, check the iptable rules because
there might be some rules rejecting ICMP or TCP traffic coming/going from/to the
container.

At this point, if the ping does not work either, try to reproduce the test
manually with the steps described above in the vPing common section with the
addition::

    neutron floatingip-create <EXT_NET_NAME>
    nova floating-ip-associate nova-test <FLOATING_IP>


Further troubleshooting is out of scope of this document, as it might be due to
problems with the SDN controller. Contact the installer team members or send an
email to the corresponding OPNFV mailing list for more information.



vPing_userdata
^^^^^^^^^^^^^^
This test case does not create any floating IP neither establishes an SSH
connection. Instead, it uses nova-metadata service when creating an instance
to pass the same script as before (ping.sh) but as 1-line text. This script
will be executed automatically when the second instance **opnfv-vping-2** is booted.

The only known problem here for this test to fail is mainly the lack of support
of cloud-init (nova-metadata service). Check the console of the instance::

    nova console-log opnfv-vping-2

If this text or similar is shown::

    checking http://169.254.169.254/2009-04-04/instance-id
    failed 1/20: up 1.13. request failed
    failed 2/20: up 13.18. request failed
    failed 3/20: up 25.20. request failed
    failed 4/20: up 37.23. request failed
    failed 5/20: up 49.25. request failed
    failed 6/20: up 61.27. request failed
    failed 7/20: up 73.29. request failed
    failed 8/20: up 85.32. request failed
    failed 9/20: up 97.34. request failed
    failed 10/20: up 109.36. request failed
    failed 11/20: up 121.38. request failed
    failed 12/20: up 133.40. request failed
    failed 13/20: up 145.43. request failed
    failed 14/20: up 157.45. request failed
    failed 15/20: up 169.48. request failed
    failed 16/20: up 181.50. request failed
    failed 17/20: up 193.52. request failed
    failed 18/20: up 205.54. request failed
    failed 19/20: up 217.56. request failed
    failed 20/20: up 229.58. request failed
    failed to read iid from metadata. tried 20

it means that the instance failed to read from the metadata service. Contact
the Functest or installer teams for more information.

NOTE: Cloud-init in not supported on scenarios dealing with ONOS and the tests
have been excluded from CI in those scenarios.


Tempest
^^^^^^^

In the upstream OpenStack CI all the Tempest test cases are supposed to pass.
If some test cases fail in an OPNFV deployment, the reason is very probably one
of the following

+-----------------------------+-----------------------------------------------------+
| Error                       | Details                                             |
+=============================+=====================================================+
| Resources required for test | Such resources could be e.g. an external network    |
| case execution are missing  | and access to the management subnet (adminURL) from |
|                             | the Functest docker container.                      |
+-----------------------------+-----------------------------------------------------+
| OpenStack components or     | Check running services in the controller and compute|
| services are missing or not | nodes (e.g. with "systemctl" or "service" commands).|
| configured properly         | Configuration parameters can be verified from the   |
|                             | related .conf files located under '/etc/<component>'|
|                             | directories.                                        |
+-----------------------------+-----------------------------------------------------+
| Some resources required for | The tempest.conf file, automatically generated by   |
| execution test cases are    | Rally in Functest, does not contain all the needed  |
| missing                     | parameters or some parameters are not set properly. |
|                             | The tempest.conf file is located in directory       |
|                             | '/home/opnfv/.rally/verification/verifier-<UUID>    |
|                             | /for-deployment-<UUID>'                             |
|                             | in the Functest Docker container. Use the "rally    |
|                             | deployment list" command in order to check the UUID |
|                             | the UUID of the current deployment.                 |
+-----------------------------+-----------------------------------------------------+


When some Tempest test case fails, captured traceback and possibly also the
related REST API requests/responses are output to the console. More detailed debug
information can be found from tempest.log file stored into related Rally deployment
folder.


Rally
^^^^^

The same error causes which were mentioned above for Tempest test cases, may also
lead to errors in Rally as well.

Possible scenarios are:
 * authenticate
 * glance
 * cinder
 * heat
 * keystone
 * neutron
 * nova
 * quotas
 * requests
 * vm

To know more about what those scenarios are doing, they are defined in directory:
*$REPOS_DIR/functest/functest/opnfv_tests/openstack/rally/scenario*
For more info about Rally scenario definition please refer to the Rally official
documentation. `[3]`_

To check any possible problems with Rally, the logs are stored under
*/home/opnfv/functest/results/rally/* in the Functest Docker container.


Controllers
-----------

Opendaylight
^^^^^^^^^^^^

If the Basic Restconf test suite fails, check that the ODL controller is
reachable and its Restconf module has been installed.

If the Neutron Reachability test fails, verify that the modules
implementing Neutron requirements have been properly installed.

If any of the other test cases fails, check that Neutron and ODL have
been correctly configured to work together. Check Neutron configuration
files, accounts, IP addresses etc.).

ONOS
^^^^
Please refer to the ONOS documentation. `ONOSFW User Guide`_ .


Features
--------

Please refer to the dedicated feature user guides for details.



VNF
---

cloudify_ims
^^^^^^^^^^^^
vIMS deployment may fail for several reasons, the most frequent ones are
described in the following table:

+-----------------------------------+------------------------------------+
| Error                             |  Comments                          |
+===================================+====================================+
|
@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
/*
 * Copyright 2014-2015 Open Networking Laboratory
 *
 * 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.onlab.packet;

import org.junit.Test;

import com.google.common.testing.EqualsTester;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass;

/**
 * Tests for class {@link IpPrefix}.
 */
public class IpPrefixTest {
    /**
     * Tests the immutability of {@link IpPrefix}.
     */
    @Test
    public void testImmutable() {
        assertThatClassIsImmutableBaseClass(IpPrefix.class);
    }

    /**
     * Tests the maximum mask length.
     */
    @Test
    public void testMaxMaskLength() {
        assertThat(IpPrefix.MAX_INET_MASK_LENGTH, is(32));
        assertThat(IpPrefix.MAX_INET6_MASK_LENGTH, is(128));
    }

    /**
     * Tests returning the IP version of the prefix.
     */
    @Test
    public void testVersion() {
        IpPrefix ipPrefix;

        // IPv4
        ipPrefix = IpPrefix.valueOf("0.0.0.0/0");
        assertThat(ipPrefix.version(), is(IpAddress.Version.INET));

        // IPv6
        ipPrefix = IpPrefix.valueOf("::/0");
        assertThat(ipPrefix.version(), is(IpAddress.Version.INET6));
    }

    /**
     * Tests whether the IP version of a prefix is IPv4.
     */
    @Test
    public void testIsIp4() {
        IpPrefix ipPrefix;

        // IPv4
        ipPrefix = IpPrefix.valueOf("0.0.0.0/0");
        assertTrue(ipPrefix.isIp4());

        // IPv6
        ipPrefix = IpPrefix.valueOf("::/0");
        assertFalse(ipPrefix.isIp4());
    }

    /**
     * Tests whether the IP version of a prefix is IPv6.
     */
    @Test
    public void testIsIp6() {
        IpPrefix ipPrefix;

        // IPv4
        ipPrefix = IpPrefix.valueOf("0.0.0.0/0");
        assertFalse(ipPrefix.isIp6());

        // IPv6
        ipPrefix = IpPrefix.valueOf("::/0");
        assertTrue(ipPrefix.isIp6());
    }

    /**
     * Tests returning the IP address value and IP address prefix length of
     * an IPv4 prefix.
     */
    @Test
    public void testAddressAndPrefixLengthIPv4() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf("1.2.3.0/24");
        assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("1.2.3.0")));
        assertThat(ipPrefix.prefixLength(), is(24));

        ipPrefix = IpPrefix.valueOf("1.2.3.4/24");
        assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("1.2.3.0")));
        assertThat(ipPrefix.prefixLength(), is(24));

        ipPrefix = IpPrefix.valueOf("1.2.3.4/32");
        assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("1.2.3.4")));
        assertThat(ipPrefix.prefixLength(), is(32));

        ipPrefix = IpPrefix.valueOf("1.2.3.5/32");
        assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("1.2.3.5")));
        assertThat(ipPrefix.prefixLength(), is(32));

        ipPrefix = IpPrefix.valueOf("0.0.0.0/0");
        assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("0.0.0.0")));
        assertThat(ipPrefix.prefixLength(), is(0));

        ipPrefix = IpPrefix.valueOf("255.255.255.255/32");
        assertThat(ipPrefix.address(),
                   equalTo(IpAddress.valueOf("255.255.255.255")));
        assertThat(ipPrefix.prefixLength(), is(32));
    }

    /**
     * Tests returning the IP address value and IP address prefix length of
     * an IPv6 prefix.
     */
    @Test
    public void testAddressAndPrefixLengthIPv6() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf("1100::/8");
        assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("1100::")));
        assertThat(ipPrefix.prefixLength(), is(8));

        ipPrefix =
            IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8885/8");
        assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("1100::")));
        assertThat(ipPrefix.prefixLength(), is(8));

        ipPrefix =
            IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8800/120");
        assertThat(ipPrefix.address(),
                   equalTo(IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8800")));
        assertThat(ipPrefix.prefixLength(), is(120));

        ipPrefix =
            IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8885/128");
        assertThat(ipPrefix.address(),
                   equalTo(IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8885")));
        assertThat(ipPrefix.prefixLength(), is(128));

        ipPrefix = IpPrefix.valueOf("::/0");
        assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("::")));
        assertThat(ipPrefix.prefixLength(), is(0));

        ipPrefix =
            IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
        assertThat(ipPrefix.address(),
                   equalTo(IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));
        assertThat(ipPrefix.prefixLength(), is(128));

        ipPrefix =
            IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8885/64");
        assertThat(ipPrefix.address(),
                   equalTo(IpAddress.valueOf("1111:2222:3333:4444::")));
        assertThat(ipPrefix.prefixLength(), is(64));
    }

    /**
     * Tests getting the Ip4Prefix and Ip6Prefix view of the IP prefix.
     */
    @Test
    public void testGetIp4AndIp6PrefixView() {
        IpPrefix ipPrefix;
        Ip4Prefix ip4Prefix;
        Ip6Prefix ip6Prefix;

        // Pure IPv4 IpPrefix
        ipPrefix = IpPrefix.valueOf("1.2.3.0/24");
        ip4Prefix = ipPrefix.getIp4Prefix();
        ip6Prefix = ipPrefix.getIp6Prefix();
        assertThat(ip4Prefix.toString(), is("1.2.3.0/24"));
        assertNull(ip6Prefix);

        // IPv4 IpPrefix that is Ip4Prefix
        ipPrefix = Ip4Prefix.valueOf("1.2.3.0/24");
        ip4Prefix = ipPrefix.getIp4Prefix();
        ip6Prefix = ipPrefix.getIp6Prefix();
        assertThat(ip4Prefix.toString(), is("1.2.3.0/24"));
        assertNull(ip6Prefix);

        // Pure IPv6 IpPrefix
        ipPrefix = IpPrefix.valueOf("1111:2222::/64");
        ip4Prefix = ipPrefix.getIp4Prefix();
        ip6Prefix = ipPrefix.getIp6Prefix();
        assertNull(ip4Prefix);
        assertThat(ip6Prefix.toString(), is("1111:2222::/64"));

        // IPv6 IpPrefix that is Ip6Prefix
        ipPrefix = Ip6Prefix.valueOf("1111:2222::/64");
        ip4Prefix = ipPrefix.getIp4Prefix();
        ip6Prefix = ipPrefix.getIp6Prefix();
        assertNull(ip4Prefix);
        assertThat(ip6Prefix.toString(), is("1111:2222::/64"));
    }

    /**
     * Tests valueOf() converter for IPv4 integer value.
     */
    @Test
    public void testValueOfForIntegerIPv4() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf(0x01020304, 24);
        assertThat(ipPrefix.toString(), is("1.2.3.0/24"));

        ipPrefix = IpPrefix.valueOf(0x01020304, 32);
        assertThat(ipPrefix.toString(), is("1.2.3.4/32"));

        ipPrefix = IpPrefix.valueOf(0x01020305, 32);
        assertThat(ipPrefix.toString(), is("1.2.3.5/32"));

        ipPrefix = IpPrefix.valueOf(0, 0);
        assertThat(ipPrefix.toString(), is("0.0.0.0/0"));

        ipPrefix = IpPrefix.valueOf(0, 32);
        assertThat(ipPrefix.toString(), is("0.0.0.0/32"));

        ipPrefix = IpPrefix.valueOf(0xffffffff, 0);
        assertThat(ipPrefix.toString(), is("0.0.0.0/0"));

        ipPrefix = IpPrefix.valueOf(0xffffffff, 16);
        assertThat(ipPrefix.toString(), is("255.255.0.0/16"));

        ipPrefix = IpPrefix.valueOf(0xffffffff, 32);
        assertThat(ipPrefix.toString(), is("255.255.255.255/32"));
    }

    /**
     * Tests invalid valueOf() converter for IPv4 integer value and
     * negative prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfIntegerNegativePrefixLengthIPv4() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf(0x01020304, -1);
    }

    /**
     * Tests invalid valueOf() converter for IPv4 integer value and
     * too long prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfIntegerTooLongPrefixLengthIPv4() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf(0x01020304, 33);
    }

    /**
     * Tests valueOf() converter for IPv4 byte array.
     */
    @Test
    public void testValueOfByteArrayIPv4() {
        IpPrefix ipPrefix;
        byte[] value;

        value = new byte[] {1, 2, 3, 4};
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 24);
        assertThat(ipPrefix.toString(), is("1.2.3.0/24"));

        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 32);
        assertThat(ipPrefix.toString(), is("1.2.3.4/32"));

        value = new byte[] {1, 2, 3, 5};
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 32);
        assertThat(ipPrefix.toString(), is("1.2.3.5/32"));

        value = new byte[] {0, 0, 0, 0};
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 0);
        assertThat(ipPrefix.toString(), is("0.0.0.0/0"));

        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 32);
        assertThat(ipPrefix.toString(), is("0.0.0.0/32"));

        value = new byte[] {(byte) 0xff, (byte) 0xff,
                            (byte) 0xff, (byte) 0xff};
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 0);
        assertThat(ipPrefix.toString(), is("0.0.0.0/0"));

        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 16);
        assertThat(ipPrefix.toString(), is("255.255.0.0/16"));

        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 32);
        assertThat(ipPrefix.toString(), is("255.255.255.255/32"));
    }

    /**
     * Tests valueOf() converter for IPv6 byte array.
     */
    @Test
    public void testValueOfByteArrayIPv6() {
        IpPrefix ipPrefix;
        byte[] value;

        value = new byte[] {0x11, 0x11, 0x22, 0x22,
                            0x33, 0x33, 0x44, 0x44,
                            0x55, 0x55, 0x66, 0x66,
                            0x77, 0x77, (byte) 0x88, (byte) 0x88};
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 120);
        assertThat(ipPrefix.toString(),
                   is("1111:2222:3333:4444:5555:6666:7777:8800/120"));

        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 128);
        assertThat(ipPrefix.toString(),
                   is("1111:2222:3333:4444:5555:6666:7777:8888/128"));

        value = new byte[] {0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00};
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 0);
        assertThat(ipPrefix.toString(), is("::/0"));

        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 128);
        assertThat(ipPrefix.toString(), is("::/128"));

        value = new byte[] {(byte) 0xff, (byte) 0xff,
                            (byte) 0xff, (byte) 0xff,
                            (byte) 0xff, (byte) 0xff,
                            (byte) 0xff, (byte) 0xff,
                            (byte) 0xff, (byte) 0xff,
                            (byte) 0xff, (byte) 0xff,
                            (byte) 0xff, (byte) 0xff,
                            (byte) 0xff, (byte) 0xff};
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 0);
        assertThat(ipPrefix.toString(), is("::/0"));

        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 64);
        assertThat(ipPrefix.toString(), is("ffff:ffff:ffff:ffff::/64"));

        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 128);
        assertThat(ipPrefix.toString(),
                   is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"));
    }

    /**
     * Tests invalid valueOf() converter for a null array for IPv4.
     */
    @Test(expected = NullPointerException.class)
    public void testInvalidValueOfNullArrayIPv4() {
        IpPrefix ipPrefix;
        byte[] value;

        value = null;
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 24);
    }

    /**
     * Tests invalid valueOf() converter for a null array for IPv6.
     */
    @Test(expected = NullPointerException.class)
    public void testInvalidValueOfNullArrayIPv6() {
        IpPrefix ipPrefix;
        byte[] value;

        value = null;
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 120);
    }

    /**
     * Tests invalid valueOf() converter for a short array for IPv4.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfShortArrayIPv4() {
        IpPrefix ipPrefix;
        byte[] value;

        value = new byte[] {1, 2, 3};
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 24);
    }

    /**
     * Tests invalid valueOf() converter for a short array for IPv6.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfShortArrayIPv6() {
        IpPrefix ipPrefix;
        byte[] value;

        value = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9};
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 120);
    }

    /**
     * Tests invalid valueOf() converter for IPv4 byte array and
     * negative prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfByteArrayNegativePrefixLengthIPv4() {
        IpPrefix ipPrefix;
        byte[] value;

        value = new byte[] {1, 2, 3, 4};
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, -1);
    }

    /**
     * Tests invalid valueOf() converter for IPv6 byte array and
     * negative prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfByteArrayNegativePrefixLengthIPv6() {
        IpPrefix ipPrefix;
        byte[] value;

        value = new byte[] {0x11, 0x11, 0x22, 0x22,
                            0x33, 0x33, 0x44, 0x44,
                            0x55, 0x55, 0x66, 0x66,
                            0x77, 0x77, (byte) 0x88, (byte) 0x88};
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, -1);
    }

    /**
     * Tests invalid valueOf() converter for IPv4 byte array and
     * too long prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfByteArrayTooLongPrefixLengthIPv4() {
        IpPrefix ipPrefix;
        byte[] value;

        value = new byte[] {1, 2, 3, 4};
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 33);
    }

    /**
     * Tests invalid valueOf() converter for IPv6 byte array and
     * too long prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfByteArrayTooLongPrefixLengthIPv6() {
        IpPrefix ipPrefix;
        byte[] value;

        value = new byte[] {0x11, 0x11, 0x22, 0x22,
                            0x33, 0x33, 0x44, 0x44,
                            0x55, 0x55, 0x66, 0x66,
                            0x77, 0x77, (byte) 0x88, (byte) 0x88};
        ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 129);
    }

    /**
     * Tests valueOf() converter for IPv4 address.
     */
    @Test
    public void testValueOfAddressIPv4() {
        IpAddress ipAddress;
        IpPrefix ipPrefix;

        ipAddress = IpAddress.valueOf("1.2.3.4");
        ipPrefix = IpPrefix.valueOf(ipAddress, 24);
        assertThat(ipPrefix.toString(), is("1.2.3.0/24"));

        ipPrefix = IpPrefix.valueOf(ipAddress, 32);
        assertThat(ipPrefix.toString(), is("1.2.3.4/32"));

        ipAddress = IpAddress.valueOf("1.2.3.5");
        ipPrefix = IpPrefix.valueOf(ipAddress, 32);
        assertThat(ipPrefix.toString(), is("1.2.3.5/32"));

        ipAddress = IpAddress.valueOf("0.0.0.0");
        ipPrefix = IpPrefix.valueOf(ipAddress, 0);
        assertThat(ipPrefix.toString(), is("0.0.0.0/0"));

        ipPrefix = IpPrefix.valueOf(ipAddress, 32);
        assertThat(ipPrefix.toString(), is("0.0.0.0/32"));

        ipAddress = IpAddress.valueOf("255.255.255.255");
        ipPrefix = IpPrefix.valueOf(ipAddress, 0);
        assertThat(ipPrefix.toString(), is("0.0.0.0/0"));

        ipPrefix = IpPrefix.valueOf(ipAddress, 16);
        assertThat(ipPrefix.toString(), is("255.255.0.0/16"));

        ipPrefix = IpPrefix.valueOf(ipAddress, 32);
        assertThat(ipPrefix.toString(), is("255.255.255.255/32"));
    }

    /**
     * Tests valueOf() converter for IPv6 address.
     */
    @Test
    public void testValueOfAddressIPv6() {
        IpAddress ipAddress;
        IpPrefix ipPrefix;

        ipAddress =
            IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8888");
        ipPrefix = IpPrefix.valueOf(ipAddress, 120);
        assertThat(ipPrefix.toString(),
                   is("1111:2222:3333:4444:5555:6666:7777:8800/120"));

        ipPrefix = IpPrefix.valueOf(ipAddress, 128);
        assertThat(ipPrefix.toString(),
                   is("1111:2222:3333:4444:5555:6666:7777:8888/128"));

        ipAddress = IpAddress.valueOf("::");
        ipPrefix = IpPrefix.valueOf(ipAddress, 0);
        assertThat(ipPrefix.toString(), is("::/0"));

        ipPrefix = IpPrefix.valueOf(ipAddress, 128);
        assertThat(ipPrefix.toString(), is("::/128"));

        ipAddress =
            IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
        ipPrefix = IpPrefix.valueOf(ipAddress, 0);
        assertThat(ipPrefix.toString(), is("::/0"));

        ipPrefix = IpPrefix.valueOf(ipAddress, 64);
        assertThat(ipPrefix.toString(), is("ffff:ffff:ffff:ffff::/64"));

        ipPrefix = IpPrefix.valueOf(ipAddress, 128);
        assertThat(ipPrefix.toString(),
                   is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"));
    }

    /**
     * Tests invalid valueOf() converter for a null IP address.
     */
    @Test(expected = NullPointerException.class)
    public void testInvalidValueOfNullAddress() {
        IpAddress ipAddress;
        IpPrefix ipPrefix;

        ipAddress = null;
        ipPrefix = IpPrefix.valueOf(ipAddress, 24);
    }

    /**
     * Tests invalid valueOf() converter for IPv4 address and
     * negative prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfAddressNegativePrefixLengthIPv4() {
        IpAddress ipAddress;
        IpPrefix ipPrefix;

        ipAddress = IpAddress.valueOf("1.2.3.4");
        ipPrefix = IpPrefix.valueOf(ipAddress, -1);
    }

    /**
     * Tests invalid valueOf() converter for IPv6 address and
     * negative prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfAddressNegativePrefixLengthIPv6() {
        IpAddress ipAddress;
        IpPrefix ipPrefix;

        ipAddress =
            IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8888");
        ipPrefix = IpPrefix.valueOf(ipAddress, -1);
    }

    /**
     * Tests invalid valueOf() converter for IPv4 address and
     * too long prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfAddressTooLongPrefixLengthIPv4() {
        IpAddress ipAddress;
        IpPrefix ipPrefix;

        ipAddress = IpAddress.valueOf("1.2.3.4");
        ipPrefix = IpPrefix.valueOf(ipAddress, 33);
    }

    /**
     * Tests invalid valueOf() converter for IPv6 address and
     * too long prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfAddressTooLongPrefixLengthIPv6() {
        IpAddress ipAddress;
        IpPrefix ipPrefix;

        ipAddress =
            IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8888");
        ipPrefix = IpPrefix.valueOf(ipAddress, 129);
    }

    /**
     * Tests valueOf() converter for IPv4 string.
     */
    @Test
    public void testValueOfStringIPv4() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf("1.2.3.4/24");
        assertThat(ipPrefix.toString(), is("1.2.3.0/24"));

        ipPrefix = IpPrefix.valueOf("1.2.3.4/32");
        assertThat(ipPrefix.toString(), is("1.2.3.4/32"));

        ipPrefix = IpPrefix.valueOf("1.2.3.5/32");
        assertThat(ipPrefix.toString(), is("1.2.3.5/32"));

        ipPrefix = IpPrefix.valueOf("0.0.0.0/0");
        assertThat(ipPrefix.toString(), is("0.0.0.0/0"));

        ipPrefix = IpPrefix.valueOf("0.0.0.0/32");
        assertThat(ipPrefix.toString(), is("0.0.0.0/32"));

        ipPrefix = IpPrefix.valueOf("255.255.255.255/0");
        assertThat(ipPrefix.toString(), is("0.0.0.0/0"));

        ipPrefix = IpPrefix.valueOf("255.255.255.255/16");
        assertThat(ipPrefix.toString(), is("255.255.0.0/16"));

        ipPrefix = IpPrefix.valueOf("255.255.255.255/32");
        assertThat(ipPrefix.toString(), is("255.255.255.255/32"));
    }

    /**
     * Tests valueOf() converter for IPv6 string.
     */
    @Test
    public void testValueOfStringIPv6() {
        IpPrefix ipPrefix;

        ipPrefix =
            IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8888/120");
        assertThat(ipPrefix.toString(),
                   is("1111:2222:3333:4444:5555:6666:7777:8800/120"));

        ipPrefix =
            IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8888/128");
        assertThat(ipPrefix.toString(),
                   is("1111:2222:3333:4444:5555:6666:7777:8888/128"));

        ipPrefix = IpPrefix.valueOf("::/0");
        assertThat(ipPrefix.toString(), is("::/0"));

        ipPrefix = IpPrefix.valueOf("::/128");
        assertThat(ipPrefix.toString(), is("::/128"));

        ipPrefix =
            IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/0");
        assertThat(ipPrefix.toString(), is("::/0"));

        ipPrefix =
            IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64");
        assertThat(ipPrefix.toString(), is("ffff:ffff:ffff:ffff::/64"));

        ipPrefix =
            IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
        assertThat(ipPrefix.toString(),
                   is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"));
    }

    /**
     * Tests invalid valueOf() converter for a null string.
     */
    @Test(expected = NullPointerException.class)
    public void testInvalidValueOfNullString() {
        IpPrefix ipPrefix;
        String fromString;

        fromString = null;
        ipPrefix = IpPrefix.valueOf(fromString);
    }

    /**
     * Tests invalid valueOf() converter for an empty string.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfEmptyString() {
        IpPrefix ipPrefix;
        String fromString;

        fromString = "";
        ipPrefix = IpPrefix.valueOf(fromString);
    }

    /**
     * Tests invalid valueOf() converter for an incorrect string.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfIncorrectString() {
        IpPrefix ipPrefix;
        String fromString;

        fromString = "NoSuchIpPrefix";
        ipPrefix = IpPrefix.valueOf(fromString);
    }

    /**
     * Tests invalid valueOf() converter for IPv4 string and
     * negative prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfStringNegativePrefixLengthIPv4() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf("1.2.3.4/-1");
    }

    /**
     * Tests invalid valueOf() converter for IPv6 string and
     * negative prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfStringNegativePrefixLengthIPv6() {
        IpPrefix ipPrefix;

        ipPrefix =
            IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8888/-1");
    }

    /**
     * Tests invalid valueOf() converter for IPv4 string and
     * too long prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfStringTooLongPrefixLengthIPv4() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf("1.2.3.4/33");
    }

    /**
     * Tests invalid valueOf() converter for IPv6 string and
     * too long prefix length.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidValueOfStringTooLongPrefixLengthIPv6() {
        IpPrefix ipPrefix;

        ipPrefix =
            IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8888/129");
    }

    /**
     * Tests IP prefix contains another IP prefix for IPv4.
     */
    @Test
    public void testContainsIpPrefixIPv4() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf("1.2.0.0/24");
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/24")));
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/32")));
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.4/32")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/16")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.3.0.0/24")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/16")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/0")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("255.255.255.255/32")));

        ipPrefix = IpPrefix.valueOf("1.2.0.0/32");
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/24")));
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/32")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.4/32")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/16")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.3.0.0/24")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/16")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/0")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("255.255.255.255/32")));

        ipPrefix = IpPrefix.valueOf("0.0.0.0/0");
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/24")));
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/32")));
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.4/32")));
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/16")));
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.3.0.0/24")));
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/16")));
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/0")));
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("255.255.255.255/32")));

        ipPrefix = IpPrefix.valueOf("255.255.255.255/32");
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/24")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/32")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.4/32")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/16")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.3.0.0/24")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/16")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/0")));
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("255.255.255.255/32")));

        // Test when there is a mistmatch in the compared IP address families
        ipPrefix = IpPrefix.valueOf("0.0.0.0/0");
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("1111:2222:3333:4444::/120")));
        ipPrefix = IpPrefix.valueOf("255.255.255.255/32");
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")));
    }

    /**
     * Tests IP prefix contains another IP prefix for IPv6.
     */
    @Test
    public void testContainsIpPrefixIPv6() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf("1111:2222:3333:4444::/120");
        assertTrue(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::/120")));
        assertTrue(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::/128")));
        assertTrue(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::1/128")));
        assertFalse(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::/64")));
        assertFalse(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4445::/120")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("::/64")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("::/0")));
        assertFalse(ipPrefix.contains(
                IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")));

        ipPrefix = IpPrefix.valueOf("1111:2222:3333:4444::/128");
        assertFalse(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::/120")));
        assertTrue(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::/128")));
        assertFalse(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::1/128")));
        assertFalse(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::/64")));
        assertFalse(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4445::/120")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("::/64")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("::/0")));
        assertFalse(ipPrefix.contains(
                IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")));

        ipPrefix = IpPrefix.valueOf("::/0");
        assertTrue(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::/120")));
        assertTrue(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::/128")));
        assertTrue(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::1/128")));
        assertTrue(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::/64")));
        assertTrue(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4445::/120")));
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("::/64")));
        assertTrue(ipPrefix.contains(IpPrefix.valueOf("::/0")));
        assertTrue(ipPrefix.contains(
                IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")));

        ipPrefix =
            IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
        assertFalse(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::/120")));
        assertFalse(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::/128")));
        assertFalse(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::1/128")));
        assertFalse(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4444::/64")));
        assertFalse(ipPrefix.contains(
                IpPrefix.valueOf("1111:2222:3333:4445::/120")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("::/64")));
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("::/0")));
        assertTrue(ipPrefix.contains(
                IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")));

        // Test when there is a mistmatch in the compared IP address families
        ipPrefix = IpPrefix.valueOf("::/0");
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/24")));
        ipPrefix = IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
        assertFalse(ipPrefix.contains(IpPrefix.valueOf("255.255.255.255/32")));
    }

    /**
     * Tests IP prefix contains IP address for IPv4.
     */
    @Test
    public void testContainsIpAddressIPv4() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf("1.2.0.0/24");
        assertTrue(ipPrefix.contains(IpAddress.valueOf("1.2.0.0")));
        assertTrue(ipPrefix.contains(IpAddress.valueOf("1.2.0.4")));
        assertFalse(ipPrefix.contains(IpAddress.valueOf("1.3.0.0")));
        assertFalse(ipPrefix.contains(IpAddress.valueOf("0.0.0.0")));
        assertFalse(ipPrefix.contains(IpAddress.valueOf("255.255.255.255")));

        ipPrefix = IpPrefix.valueOf("1.2.0.0/32");
        assertTrue(ipPrefix.contains(IpAddress.valueOf("1.2.0.0")));
        assertFalse(ipPrefix.contains(IpAddress.valueOf("1.2.0.4")));
        assertFalse(ipPrefix.contains(IpAddress.valueOf("1.3.0.0")));
        assertFalse(ipPrefix.contains(IpAddress.valueOf("0.0.0.0")));
        assertFalse(ipPrefix.contains(IpAddress.valueOf("255.255.255.255")));

        ipPrefix = IpPrefix.valueOf("0.0.0.0/0");
        assertTrue(ipPrefix.contains(IpAddress.valueOf("1.2.0.0")));
        assertTrue(ipPrefix.contains(IpAddress.valueOf("1.2.0.4")));
        assertTrue(ipPrefix.contains(IpAddress.valueOf("1.3.0.0")));
        assertTrue(ipPrefix.contains(IpAddress.valueOf("0.0.0.0")));
        assertTrue(ipPrefix.contains(IpAddress.valueOf("255.255.255.255")));

        ipPrefix = IpPrefix.valueOf("255.255.255.255/32");
        assertFalse(ipPrefix.contains(IpAddress.valueOf("1.2.0.0")));
        assertFalse(ipPrefix.contains(IpAddress.valueOf("1.2.0.4")));
        assertFalse(ipPrefix.contains(IpAddress.valueOf("1.3.0.0")));
        assertFalse(ipPrefix.contains(IpAddress.valueOf("0.0.0.0")));
        assertTrue(ipPrefix.contains(IpAddress.valueOf("255.255.255.255")));

        // Test when there is a mistmatch in the compared IP address families
        ipPrefix = IpPrefix.valueOf("0.0.0.0/0");
        assertFalse(ipPrefix.contains(IpAddress.valueOf("1111:2222:3333:4444::")));
        ipPrefix = IpPrefix.valueOf("255.255.255.255/32");
        assertFalse(ipPrefix.contains(IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));
    }

    /**
     * Tests IP prefix contains IP address for IPv6.
     */
    @Test
    public void testContainsIpAddressIPv6() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf("1111:2222:3333:4444::/120");
        assertTrue(ipPrefix.contains(
                IpAddress.valueOf("1111:2222:3333:4444::")));
        assertTrue(ipPrefix.contains(
                IpAddress.valueOf("1111:2222:3333:4444::1")));
        assertFalse(ipPrefix.contains(
                IpAddress.valueOf("1111:2222:3333:4445::")));
        assertFalse(ipPrefix.contains(IpAddress.valueOf("::")));
        assertFalse(ipPrefix.contains(
                IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));

        ipPrefix = IpPrefix.valueOf("1111:2222:3333:4444::/128");
        assertTrue(ipPrefix.contains(
                IpAddress.valueOf("1111:2222:3333:4444::")));
        assertFalse(ipPrefix.contains(
                IpAddress.valueOf("1111:2222:3333:4444::1")));
        assertFalse(ipPrefix.contains(
                IpAddress.valueOf("1111:2222:3333:4445::")));
        assertFalse(ipPrefix.contains(IpAddress.valueOf("::")));
        assertFalse(ipPrefix.contains(
                IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));

        ipPrefix = IpPrefix.valueOf("::/0");
        assertTrue(ipPrefix.contains(
                IpAddress.valueOf("1111:2222:3333:4444::")));
        assertTrue(ipPrefix.contains(
                IpAddress.valueOf("1111:2222:3333:4444::1")));
        assertTrue(ipPrefix.contains(
                IpAddress.valueOf("1111:2222:3333:4445::")));
        assertTrue(ipPrefix.contains(IpAddress.valueOf("::")));
        assertTrue(ipPrefix.contains(
                IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));

        ipPrefix =
            IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
        assertFalse(ipPrefix.contains(
                IpAddress.valueOf("1111:2222:3333:4444::")));
        assertFalse(ipPrefix.contains(
                IpAddress.valueOf("1111:2222:3333:4444::1")));
        assertFalse(ipPrefix.contains(
                IpAddress.valueOf("1111:2222:3333:4445::")));
        assertFalse(ipPrefix.contains(IpAddress.valueOf("::")));
        assertTrue(ipPrefix.contains(
                IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));

        // Test when there is a mistmatch in the compared IP address families
        ipPrefix = IpPrefix.valueOf("::/0");
        assertFalse(ipPrefix.contains(IpAddress.valueOf("1.2.0.0")));
        ipPrefix = IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
        assertFalse(ipPrefix.contains(IpAddress.valueOf("255.255.255.255")));
    }

    /**
     * Tests equality of {@link IpPrefix} for IPv4.
     */
    @Test
    public void testEqualityIPv4() {
        new EqualsTester()
            .addEqualityGroup(IpPrefix.valueOf("1.2.0.0/24"),
                              IpPrefix.valueOf("1.2.0.0/24"),
                              IpPrefix.valueOf("1.2.0.4/24"))
            .addEqualityGroup(IpPrefix.valueOf("1.2.0.0/16"),
                              IpPrefix.valueOf("1.2.0.0/16"))
            .addEqualityGroup(IpPrefix.valueOf("1.2.0.0/32"),
                              IpPrefix.valueOf("1.2.0.0/32"))
            .addEqualityGroup(IpPrefix.valueOf("1.3.0.0/24"),
                              IpPrefix.valueOf("1.3.0.0/24"))
            .addEqualityGroup(IpPrefix.valueOf("0.0.0.0/0"),
                              IpPrefix.valueOf("0.0.0.0/0"))
            .addEqualityGroup(IpPrefix.valueOf("255.255.255.255/32"),
                              IpPrefix.valueOf("255.255.255.255/32"))
            .testEquals();
    }

    /**
     * Tests equality of {@link IpPrefix} for IPv6.
     */
    @Test
    public void testEqualityIPv6() {
        new EqualsTester()
            .addEqualityGroup(
                IpPrefix.valueOf("1111:2222:3333:4444::/120"),
                IpPrefix.valueOf("1111:2222:3333:4444::1/120"),
                IpPrefix.valueOf("1111:2222:3333:4444::/120"))
            .addEqualityGroup(
                IpPrefix.valueOf("1111:2222:3333:4444::/64"),
                IpPrefix.valueOf("1111:2222:3333:4444::/64"))
            .addEqualityGroup(
                IpPrefix.valueOf("1111:2222:3333:4444::/128"),
                IpPrefix.valueOf("1111:2222:3333:4444::/128"))
            .addEqualityGroup(
                IpPrefix.valueOf("1111:2222:3333:4445::/64"),
                IpPrefix.valueOf("1111:2222:3333:4445::/64"))
            .addEqualityGroup(
                IpPrefix.valueOf("::/0"),
                IpPrefix.valueOf("::/0"))
            .addEqualityGroup(
                IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"),
                IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"))
            .testEquals();
    }

    /**
     * Tests object string representation for IPv4.
     */
    @Test
    public void testToStringIPv4() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf("1.2.3.0/24");
        assertThat(ipPrefix.toString(), is("1.2.3.0/24"));

        ipPrefix = IpPrefix.valueOf("1.2.3.4/24");
        assertThat(ipPrefix.toString(), is("1.2.3.0/24"));

        ipPrefix = IpPrefix.valueOf("0.0.0.0/0");
        assertThat(ipPrefix.toString(), is("0.0.0.0/0"));

        ipPrefix = IpPrefix.valueOf("255.255.255.255/32");
        assertThat(ipPrefix.toString(), is("255.255.255.255/32"));
    }

    /**
     * Tests object string representation for IPv6.
     */
    @Test
    public void testToStringIPv6() {
        IpPrefix ipPrefix;

        ipPrefix = IpPrefix.valueOf("1100::/8");
        assertThat(ipPrefix.toString(), is("1100::/8"));

        ipPrefix = IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8885/8");
        assertThat(ipPrefix.toString(), is("1100::/8"));

        ipPrefix = IpPrefix.valueOf("::/0");
        assertThat(ipPrefix.toString(), is("::/0"));

        ipPrefix = IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
        assertThat(ipPrefix.toString(),
                   is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"));
    }
}