HackWeek 17 - Continuing with the REST API
The Libyui REST API Project
I spent the 17th HackWeek working on the previous project - libyui REST API for testing the applications.
You can read some rationale in the blog post for the previous Hackweek.
In short it allows inspecting the current user interface of a programm via a REST API. The API can be used from many testing frameworks, there is a simple experimental wrapper for the Cucumber framework.
Examples
The REST API can be also used directly from the command line, this is a short example how it works:
First start an YaST module, specify the port which will be used by the REST API:
YUI_HTTP_PORT=14155 /usr/sbin/yast timezone
Inspecting with cURL
Then you can inspect the current dialog directly from the command line
# curl http://localhost:14155/dialog
{
"class" : "YDialog",
"hstretch" : true,
"type" : "main",
"vstretch" : true,
"widgets" :
[
{
"class" : "YVBox",
"help_text" : "...",
"hstretch" : true,
"id" : "WizardDialog",
"vstretch" : true,
"widgets" :
[
{
"class" : "YReplacePoint",
"id" : "topmenu",
...
You can also send some action, like pressing the Cancel
button:
curl -i -X POST "http://localhost:14155/widgets?action=press_button&label=Cancel"
Using the Cucumber Wrapper
The experimental Cucumber wrapper allows writing the tests in a native English language. The advantage is that people not familiar with YaST internals can write the tests easily. And even non-developers could use it.
Feature: To install the 3rd party packages I must be able to add a new package
repository to the package management.
Scenario: Adding a new repository
Given I start the "/usr/sbin/yast2 repositories" application
Then the dialog heading should be "Configured Software Repositories"
When I click button "Add"
Then the dialog heading should be "Add On Product"
When I click button "Next"
Then the dialog heading should be "Repository URL"
Then continue...
What Has Been Improved
Here is a short summary what has been improved since the last HackWeek.
More Details and More Actions
The HTTP server now returns more details about the UI like the table content, the combo box values, etc… Maybe something is still missing but adding more details for specific widgets should be rather easy.
Also some more actions have been added, now it is possible to set a combo box value or select the active radio button via the REST API.
Processing the Server Requests
Originally the HTTP server was processing the data only when the UI.UserInput
call was waiting for the input. That was quite limiting as the HTTP requests
might have timed out before before reaching that point.
Now the server is responsive also during the other UI calls and even when there is no UI call processed at all. So the API is not blocked when YaST is doing some time consuming action like installing packages. The response now contains the current progress state as displayed in the UI.
Moreover it even works when there is no UI dialog open yet!
# cat ./test.rb
sleep(30)
# YUI_HTTP_PORT=14155 /usr/sbin/yast2 ./test.rb &
[1] 23578
# curl -i "http://localhost:14155/dialog"
HTTP/1.1 404 Not Found
Connection: Keep-Alive
Content-Length: 34
Content-Encoding: application/json
Date: Fri, 13 Jul 2018 05:37:42 GMT
{ "error" : "No dialog is open" }
Text Mode (Ncurses UI) Support
This is the most significant change, now the ncurses texmode UI also supports the embedded REST Server!
So you can see the updated Cucumber test used for testing in the Qt UI from the last HackWeek running in the text mode!
The only problematic part is that the Cucumber and YaST fight for the terminal
output. That means we cannot run the YaST module directly but use some wrapper.
In this case we run it in a new xterm
session. But for the real automated
tests it would be better to run it in a screen
or tmux
session in background
so it works also without any X server.
Also some more complex scenarios work in the text mode, like a complete openSUSE Leap 15.0 installation running inside a VirtualBox VM:
In theory the REST API should work the same way in both graphical and text mode, from the outside you should not see a difference. Unfortunately in reality there are some differences you need to be aware…
The Text Mode Differences
Some differences are caused by the different UI implementation - like the
Ncurses UI does not implement the Wizard widget and the main window has different
properties. For example the main navigation buttons like Back
or Next
have YPushButton
class in the text mode but in the graphical mode
they have YQWizardButton
class and the dialog content is wrapped in an
additional YWizard
object.
Another difference might be that YaST (or the libyui application in general) might display a different content in the graphical mode and in the text mode. For example the YaST time zone selection displays a nice clickable map in the graphics mode:
Obviously the world map cannot be displayed in the text mode:
But the bigger difference is that in the graphical mode the time zone is selected
using the ComboBox
widgets while in the text mode there are SelectionBox
widgets!
What is Still Working
The original support for generic libyui applications is still present. That means the REST API is not bound to YaST but can be used by any libyui application.
Here is a test for the libyui ManyWidgets example which is a standalone C++ application not using YaST at all:
Prepared Testing Packages
If you want to test this libyui feature in openSUSE Leap 15.0 then you can install the packages from the home:lslezak:libyui-rest-api OBS project. See more details here.
Sources
The source code is available in the http_server
branches in the libyui/libyui, libyui/ncurses and libyui/qt Git repositories.
TODO
There are lots of missing things, but the project is becoming more usable for the basic application testing.
The most important missing features:
- Trigger
notify
orimmediate
events - if a widget with these properties is changed via the API these UI events are not created. Which usually means after changing a widget via the API the dialog is not updated as when the change is done by user. - Authentication support
- Move the web server to a separate plugin so it is an optional feature which can be added only when needed
- SSL (HTTPS) support
- IPv6 support
- and many more…
I will continue with the project at the next HackWeek if possible…