Adds tests according to the CI

justification
Adds tests according to the CI wiki specifically the standard test interface in the spec.
The playbook includes Tier1 level test cases that have been tested in the following contexts and
is passing reliably: Classic. Test logs are stored in the artifacts directory.
The following steps are used to execute the tests using the standard test interface:

Test enveronment
Make sure you have installed packages from the spec
```
ansible-2.4.1.0-2.fc28.noarch
python2-dnf-2.7.5-1.fc28.noarch
libselinux-python-2.7-2.fc28.x86_64
standard-test-roles-2.5-1.fc28.noarch
Run tests for Classic
Snip of the example test run for Classic tests:
```

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Setup
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

dhcpcd-6.11.3-5.fc28.x86_64
:: [ 20:04:13 ] :: [   PASS   ] :: Checking for the presence of dhcpcd rpm
:: [ 20:04:13 ] :: [   LOG    ] :: Package versions:
:: [ 20:04:13 ] :: [   LOG    ] ::   dhcpcd-6.11.3-5.fc28.x86_64
:: [ 20:04:13 ] :: [  BEGIN   ] :: Running 'cp dhcpcd-tests.py /usr/bin/'
:: [ 20:04:13 ] :: [   PASS   ] :: Command 'cp dhcpcd-tests.py /usr/bin/' (Expected 0, got 0)
:: [ 20:04:13 ] :: [  BEGIN   ] :: Running 'cp /etc/resolv.conf /var/run/resolv.conf'
:: [ 20:04:13 ] :: [   PASS   ] :: Command 'cp /etc/resolv.conf /var/run/resolv.conf' (Expected 0, got 0)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 0s
::   Assertions: 3 good, 0 bad
::   RESULT: PASS

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Test
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: [ 20:04:13 ] :: [   LOG    ] :: Starting dhcpcd tests ...
:: [ 20:04:13 ] :: [  BEGIN   ] :: Running '/usr/bin/python3 /usr/bin/dhcpcd-tests.py'
test_dhcpcd_clientid_vendorclassid_userclass (__main__.DhcpcdTests)
verify dhcpcd sends custom clientid vendor class id and userclass ... reading from file /tmp/dhcpcd-tcp-dump.pcap, link-type EN10MB (Ethernet)
ok
test_dhcpcd_dns_domain (__main__.DhcpcdTests)
dhcpcd request DNS and domain name ... ok
test_dhcpcd_ipv4 (__main__.DhcpcdTests)
dhcpcd gets address ... ok
test_dhcpcd_mtu (__main__.DhcpcdTests)
dhcpcd gets MTU 1492 ... ok

----------------------------------------------------------------------
Ran 4 tests in 207.483s

OK
:: [ 20:07:41 ] :: [   PASS   ] :: Command '/usr/bin/python3 /usr/bin/dhcpcd-tests.py' (Expected 0, got 0)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 208s
::   Assertions: 1 good, 0 bad
::   RESULT: PASS

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Cleanup
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: [ 20:07:41 ] :: [  BEGIN   ] :: Running 'rm /usr/bin/dhcpcd-tests.py'
:: [ 20:07:41 ] :: [   PASS   ] :: Command 'rm /usr/bin/dhcpcd-tests.py' (Expected 0, got 0)
:: [ 20:07:41 ] :: [  BEGIN   ] :: Running 'cp /var/run/resolv.conf /etc/resolv.conf'
:: [ 20:07:41 ] :: [   PASS   ] :: Command 'cp /var/run/resolv.conf /etc/resolv.conf' (Expected 0, got 0)
:: [ 20:07:41 ] :: [   LOG    ] :: dhcpcd tests done
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 0s
::   Assertions: 2 good, 0 bad
::   RESULT: PASS

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   TEST PROTOCOL
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    Package       : dhcpcd
    Installed     : dhcpcd-6.11.3-5.fc28.x86_64
    beakerlib RPM : beakerlib-1.17-13.fc28.noarch
    Test started  : 2018-05-22 20:04:11 IST
    Test finished : 2018-05-22 20:07:41 IST (still running)
    Test duration : 210 seconds
    Test name     : unknown
    Distro        : Fedora release 28 (Twenty Eight)
    Hostname      : Zeus
    Architecture  : x86_64
    CPUs          : 8 x Intel(R) Core(TM) i7-4700MQ CPU @ 2.40GHz
    RAM size      : 15731 MB
    HDD size      : 226.83 GB

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Setup
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: [ 20:04:13 ] :: [   PASS   ] :: Checking for the presence of dhcpcd rpm
:: [ 20:04:13 ] :: [   LOG    ] :: Package versions:
:: [ 20:04:13 ] :: [   LOG    ] ::   dhcpcd-6.11.3-5.fc28.x86_64
:: [ 20:04:13 ] :: [   PASS   ] :: Command 'cp dhcpcd-tests.py /usr/bin/' (Expected 0, got 0)
:: [ 20:04:13 ] :: [   PASS   ] :: Command 'cp /etc/resolv.conf /var/run/resolv.conf' (Expected 0, got 0)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 0s
::   Assertions: 3 good, 0 bad
::   RESULT: PASS

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Test
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: [ 20:04:13 ] :: [   LOG    ] :: Starting dhcpcd tests ...
:: [ 20:07:41 ] :: [   PASS   ] :: Command '/usr/bin/python3 /usr/bin/dhcpcd-tests.py' (Expected 0, got 0)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 208s
::   Assertions: 1 good, 0 bad
::   RESULT: PASS

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Cleanup
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: [ 20:07:41 ] :: [   PASS   ] :: Command 'rm /usr/bin/dhcpcd-tests.py' (Expected 0, got 0)
:: [ 20:07:41 ] :: [   PASS   ] :: Command 'cp /var/run/resolv.conf /etc/resolv.conf' (Expected 0, got 0)
:: [ 20:07:41 ] :: [   LOG    ] :: dhcpcd tests done
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 0s
::   Assertions: 2 good, 0 bad
::   RESULT: PASS

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   unknown
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: [ 20:07:41 ] :: [   LOG    ] :: JOURNAL XML: /var/tmp/beakerlib-yayPLF0/journal.xml
:: [ 20:07:41 ] :: [   LOG    ] :: JOURNAL TXT: /var/tmp/beakerlib-yayPLF0/journal.txt
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 210s
::   Phases: 3 good, 0 bad
::   OVERALL RESULT: PASS

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Setup
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

