Skip to content

Commit bf311f7

Browse files
achow101vijaydasmp
authored andcommitted
Merge bitcoin#29034: test: detect OS in functional tests consistently using platform.system()
878d914 doc: test: mention OS detection preferences in style guideline (Sebastian Falbesoner) 4c65ac9 test: detect OS consistently using `platform.system()` (Sebastian Falbesoner) 37324ae test: use `skip_if_platform_not_linux` helper where possible (Sebastian Falbesoner) Pull request description: There are at least three ways to detect the operating system in Python3: - `os.name` (https://docs.python.org/3.9/library/os.html#os.name) - `sys.platform` (https://docs.python.org/3.9/library/sys.html#sys.platform) - `platform.system()` (https://docs.python.org/3.9/library/platform.html#platform.system) We are currently using all of them in functional tests (both in individual tests and shared test framework code), which seems a bit messy. This PR consolidates into using `platform.system()`, as it appears to be one most consistent and easy to read (see also [IRC discussion](https://bitcoin-irc.chaincode.com/bitcoin-core-dev/2023-12-08#989301;) and table below). `sys.platform` is inconsistent as it has the major version number encoded for BSD systems, which doesn't make much sense for e.g. OpenBSD, where there is no concept of major versions, but instead the version is simply increased by 0.1 on each release. Note that `os.name` is still useful to detect whether we are running a POSIX system (see `BitcoinTestFramework.skip_if_platform_not_posix`), so for this use-case it is kept as only exception. The following table shows values for common operating systems, found via ``` $ python3 -c "import os; import sys; import platform; print(os.name, sys.platform, platform.system())" ``` | OS | os.name | sys.platform | platform.system() | |--------------|---------|--------------|--------------------| | Linux 6.2.0 | posix | linux | Linux | | MacOS* | posix | darwin | Darwin | | OpenBSD 7.4 | posix | openbsd7 | OpenBSD | | Windows* | nt | win32 | Windows | \* = I neither have a MacOS nor a Windows machine available, so I extracted the values from documentation and our current code. Also I'm relying on CI for testing the relevant code-paths. Having reviewers to this this locally would be very appreciated, if this gets Concept ACKed. ACKs for top commit: kevkevinpal: ACK [878d914](bitcoin@878d914) achow101: ACK 878d914 hebasto: ACK 878d914, I have reviewed the code and it looks OK. pablomartin4btc: tACK 878d914 Tree-SHA512: 24513d493e47f572028c843260b81c47c2c29bfb701991050255c9f9529cd19065ecbc7b3b6e15619da7f3f608b4825c345ce6fee30d8fd1eaadbd08cff400fc
1 parent 67891f5 commit bf311f7

11 files changed

Lines changed: 31 additions & 32 deletions

File tree

test/functional/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ don't have test cases for.
3737
`set_test_params()`, `add_options()` and `setup_xxxx()` methods at the top of
3838
the subclass, then locally-defined helper methods, then the `run_test()` method.
3939
- Use `f'{x}'` for string formatting in preference to `'{}'.format(x)` or `'%s' % x`.
40+
- Use `platform.system()` for detecting the running operating system and `os.name` to
41+
check whether it's a POSIX system (see also the `skip_if_platform_not_{linux,posix}`
42+
methods in the `BitcoinTestFramework` class, which can be used to skip a whole test
43+
depending on the platform).
4044

4145
#### Naming guidelines
4246

