How to pass information between a listener and a (one or more) test cases in Robot Framework? - listener

I have a test where I need to write the results into a database. I want to set up the connection to database (using username, password, database, host) via startSuite function in listener (which will run at the beginning of all testcases) and close it in endSuite. My question is, how do I pass the connection (or cursors) back to Robot Framework code to use in testcases.
Currently I am doing this:
*** Test Cases ***
RecordinTestflow
Setup1
${return} = Record Start in Testflow ${data}
where Setup1 is a python function which will setup the connection and RecordStartinTestFlow will use that connection. I want to move the Setup1 to a listener python script.
Thank you.

An external listener can't send information to a test case. However, if you use a keyword library as a listener, it can. The downside is that you have to import the listener in the test suite, rather than specify it on the command line.
The robot framework user guide has a section title Test libraries as listeners which describes how to do it.
Here's a contrived example showing how a listener method can set a suite variable which the test case can then use.
First, the listener:
from robot.libraries.BuiltIn import BuiltIn
class ListenerExample(object):
ROBOT_LISTENER_API_VERSION = 2
ROBOT_LIBRARY_SCOPE = "GLOBAL"
def __init__(self):
self.ROBOT_LIBRARY_LISTENER = self
def _start_suite(self, name, attrs):
message = "hello, world"
BuiltIn().set_suite_variable("${from listener}", message)
Next, a simple test case that shows how the variable gets set as soon as the suite starts. Notice that the test itself doesn't define ${from listener}. Instead, it gets defined as soon as the listener method is called.
*** Settings ***
| Library | ListenerExample.py
*** Test Cases ***
| Example of getting data from a listener
| | should be equal | ${from listener} | hello, world
In your case, of course, you would change message to be your database cursor or whatever else you want it to be.
Of course, you can also put keywords in this library that you can use as well.

Related

How can I run a command from inside another stack command?

I have a callback handler in a stack that looks for telemetry data. When it gets some, I parse it and then want to save it. However, to save it requires other functions and commands in the same stack.
I could put it on the card, but where? I use the openCard end openCard and that's about it in the card.
The stack has all the functions and commands I need. There's no button to press to run the save code - I need it to run automatically.
How can I put the chunk of code on the card and then have the stack 'call it'?
I know how to call commands from the card, but not from the stack.
Generically, you simply call either a command handler or a function handler in-line:
on mouseUp -- a "main" handler
doSomething -- a command handler
dosomethingElse -- another command handler
put doYetAnotherThing(paramList) into field 1 -- a function handler
end mouseUp
on doSomething
well, do something
end doSomething
on doSomethingElse
you get the picture
...
Try making a simple main handler that does silly trivial things for each of the three "subRoutine" calls above. You will be an expert in a matter of hours.
The placement of the three has to be managed. Generally, they reside in the script where the main handler lives. But they can be anywhere in LC.
If you want to call a handler in a card (or any other control) from another script, you can use one of the following commands:
dispatch "command" to control with param1, param2, …
send "command" to control [in time]
put value(command, control) into tResult
Dispatch happily continues even if the command isn't handled by the control. You can check that of course.
Send has the advantage that you can schedule the sending forwards in time, but is a bit harder if you want to also send some parameters.
Value is good candidate if you call a function and want the result back.
Note that ""openCard" and "preOpenCard" messages can be trapped and worked in the stack script, as long as there are no such handlers in the card script. And even if there are, you can "pass" each message after the card script handler is done with it";
Try creating a command on the stack that is called every X times while the user is on that card. This command must be called to itself and to the other manipulators that you use to obtain the data. This same manipulator will be in charge of saving the data.
# Code on the card
local sTelemetryData
on openCard
// If the card belongs to the pile where all the telemetry is or if this pile is a library.
getTelemetryData
// otherwise you will have to call the getTelemetryData command. You can use send, disparsh, or call.
// call "getTelemetryData" to stack "stack name"
end openCard
# Code on the stack
constant kTime = 100
local sPendingMessageID
on getTelemetryData
if the short name of this card is not "TelemetryData"
then exit getTelemetryData
if sPendingMessageID is a number
then cancel sPendingMessageID
// call the commands and functions that look up the telemetry data.
// The data must be stored in the sTelemetryData variable to save it and at once use this variable as a flag
if sTelemetryData is not empty then
// The data is sent to be saved
end if
put empty into sTelemetryData
send "getTelemetryData" to me in kTime milliseconds
put the result into sPendingMessageID
end getTelemetryData

how to use the recognized text with Google Assistant's hotword.py code

