1# REQUIRES: curl, httplib, thread_support
2
3#int main () {
4#  int x = 1;
5#  return x;
6#}
7#
8#Build as : clang -g main.c -o main-debug.exe
9#Then run : cp main-debug.exe main.exe && strip main.exe
10#resulting buildid: 2c39b7557c50162aaeb5a3148c9f76e6e46012e3
11
12# RUN: rm -rf %t
13# RUN: mkdir %t
14# # Query the debuginfod server for artifacts
15# RUN: DEBUGINFOD_CACHE_PATH=%t %python %s --server-cmd 'llvm-debuginfod -v -c 3 %S/Inputs' \
16# RUN:   --tool-cmd 'llvm-debuginfod-find --dump --executable 2c39b7557c50162aaeb5a3148c9f76e6e46012e3' | \
17# RUN:   diff - %S/Inputs/main.exe
18# RUN: DEBUGINFOD_CACHE_PATH=%t %python %s --server-cmd 'llvm-debuginfod -v -c 3 %S/Inputs' \
19# RUN:   --tool-cmd 'llvm-debuginfod-find --dump --debuginfo 2c39b7557c50162aaeb5a3148c9f76e6e46012e3' | \
20# RUN:   diff - %S/Inputs/main-debug.exe
21# Debuginfod server does not yet support source files
22
23# # The artifacts should still be present in the cache without needing to query
24# # the server.
25# RUN: DEBUGINFOD_CACHE_PATH=%t llvm-debuginfod-find --dump \
26# RUN:   --executable 2c39b7557c50162aaeb5a3148c9f76e6e46012e3 | \
27# RUN:   diff - %S/Inputs/main.exe
28# RUN: DEBUGINFOD_CACHE_PATH=%t llvm-debuginfod-find --dump \
29# RUN:   --debuginfo 2c39b7557c50162aaeb5a3148c9f76e6e46012e3 | \
30# RUN:   diff - %S/Inputs/main-debug.exe
31
32
33
34# This script is used to test the debuginfod client within a host tool against
35# the debuginfod server.
36# It first stands up the debuginfod server and then executes the tool.
37# This way the tool can make debuginfod HTTP requests to the debuginfod server.
38import argparse
39import threading
40import subprocess
41import sys
42import os
43import io
44
45# Starts the server and obtains the port number from the first line of stdout.
46# Waits until the server has completed one full directory scan before returning.
47def start_debuginfod_server(server_args):
48    process = subprocess.Popen(
49        server_args,
50        env=os.environ,
51        stdout=subprocess.PIPE)
52    port = -1
53    # Obtain the port.
54    stdout_reader = io.TextIOWrapper(process.stdout, encoding='ascii')
55    stdout_line = stdout_reader.readline()
56    port = int(stdout_line.split()[-1])
57    # Wait until a directory scan is completed.
58    while True:
59        stdout_line = stdout_reader.readline().strip()
60        print(stdout_line, file=sys.stderr)
61        if stdout_line == 'Updated collection':
62            break
63    return (process, port)
64
65# Starts the server with the specified args (if nonempty), then runs the tool
66# with specified args.
67# Sets the DEBUGINFOD_CACHE_PATH env var to point at the given cache_directory.
68# Sets the DEBUGINFOD_URLS env var to point at the local server.
69def test_tool(server_args, tool_args):
70    server_process = None
71    client_process = None
72    port = None
73    server_process, port = start_debuginfod_server(server_args)
74    try:
75        env = os.environ
76        if port is not None:
77            env['DEBUGINFOD_URLS'] = 'http://localhost:%s' % port
78        client_process = subprocess.Popen(
79            tool_args, env=os.environ)
80        client_code = client_process.wait()
81        if client_code != 0:
82            print('nontrivial client return code %s' % client_code, file=sys.stderr)
83            return 1
84        if server_process is not None:
85            server_process.terminate()
86            server_code = server_process.wait()
87            if server_code != -15:
88                print('nontrivial server return code %s' % server_code, file=sys.stderr)
89                return 1
90
91    finally:
92        if server_process is not None:
93            server_process.terminate()
94        if client_process is not None:
95            client_process.terminate()
96    return 0
97
98def main():
99    parser = argparse.ArgumentParser()
100    parser.add_argument('--server-cmd', default='', help='Command to start the server. If not present, no server is started.', type=str)
101    parser.add_argument('--tool-cmd', required=True, type=str)
102    args = parser.parse_args()
103    result = test_tool(args.server_cmd.split(),
104        args.tool_cmd.split())
105    sys.exit(result)
106
107if __name__ == '__main__':
108    main()
109