CI test fixtures

Added in version 0.9.1.

The library provides a set of fixtures that can be used with pytest to setup a simple test environment for functional network tests.

Usage:

# file: conftest.py
pytest_plugins = [
    "pyroute2.fixtures.iproute",
    "pyroute2.fixtures.plan9"
]

# file: my_test.py
def test_my_code(sync_context):
    # here you have access to
    #
    sync_context.ipr        # IPRoute instance running in a netns
    sync_context.netns      # ready to use netns with a test link up
    sync_context.test_link  # test link in the netns
    sync_context.test_link.index    # interface index
    sync_context.test_link.ifname   # interface name
    sync_context.test_link.address  # MAC address

The fixtures set up a network namespace with a unique name, a dummy interface within the namespace, and bring the interface up. They form a tree of dependencies, so if you use e.g. test_link_ifname fixture, you may be sure that the namespace and the interface are already set up properly.

Fixtures dependencies diagram:

_images/aafig-6ac1f8f05ce2ac06a5503c443e4a8893699f060a.svg
pyroute2.fixtures.iproute._nsname() Generator[str]

Network namespace.

  • Name: nsname

  • Scope: function

Create a unique network namespace and yield its name. Remove the netns on cleanup.

It’s safe to create and modify interfaces, addresses, routes etc. in the test network namespace, as it is disconnected from the main system, and the test cleanup will remove the namespace with all its content.

Example usage:

def test_list_interfaces(nsname):
    subprocess.Popen(
        ['ip', 'netns', 'exec', nsname, 'ip', 'link'],
        stdout=subprocess.PIPE,
    )
    # ...

Test interface ifinfmsg.

  • Name: test_link_ifinfmsg

  • Scope: function

  • Depends: nsname

Create a test interface in the test netns and yield ifinfmsg. Remove the interface on cleanup.

This fixture depends on nsname, and it means that the network namespace will be created automatically if you use this fixture.

Example usage:

def test_check_interface(nsname, test_link_ifinfmsg):
    link = test_link_ifinfmsg
    ns = ['ip', 'netns', 'exec', nsname]
    up = ['ip', 'link', 'set', 'dev', link.get('ifname'), 'up']
    subprocess.Popen(ns + up)
    # ...

Test interface spec.

  • Name: test_link

  • Scope: function

  • Depends: nsname, test_link_ifinfmsg

Yield TestInterface object for the test interface, providing a convenient way to access some important interface properties.

Test interface MAC address.

  • Name: test_link_address

  • Scope: function

  • Depends: test_link

Yield test interface MAC address. The network namespace and the test interface exist at this point.

Test interface MAC index.

  • Name: test_link_index

  • Scope: function

  • Depends: test_link

Yield test interface index. The network namespace and the test interface exist at this point.

Test interface MAC ifname.

  • Name: test_link_ifname

  • Scope: function

  • Depends: test_link

Yield test interface ifname. The network namespace and the test interface exist at this point.

pyroute2.fixtures.iproute._async_ipr(request, nsname: str) AsyncGenerator[AsyncIPRoute]

AsyncIPRoute instance.

  • Name: async_ipr

  • Scope: function

  • Depends: nsname

Yield AsyncIPRoute instance, running within the test network namespace. You can provide additional keyword arguments to AsyncIPRoute:

@pytest.mark.parametrize(
    'async_ipr',
    [
        {
            'ext_ack': True,
            'strict_check': True,
        },
    ],
    indirect=True
)
@pytest.mark.asyncio
async def test_my_case(async_ipr):
    await async_ipr.link('set', index=1, state='up')
pyroute2.fixtures.iproute._sync_ipr(request, nsname: str) Generator[IPRoute]

IPRoute instance.

  • Name: sync_ipr

  • Scope: function

  • Depends: nsname

Yield IPRoute instance, running within the test network namespace. You can provide additional keyword arguments to IPRoute:

@pytest.mark.parametrize(
    'sync_ipr',
    [
        {
            'ext_ack': True,
            'strict_check': True,
        },
    ],
    indirect=True
)
def test_my_case(sync_ipr):
    sync_ipr.link('set', index=1, state='up')
pyroute2.fixtures.iproute._async_context(async_ipr: AsyncIPRoute, test_link: TestInterface) AsyncGenerator[TestContext[AsyncIPRoute]]

Asynchronous TestContext.

  • Name: async_context

  • Scope: function

  • Depends: async_ipr, test_link

Yield TestContext with AsyncIPRoute.

pyroute2.fixtures.iproute._sync_context(sync_ipr: IPRoute, test_link: TestInterface) Generator[TestContext[IPRoute]]

Synchronous TestContext.

  • Name: sync_context

  • Scope: function

  • Depends: sync_ipr, test_link

Yield TestContext with IPRoute.

pyroute2.fixtures.iproute._ndb(nsname: str) Generator[NDB]

NDB instance.

  • Name: ndb

  • Scope: function

  • Depends: nsname

Yield NDB instance running in the test network namespace.

class pyroute2.fixtures.iproute.TestInterface(index: int, ifname: str, address: str, nsname: str)

Test interface spec.

Provided by test_link fixture.

Provides shortcuts to some important interface properties, like TestInterface.index or TestInterface.netns.

property index: int

Test interface index.

Is always greater than 1, as index 1 has the the loopback interface.

property ifname: str

Test interface ifname.

The name length must be greater than 1 and less or equal IFNAMSIZ.

property address: str

Test interface MAC address.

In the form xx:xx:xx:xx:xx:xx.

property netns: str

Test interface netns.

A string name of the network namespace.

class pyroute2.fixtures.iproute.TestContext(ipr: T, test_link: TestInterface)

The test context.

Provided by async_context and sync_context fixtures.

Provides convenient shortcuts to RTNL API, the network namespace name and the test interface spec.

property ipr: T

RTNL API.

Return RTNL API instance, either IPRoute, or AsyncIPRoute.

Test interface spec.

Return TestInterface object for the test interface.

property netns: str

Network namespace.

A string name of the network namespace.