dhcpcd-6.11.3-5.fc28.x86_64
:: [ 20:08:23 ] :: [   PASS   ] :: Checking for the presence of dhcpcd rpm
:: [ 20:08:23 ] :: [   LOG    ] :: Package versions:
:: [ 20:08:23 ] :: [   LOG    ] ::   dhcpcd-6.11.3-5.fc28.x86_64
:: [ 20:08:23 ] :: [  BEGIN   ] :: Running 'cp /etc/dhcpcd.duid /var/run/dhcpcd.duid'
:: [ 20:08:23 ] :: [   PASS   ] :: Command 'cp /etc/dhcpcd.duid /var/run/dhcpcd.duid' (Expected 0, got 0)
:: [ 20:08:23 ] :: [  BEGIN   ] :: Running 'cp /etc/resolv.conf /var/run/resolv.conf'
:: [ 20:08:23 ] :: [   PASS   ] :: Command 'cp /etc/resolv.conf /var/run/resolv.conf' (Expected 0, got 0)
:: [ 20:08:23 ] :: [  BEGIN   ] :: Running 'cp dhcpcd-tests.py /usr/bin/'
:: [ 20:08:23 ] :: [   PASS   ] :: Command 'cp dhcpcd-tests.py /usr/bin/' (Expected 0, got 0)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 0s
::   Assertions: 4 good, 0 bad
::   RESULT: PASS

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Test
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: [ 20:08:23 ] :: [   LOG    ] :: Starting dhcpcd tests ...
:: [ 20:08:23 ] :: [  BEGIN   ] :: Running '/usr/bin/python3 /usr/bin/dhcpcd-tests.py'
test_dhcp6s_assigns_static_address_using_duid1 (__main__.DhcpcdTests)
DHCP6c gets the (static) addresses to hosts using known DUID value 00:01:00:01:22:8a:88:26:08:00:27:87:00:7e ... veth-test: DHCPv6 REPLY: Not On Link
ok
test_dhcp6s_assigns_static_address_using_duid2 (__main__.DhcpcdTests)
DHCP6c gets the (static) addresses to hosts using known DUID value 00:01:00:01:22:8d:cb:58:0a:00:27:00:00:00 ... veth-test: DHCPv6 REPLY: Not On Link
ok
test_dhcp6s_gets_rdnss_dnssl (__main__.DhcpcdTests)
DHCP6c gets the RDNSS DNSSL ... veth-test: DHCPv6 REPLY: Not On Link
ok

----------------------------------------------------------------------
Ran 3 tests in 47.880s

