Skip to content

Commit 2311915

Browse files
committed
Add a separate test driver for python
Add support for valgrind. Add support for --debug. Fixup LSP.__init__ to launch tasks only once all attributes have been declared.
1 parent 7d6d5ab commit 2311915

File tree

7 files changed

+70
-44
lines changed

7 files changed

+70
-44
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
title: 'called_by'
2+
driver: python
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
title: 'called_by_dispatching'
2+
driver: python
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
title: 'logs_cycling'
2+
driver: python

testsuite/drivers/basic.py

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,36 +29,16 @@ def run(self, previous_values, slot):
2929

3030
status = TestStatus.PASS
3131

32-
# If there is a "test.py", evaluate it
33-
if os.path.exists(os.path.join(wd, "test.py")):
34-
# Load test.py as a module
35-
python_file = os.path.join(wd, "test.py")
36-
spec = importlib.util.spec_from_file_location("module.name", python_file)
37-
module = importlib.util.module_from_spec(spec)
38-
spec.loader.exec_module(module)
39-
40-
# Look for functions with the decorator @simple_test and run them
41-
errors = [
42-
f"no function with @simple_test or @complex_test found in {python_file}"
43-
]
44-
45-
for _, obj in inspect.getmembers(module):
46-
if inspect.isfunction(obj) and (
47-
hasattr(obj, "simple_test") or hasattr(obj, "complex_test")
48-
):
49-
errors = obj(wd)
50-
51-
if len(errors) > 0:
52-
self.result.log = "\n".join(errors)
53-
status = TestStatus.FAIL
54-
55-
self.result.set_status(status)
32+
# Safety check, make sure we're not inavertently using the wrong
33+
# driver.
34+
json_files = glob.glob(os.path.join(wd, "*.json"))
35+
if not json_files:
36+
self.result.out = "No JSON files found in %s" % wd
37+
self.result.set_status(TestStatus.FAIL)
5638
self.push_result()
57-
58-
# Stop processing, do not look for .json files
5939
return
6040

61-
for json in glob.glob(os.path.join(wd, "*.json")):
41+
for json in json_files:
6242
cmd = [self.env.tester_run, json]
6343
if self.env.options.format:
6444
cmd.append("--format=%s" % self.env.options.format)

testsuite/drivers/lsp_python_driver.py

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,34 @@
6464
# # and the initialize/initialized/didChangeConfiguration requests
6565
# # have been sent by the framework.
6666

67-
RLIMIT_SECONDS = 10.0
67+
68+
# Global configuration options
69+
# Time limit for the test globally
70+
RLIMIT_SECONDS = 60.0
71+
# Timeout for a response to a request
72+
RESPONSE_TIMEOUT = 2.0
73+
DEBUG_MODE = False
74+
75+
76+
def set_debug_mode(mode : bool = True):
77+
"""Set the debug mode."""
78+
global DEBUG_MODE
79+
DEBUG_MODE = mode
80+
81+
82+
def set_wait_factor(factor : float):
83+
"""Set the wait factor."""
84+
global RLIMIT_SECONDS
85+
global RESPONSE_TIMEOUT
86+
RLIMIT_SECONDS = RLIMIT_SECONDS * factor
87+
RESPONSE_TIMEOUT = RESPONSE_TIMEOUT * factor
6888

6989

7090
class LSP(object):
7191