How do I get the spoken text from the hotword.py code & do my own actions on the recognised text rather than Google going off and reacting to the text?
I've installed GA on the Pi3 & after some initial issues with usb mic/analogue audio settings and certain Python files missing this got me going:
When installing Google Assistant, I an error "...googlesamples.assistant' is a package and cannot be directly executed..."
I then followed the Google Next steps : https://developers.google.com/assistant/sdk/prototype/getting-started-pi-python/run-sample and created a new project "myga/" with a hotword.py file that contains:
def process_event(event):
"""Pretty prints events.
Prints all events that occur with two spaces between each new
conversation and a single space between turns of a conversation.
Args:
event(event.Event): The current event to process.
"""
if event.type == EventType.ON_CONVERSATION_TURN_STARTED:
print()
#GPIO.output(25,True) see https://stackoverflow.com/questions/44219740/how-can-i-get-an-led-to-light-on-google-assistant-listening
if event.type == EventType.ON_RECOGNIZING_SPEECH_FINISHED:
print("got some work to do here with the phrase or text spoken!")
print(event)
if (event.type == EventType.ON_CONVERSATION_TURN_FINISHED and
event.args and not event.args['with_follow_on_turn']):
print()
#GPIO.output(25,False) or also see https://blog.arevindh.com/2017/05/20/voice-activated-google-assistant-on-raspberry-pi-with-visual-feedback/
I'd like code to react to the ON_RECOGNIZING_SPEECH_FINISHED event I think and at either do my own action by matching simple requests or if the phrase is not in my list then let Google handle it. How do I do that?
Eventually I'd be asking "OK Google, turn BBC1 on" or "OK Google, play my playlist" or "OK Google, show traffic" and hotword.py would run other applications to do those tasks.
Thanks, Steve
See the documentation here for all available methods -
https://developers.google.com/assistant/sdk/reference/library/python/
You can use the stop_conversation() method to stop Google Assistant handling that request and act on your own.
Here's what you need to do at a high level -
Build your own dictionary of commands that you'd like to handle -
"turn BBC1 on", "play my playlist" etc.
On EventType.ON_RECOGNIZING_SPEECH_FINISHED event check if the
recognized command exists in your dictionary.
If the recognized command exists in your dictionary call the assistant.stop_conversation() method and handle the command on your own. If not do nothing (let google handle it)
pseudo code -
local_commands = ['turnBBCOn', 'playLocalPlaylist']
function turnBBCOn() :
#handle locally
function playLocalPlaylist() :
#handle locally
def process_event(event):
if event.type == EventType.ON_CONVERSATION_TURN_STARTED:
print()
if event.type == EventType.ON_RECOGNIZING_SPEECH_FINISHED:
print(event.args['text'])
if event.args['text'] in local_commands:
assistant.stop_conversation()
if(event.args['text']='turn BBC1 on')
turnBBCOn()
elif(event.args['text']='play my playlist')
playLocalPlaylist()
if (event.type == EventType.ON_CONVERSATION_TURN_FINISHED and
event.args and not event.args['with_follow_on_turn']):
print()
I have recently integrated google assistant SDK with Raspberry Pi 3. I have taken reference from below git repository and created action.py and actionbase.py classes can handle my custom command. I found it very clean and flexible way to create your own custom commands.
You can register your custom command in action.py file like below
actor = actionbase.Actor()
actor.add_keyword(
_('ip address'), SpeakShellCommandOutput(
say, "ip -4 route get 1 | head -1 | cut -d' ' -f8",
_('I do not have an ip address assigned to me.')))
return actor
action.py
Write your custom code in action.py
"""Speaks out the output of a shell command."""
def __init__(self, say, shell_command, failure_text):
self.say = say
self.shell_command = shell_command
self.failure_text = failure_text
def run(self, voice_command):
output = subprocess.check_output(self.shell_command, shell=True).strip()
if output:
self.say(output.decode('utf-8'))
elif self.failure_text:
self.say(self.failure_text)
You can full source code here. https://github.com/aycgit/google-assistant-hotword
The text is contained within the event arguments. By calling event.args you can make use of the text. Here is an example.
https://github.com/shivasiddharth/GassistPi/blob/master/src/main.py

Whether Grail integration test case will commit data into database

I am new to Grails and learning Grails currently.
I configured Mysql as my database. and when I run-app I can see table create in my database.
I tried to do a save() in test case both Unit (extend Specification) and Integration test (extend IntegrationSpec), Test method is shown as follow, which could be passed successfully.
void "test first save"() {
when: "when have user id is 'joe', and password is 'secret'"
def userId = "joe"
def password = "secret"
then: "create a user use ${userId} and ${password}"
User user = new User(userId: userId, password: password, homepage: 'http://www.grailsinaction.com')
expect: "user can be saved successfully"
assert user.save(flush:true, failOnError:true)
assert user.id
def foundUser = User.get(user.id)
assert foundUser?.userId == 'joe'
}
but I found there are no data inserted into database in both unit and integration test.
I understood that Unit test will only mock the persistence, but integration test should use real database for the testing purpose.
So my question is whether integration should commit data into database? If so, anything could be wrong to make committing not occurred?
The integration test runner is configured to start a new transaction for every test, and explicitly roll it back at the end of the test. This is convenient because you don't have to do any cleanup work between tests - everything is reset automatically for you. Note that any work done before the tests start (e.g. in BootStrap) will remain for each test since it is committed already, and the rollback resets back to the state at the beginning of each test.
You can disable this for an individual test class by adding
static transactional = false
but I would avoid this except in rare cases where you are testing transaction commits and rollbacks and need full control at that level.
Also note that the Hibernate dbCreate setting will affect things. If you configure data to remain after the tests run but use create-drop, the tables will be dropped at startup and at shutdown, so using create (which only drops at startup) or explicit migrations would be needed to view anything.
FYI - in your test, the line
def foundUser = User.get(user.id)
will not hit the database - Hibernate will simply give you back the instance you just saved. You can see this by turning on SQL logging. If you want to really re-load the object, you need to clear the Hibernate session to force it to issue a query. One easy way to do this is with the withSession method on domain classes (it's independent of the class it's called on, so use any), e.g.
User.withSession { session ->
session.flush()
session.clear()
}
I added a flush call to ensure that everything it pushed before clearing.

