Skip to content

Commit 0290cff

Browse files
authoredApr 16, 2021
Merge pull request launchableinc#194 from launchableinc/win32
Windows support
2 parents 4ba07bf + 7c0ec3d commit 0290cff

File tree

8 files changed

+49
-16
lines changed

8 files changed

+49
-16
lines changed
 

‎.github/workflows/python-package.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ on:
1212
jobs:
1313
build:
1414

15-
runs-on: ubuntu-latest
15+
runs-on: ${{ matrix.os }}
1616
strategy:
1717
matrix:
18+
os: [ubuntu-latest, windows-latest]
1819
python-version: [3.5, 3.6, 3.7, 3.8, 3.9]
1920

2021
steps:

‎launchable/commands/record/case_event.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import datetime
22
import os
3+
import sys
34
from typing import Callable, Dict
45
from junitparser import Failure, Error, Skipped, TestCase, TestSuite # type: ignore
56
from ...testpath import TestPath
@@ -52,10 +53,17 @@ def from_case_and_suite(cls, path_builder: TestPathBuilder, case: TestCase, suit
5253
break
5354
elif isinstance(r, Skipped):
5455
status = CaseEvent.TEST_SKIPPED
56+
57+
def path_canonicalizer(test_path: TestPath) -> TestPath:
58+
if sys.platform == "win32":
59+
for p in test_path:
60+
p['name'] = p['name'].replace("\\", "/")
61+
62+
return test_path
5563

5664
return {
5765
"type": cls.EVENT_TYPE,
58-
"testPath": path_builder(case, suite, report_file),
66+
"testPath": path_canonicalizer(path_builder(case, suite, report_file)),
5967
"duration": case.time,
6068
"status": status,
6169
"stdout": case._elem.attrib.get("system-out") or "",

‎launchable/test_runners/bazel.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
from os.path import join
3+
from pathlib import Path
34

45
import click
56
from junitparser import TestCase, TestSuite # type: ignore
@@ -32,17 +33,17 @@ def record_tests(client, workspace):
3233
"""
3334
Takes Bazel workspace, then report all its test results
3435
"""
35-
base = join(workspace, 'bazel-testlogs')
36-
if not os.path.exists(base):
37-
exit("No such directory: %s" % base)
36+
base = Path(workspace).joinpath('bazel-testlogs').resolve()
37+
if not base.exists():
38+
exit("No such directory: %s" % str(base))
3839

3940
default_path_builder = client.path_builder
4041

4142
def f(case: TestCase, suite: TestSuite, report_file: str) -> TestPath:
4243
# In Bazel, report path name contains package & target.
4344
# for example, for //foo/bar:zot, the report file is at bazel-testlogs/foo/bar/zot/test.xml
4445
# TODO: robustness
45-
pkgNtarget = report_file[len(base)+1:-len("/test.xml")]
46+
pkgNtarget = report_file[len(str(base))+1:-len("/test.xml")]
4647

4748
# last path component is the target, the rest is package
4849
# TODO: does this work correctly when on Windows?

‎launchable/utils/session.py

+19-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import click
21
import os
3-
import json
2+
import sys
43
from pathlib import Path
54
import shutil
65
from typing import Optional
@@ -19,13 +18,20 @@ def _session_file_path(build_name: str) -> Path:
1918
return _session_file_dir() / (hashlib.sha1("{}:{}".format(build_name, _get_session_id()).encode()).hexdigest() + ".txt")
2019

2120

22-
def _get_session_id():
23-
id = os.getsid(os.getpid())
21+
def _get_session_id() -> str:
22+
if sys.platform == "win32":
23+
import wmi # type: ignore
24+
c = wmi.WMI()
25+
wql = "Associators of {{Win32_Process='{}'}} Where Resultclass = Win32_LogonSession Assocclass = Win32_SessionProcess".format(os.getpid())
26+
res = c.query(wql)
27+
id = res[0].LogonId
28+
else:
29+
id = str(os.getsid(os.getpid()))
2430

2531
# CircleCI changes unix session id each steps, so set non change variable
2632
# https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables
2733
if os.environ.get("CIRCLECI") is not None:
28-
id = os.environ.get("CIRCLE_WORKFLOW_ID")
34+
id = os.environ.get("CIRCLE_WORKFLOW_ID") or ""
2935

3036
return id
3137

@@ -67,7 +73,14 @@ def clean_session_files(days_ago: int = 0) -> None:
6773
for child in _session_file_dir().iterdir():
6874
file_created = datetime.datetime.fromtimestamp(
6975
child.stat().st_mtime)
70-
clean_date = datetime.datetime.now() - datetime.timedelta(days=days_ago)
76+
77+
if sys.platform == "win32":
78+
# Windows sometimes misses to delete session files at Unit Test
79+
microseconds = -10
80+
else:
81+
microseconds = 0
82+
83+
clean_date = datetime.datetime.now() - datetime.timedelta(days=days_ago, microseconds=microseconds)
7184
if file_created < clean_date:
7285
child.unlink()
7386

‎setup.cfg

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ install_requires =
2222
junitparser>=2.0.0
2323
setuptools
2424
more_itertools
25+
wmi;platform_system=='Windows'
2526
python_requires = >=3.4
2627

2728
[options.entry_points]

‎tests/cli_test_case.py

-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ def assert_json_orderless_equal(self, a, b):
7878
"""
7979
Compare two JSON trees ignoring orders of items in list & dict
8080
"""
81-
8281
def tree_sorted(obj):
8382
if isinstance(obj, dict):
8483
return sorted((k, tree_sorted(v)) for k, v in obj.items())

‎tests/commands/record/test_tests.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from pathlib import Path
22
import responses # type: ignore
33
import gzip
4+
import sys
45
from tests.cli_test_case import CliTestCase
56

67

@@ -12,8 +13,15 @@ def test_filename_in_error_message(self):
1213
broken_xml = str(Path(__file__).parent.joinpath('../../data/broken_xml/broken.xml').resolve())
1314
result = self.cli('record', 'tests', '--build', self.build_name, 'file', normal_xml, broken_xml)
1415

16+
def remove_backslash(input: str) -> str:
17+
# Hack for Windowns. They containts double escaped backslash such as \\\\
18+
if sys.platform == "win32":
19+
return input.replace("\\", "")
20+
else:
21+
return input
22+
1523
# making sure the offending file path name is being printed.
16-
self.assertIn(broken_xml, result.output)
24+
self.assertIn(remove_backslash(broken_xml), remove_backslash(result.output))
1725

1826
# normal.xml
1927
self.assertIn('open_class_user_test.rb', gzip.decompress(b''.join(responses.calls[1].request.body)).decode())

‎tests/test_runners/test_gradle.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from tests.cli_test_case import CliTestCase
77
from launchable.utils.http_client import get_base_url
88
import tempfile
9+
import os
910
from tests.helper import ignore_warnings
1011

1112

@@ -31,8 +32,7 @@ def test_subset_rest(self):
3132
responses.replace(responses.POST, "{}/intake/organizations/{}/workspaces/{}/subset".format(get_base_url(), self.organization, self.workspace),
3233
json={'testPaths': [[{'type': 'class', 'name': 'com.launchableinc.rocket_car_gradle.App2Test'}], [{'type': 'class', 'name': 'com.launchableinc.rocket_car_gradle.AppTest'}], [{'type': 'class', 'name': 'com.launchableinc.rocket_car_gradle.utils.UtilsTest'}]]}, status=200)
3334

34-
rest = tempfile.NamedTemporaryFile()
35-
35+
rest = tempfile.NamedTemporaryFile(delete=False)
3636
result = self.cli('subset', '--target', '10%', '--build',
3737
self.build_name, '--rest', rest.name, 'gradle', str(self.test_files_dir.joinpath('java/app/src/test/java').resolve()))
3838

@@ -41,6 +41,8 @@ def test_subset_rest(self):
4141
'\n'), "--tests com.launchableinc.rocket_car_gradle.App2Test --tests com.launchableinc.rocket_car_gradle.AppTest --tests com.launchableinc.rocket_car_gradle.utils.UtilsTest")
4242
self.assertEqual(rest.read().decode(
4343
), '--tests com.launchableinc.rocket_car_gradle.sub.App3Test')
44+
rest.close()
45+
os.unlink(rest.name)
4446

4547
@responses.activate
4648
def test_record_test_gradle(self):

0 commit comments

Comments
 (0)
Please sign in to comment.