With --major-mode server
Artemis runs an 'analysis server' with a JSON interface for controlling it externally and
reporting what it finds.
In this mode all other arguments except those prefixed by analysis-server-*
are ignored, including the URL.
There is a debug view which shows the internal browser, which is shown when the option --analysis-server-debug-view
is given.
The concolic advice mode is documented at :ref:`server-concolic-advice`.
The server runs on port 8008 by default. This can be changed with the --analysis-server-port
option.
Calls to the server are expected to POST a JSON message with the following format:
{ "command": "pageload", "url": "http://www.example.com" }
We do not use REST-style URLs to avoid the complications of URL-encoding complex strings like URLs or XPaths.
The command
property must always be set, and the rest of the properties depend on which command was used.
There is an echo command which can be used to check the server is running:
curl -w "\n" --data '{"command":"echo","message":"Hello, World"}' localhost:8008
This should return:
{ "message": "Hello, World" {
Only one command can be sent per request. The server is designed to be blocking; any requests sent while another is still being processed will return an error.
echo
Used for testing. Returns the text provided in the
message
field. The optionaldelay
field is the number of seconds to delay before sending back the response (integers 0--30 are valid).Send:
{ "command": "echo", "message": "Hello, World", "delay": 1 }
Receive:
{"message": "Hello, World"}
exit
Shuts down the server.
Send:
{"command": "exit"}
Receive:
{"message", "Server is shutting down"}
pageload
Loads a URL in the Artemis browser. The final URL we end up on after redirects etc. is returned.
The optional
timeout
parameter is the number of milliseconds to wait before cancelling the load and returning an error (integers 0--3600000 accepted), 0 implies no timeout.Send:
{ "command": "pageload", "url": "http://www.example.com", "timeout": 5000 }
Receive:
{ "pageload": "done", "url": "http://www.example.com" }
backbutton
Uses the browser history to go back one page.
It is an error to call this command before there are at least two pages in the history. Due to an implementation issue, "about:blank" is never accessible via this command.
Send:
{"command": "backbutton"}
Receive:
{ "backbutton": "done", "url": "http://www.example.com" }
handlers
Lists the event handlers registered on the current page. The list returned shows XPath expressions identifying the DOM elements with events, and a list of events attached to each. The special cases "document" or "window" may also be given as an identifier for events registered on those objects.
There must already have been a page load command issued.
Send:
{"command": "handlers"}
Receive: (e.g for the handlers.html test case)
{ "handlers": [ { "element": "//a[@id='dom-attr']", "events": ["click"] }, { "element": "//a[@id='js-attr']", "events": ["click"] }, { "element": "//a[@id='listener']", "events": ["click", "focus"] } ] }
It is also possible to specify a filter (by XPath) and receive only the handlers registered on matching elements.
Send:
{ "command": "handlers", "filter": "id('listener')" }
Receive: (e.g for the handlers.html test case)
{ "handlers": [ { "element": "//a[@id='listener']", "events": ["click", "focus"] } ] }
The XPath identifiers returned are Artemis' internally generated ones and may not match the filter, even if it selects a single element.
click
Clicks on an element specified by XPath.
For now then only type of click is a JavaScript-level click, with no option for a GUI click.
N.B. This is now just a special case of the newer
event
command.Send:
{ "command": "click", "element": "id(\"clickable\")" }
Receive:
{"click": "done"}
There is an optional
method
field, which allows you to choose the type of click performed. Possible values are:simple
(default)Just generates a click event, in the saem way as the
event
command would.simulate-js
Uses JavaScript events to simulate a user click.
simulate-gui
Uses GUI events to simulate a click.
N.B. This click is done by clicking the coordinates at the centre of the element. If the element is behind another element or the element bounding box is larger than the clickable/visible area, this command can miss and click the wrong thing.
Send:
{ "command": "click", "element": "id(\"clickable\")", "method": "simulate-js" }
Receive:
{"click": "done"}
event
Triggers a JavaScript event on the element at the specified XPath. (Or custom event; see below.)
N.B. Event names are given as "change" or "focus, not "onchange", "onfocus", etc.
Send (e.g. on handlers.html):
{ "command": "event", "element": "id(\"listener\")", "event": "focus" }
Receive:
{"event": "done"}
There are also some custom Artemis event types which are not the standard JavaScript events. These are handled separately by Artemis and are not triggered as JavaScript events directly.
So far there is only one implemented: for pressing
Enter
on a form field (e.g. to submit the form).Send (e.g. on form-submission.html):
{ "command": "event", "element": "id(\"input-text\")", "event": "ARTEMIS-press-enter" }
Receive:
{"event": "done"}
page
Returns information about the current page (the URL, page title, and DOM statistics).
Send:
{"command": "page"}
Receive:
{ "url": "http://www.example.com", "title": "Example Domain", "elements": 12, "characters": 1262 }
The optional "dom" parameter can be set to True to include the entire DOM dump.
Send:
{ "command": "page", "dom": true }
Receive:
{ "url": "http://www.example.com", "title": "Example Domain", "dom": "<html> ... </html>", "elements": 12, "characters": 1262 }
element
Returns the string representation of each element (if any) matching a given XPath.
Send: (e.g. for the click.html test page)
{ "command": "element", "element": "id(\"clickable\")" }
Receive:
{ "elements": [ "<a href=\"\" id=\"clickable\">Click here to add new buttons to the page.</a>" ] }
There is also an optional
property
field which will return the string representation of that object property instead.Send:
{ "command": "element", "element": "id(\"clickable\")", "property": "nodeName" }
Receive:
{ "elements": [ "A" ] }
fieldsread
Returns a list of the form fields which have been read by different events since the last page load.
Send:
{"command": "fieldsread"}
Receive: (e.g. from form.html test page)
{ "fieldsread": [ { "element": "//button[1]", "event": "click", "reads": [ { "count": 2, "field": "//input[@id='first']" } ] }, { "element": "//button[2]", "event": "click", "reads": [ { "count": 1, "field": "//input[@id='second']" } ] }, { "element": "//button[3]", "event": "click", "reads": [ { "count": 3, "field": "//input[@id='first']" }, { "count": 3, "field": "//input[@id='second']" } ] } ] }
Each "event object" contains the event type triggered and target element (XPath as passed in via the
click
command), and a list of the form fields which were read by the handler for that event. Each of these "read objects" contains an XPath to the field and a count of the number of times the field value was read (at a low level in the JavaScript interpreter).
forminput
Injects values into form fields and triggers their change handlers. The method of injection can be changed with the optional
method
parameter (see below).Send:
{ "command": "forminput", "field": "id('input-text')", "value": "Hello, world." }
Receive:
{"forminput": "done"}
The valid element types for
field
areinput
andselect
.The
value
property can be set to a string (as above), integer, or bool. Strings are used when injecting into text fields or select boxes. Integers can be used to inject into a select box by index (sets theselectedIndex
property to the given value). Booleans are used to inject into inputs with typecheckbox
orradio
.The allowable combinations of
field
andvalue
are:input
(not checkbox or radio)input
with type checkbox or radioselect
String
Sets
.value
Invalid
Sets
.value
Int
Invalid
Invalid
Sets
.selectedIndex
Bool
Invalid
Sets
.checked
Invalid
For example, the following commands are all valid on the form-injections.html test case:
{ "command": "forminput", "field": "id('input-text')", "value": "Hello, world." }
This one sets the checkbox to ticked:
{ "command": "forminput", "field": "id('input-checkbox')", "value": true }
When injecting into a select box, the
value
attribute of the appropriateoption
element must be given, which is not necessarily the text which appears in the UI.:<select id="input-select" > <option value="first" >First Option</option> <option value="second" >Second Option</option> <option value="third" >Third Option</option> </select>
This one selects "Third Option" in the UI:
{ "command": "forminput", "field": "id('input-select')", "value": "third" }
This one also selects "Third Option", by using the index:
{ "command": "forminput", "field": "id('input-select')", "value": 2 }
The form-injections.html example includes a 'marker' element so you can confirm the form input worked:
{ "command": "element", "element": "id('status')" }
{ "elements": [ "<strong id=\"status\">#input-text set to 'Hello, World'</strong>" ] }
There is a
method
field, which allows you to choose the type of injection performed. Possible values are:inject
Inject the value into the
.value
property (depending on the input type; see above).onchange
(default)Inject the value and trigger the
onchange
handler for the form field.simulate-js
Uses JavaScript events to simulate a user filling the form field as closely as possible. The support for text inputs is currently much more sophisticated than for checkboxes, radio buttons, and select boxes.
When
simulate-js
is used, an extra optional propertynoblur
can be set to booleantrue
to stop the 'blur' (de-focus) event being triggered on this element once the injection is complete. This can be useful (for example) to stop auto-complete boxes being hidden when the field is deselected.simulate-gui
Not yet implemented.
Send:
{ "command": "forminput", "field": "id('input-text')", "value": "Hello, world.", "method": "inject" }
Receive:
{"forminput": "done"}
xpath
Evaluates an XPath query and returns the result.
The result may be a String, Number, Boolean or Node-Set. Node-sets are represented as an array of the string representations of the nodes.
Node-set (all examples on the click.html test case):
{ "command": "xpath", "xpath": "//h1" }
{ "result": [ "<h1>Clickable elements</h1>" ] }
String:
{ "command": "xpath", "xpath": "string(//h1)" }
{ "result": "Clickable elements" }
Number:
{ "command": "xpath", "xpath": "string-length(string(//h1))" }
{ "result": 18 }
Boolean:
{ "command": "xpath", "xpath": "string-length(string(//h1)) > 10" }
{ "result": true }
It is also possible to provide a list of XPaths to evaluate. The result will be a list of the results of each XPath as above:
{ "command": "xpath", "xpath": [ "//h1", "string(//h1)", "string-length(string(//h1))", "string-length(string(//h1)) > 10" ] }
{ "result": [ [ "<h1>Clickable elements</h1>" ], "Clickable elements", 18, true ] }
N.B. Non-matching queries are handled as normal in a browser's XPath evaluation:
//does-not-exist => [] string(//does-not-exist) => "" boolean(//does-not-exist) => false
An XPath which cannot be evaluated (because it is invalid) will return an error.
windowsize
Set the size of the browser window.
Send:
{ "command": "windowsize", "width": 1024, "height": 768 }
Receive:
{ "windowsize": "done" }
concolicadvice
Allows the server to record traces nito a concolic execution tree and return advice about new form field values which can lead to new exploration.
See the :ref:`server-concolic-advice` documentation for details.
evaluate-js
Evaluates a JavaScript string on the current page.
Send:
{ "command": "evaluatejs", "js": "document.getElementById('clickable').click()" }
Receive:
{ "evaluatejs": "done" }
setsymbolicvalues
Sets the internal symbolic values of variables accessed via
artemisInputBoolean()
,artemisInputInteger()
, andartemisInputString()
. This can be used for testing the internal concolic engine of the platform. For normal testing of web pages theforminput
command should be used instead for concolic testing.The
values
parameter is a mapping from variable names (strings) to values, which may be strings, integers or booleans.The
reset
parameter is optional, and if set totrue
, the internal symbolic value table will be cleared before setting these replacement values.Send:
{ "command": "setsymbolicvalues", "values": { "X": "Hello", "Y": 123, "Z": true }, "reset": true }
Receive:
{ "setsymbolicvalues": "done" }
Now a call like the following would update the DOM with the injected symbolic values:
{ "command": "evaluatejs", "js": "document.getElementById('status').textContent = artemisInputString('X') + ' ' + artemisInputInteger('Y') + ' ' + artemisInputBoolean('Z');" }
coverage
Returns a report of the line coverage from the executed commands. The line coverage is taken since the server was started, and cannot be reset.
The
report
is a list of reports for each distinct JavaScript source (web page, JS file, etc.). The line-by-line coverage report is human-readable, not in a good machine-readable format. It can be parsed with analyse-coverage.py.The
linescovered
parameter is a list of line numbers which were covered.N.B. A line is considered covered if some interpretation was done on that line. So the close-braces of if statements, else statements, blank lines, and so on will never be considered covered.
Send:
{ "command": "coverage" }
Receive:
{ "coverage": [ { "url": "...", "line": "...", "linescovered": [...] "report": "..." }, { ... } ] }