OK
:: [ 20:09:11 ] :: [   PASS   ] :: Command '/usr/bin/python3 /usr/bin/dhcpcd-tests.py' (Expected 0, got 0)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 48s
::   Assertions: 1 good, 0 bad
::   RESULT: PASS

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Cleanup
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: [ 20:09:11 ] :: [  BEGIN   ] :: Running 'rm /usr/bin/dhcpcd-tests.py'
:: [ 20:09:11 ] :: [   PASS   ] :: Command 'rm /usr/bin/dhcpcd-tests.py' (Expected 0, got 0)
:: [ 20:09:11 ] :: [  BEGIN   ] :: Running 'mv /var/run/dhcpcd.duid /etc/dhcpcd.duid'
:: [ 20:09:11 ] :: [   PASS   ] :: Command 'mv /var/run/dhcpcd.duid /etc/dhcpcd.duid' (Expected 0, got 0)
:: [ 20:09:11 ] :: [  BEGIN   ] :: Running 'cp /var/run/resolv.conf /etc/resolv.conf'
:: [ 20:09:11 ] :: [   PASS   ] :: Command 'cp /var/run/resolv.conf /etc/resolv.conf' (Expected 0, got 0)
:: [ 20:09:11 ] :: [   LOG    ] :: dhcpcd tests done
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 0s
::   Assertions: 3 good, 0 bad
::   RESULT: PASS

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   TEST PROTOCOL
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    Package       : dhcpcd
    Installed     : dhcpcd-6.11.3-5.fc28.x86_64
    beakerlib RPM : beakerlib-1.17-13.fc28.noarch
    Test started  : 2018-05-22 20:08:21 IST
    Test finished : 2018-05-22 20:09:11 IST (still running)
    Test duration : 50 seconds
    Test name     : unknown
    Distro        : Fedora release 28 (Twenty Eight)
    Hostname      : Zeus
    Architecture  : x86_64
    CPUs          : 8 x Intel(R) Core(TM) i7-4700MQ CPU @ 2.40GHz
    RAM size      : 15731 MB
    HDD size      : 226.83 GB

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Setup
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: [ 20:08:23 ] :: [   PASS   ] :: Checking for the presence of dhcpcd rpm
:: [ 20:08:23 ] :: [   LOG    ] :: Package versions:
:: [ 20:08:23 ] :: [   LOG    ] ::   dhcpcd-6.11.3-5.fc28.x86_64
:: [ 20:08:23 ] :: [   PASS   ] :: Command 'cp /etc/dhcpcd.duid /var/run/dhcpcd.duid' (Expected 0, got 0)
:: [ 20:08:23 ] :: [   PASS   ] :: Command 'cp /etc/resolv.conf /var/run/resolv.conf' (Expected 0, got 0)
:: [ 20:08:23 ] :: [   PASS   ] :: Command 'cp dhcpcd-tests.py /usr/bin/' (Expected 0, got 0)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 0s
::   Assertions: 4 good, 0 bad
::   RESULT: PASS

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Test
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: [ 20:08:23 ] :: [   LOG    ] :: Starting dhcpcd tests ...
:: [ 20:09:11 ] :: [   PASS   ] :: Command '/usr/bin/python3 /usr/bin/dhcpcd-tests.py' (Expected 0, got 0)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 48s
::   Assertions: 1 good, 0 bad
::   RESULT: PASS

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Cleanup
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: [ 20:09:11 ] :: [   PASS   ] :: Command 'rm /usr/bin/dhcpcd-tests.py' (Expected 0, got 0)
:: [ 20:09:11 ] :: [   PASS   ] :: Command 'mv /var/run/dhcpcd.duid /etc/dhcpcd.duid' (Expected 0, got 0)
:: [ 20:09:11 ] :: [   PASS   ] :: Command 'cp /var/run/resolv.conf /etc/resolv.conf' (Expected 0, got 0)
:: [ 20:09:11 ] :: [   LOG    ] :: dhcpcd tests done
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 0s
::   Assertions: 3 good, 0 bad
::   RESULT: PASS

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   unknown
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: [ 20:09:11 ] :: [   LOG    ] :: JOURNAL XML: /var/tmp/beakerlib-KThVq51/journal.xml
:: [ 20:09:11 ] :: [   LOG    ] :: JOURNAL TXT: /var/tmp/beakerlib-KThVq51/journal.txt
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::   Duration: 50s
::   Phases: 3 good, 0 bad
::   OVERALL RESULT: PASS
This commit is contained in:
Susant Sahani 2018-05-22 20:03:03 +05:30
parent 1176d1d556
commit 97d0b20c69
15 changed files with 680 additions and 0 deletions

View File

@ -0,0 +1,20 @@
debug
# Inform the DHCP server of our hostname for DDNS.
hostname
# Use the hardware address of the interface for the Client ID.
clientid
# Persist interface configuration when dhcpcd exits.
persistent
# A list of options to request from the DHCP server.
option domain_name_servers, domain_name, domain_search, host_name
option classless_static_routes
# Most distributions have NTP support.
option ntp_servers
# Respect the network MTU. This is applied to DHCP routes.
option interface_mtu
# A ServerID is required by RFC2131.
require dhcp_server_identifier

View File