accessing a variable outside a Requesthandler

i'm using CSS3 accordion effect, and i want to detect if a hacker will
make a script to make a parallel request; ie:
i've a login form and a registration form in the same page, but only
one is visible because there is a CSS3: to access the page, the user
agent must be HTML5 compatible.
the tip i use is:
class Register(tornado.web.RequestHandler):
def post(self):
tt = self.get_argument("_xsrf") + str(time.time())
rtime = float(tt.replace(self.get_argument("_xsrf"), ""))
print rtime
class LoginHandler(BaseHandler):
def post(self):
tt = self.get_argument("_xsrf") + str(time.time())
ltime = float(tt.replace(self.get_argument("_xsrf"), ""))
print ltime
i've used the xsrf variable because it's unique for every user, to
avoid making the server think that the request is coming from the same
machine.
now what i want: how to make the difference between time values:
abs(ltime - rtime) ; mean, how do i access to rtime outside the class,
i just know how to access the value outside the method, i want to make
this operation to detect if the value is small, then the user is using
a script to make a parallel request to kill the server!
in other words (for general python users)
if i have:
class Product:
def info(self):
self.price = 1000
def show(self):
print self.price
>>> car = Product()
>>> car.info()
>>> car.show()
1000
but what if i've another
class User:
pass
then how do make a method that prints me the self.price, i've tried
inheritance, but got error: AttributeError: User instance has no
attribute 'price', so only methods are passed, not attributs?
It sounds like you need to understand Model objects and patterns that use persistant storage of data. tornado.web.RequestHandler and any object that you subclass from it only exists for the duration of your request. From when the URL is received on the server to when data is sent back to the browser via a self.write() or self.finish().
I would recommend you look at some of the Django or Flask tutorials for some basic ideas of how to build a MVC application in Python (There is no Tornado Tutorials that cover this that I know of).

Exceptions in Yesod

I had made a daemon that used a very primitive form of ipc (telnet and send a String that had certain words in a certain order). I snapped out of it and am now using JSON to pass messages to a Yesod server. However, there were some things I really liked about my design, and I'm not sure what my choices are now.
Here's what I was doing:
buildManager :: Phase -> IO ()
buildManager phase = do
let buildSeq = findSeq phase
jid = JobID $ pack "8"
config = MkConfig $ Just jid
flip C.catch exceptionHandler $
runReaderT (sequence_ $ buildSeq <*> stages) config
-- ^^ I would really like to keep the above line of code, or something like it.
return ()
each function in buildSeq looked like this
foo :: Stage -> ReaderT Config IO ()
data Config = MkConfig (Either JobID Product) BaseDir JobMap
JobMap is a TMVar Map that tracks information about current jobs.
so now, what I have are Handlers, that all look like this
foo :: Handler RepJson
foo represents a command for my daemon, each handler may have to process a different JSON object.
What I would like to do is send one JSON object that represents success, and another JSON object that espresses information about some exception.
I would like foos helper function to be able to return an Either, but I'm not sure how I get that, plus the ability to terminate evaluation of my list of actions, buildSeq.
Here's the only choice I see
1) make sure exceptionHandler is in Handler. Put JobMap in the App record. Using getYesod alter the appropriate value in JobMap indicating details about the exception,
which can then be accessed by foo
Is there a better way?
What are my other choices?
Edit: For clarity, I will explain the role ofHandler RepJson. The server needs some way to accept commands such as build stop report. The client needs some way of knowing the results of these commands. I have chosen JSON as the medium with which the server and client communicate with each other. I'm using the Handler type just to manage the JSON in/out and nothing more.
Philosophically speaking, in the Haskell/Yesod world you want to pass the values forward, rather than return them backwards. So instead of having the handlers return a value, have them call forwards to the next step in the process, which may be to generate an exception.
Remember that you can bundle any amount of future actions into a single object, so you can pass a continuation object to your handlers and foos that basically tells them, "After you are done, run this blob of code." That way they can be void and return nothing.