Skip to content

Commit 0b7fb1d

Browse files
committed
Merge branch 'topic/ci-win' into 'master'
Add CIs on Windows See merge request eng/ide/ada_language_server!1839
2 parents 4046598 + 02f8e6b commit 0b7fb1d

File tree

10 files changed

+101
-34
lines changed

10 files changed

+101
-34
lines changed

.gitlab-ci.plan

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
def build_(qualifier={}):
22
with defaults(qualifier=qualifier):
33
anod_build("als")
4-
anod_build("vscode-extension")
4+
anod_build("vscode-extension", qualifier={"mono-plat": True})
55

66

77
def test_als_(qualifier={}):
@@ -19,10 +19,10 @@ def test_als_cov_(qualifier={}):
1919

2020

2121
def test_vscode_extension_(qualifier={}):
22-
with defaults(qualifier=qualifier):
23-
# Install the component built in the preceding CI build job
24-
anod_install("vscode-extension")
25-
anod_test("vscode-extension", qualifier=qualifier | {"coverage": True})
22+
component_qual = qualifier | {"mono-plat": True}
23+
# Install the component built in the preceding CI build job
24+
anod_install("vscode-extension", qualifier=component_qual)
25+
anod_test("vscode-extension", qualifier=component_qual | {"coverage": True})
2626

2727

2828
def build_test_gs_(qualifier={}):
@@ -62,14 +62,29 @@ def build_test_gs_edge():
6262

6363

6464
def test_integration_testsuite():
65-
# The two components below have been built by the build job of the CI
65+
# These two components have been built by the build job of the CI, install them.
6666
anod_install("als")
67-
anod_install("vscode-extension")
68-
# Install gps component to avoid it getting rebuilt. We are only interested in
69-
# vscode tests in the integration-testsuite, not gps.
70-
anod_install("gps")
67+
anod_install("vscode-extension", qualifier={"mono-plat": True})
68+
69+
# For the following components, we'd like to install with latest=True to be
70+
# resilient to failures in nightly builds.
71+
#
72+
# We need to do this instead of running the whole plan with --latest because
73+
# currently --latest bypasses the local offline Cathod component cache and prevents
74+
# installing components built in the same CI pipeline.
75+
for dep in (
76+
# Install gps component to avoid it getting rebuilt. Here we are only interested
77+
# in vscode tests in the integration-testsuite, not gps.
78+
"gps",
79+
"gnat",
80+
"gnatdas",
81+
"gnatsas",
82+
"spark2014",
83+
):
84+
anod_install(dep, latest=True)
85+
7186
# Run the subset of integration-testsuite that uses VS Code
7287
anod_test(
7388
"integration-testsuite",
74-
qualifier={"run-tools": "vscode", "cleanup-mode": "none"},
89+
qualifier={"run-tools": "vscode", "cleanup-mode": "none", "mono-plat": True},
7590
)

.gitlab-ci.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ include:
2121
cpus: 16
2222
disk: 80
2323
image: systemgtk
24+
windows: true
25+
windows-cpus: 8
26+
# 8GB of memory leads to heap exhaustion during compilation. We need more.
27+
windows-mem: 16
2428
save-component: true
2529

2630
# Testing of the ALS
@@ -30,6 +34,7 @@ include:
3034
anod-args: run test_als_$ACI_TRACK
3135
image: systemgtk
3236
disk: 80
37+
windows: true
3338

3439
# Testing of the ALS with coverage
3540
- component: $CI_SERVER_FQDN/eng/gitlab-templates/test@~latest
@@ -50,6 +55,7 @@ include:
5055
job-name: vscode-extension
5156
anod-args: run test_vscode_extension_$ACI_TRACK
5257
image: systemgtk
58+
windows: true
5359

5460
# Integration testsuite
5561
- component: $CI_SERVER_FQDN/eng/gitlab-templates/test@~latest
@@ -62,6 +68,7 @@ include:
6268
image: systemgtk
6369
cpus: 4
6470
disk: 80
71+
windows: true
6572
rules:
6673
# Does not work on edge
6774
- if: $CI_PIPELINE_SOURCE == 'merge_request_event' && $CI_TARGET_BRANCH_NAME != 'edge'
@@ -75,6 +82,7 @@ include:
7582
image: systemgtk
7683
disk: 80
7784
stage: optional
85+
windows: true
7886
rules:
7987
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
8088
when: manual
@@ -180,3 +188,13 @@ vscode-extension:linux:
180188
paths:
181189
- anod-logs/
182190
- coverage/cobertura-coverage.xml
191+
192+
als:windows:
193+
variables:
194+
# In GitLab CI tests timeout more often on Windows, so we multiply
195+
# testsuite timeouts by the following factor
196+
ALS_WAIT_FACTOR: "2"
197+
198+
vscode-extension:windows:
199+
variables:
200+
MOCHA_TIMEOUT: "30000"

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ repos:
44
hooks:
55
- id: flake8
66
types: [file]
7-
files: \.(py|anod|plan)$
7+
files: \.(py)$
88
additional_dependencies:
99
- flake8-bugbear
1010
- flake8-builtins
@@ -16,7 +16,7 @@ repos:
1616
hooks:
1717
- id: black
1818
types_or: [file]
19-
files: \.(py|plan)$
19+
files: \.(py)$
2020
- repo: https://github.com/pre-commit/mirrors-mypy
2121
rev: v1.8.0
2222
hooks:

integration/vscode/ada/test/general/helpers.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ suite('parallelize', function () {
290290
* overall the computation shouldn't take more than the
291291
* time needed to process one data item (with a margin).
292292
*/
293-
const margin = singleWorkDurationMs * 0.2;
293+
const margin = singleWorkDurationMs * 0.4;
294294
/**
295295
* When processing 4 items with 3 threads, the first parallel
296296
* batch processes 3 items and a second batch processes 1 item.
@@ -303,7 +303,7 @@ suite('parallelize', function () {
303303
assert.ok(
304304
duration < expectedTotalWorkDuration,
305305
`The computation took ${duration}ms when we expected` +
306-
` no more than ${expectedTotalWorkDuration}`,
306+
` no more than ${expectedTotalWorkDuration}ms`,
307307
);
308308
}
309309
});

integration/vscode/ada/test/general/tasks.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ import {
2626
import { runTaskAndGetResult } from '../../src/taskProviders';
2727

2828
suite('Task Providers', function () {
29-
this.timeout('15s');
29+
// Set timeout to 15 seconds unless already configured to more
30+
this.timeout(Math.max(this.timeout(), 15000));
3031

3132
let projectPath: string;
3233

testsuite/ada_lsp/config_file/test.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,19 @@
2323
subprocess.check_call(["gprconfig", "--batch", "--config=Ada,,light,,GNAT"])
2424

2525

26-
@test()
26+
@test(
27+
als_settings={
28+
# Disable indexing to avoid wasting computation resources and risking test
29+
# timeouts
30+
"enableIndexing": False
31+
},
32+
timeout=30,
33+
)
2734
async def do_testing(lsp: ALSLanguageClient) -> None:
2835
# Set configuration file
2936
lsp.didChangeConfig(
3037
{"projectFile": URI("main.gpr"), "gprConfigurationFile": URI("default.cgpr")}
3138
)
32-
await lsp.awaitIndexingEnd()
3339

3440
# Send a didOpen for main.adb
3541
open_params, main_adb_uri = didOpenTextDocumentParams("main.adb")
@@ -49,7 +55,6 @@ async def do_testing(lsp: ALSLanguageClient) -> None:
4955
lsp.didChangeConfig(
5056
{"projectFile": "main1.gpr", "gprConfigurationFile": "default.cgpr"}
5157
)
52-
await lsp.awaitIndexingEnd()
5358

5459
# Send a didOpen for main.adb
5560
open_params, main_adb_uri = didOpenTextDocumentParams("main.adb")

testsuite/ada_lsp/configuration_warning_null_setting/test.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
not when resetting it using a null value for a setting.
44
"""
55

6-
import asyncio
76
from drivers.pylsp import (
87
ALSLanguageClient,
98
assertEqual,
@@ -18,7 +17,14 @@
1817
]
1918

2019

21-
@test()
20+
@test(
21+
als_settings={
22+
# Disable indexing to avoid wasting computation resources and risking test
23+
# timeouts
24+
"enableIndexing": False
25+
},
26+
timeout=30,
27+
)
2228
async def main(lsp: ALSLanguageClient) -> None:
2329
# There is no config file
2430
lsp.didOpenVirtual()
@@ -36,7 +42,7 @@ async def main(lsp: ALSLanguageClient) -> None:
3642
)
3743

3844
# Wait for didChangeConfig to be handled
39-
await asyncio.sleep(2)
45+
await lsp.sleep(2)
4046

4147
total_log_msg = len(lsp.log_messages)
4248
total_show_msg = len(lsp.messages)
@@ -47,7 +53,7 @@ async def main(lsp: ALSLanguageClient) -> None:
4753
lsp.didChangeConfig({"logThreshold": None, "insertWithClauses": None})
4854

4955
# Wait for didChangeConfig to be handled
50-
await asyncio.sleep(2)
56+
await lsp.sleep(2)
5157

5258
# Check that no messages were sent after using None/null as the value for
5359
# a setting

testsuite/ada_lsp/initial_memory_footprint/test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ async def check_memory_footprint(
4545
"--tracefile",
4646
"./traces_with_runtime_indexing.cfg",
4747
]
48-
)
48+
),
49+
timeout=30,
4950
)
5051
async def test_with_indexing(lsp: ALSLanguageClient) -> None:
5152
await check_memory_footprint(

testsuite/drivers/pylsp.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ def run(self) -> None:
100100
env = {
101101
"ALS": self.env.als,
102102
"ALS_HOME": self.env.als_home,
103+
"ALS_WAIT_FACTOR": str(self.env.wait_factor),
103104
"PYTHONPATH": os.path.dirname(os.path.dirname(__file__)),
104105
}
105106

@@ -118,14 +119,16 @@ def run(self) -> None:
118119
if r.status != 0:
119120
raise TestAbortWithFailure("non-zero status code")
120121
else:
122+
# Usually we specify a timeout here, however a test file may
123+
# contain multiple tests. So instead we apply a timeout to each
124+
# test in async_wrapper()
121125
p: ProcessResult = self.shell(
122126
cmd,
123127
# Start the test process directly in the test work dir. This way
124128
# tests can simply assume that the current dir is the test work dir.
125129
cwd=str(wd),
126130
env=env,
127131
ignore_environ=False,
128-
timeout=15, # seconds
129132
stdin=None,
130133
)
131134

@@ -477,6 +480,11 @@ def assertLocationsList(
477480
"""
478481
assertLocationsList(actual, expected)
479482

483+
async def sleep(self, seconds: float) -> None:
484+
"""Wait for the given amount of seconds multiplied by ALS_WAIT_FACTOR."""
485+
wait_factor: int = int(os.environ.get("ALS_WAIT_FACTOR", "1"))
486+
await asyncio.sleep(seconds * wait_factor)
487+
480488

481489
def als_client_factory() -> ALSLanguageClient:
482490
"""This function is an ugly copy-paste of pytest_lsp.make_test_lsp_client. It is
@@ -591,6 +599,8 @@ def test(
591599
initialize: bool = True,
592600
shutdown: bool = True,
593601
assert_no_lsp_errors: bool = True,
602+
als_settings: ALSSettings | None = None,
603+
timeout=15,
594604
) -> Callable:
595605
"""A decorator to mark a function as a test entry point. The function must receive a
596606
single parameter of type LanguageClient.
@@ -618,6 +628,9 @@ def test(
618628
of the test function.
619629
:param assert_no_lsp_errors: automatically assert that no LSP log message of level
620630
error were received after the end of the test function.
631+
:param als_settings: ALS settings to send as 'initializationOptions' with the
632+
'initialize' request. Only applicable if initialize=True (which is the default).
633+
:param timeout: test timeout in seconds
621634
"""
622635

623636
async def async_wrapper(
@@ -642,13 +655,22 @@ async def async_wrapper(
642655
# ALS doesn't support the newer workspaceFolders property so we
643656
# have to use the older rootURI property.
644657
root_uri=URI(os.getcwd()),
658+
initialization_options=(
659+
{"ada": als_settings} if als_settings is not None else None
660+
),
645661
)
646662
)
647663

648664
LOG.info("Running test function: %s", func.__name__)
649665

650-
# Run the test
651-
await func(client)
666+
actual_timeout = timeout
667+
if "ALS_WAIT_FACTOR" in os.environ:
668+
factor = int(os.environ["ALS_WAIT_FACTOR"])
669+
actual_timeout *= factor
670+
671+
# Run the test with a timeout
672+
async with asyncio.timeout(actual_timeout):
673+
await func(client)
652674

653675
if assert_no_lsp_errors:
654676
# Assert the absence of Error LSP log messages

testsuite/testsuite.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import datetime
44
import logging
55
import os
6+
from shutil import which
67
import sys
7-
from distutils.spawn import find_executable
88

99
from drivers.basic import JsonTestDriver
1010
from drivers.gnatcov import GNATcov
@@ -80,23 +80,22 @@ def lookup_program(self, *args):
8080
return path + ".exe"
8181

8282
# Otherwise, look for the requested program name in the PATH.
83-
#
84-
# TODO (S710-005): for some reason, on Windows we need to strip the
85-
# ".exe" suffix for the tester-run program to be able to spawn ALS.
86-
result = find_executable(os.path.basename(path))
83+
result = which(os.path.basename(path))
8784
if result is None:
8885
raise RuntimeError(
8986
"Could not find executable for {}".format(os.path.basename(path))
9087
)
91-
return result[: -len(".exe")] if result.endswith(".exe") else result
88+
# TODO (S710-005): for some reason, on Windows we need to strip the
89+
# ".exe" suffix for the tester-run program to be able to spawn ALS.
90+
return result[: -len(".exe")] if result.lower().endswith(".exe") else result
9291

9392
def set_up(self):
9493
# Root directory for the "ada_language_server" repository
9594
self.env.repo_base = os.path.abspath(
9695
os.path.join(os.path.dirname(__file__), "..")
9796
)
9897

99-
self.env.wait_factor = 1
98+
self.env.wait_factor = int(os.environ.get("ALS_WAIT_FACTOR", "1"))
10099

101100
# Absolute paths to programs that test drivers can use
102101
if self.env.options.valgrind_memcheck:

0 commit comments

Comments
 (0)