File: test_futures.py

package info (click to toggle)
pystemd 0.13.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,296 kB
  • sloc: python: 1,431; sh: 17; makefile: 8
file content (89 lines) | stat: -rw-r--r-- 3,266 bytes parent folder | download
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
#!/usr/bin/env fbpython
# (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.

from __future__ import annotations

import os
import unittest
from unittest.mock import MagicMock, Mock, patch

import pystemd.futures


@patch.object(pystemd.futures, "TransientUnitPoolExecutor", autospec=True)
class TestFuturesRun(unittest.TestCase):
    def test_run(self, TransientUnitPoolExecutor: MagicMock) -> None:
        function = Mock()
        properties = Mock()

        result = pystemd.futures.run(function, properties=properties, kwargs="kwarg")
        poold = TransientUnitPoolExecutor.return_value.__enter__.return_value
        self.assertEqual(result, poold.submit.return_value.result.return_value)
        TransientUnitPoolExecutor.assert_called_once_with(
            properties=properties, max_workers=1
        )
        poold.submit.assert_called_once_with(function, kwargs="kwarg")


@patch.object(pystemd.futures, "TransientUnitContext", autospec=True)
class TestFuturesPool(unittest.TestCase):
    def test_run(self, TransientUnitContext: MagicMock) -> None:
        properties = Mock()
        context = TransientUnitContext.return_value
        with pystemd.futures.TransientUnitPoolExecutor(properties):
            TransientUnitContext.assert_called_once_with(properties)
            context.start_unit.assert_called_once()
        context.stop_unit.assert_called_once()


@patch("os.setuid", autospec=True)
@patch("os.setgid", autospec=True)
@patch("os.open", autospec=True)
@patch("pystemd.cutils.setns", autospec=True)
@patch.object(pystemd.futures.psutil, "Process", autospec=True)
@patch.object(pystemd.futures, "Path", autospec=True)
class TestEnterUnit(unittest.TestCase):
    def test_enter(
        self,
        Path: MagicMock,
        Process: MagicMock,
        setns: MagicMock,
        os_open: MagicMock,
        os_setgid: MagicMock,
        os_setuid: MagicMock,
    ) -> None:
        unit = Mock()
        main_pid = unit.Service.MainPID
        p = Process.return_value
        uid = p.uids.return_value.real
        gid = p.gids.return_value.real

        pystemd.futures.enter_unit(unit)

        Process.assert_called_once_with(main_pid)
        unit.Service.AttachProcesses.assert_called_once_with("/", [os.getpid()])
        Path.assert_called_once_with(f"/proc/{main_pid}/ns")
        os_setgid.assert_called_once_with(gid)
        os_setuid.assert_called_once_with(uid)


@patch.object(pystemd.futures, "enter_unit", autospec=True)
@patch.object(pystemd.futures, "TransientUnitContext", autospec=True)
class TestTransientUnitProcess(unittest.TestCase):
    def test_pre_run(self, TransientUnitContext: MagicMock, enter_unit: Mock):
        properties = {b"foo": b"bar"}
        target = Mock()
        p = pystemd.futures.TransientUnitProcess(properties=properties, target=target)
        # fake call to per_run
        p.pre_run()
        TransientUnitContext.assert_called_once_with(
            properties=properties,
            main_process=[
                "/bin/bash",
                "-c",
                f"exec tail --pid={p.pid} -f /dev/null",
            ],
        )
        enter_unit.assert_called_once_with(
            TransientUnitContext.return_value.start_unit.return_value
        )