@ -0,0 +1,20 @@
debug
# Inform the DHCP server of our hostname for DDNS.
hostname
# Use the hardware address of the interface for the Client ID.
clientid
# Persist interface configuration when dhcpcd exits.
persistent
# A list of options to request from the DHCP server.
option domain_name_servers, domain_name, domain_search, host_name
option classless_static_routes
# Most distributions have NTP support.
option ntp_servers
# Respect the network MTU. This is applied to DHCP routes.
option interface_mtu
# A ServerID is required by RFC2131.
require dhcp_server_identifier

213
tests/ipv4-tests/dhcpcd-tests.py Executable file
View File

@ -0,0 +1,213 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1+
# ~~~
# Description: Tests for dhcpcd - a DHCP client
#
# Author: Susant Sahani <susant@redhat.com>
# Copyright (c) 2018 Red Hat, Inc.
# ~~~
import errno
import os
import sys
import time
import unittest
import subprocess
import signal
import shutil
import psutil
import socket
from pyroute2 import IPRoute
DHCPCD_CI_DIR="/var/run/dhcpcd-ci"
DHCPCD_LOG_FILE='/var/run/dhcpcd-ci/dhcpcd-test-log'
DHCPCD_PID_FILE='/var/run/dhcpcd.pid'
DHCPCD_TCP_DUMP_FILE='/tmp/dhcpcd-tcp-dump.pcap'
DNSMASQ_PID_FILE='/var/run/dhcpcd-ci/test-dnsmasq.pid'
DNSMASQ_LOG_FILE='/var/run/dhcpcd-ci/dnsmasq-log-file'
def setUpModule():
"""Initialize the environment, and perform sanity checks on it."""
if shutil.which('dhcpcd') is None:
raise OSError(errno.ENOENT, 'dhcpcd not found')
if shutil.which('dnsmasq') is None:
raise OSError(errno.ENOENT, 'dnsmasq not found')
def tearDownModule():
pass
class GenericUtilities():
"""Provide a set of utility functions start stop daemons. write config files etc """
def StartDnsMasq(self, conf):
"""Start DnsMasq"""
conf_file=os.path.join(DHCPCD_CI_DIR, conf)
subprocess.check_output(['dnsmasq', '-8', DNSMASQ_LOG_FILE, '--log-dhcp', '--pid-file=/var/run/dhcpcd-ci/test-dnsmasq.pid',
'-C', conf_file, '-i', 'veth-peer', '-R'])
def StartDhcpcd(self, conf):
""" Start dnsmaq """
conf_file=os.path.join(DHCPCD_CI_DIR, conf)
subprocess.check_output(['dhcpcd', '-4', '-M', '-d', '--logfile', DHCPCD_LOG_FILE, '-f', conf_file, 'veth-test'])
def StopDaemon(self, pid_file):
with open(pid_file, 'r') as f:
pid = f.read().rstrip(' \t\r\n\0')
os.kill(int(pid), signal.SIGTERM)
os.remove(pid_file)
def findTextInDaemonLogs(self, log_file, **kwargs):
"""dnsmasq server logs."""
if kwargs is not None:
with open (log_file, 'rt') as in_file:
contents = in_file.read()
for key in kwargs:
self.assertRegex(contents, kwargs[key])
def FindProtocolFieldsinTCPDump(self, **kwargs):
"""Look attributes in tcpdump."""
contents = subprocess.check_output(['tcpdump', '-vv', '-r', DHCPCD_TCP_DUMP_FILE]).rstrip().decode('utf-8')
if kwargs is not None:
for key in kwargs:
self.assertRegex(contents, kwargs[key])
def SetupVethInterface(self):
"""Setup veth interface"""
ip = IPRoute()
ip.link('add', ifname='veth-test', peer='veth-peer', kind='veth')
idx_veth_test = ip.link_lookup(ifname='veth-test')[0]
idx_veth_peer = ip.link_lookup(ifname='veth-peer')[0]
ip.link('set', index=idx_veth_test, address='02:01:02:03:04:08')
ip.link('set', index=idx_veth_peer, address='02:01:02:03:04:09')
ip.link('set', index=idx_veth_test, state='up')
ip.link('set', index=idx_veth_peer, state='up')
ip.addr('add', index=idx_veth_peer, address='192.168.111.50')
ip.close()
def TearDownVethInterface(self):
ip = IPRoute()
ip.link('del', index=ip.link_lookup(ifname='veth-test')[0])
ip.close()
def StartCaptureBOOTPPackets(self):
"""Start tcpdump to capture dhcp packets"""
subprocess.check_output(['systemctl','restart', 'tcpdumpd.service'])
def StopCapturingPackets(self):
subprocess.check_output(['systemctl', 'stop', 'tcpdumpd.service'])
time.sleep(3);
class DhcpcdTests(unittest.TestCase, GenericUtilities):
def setUp(self):
""" setup veth and write radvd and dhcpv6configs """
self.SetupVethInterface()
def tearDown(self):
self.StopDaemon(DHCPCD_PID_FILE)
self.StopDaemon(DNSMASQ_PID_FILE)
self.TearDownVethInterface()
def test_dhcpcd_ipv4(self):
""" dhcpcd gets address """
self.StartDnsMasq('dnsmasq-ipv4.conf')
time.sleep(1)
self.StartDhcpcd('dhcpcd-domain-dns.conf')
time.sleep(5)
output=subprocess.check_output(['ip','address', 'show', 'veth-test']).rstrip().decode('utf-8')
# Address prefix
self.assertRegex(output, "192.168.111.*")
# Default route
output=subprocess.check_output(['ip','route', 'show', 'dev', 'veth-test']).rstrip().decode('utf-8')
self.assertRegex(output, "default via 192.168.1.1*")
def test_dhcpcd_dns_domain(self):
""" dhcpcd request DNS and domain name """
self.StartDnsMasq('dnsmasq-ipv4.conf')
time.sleep(1)
self.StartDhcpcd('dhcpcd-domain-dns.conf')
output=subprocess.check_output(['ip','address', 'show', 'veth-test']).rstrip().decode('utf-8')
# Address prefix
self.assertRegex(output, "192.168.111.*")
# Default route
output=subprocess.check_output(['ip','route', 'show', 'dev', 'veth-test']).rstrip().decode('utf-8')
self.assertRegex(output, "default via 192.168.1.1*")
# Dump the lease file
output=subprocess.check_output(['dhcpcd','-U', '-4', 'veth-test'], stderr=subprocess.STDOUT).rstrip().decode('utf-8')
self.assertRegex(output, 'domain_name=example-test.com')
self.assertRegex(output, 'domain_name_servers=\'8.8.8.8 8.8.4.4\'')
self.assertRegex(output, 'routers=192.168.1.1')
def test_dhcpcd_mtu(self):
""" dhcpcd gets MTU 1492 """
self.StartDnsMasq('dnsmasq-mtu.conf')
time.sleep(1)
self.StartDhcpcd('dhcpcd-mtu.conf')
time.sleep(5)
output=subprocess.check_output(['ip','address', 'show', 'veth-test']).rstrip().decode('utf-8')
# Address prefix
self.assertRegex(output, "192.168.111.*")
# Dump the lease file
output=subprocess.check_output(['dhcpcd','-U', '-4', 'veth-test'], stderr=subprocess.STDOUT).rstrip().decode('utf-8')
self.assertRegex(output, 'interface_mtu=1492')
def test_dhcpcd_clientid_vendorclassid_userclass(self):
""" verify dhcpcd sends custom clientid vendor class id and userclass """
self.StartDnsMasq('dnsmasq-vendorclass.conf')
time.sleep(1)
self.StartCaptureBOOTPPackets()
self.StartDhcpcd('dhcpcd-vendorclass.conf')
time.sleep(5)
self.StopCapturingPackets()
output=subprocess.check_output(['ip','address', 'show', 'veth-test']).rstrip().decode('utf-8')
# Address prefix
self.assertRegex(output, "192.168.111.*")
self.findTextInDaemonLogs(DNSMASQ_LOG_FILE, vendor_class='vendor class: Zeus_dhcpcd_vendorclass_id',
user_class='user class: AAAA BBBB CCCC DDDD',
host_name='client provides name: Zeus')
self.findTextInDaemonLogs(DHCPCD_LOG_FILE, client_id='using ClientID 00:11:11:12:12:13:13:14:14:15:15:16:16')
self.FindProtocolFieldsinTCPDump(vendor='Vendor-Option Option 43, length 11: 104.101.108.108.111.32.119.111.114.108.100',
user_class='instance#1:.*AAAA BBBB CCCC DDDD", length 19',
vendor_class='Vendor-Class Option 60, length 26:.*Zeus_dhcpcd_vendorclass_id',
host_name='Hostname.*Zeus')
os.remove(DHCPCD_TCP_DUMP_FILE)
if __name__ == '__main__':
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
verbosity=3))

