1*** Settings ***
2Library         String
3Library         Process
4Library         Collections
5Library         OperatingSystem
6Library         helper.py
7
8*** Variables ***
9${SERVER_REMOTE_DEBUG}       False
10${SERVER_REMOTE_PORT}        12345
11${SERVER_REMOTE_SUSPEND}     y
12${SKIP_RUNNING_SERVER}       False
13${CONFIGURATION}             Release
14${PORT_NUMBER}               9999
15${DIRECTORY}                 ${CURDIR}/../output/bin/${CONFIGURATION}
16${RENODETOOLS}               ${CURDIR}/../tools
17${BINARY_NAME}               Renode.exe
18${HOTSPOT_ACTION}            None
19${DISABLE_GUI}               False
20${DEFAULT_UART_TIMEOUT}      8
21${CREATE_SNAPSHOT_ON_FAIL}   True
22${SAVE_LOGS}                 True
23${SAVE_LOGS_WHEN}            Fail
24${HOLD_ON_ERROR}             False
25${CREATE_EXECUTION_METRICS}  False
26${NET_PLATFORM}              False
27${PROFILER_PROCESS}          None
28
29*** Keywords ***
30Setup
31    ${SYSTEM}=          Evaluate    platform.system()    modules=platform
32
33    ${CONFIGURATION}=  Set Variable If  not ${SKIP_RUNNING_SERVER} and ${SERVER_REMOTE_DEBUG}
34    ...    Debug
35    ...    ${CONFIGURATION}
36
37    # without --hide-log the output buffers may get full and the program can hang
38    # http://robotframework.org/robotframework/latest/libraries/Process.html#Standard%20output%20and%20error%20streams
39    @{PARAMS}=           Create List  --robot-server-port  ${PORT_NUMBER}  --hide-log
40
41    IF  ${DISABLE_GUI}
42        Insert Into List  ${PARAMS}  0  --disable-gui
43    END
44
45    IF  not ${SKIP_RUNNING_SERVER}
46        File Should Exist    ${DIRECTORY}/${BINARY_NAME}  msg=Robot Framework remote server binary not found (${DIRECTORY}/${BINARY_NAME}). Did you forget to build it in ${CONFIGURATION} configuration?
47    END
48
49    # this handles starting on Linux/macOS using mono launcher
50    IF  not ${SKIP_RUNNING_SERVER} and not ${SERVER_REMOTE_DEBUG} and not '${SYSTEM}' == 'Windows' and not ${NET_PLATFORM}
51        Start Process  mono  ${BINARY_NAME}  @{PARAMS}  cwd=${DIRECTORY}
52    END
53
54    # this handles starting on Windows without an explicit launcher
55    # we use 'shell=true' to execute process from current working directory
56    IF  not ${SKIP_RUNNING_SERVER} and not ${SERVER_REMOTE_DEBUG} and '${SYSTEM}' == 'Windows'
57        Start Process  ${BINARY_NAME}  @{PARAMS}  cwd=${DIRECTORY}  shell=true
58    END
59
60    # this handles starting on all platforms with dotnet launcher
61    # we use 'shell=true' to execute process from current working directory
62    IF  not ${SKIP_RUNNING_SERVER} and not ${SERVER_REMOTE_DEBUG} and ${NET_PLATFORM}
63        Start Process  dotnet ${BINARY_NAME}  @{PARAMS}  cwd=${DIRECTORY}  shell=true
64    END
65
66    IF  not ${SKIP_RUNNING_SERVER} and ${SERVER_REMOTE_DEBUG} and not '${SYSTEM}' == 'Windows' and not ${NET_PLATFORM}
67        Start Process  mono
68          ...            --debug
69          ...            --debugger-agent\=transport\=dt_socket,address\=0.0.0.0:${SERVER_REMOTE_PORT},server\=y,suspend\=${SERVER_REMOTE_SUSPEND}
70          ...            ${BINARY_NAME}  @{PARAMS}  cwd=${DIRECTORY}
71    END
72
73    IF  not ${SKIP_RUNNING_SERVER} and ${SERVER_REMOTE_DEBUG} and '${SYSTEM}' == 'Windows'
74         Fatal Error  Windows doesn't support server remote debug option.
75    END
76
77    #The distinction between operating systems is because localhost is not universally understood on Linux and 127.0.0.1 is not always available on Windows.
78    IF  not '${SYSTEM}' == 'Windows'
79        Wait Until Keyword Succeeds  60s  1s
80          ...   Import Library  Remote  http://127.0.0.1:${PORT_NUMBER}/
81    END
82
83    IF  '${SYSTEM}' == 'Windows'
84        Wait Until Keyword Succeeds  60s  1s
85          ...   Import Library  Remote  http://localhost:${PORT_NUMBER}/
86    END
87
88    Setup Renode
89
90Setup Renode
91    Set Default Uart Timeout  ${DEFAULT_UART_TIMEOUT}
92
93    IF  ${SAVE_LOGS}
94        Enable Logging To Cache
95    END
96
97    ${allowed_chars}=   Set Variable                 abcdefghijklmnopqrstuvwxyz01234567890_-
98    ${metrics_fname}=   Convert To Lower Case        ${SUITE_NAME}
99    ${metrics_fname}=   Replace String               ${metrics_fname}      ${SPACE}              _
100    ${metrics_fname}=   Replace String Using Regexp  ${metrics_fname}      [^${allowed_chars}]+  ${EMPTY}
101    ${metrics_path}=    Join Path                    ${RESULTS_DIRECTORY}  profiler-${metrics_fname}
102
103    IF      ${CREATE_EXECUTION_METRICS}
104        Execute Command    EnableProfilerGlobally "${metrics_path}"
105    END
106
107    Reset Emulation
108
109Teardown
110    IF  not ${SKIP_RUNNING_SERVER}
111        Stop Remote Server
112    END
113
114    IF  not ${SKIP_RUNNING_SERVER}
115        Wait For Process
116    END
117
118Sanitize Test Name
119    [Arguments]        ${test_name}
120    ${test_name}=      Replace String  ${test_name}  ${SPACE}  _
121    # double quotes because editor syntax highlighting gets confused with a single one
122    ${test_name}=      Replace String Using Regexp  ${test_name}  [/""]  -
123    RETURN             ${test_name}
124
125Create Snapshot Of Failed Test
126    Return From Keyword If   'skipped' in @{TEST TAGS}
127
128    ${retry_index}=    Get Variable Value   \${RETRYFAILED_RETRY_INDEX}  0
129    ${test_name}=      Set Variable  ${SUITE NAME}.${TEST NAME}.fail${retry_index}.save
130    ${test_name}=      Sanitize Test Name  ${test_name}
131
132    ${snapshots_dir}=  Set Variable  ${RESULTS_DIRECTORY}/snapshots
133    Create Directory   ${snapshots_dir}
134
135    ${snapshot_path}=  Set Variable  "${snapshots_dir}/${test_name}"
136    Execute Command  Save ${snapshot_path}
137    Log To Console   !!!!! Emulation's state saved to ${snapshot_path}
138
139Save Test Log
140    Return From Keyword If   'skipped' in @{TEST TAGS}
141
142    ${retry_index}=    Get Variable Value   \${RETRYFAILED_RETRY_INDEX}  0
143    ${test_name}=      Set Variable  ${SUITE NAME}.${TEST NAME}.fail${retry_index}
144    ${test_name}=      Sanitize Test Name  ${test_name}
145
146    ${logs_dir}=       Set Variable  ${RESULTS_DIRECTORY}/logs
147    Create Directory   ${logs_dir}
148
149    ${log_path}=       Set Variable  ${logs_dir}/${test_name}.log
150    Log To Console     !!!!! Log saved to "${log_path}"
151    Save Cached Log    ${log_path}
152
153Test Setup
154    IF  'profiling' in @{TEST TAGS}
155        Start Profiler
156    END
157
158Test Teardown
159    Stop Profiler
160
161    ${failed}=  Run Keyword If Test Failed  Set Variable  True
162    IF  ${failed}
163        # Some of the exception messages end with whitespace.
164        ${message}=  Strip String  ${TEST_MESSAGE}  mode=right
165        Set Test Message           ${message}
166    END
167
168    ${timed_out}=  Run Keyword If Timeout Occurred  Set Variable  True
169    IF  ${timed_out}  RETURN
170
171    IF  ${CREATE_SNAPSHOT_ON_FAIL}
172        Run Keyword If Test Failed
173          ...   Create Snapshot Of Failed Test
174    END
175
176    IF  ${SAVE_LOGS}
177        IF  "${SAVE_LOGS_WHEN}" == "Always"
178            Save Test Log
179        ELSE IF  "${SAVE_LOGS_WHEN}" == "Fail"
180            Run Keyword If Test Failed
181              ...   Save Test Log
182        END
183    END
184
185    IF  ${HOLD_ON_ERROR}
186        ${res}=  Run Keyword If Test Failed
187        ...    Run Keyword And Ignore Error
188        ...    Import Library  Dialogs
189
190        Run Keyword If Test Failed  Run Keywords
191        ...         Run Keyword If    '${res[0]}' == 'FAIL'    Log                Couldn't load the Dialogs library - interactive debugging is not possible    console=True
192        ...    AND  Run Keyword If    '${res[0]}' != 'FAIL'    Open GUI
193        ...    AND  Run Keyword If    '${res[0]}' != 'FAIL'    Pause Execution    Test failed. Press OK once done debugging.
194        ...    AND  Run Keyword If    '${res[0]}' != 'FAIL'    Close GUI
195    END
196
197    Reset Emulation
198    Clear Cached Log
199
200Hot Spot
201    Handle Hot Spot  ${HOTSPOT_ACTION}
202
203Start Profiler Or Skip
204    IF  not ${NET_PLATFORM}
205        Fail                   Failed to run profiler. Available only for .NET platform.  skipped
206    END
207
208    Start Profiler
209
210Start Profiler
211    IF  not ${NET_PLATFORM}
212        Fail                   Failed to run profiler. Available only for .NET platform.
213    END
214
215    ${test_name}=               Set Variable  ${SUITE NAME}.${TEST NAME}
216    ${test_name}=               Sanitize Test Name  ${test_name}
217
218    ${traces_dir}=              Set Variable  ${RESULTS_DIRECTORY}/traces
219    Create Directory            ${traces_dir}
220
221    ${trace_path}=              Set Variable  ${traces_dir}/${test_name}
222    Log To Console              !!!!! Writing nettrace to "${trace_path}.nettrace"
223    Log To Console              !!!!! Writing speedscope trace to "${trace_path}.speedscope.json"
224    # note that those logs may not be bundled with log and snapshot saving info
225
226    ${proc}=                    Start Process  dotnet  trace  collect  -p  ${RENODE_PID}  --format  Speedscope  -o  ${trace_path}.nettrace
227    Set Test Variable           ${PROFILER_PROCESS}  ${proc}
228
229Stop Profiler
230    IF  ${PROFILER_PROCESS}
231        Terminate Process           ${PROFILER_PROCESS}
232        Set Test Variable           ${PROFILER_PROCESS}  None
233    END
234