test/functional/feature_bind_extra.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,12 @@
77
that bind happens on the expected ports.
88
"""
99

10-
import sys
11-
1210
from test_framework.netutil import (
1311
addr_to_hex,
1412
get_bind_addrs,
1513
)
1614
from test_framework.test_framework import (
1715
BitcoinTestFramework,
18-
SkipTest,
1916
)
2017
from test_framework.util import (
2118
assert_equal,
@@ -32,12 +29,11 @@ def set_test_params(self):
3229
self.bind_to_localhost_only = False
3330
self.num_nodes = 2
3431

35-
def setup_network(self):
32+
def skip_test_if_missing_module(self):
3633
# Due to OS-specific network stats queries, we only run on Linux.
37-
self.log.info("Checking for Linux")
38-
if not sys.platform.startswith('linux'):
39-
raise SkipTest("This test can only be run on Linux.")
34+
self.skip_if_platform_not_linux()
4035

36+
def setup_network(self):
4137
loopback_ipv4 = addr_to_hex("127.0.0.1")
4238

4339
# Start custom ports by reusing unused p2p ports

test/functional/feature_config_args.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import platform
99
import pathlib
1010
import re
11-
import sys
1211
import tempfile
1312
import time
1413

@@ -117,7 +116,7 @@ def test_config_file_parser(self):
117116
def test_config_file_log(self):
118117
# Disable this test for windows currently because trying to override
119118
# the default datadir through the environment does not seem to work.
120-
if sys.platform == "win32":
119+
if platform.system() == "Windows":
121120
return
122121

123122
self.log.info('Test that correct configuration path is changed when configuration file changes the datadir')
@@ -339,7 +338,7 @@ def test_ignored_conf(self):
339338
def test_ignored_default_conf(self):
340339
# Disable this test for windows currently because trying to override
341340
# the default datadir through the environment does not seem to work.
342-
if sys.platform == "win32":
341+
if platform.system() == "Windows":
343342
return
344343

345344
self.log.info('Test error is triggered when dash.conf in the default data directory sets another datadir '

test/functional/feature_init.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Stress tests related to node initialization."""
6-
import os
76
from pathlib import Path
87
from random import randint
8+
import platform
99
import shutil
1010

1111
from test_framework.test_framework import BitcoinTestFramework, SkipTest
@@ -37,7 +37,7 @@ def run_test(self):
3737
# and other approaches (like below) don't work:
3838
#
3939
# os.kill(node.process.pid, signal.CTRL_C_EVENT)
40-
if os.name == 'nt':
40+
if platform.system() == 'Windows':
4141
raise SkipTest("can't SIGTERM on Windows")
4242

4343
self.stop_node(0)

test/functional/feature_notifications.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
66
"""Test the -alertnotify, -blocknotify, -chainlocknotify, -instantsendnotify and -walletnotify options."""
77
import os
8+
import platform
89

910
from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE
1011

@@ -16,13 +17,13 @@
1617

1718
# Linux allow all characters other than \x00
1819
# Windows disallow control characters (0-31) and /\?%:|"<>
19-
FILE_CHAR_START = 32 if os.name == 'nt' else 1
20+
FILE_CHAR_START = 32 if platform.system() == 'Windows' else 1
2021
FILE_CHAR_END = 128
21-
FILE_CHARS_DISALLOWED = '/\\?%*:|"<>' if os.name == 'nt' else '/'
22+
FILE_CHARS_DISALLOWED = '/\\?%*:|"<>' if platform.system() == 'Windows' else '/'
2223
UNCONFIRMED_HASH_STRING = 'unconfirmed'
2324

2425
def notify_outputname(walletname, txid):
25-
return txid if os.name == 'nt' else f'{walletname}_{txid}'
26+
return txid if platform.system() == 'Windows' else f'{walletname}_{txid}'
2627

2728

2829
class NotificationsTest(DashTestFramework):
@@ -169,7 +170,7 @@ def expect_wallet_notify(self, tx_details):
169170
# Universal newline ensures '\n' on 'nt'
170171
assert_equal(text[-1], '\n')
171172
text = text[:-1]
172-
if os.name == 'nt':
173+
if platform.system() == 'Windows':
173174
# On Windows, echo as above will append a whitespace
174175
assert_equal(text[-1], ' ')
175176
text = text[:-1]