View File

@ -0,0 +1,9 @@
debug
hostname Zeus
# Use custom Client ID.
clientid 00:11:11:12:12:13:13:14:14:15:15:16:16
vendorclassid Zeus_dhcpcd_vendorclass_id
userclass "AAAA BBBB CCCC DDDD"
vendor ,"hello world"
# A ServerID is required by RFC2131.
require dhcp_server_identifier

View File

@ -0,0 +1,15 @@
interface=veth-peer
bind-interfaces
# Optionally set a domain name
domain=example-test.com
# Set default gateway
dhcp-option=3,192.168.1.1
# Set DNS servers to announce
dhcp-option=6,8.8.8.8,8.8.4.4
# Dynamic range of IPs to make available to LAN PC and the lease time.
# Ideally set the lease time to 5m only at first to test everything works okay before you set long-lasting records.
dhcp-range=192.168.111.50,192.168.111.100,255.255.255.0,1h

View File

@ -0,0 +1,18 @@
interface=veth-peer
bind-interfaces
# Optionally set a domain name
domain=example-test.com
# Set default gateway
dhcp-option=3,192.168.1.1
# Set DNS servers to announce
dhcp-option=6,8.8.8.8,8.8.4.4
# MTU
dhcp-option=26,1492
# Dynamic range of IPs to make available to LAN PC and the lease time.
# Ideally set the lease time to 5m only at first to test everything works okay before you set long-lasting records.
dhcp-range=192.168.111.50,192.168.111.100,255.255.255.0,1h

