Skip to content
test_global_client.py 4.52 KiB
Newer Older
#  Copyright 2019-2021  Dom Sekotill <dom.sekotill@kodo.org.uk>
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

"""
Test cases for wpa_supplicant.client.GlobalClient
"""

import pathlib
import unittest
from unittest.mock import patch

from tests import _anyio as anyio_mock
from wpa_supplicant.client import GlobalClient
from wpa_supplicant.client import InterfaceClient


class InterfaceMethodsTests(unittest.TestCase):
	"""
	Tests for the *_interface(s?) methods
	"""

	def setUp(self):
		self.client = client = GlobalClient()
		client.sock = anyio_mock.AsyncMock()
		client.sock.send.return_value = None

	@anyio_mock.with_anyio()
	async def test_connect(self):
		"""
		Check that connect sets ctrl_dir
		"""
		client1 = GlobalClient()
		client2 = GlobalClient()
Dom Sekotill's avatar
Dom Sekotill committed
		with patch(
			"wpa_supplicant.client.base.BaseClient.connect",
			new_callable=anyio_mock.AsyncMock,
		):
			await client1.connect("/tmp/foo/bar")
			await client2.connect(pathlib.Path("/tmp/foo/bar"))

		self.assertIsInstance(client1.ctrl_dir, pathlib.Path)
		self.assertIsInstance(client2.ctrl_dir, pathlib.Path)

		assert client1.ctrl_dir == pathlib.Path("/tmp/foo")
		assert client2.ctrl_dir == pathlib.Path("/tmp/foo")

	@anyio_mock.with_anyio()
	async def test_list_interfaces(self):
		Check list_interfaces() processes lines of names in a list
		"""
		async with self.client as client:
Dom Sekotill's avatar
Dom Sekotill committed
			# fmt: off
			client.sock.receive.return_value = (
				b"enp0s0\n"
				b"enp1s0\n"
				b"wlp2s0\n"
			)
Dom Sekotill's avatar
Dom Sekotill committed
			# fmt: on
			self.assertEqual(
				await client.list_interfaces(), {"enp0s0", "enp1s0", "wlp2s0"},
			)

			client.sock.send.assert_called_once_with(b"INTERFACES")

	@anyio_mock.with_anyio()
	async def test_add_interface(self):
		"""
		Check add_interface() sends the correct arguments
		"""
		async with self.client as client:
Dom Sekotill's avatar
Dom Sekotill committed
			client.ctrl_dir = pathlib.Path("/tmp")
			client.sock.receive.return_value = b"OK"
Dom Sekotill's avatar
Dom Sekotill committed
			assert await client.add_interface("enp1s0", driver="wired") is None

			client.sock.send.assert_called_once()
			args = client.sock.send.call_args[0]
			assert args[0].startswith(b"INTERFACE_ADD enp1s0\t\twired\tDIR=/tmp GROUP=")
Dom Sekotill's avatar
Dom Sekotill committed
	@patch(
		"wpa_supplicant.client.interfaces.InterfaceClient.connect",
		new_callable=anyio_mock.AsyncMock,
	)
	@anyio_mock.with_anyio()
	async def test_connect_interface(self, connect_mock):
		"""
		Check connect_interface() returns a connected InterfaceClient
		"""
		async with self.client as client:
Dom Sekotill's avatar
Dom Sekotill committed
			client.ctrl_dir = pathlib.Path("/tmp")
			client.sock.receive.side_effect = [
				b"enp1s0\n",  # Response to INTERFACES
			]

Dom Sekotill's avatar
Dom Sekotill committed
			ifclient = await client.connect_interface("enp1s0")
			self.assertIsInstance(ifclient, InterfaceClient)
			connect_mock.assert_called_once_with(pathlib.Path("/tmp/enp1s0"))

			# Check only INTERFACES was sent
			client.sock.send.assert_called_once_with(b"INTERFACES")

Dom Sekotill's avatar
Dom Sekotill committed
	@patch(
		"wpa_supplicant.client.interfaces.InterfaceClient.connect",
		new_callable=anyio_mock.AsyncMock,
	)
	@anyio_mock.with_anyio()
	async def test_connect_interface_with_add(self, connect_mock):
		"""
		Check connect_interface() adds the interface when not already managed
		"""
		async with self.client as client:
Dom Sekotill's avatar
Dom Sekotill committed
			client.ctrl_dir = pathlib.Path("/tmp")
			client.sock.receive.side_effect = [
Dom Sekotill's avatar
Dom Sekotill committed
				b"",  # Response to INTERFACES
				b"OK",  # Response to INTERFACE_ADD
			]

Dom Sekotill's avatar
Dom Sekotill committed
			ifclient = await client.connect_interface("enp1s0")
			self.assertIsInstance(ifclient, InterfaceClient)
			connect_mock.assert_called_once_with(pathlib.Path("/tmp/enp1s0"))

			# Check INTERFACE_ADD sent after INTERFACES
			args = client.sock.send.call_args_list
			self.assertTupleEqual(args[0][0], (b"INTERFACES",))
			assert args[1][0][0].startswith(b"INTERFACE_ADD enp1s0\t")

	@anyio_mock.with_anyio()
	async def test_unconnected(self):
		"""
		Check that calling add_interface() on an unconnected client raises RuntimeError

		This is similar to the identically-named test on the base class, but checks there
		are no issues related to the socket directory not being set.
		"""
		client = GlobalClient()

		with self.assertRaises(RuntimeError):
			await client.add_interface("interface")