test/functional/rpc_bind.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test running dashd with the -rpcbind and -rpcallowip options."""
66

7-
import sys
8-
97
from test_framework.netutil import all_interfaces, addr_to_hex, get_bind_addrs, test_ipv6_local
108
from test_framework.test_framework import BitcoinTestFramework, SkipTest
119
from test_framework.util import assert_equal, assert_raises_rpc_error, get_rpc_proxy, rpc_port, rpc_url
@@ -17,6 +15,10 @@ def set_test_params(self):
1715
self.num_nodes = 1
1816
self.supports_cli = False
1917

18+
def skip_test_if_missing_module(self):
19+
# due to OS-specific network stats queries, this test works only on Linux
20+
self.skip_if_platform_not_linux()
21+
2022
def setup_network(self):
2123
self.add_nodes(self.num_nodes, None)
2224

@@ -61,14 +63,9 @@ def run_allowip_test(self, allow_ips, rpchost, rpcport):
6163
self.stop_nodes()
6264

6365
def run_test(self):
64-
# due to OS-specific network stats queries, this test works only on Linux
6566
if sum([self.options.run_ipv4, self.options.run_ipv6, self.options.run_nonloopback]) > 1:
6667
raise AssertionError("Only one of --ipv4, --ipv6 and --nonloopback can be set")
6768

68-
self.log.info("Check for linux")
69-
if not sys.platform.startswith('linux'):
70-
raise SkipTest("This test can only be run on linux.")
71-
7269
self.log.info("Check for ipv6")
7370
have_ipv6 = test_ipv6_local()
7471
if not have_ipv6 and not (self.options.run_ipv4 or self.options.run_nonloopback):

test/functional/test_framework/p2p.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from collections import defaultdict
2525
from io import BytesIO
2626
import logging
27+
import platform
2728
import struct
2829
import sys
2930
import threading
@@ -786,7 +787,7 @@ def __init__(self):
786787

787788
NetworkThread.listeners = {}
788789
NetworkThread.protos = {}
789-
if sys.platform == 'win32':
790+
if platform.system() == 'Windows':
790791
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
791792
NetworkThread.network_event_loop = asyncio.new_event_loop()
792793

test/functional/test_framework/test_node.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212
import json
1313
import logging
1414
import os.path
15+
import platform
1516
import re
1617
import subprocess
1718
import tempfile
1819
import time
1920
import urllib.parse
2021
import shlex
21-
import sys
2222
import collections
2323
from pathlib import Path
2424

@@ -575,7 +575,7 @@ def test_success(cmd):
575575
cmd, shell=True,
576576
stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) == 0
577577

578-
if not sys.platform.startswith('linux'):
578+
if platform.system() != 'Linux':
579579
self.log.warning("Can't profile with perf; only available on Linux platforms")
580580
return None
581581

test/functional/test_framework/util.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
import pathlib
1717
import random
1818
import shutil
19+
import platform
1920
import re
20-
import sys
2121
import time
2222
import urllib.parse
2323

@@ -438,12 +438,12 @@ def get_temp_default_datadir(temp_dir: pathlib.Path) -> Tuple[dict, pathlib.Path
438438
"""Return os-specific environment variables that can be set to make the
439439
GetDefaultDataDir() function return a datadir path under the provided
440440
temp_dir, as well as the complete path it would return."""
441-
if sys.platform == "win32":
441+
if platform.system() == "Windows":
442442
env = dict(APPDATA=str(temp_dir))
443443
datadir = temp_dir / "Bitcoin"
444444
else:
445445
env = dict(HOME=str(temp_dir))
446-
if sys.platform == "darwin":
446+
if platform.system() == "Darwin":
447447
datadir = temp_dir / "Library/Application Support/Bitcoin"
448448
else:
449449
datadir = temp_dir / ".bitcoin"

test/functional/test_runner.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import configparser
1818
import datetime
1919
import os
20+
import platform
2021
import time
2122
import shutil
2223
import signal
@@ -42,7 +43,7 @@
4243
CROSS = "x "
4344
CIRCLE = "o "
4445

45-
if os.name == 'nt': #type:ignore
46+
if platform.system() != 'Windows': #type:ignore
4647
import ctypes
4748
kernel32 = ctypes.windll.kernel32 # type: ignore
4849
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4

0 commit comments

Comments
 (0)