View File

@ -0,0 +1,6 @@
interface=veth-peer
bind-interfaces
# Dynamic range of IPs to make available to LAN PC and the lease time.
# Ideally set the lease time to 5m only at first to test everything works okay before you set long-lasting records.
dhcp-range=192.168.111.50,192.168.111.100,255.255.255.0,1h

63
tests/ipv4-tests/runtest.sh Executable file
View File

@ -0,0 +1,63 @@
#!/bin/bash
# SPDX-License-Identifier: LGPL-2.1+
# ~~~
# runtest.sh of dhcpcd
# Description: a DHCP and DHCPv6 client. It's also an IPv4LL (aka ZeroConf) client.
#
# Author: Susant Sahani <susant@redhat.com>
# Copyright (c) 2018 Red Hat, Inc.
# ~~~
# Include Beaker environment
. /usr/share/beakerlib/beakerlib.sh || exit 1
PACKAGE="dhcpcd"
DHCPCD_CI_DIR="/var/run/dhcpcd-ci"
SERVICE_UNITDIR="/var/run/systemd/system"
RESOLVE_CONF="/etc/resolv.conf"
rlJournalStart
rlPhaseStartSetup
rlAssertRpm $PACKAGE
rlRun "systemctl stop firewalld" 0,5
rlRun "setenforce 0" 0,1
rlFileBackup "$RESOLVE_CONF"
rlRun "[ -e /sys/class/net/veth-test ] && ip link del veth-test" 0,1
rlLog "Create work dir ..."
rlRun "mkdir -p $DHCPCD_CI_DIR"
rlRun "cp *.conf $DHCPCD_CI_DIR"
rlRun "cp tcpdumpd.service $SERVICE_UNITDIR"
rlRun "cp dhcpcd-tests.py /usr/bin/"
rlRun "systemctl daemon-reload"
rlPhaseEnd
rlPhaseStartTest
rlLog "Starting dhcpcd tests ..."
rlRun "/usr/bin/python3 /usr/bin/dhcpcd-tests.py"
rlPhaseEnd
rlPhaseStartCleanup
rlRun "rm /usr/bin/dhcpcd-tests.py"
rlRun "[ -e /sys/class/net/veth-test ] && ip link del veth-test" 0,1
rlFileRestore
rlLog "remove work dir"
rlRun "rm -rf $DHCPCD_CI_DIR"
rlRun "rm $SERVICE_UNITDIR/tcpdumpd.service"
rlRun "systemctl daemon-reload"
rlRun "setenforce 1" 0,1
rlLog "dhcpcd tests done"
rlPhaseEnd
rlJournalPrintText
rlJournalEnd
rlGetTestState

View File

@ -0,0 +1,10 @@
[Unit]
Description=TCPDumpd
After=multi-user.target network.target
[Service]
Type=simple
ExecStart=/usr/sbin/tcpdump -i veth-peer port 67 or port 68 -vvv -w "/tmp/dhcpcd-tcp-dump.pcap"
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,20 @@
option domain-name-servers 2001:888:0db8:1::a 2001:888:db8:1::d;
option domain-name "test.com";
host zeus {
duid 00:01:00:01:22:8a:88:26:08:00:27:87:00:7e;
address 2001:888:db8:1::b infinity;
};
host test {
duid 00:01:00:01:22:8d:cb:58:0a:00:27:00:00:00;
address 2001:888:db8:1::c infinity;
};
interface veth-peer {
address-pool pool1 10;
};
pool pool1 {
range 2001:888:0db8:1::1000 to 2001:888:0db8:1::2000;
};

View File

@ -0,0 +1,8 @@
debug
interface veth-test
# Inform the DHCP server of our hostname for DDNS.
hostname
dhcp6
ipv6only
# Persist interface configuration when dhcpcd exits.
persistent

192
tests/ipv6-tests/dhcpcd-tests.py Executable file
View File