7292
def __init__(
7393
self,
74-
cl: str | list[str] = "ada_language_server",
94+
cl: str | list[str] | None = "ada_language_server",
7595
working_dir: str = ".",
7696
env: dict | None = None
7797
):
@@ -82,6 +102,10 @@ def __init__(
82102

83103
if env is not None:
84104
env = os.environ.copy() | env
105+
106+
if cl is None:
107+
cl = os.environ.get("ALS", "ada_language_server")
108+
85109
# Launch the lsp server, with pipes ready for input/output
86110
self.process = subprocess.Popen(
87111
cl,
@@ -106,32 +130,40 @@ def __init__(
106130
# Launch a task that will receive messages from the LSP server
107131
# and store them in a queue
108132
self.task = threading.Thread(target=self.receive_task)
109-
self.task.start()
110-
111133
self.k_task = threading.Thread(target=self.kill_task)
112-
self.k_task.start()
113134

114135
# Error messages encountered
115136
self.errors = []
116137

117138
# A list of bytes containing everything we sent to the server
118139
self.replay = []
119140

141+
# Start the tasks after all the attributes have been declared
142+
self.task.start()
143+
self.k_task.start()
144+
145+
# If we are in debug mode, insert a debug point
146+
if DEBUG_MODE:
147+
self.debug_here()
148+
149+
120150
def kill_task(self):
121151
while True:
122152
time.sleep(0.2)
123153
now = time.time()
124154

125-
# If we have reached the time limit, kill the process
126-
if now > self.kill_me_at:
127-
self.errors.append("rlimit time limit reached")
128-
self.process.kill()
129-
break
155+
# If we have reached the time limit, kill the process,
156+
# unless we are debugging.
157+
if not DEBUG_MODE:
158+
if now > self.kill_me_at:
159+
self.errors.append("rlimit time limit reached")
160+
self.process.kill()
161+
break
130162

131163
# If we have received a license to kill, check if it is time
132164
# to kill the process!
133165
if self.license_to_kill is not None:
134-
if now - self.license_to_kill > 2.0:
166+
if now - self.license_to_kill > RESPONSE_TIMEOUT:
135167
self.process.kill()
136168
break
137169

@@ -163,7 +195,7 @@ def receive_task(self):
163195
time.sleep(0.01)
164196

165197
def send(
166-
self, message: LSPMessage, expect_response=True, timeout: float = 2.0
198+
self, message: LSPMessage, expect_response=True
167199
) -> LSPResponse | None:
168200
"""Send a message to the LSP server.
169201
If expect_response is True, wait for a response for at most timeout seconds.
@@ -178,7 +210,7 @@ def send(
178210
start_time = time.time()
179211

180212
if expect_response:
181-
while time.time() - start_time <= timeout:
213+
while time.time() - start_time <= RESPONSE_TIMEOUT:
182214
# Check if there is something in the queue
183215
if self.queue.empty():
184216
time.sleep(0.1)
@@ -190,7 +222,7 @@ def send(
190222
return LSPResponse(
191223
{
192224
"error": f"response to {message.id} ({message.method})"
193-
" not received in {timeout} seconds"
225+
f" not received in {RESPONSE_TIMEOUT} seconds"
194226
}
195227
)
196228

@@ -201,7 +233,7 @@ def error(self, message):
201233
def debug_here(self):
202234
"""Insert a debug point in the test."""
203235
print("## Debug point reached. Attach with:", file=sys.stderr)
204-
print(f" gdb --pid={self.process.pid}", file=sys.stderr)
236+
print(f" gdb -p {self.process.pid}", file=sys.stderr)
205237
print("", file=sys.stderr)
206238
print("## Press Enter to continue", file=sys.stderr)
207239
input()

testsuite/drivers/lsp_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def assertField(self, field, expected):
7878
for f in fields:
7979
if f not in value:
8080
raise ResponseAssertionError(
81-
self._line_info() + f"Field {field} not found"
81+
self._line_info() + f"Field {field} not found in {value}"
8282
)
8383
value = value.get(f)
8484
if value != expected:

testsuite/drivers/python_driver.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
import inspect
88
import importlib.util
99

10-
from drivers.lsp_python_driver import run_simple_test
10+
from drivers.lsp_python_driver import set_debug_mode, set_wait_factor
1111

1212

1313
class PythonTestDriver(ALSTestDriver):
1414
"""Each test should have:
1515
- a test.yaml containing
1616
title: '<test name>'
17+
driver: python
1718
1819
- a number of test drivers, in .json files.
1920
"""
@@ -28,6 +29,16 @@ def run(self, previous_values, slot):
2829

2930
status = TestStatus.PASS
3031

32+
os.environ["ALS"] = self.env.als
33+
os.environ["ALS_HOME"] = self.env.als_home
34+
35+
if self.env.main_options.debug:
36+
set_debug_mode(True)
37+
38+
if self.env.wait_factor:
39+
set_wait_factor(self.env.wait_factor)
40+
41+
3142
# If there is a "test.py", evaluate it
3243
if os.path.exists(os.path.join(wd, "test.py")):
3344
# Load test.py as a module

0 commit comments

Comments
 (0)