@ -0,0 +1,192 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1+
# ~~~
# Description: DHCPv6 Tests for dhcpcd - a DHCP client
#
# Author: Susant Sahani <susant@redhat.com>
# Copyright (c) 2018 Red Hat, Inc.
# ~~~
import errno
import os
import sys
import time
import unittest
import subprocess
import signal
import shutil
import psutil
import socket
from pyroute2 import IPRoute
DHCPCD_CI_DIR="/var/run/dhcpcd-ci"
DHCPCD_LOG_FILE='/var/run/dhcpcd-ci/dhcpcd-test-log'
DHCPCD_CONF_FILE='/var/run/dhcpcd-ci/dhcpcd-test.conf'
DHCPCD_PID_FILE='/var/run/dhcpcd.pid'
DHCPCD_DUID_FILE='/etc/dhcpcd.duid'
RADVD_LOG_FILE ='/var/run/dhcpcd-ci/radvd.log'
RADVD_CONFIG_FILE ='/var/run/dhcpcd-ci/radvd-ci.conf'
RADVD_PID_FILE='/var/run/dhcpcd-ci/radvd.pid'
DHCP6S_CONFIG_FILE='/var/run/dhcpcd-ci/dhcp6s.conf'
DHCP6S_PID_FILE='/var/run/dhcp6s.pid'
RESOLVE_CONF='/etc/resolv.conf'
def setUpModule():
"""Initialize the environment, and perform sanity checks on it."""
if shutil.which('dhcpcd') is None:
raise OSError(errno.ENOENT, 'dhcpcd not found')
if shutil.which('dhcp6s') is None:
raise OSError(errno.ENOENT, 'dhcdp6s not found')
if shutil.which('radvd') is None:
raise OSError(errno.ENOENT, 'radvd not found')
def tearDownModule():
pass
class GenericUtilities():
"""Provide a set of utility functions start stop daemons. write config files etc """
def StartDhcp6s(self):
"""Start dhcp6s"""
subprocess.check_output(['dhcp6s', '-c', DHCP6S_CONFIG_FILE, 'veth-peer', '-dD'])
def StartRadvd(self):
"""Start radvd"""
subprocess.check_output(['radvd', '-d5', '-C', RADVD_CONFIG_FILE, '-p', RADVD_PID_FILE, '-l', RADVD_LOG_FILE])
def StartDhcpcd(self):
subprocess.check_output(['dhcpcd', '-6', '-M', '-d', '--logfile', DHCPCD_LOG_FILE, '-f', DHCPCD_CONF_FILE, 'veth-test'])
def StopDaemon(self, pid_file):
with open(pid_file, 'r') as f:
pid = f.read().rstrip(' \t\r\n\0')
os.kill(int(pid), signal.SIGTERM)
os.remove(pid_file)
def WriteConfigFile(self, path, contents):
"""Write a config file, and queue it to be removed."""
with open(path, 'w') as unit:
unit.write(contents)
self.addCleanup(os.remove, path)
def findTextInDaemonLogs(self, log_file, **kwargs):
"""dnsmasq server logs."""
if kwargs is not None:
with open (log_file, 'rt') as in_file:
contents = in_file.read()
for key in kwargs:
self.assertRegex(contents, kwargs[key])
def SetupVethInterface(self):
"""Setup veth interface"""
ip = IPRoute()
ip.link('add', ifname='veth-test', peer='veth-peer', kind='veth')
idx_veth_test = ip.link_lookup(ifname='veth-test')[0]
idx_veth_peer = ip.link_lookup(ifname='veth-peer')[0]
ip.link('set', index=idx_veth_test, address='02:01:02:03:04:08')
ip.link('set', index=idx_veth_peer, address='02:01:02:03:04:09')
ip.link('set', index=idx_veth_test, state='up')
ip.link('set', index=idx_veth_peer, state='up')
ip.addr('add', index=idx_veth_peer, address='192.168.111.50')
ip.close()
def TearDownVethInterface(self):
ip = IPRoute()
ip.link('del', index=ip.link_lookup(ifname='veth-test')[0])
ip.close()
class DhcpcdTests(unittest.TestCase, GenericUtilities):
def setUp(self):
""" setup veth and write radvd and dhcpv6configs """
self.SetupVethInterface()
def tearDown(self):
self.StopDaemon(DHCPCD_PID_FILE)
self.StopDaemon(RADVD_PID_FILE)
self.StopDaemon(DHCP6S_PID_FILE)
self.TearDownVethInterface()
def test_dhcp6s_gets_rdnss_dnssl(self):
""" DHCP6c gets the RDNSS DNSSL """
self.StartDhcp6s()
self.StartRadvd()
time.sleep(1)
self.WriteConfigFile(DHCPCD_DUID_FILE, '''00:01:00:01:22:8a:88:26:08:00:27:87:00:7e\n''')
self.StartDhcpcd()
time.sleep(10)
output=subprocess.check_output(['ip','address', 'show', 'veth-test']).rstrip().decode('utf-8')
# Address prefix
self.assertRegex(output, "2001:888:db8:1::b")
self.findTextInDaemonLogs(RESOLVE_CONF,
dns1='2001:888:db8:1::a',
dns2='2001:888:db8:1::d',
search='test.com')
def test_dhcp6s_assigns_static_address_using_duid2(self):
""" DHCP6c gets the (static) addresses to hosts using known DUID value 00:01:00:01:22:8d:cb:58:0a:00:27:00:00:00 """
self.StartDhcp6s()
self.StartRadvd()
time.sleep(1)
self.WriteConfigFile(DHCPCD_DUID_FILE, '''00:01:00:01:22:8d:cb:58:0a:00:27:00:00:00\n''')
self.StartDhcpcd()
time.sleep(10)
output=subprocess.check_output(['ip','address', 'show', 'veth-test']).rstrip().decode('utf-8')
# Address
self.assertRegex(output, "2001:888:db8:1::c")
self.findTextInDaemonLogs(RESOLVE_CONF,
dns='2001:888:db8:1::a',
search='test.com')
def test_dhcp6s_assigns_static_address_using_duid1(self):
""" DHCP6c gets the (static) addresses to hosts using known DUID value 00:01:00:01:22:8a:88:26:08:00:27:87:00:7e """
self.StartDhcp6s()
self.StartRadvd()
time.sleep(1)
self.WriteConfigFile(DHCPCD_DUID_FILE, '''00:01:00:01:22:8a:88:26:08:00:27:87:00:7e\n''')
self.StartDhcpcd()
time.sleep(10)
output=subprocess.check_output(['ip','address', 'show', 'veth-test']).rstrip().decode('utf-8')
# Address prefix
self.assertRegex(output, "2001:888:db8:1::b")
self.findTextInDaemonLogs(RESOLVE_CONF,
dns='2001:888:db8:1::a',
search='test.com')
if __name__ == '__main__':
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
verbosity=3))

View File

@ -0,0 +1,9 @@
interface veth-peer
{
AdvSendAdvert on;
AdvManagedFlag on;
AdvOtherConfigFlag on;
prefix 2001:888:0db8:1::/64 {
AdvAutonomous off;
};
};

59
tests/ipv6-tests/runtest.sh Executable file
View File

@ -0,0 +1,59 @@
#!/bin/bash
# SPDX-License-Identifier: LGPL-2.1+
# ~~~
# runtest.sh of dhcpcd
# Description: a DHCP and DHCPv6 client. It's also an IPv4LL (aka ZeroConf) client.
#
# Author: Susant Sahani <susant@redhat.com>
# Copyright (c) 2018 Red Hat, Inc.
# ~~~
# Include Beaker environment
. /usr/share/beakerlib/beakerlib.sh || exit 1
PACKAGE="dhcpcd"
DHCPCD_CI_DIR="/var/run/dhcpcd-ci"
DHCPCD_DUID_FILE="/etc/dhcpcd.duid"
RESOLVE_CONF="/etc/resolv.conf"
rlJournalStart
rlPhaseStartSetup
rlAssertRpm $PACKAGE
rlRun "systemctl stop firewalld" 0,5
rlRun "setenforce 0" 0,1
rlFileBackup "$RESOLVE_CONF"
rlFileBackup "$DHCPCD_DUID_FILE"
rlRun "[ -e /sys/class/net/veth-test ] && ip link del veth-test" 0,1
rlLog "Create work dir ..."
rlRun "mkdir -p $DHCPCD_CI_DIR"
rlRun "cp *.conf $DHCPCD_CI_DIR"
rlRun "cp dhcpcd-tests.py /usr/bin/"
rlPhaseEnd
rlPhaseStartTest
rlLog "Starting dhcpcd tests ..."
rlRun "/usr/bin/python3 /usr/bin/dhcpcd-tests.py"
rlPhaseEnd
rlPhaseStartCleanup
rlRun "rm /usr/bin/dhcpcd-tests.py"
rlRun "[ -e /sys/class/net/veth-test ] && ip link del veth-test" 0,1
rlFileRestore
rlLog "remove work dir"
rlRun "rm -rf $DHCPCD_CI_DIR"
rlRun "setenforce 1" 0,1
rlLog "dhcpcd tests done"
rlPhaseEnd
rlJournalPrintText
rlJournalEnd
rlGetTestState

18
tests/tests.yml Normal file
View File

@ -0,0 +1,18 @@
- hosts: localhost
roles:
- role: standard-test-beakerlib
tags:
- classic
tests:
- ipv4-tests
- ipv6-tests
required_packages:
- radvd
- dnsmasq
- python3
- tcpdump
- systemd
- iproute
- dhcpcd
- wide-dhcpv6
- python3-pyroute2