Assert_receive to test Genserver message handlers? - erlang

I would like to be able to catch messages going to my GenServer's handle_info in tests, to check those are what I intend to.
1/ Is there a way to print somehow every message coming through?
2/ Using assert_receive is there a way to catch those messages? Should I set the assert_receive before or after the call to the external service that will result in the handle_info trigger? What syntax should I use?
I tried many combinations of assert_receive and I tried a receive do... to try and display messages getting in, with no success.

Both ExUnit.Assertions.assert_receive/3 and ExUnit.Assertions.assert_received/2 do assert messages coming into the current process’ mailbox. The former is to be called either before or after the message was actually sent:
Asserts that a message matching pattern was or is going to be received within the timeout period, specified in milliseconds.
the latter is to be called after:
Asserts that a message matching pattern was received and is in the current process’ mailbox.
That said, both are unlikely a good fit to test the existing GenServer. Messages are to arrive at the GenServer’s messagebox, this functionality is provided by OTP and you should not test it. If you need to log messages, add a call to Logger.log/3 to the handle_info/2 and check the log actually happens with ExUnit.CaptureLog.capture_log/2. If it performs some action upon message arrival, test this action.
In general, you should test your code, not OTP.

Related

Twilio: Responding to user input with multiple distinct messages

I'm working on a twilio-programable-sms chatbot that needs to provide a good chunk of information to a user at the outset of the first conversation. Currently, what we've written is about 562 characters. For some of our users, this gets broken up into chunks of 160 characters that do not necessarily show up in their SMS app in the right order.
To account for this, we're trying to break our message down into 160 character or less distinct messages that each send one-after-the-other.
However, my teammates and I are currently unsure how to accomplish this. Our application is currently written to provide a twiml response for each message that is received from a user. I've been unable to find a way to create a twiml response that indicates a number of consecutive messages, and the theoretical solutions we've come up with feel hacky and flawed.
To demonstrate, currently our code looks like this. As you can see, when a new user sends in the keyword "start" we join 4 messages together in one long text response. However we'd like each message to be sent individually, one after the other, about a second or two apart.
case #body
when "start"
if !!#user
CreateMessage::SubscriptionMessage.triage_subscribable_type(!!#user)
else
[
CreateMessage::AlphaMessage.personalized_welcome(#conversation.from, true),
CreateMessage::SubscriptionMessage.introduce_bcd,
CreateMessage::SubscriptionMessage.for_example,
CreateMessage::SubscriptionMessage.intvite_to_start
].join("\n\n")
end
We'd like to avoid creating a background worker/cron job, if possible - but welcome any and all suggested solutions.
I think your question is more on how to design synchronous(webhook response) vs asynchronous responses/messages. I have not used twiml but the concepts are same.
If you don't want to use a background job, then send fir N-1 messages using API with time delay in between, and the last message as response.
If you are OK with using background jobs, then send 1st message as response and queue a job for sending the remaining messages using API.

How to remove Ephemeral Messages

I'm trying to figure out the mechanism to post an ephemeral message to a user and then remove it and replace it with a message visible to all. Similar behavior to giphy in which the Slash Command shows an interactive ephemeral message and creates a channel message once the user decides which gif to send. I'm also curious about updating the ephemeral message. I assume this can be done by the response_url if we use an interactive ephemeral message.
I initially figured I'd just create a ephemeral message using chat.postEphemeral and then call chat.delete on it, but it seems chat.delete and chat.update can't be called on a message created using chat.postEphemeral.
The Slack message guidelines seems to suggest that a multi-step interactive flow should always be handled in an ephemeral way so that other channel user don't see all intermediate messages before the result but I'm having bad luck figuring out how to get rid of the ephemeral when done. Probably just being bad at reading but any help appreciated.
Edit with more details:
The documentation around using response_url and postEphemeral states
As you replace messages using chat.update or the replace_original
option, you cannot change a message's type from ephemeral to
in_channel. Once a message has been issued, it will retain its
visibility quality for life.
The message guidelines suggest:
If a user has initiated an action that has multiple steps, those steps
should be shown as ephemeral messages visible only to that user until
the entire action is complete to avoid cluttering the channel for
everyone.
Presumably, I should be able to create an interaction in which I first send an in_channel interactive message.
When a user initiates an action, I should be able to send them a series of ephemeral messages using the response_url and passing response_type: 'ephemeral' and replace_original: false?
A new ephemeral interactive message created this way will have its own response_url for making edits, right?
Once I am done with the interactive flow via ephemeral messages, I can modify the original interactive message using its original response_url?
Lastly, how do I get rid of the last ephemeral edit? Or do I just change it to something like "Workflow completed" and hope for the best? I'm asking because Slash commands obviously seem to have a way to essentially replace the ephemeral message for an in_channel message and I'm trying to figure this kind of workflow out.
I searched high and low on how to do this and finally came across the answer.
Your ephemeral message must trigger an action, i.e. button click.
Your response to the action must use the following body
{
'response_type': 'ephemeral',
'text': '',
'replace_original': true,
'delete_original': true
}
'delete_original': true is the key here, which as far as I can tell is not mentioned in any of the API guides, however it is present in the API field guide under Top-level message fields
If you wish to change the response_type of your message instead of deleting it, you must do so by first deleting the ephemeral message and then posting the same message with 'response_type': 'in_channel'.
In my use case I wanted to take an ephemeral message and repost it with the exact same message body as an in-channel message. I have not found a way to retrieve the content of your ephemeral message, so the best method I've found is to pass whatever necessary data spawned your ephemeral message in the button's value so that your action handler can read this data and dynamically recreate the message body.
In my case, this was the user input being used to perform a query. On the off chance that data in the database changes between the time the original ephemeral message is posted and the in-channel version is posted they will be different. You may be able to send a JSON string directly through this value field and avoid making additional database calls and running the risk of messages changing when posted to the channel. The character limit of value is 2000 so JSON passing is extremely limited.
Assuming you use the same code to generate this body when initially creating the ephemeral message and also when recreating it in-channel, you should receive the same body and essentially are able to change an ephemeral message to in-channel message.
Some ephemeral messages can be "soft" deleted/replaced but only when posted as part of a message with interactive features like buttons or menus. When a button is clicked or a menu selection made, you have a chance to instruct Slack to either "delete" the original message, or replace it with a new one. These docs detail using responses and response_url to accomplish that.
A message created with chat.postEphemeral that itself has no interactive features can never be explicitly deleted. Once it's delivered, it's like a ghost and will disappear following a restart or refresh.
Answering your bulleted questions in order:
Correct, you essentially start a new chain of interactivity with net new ephemeral message you post to that user
Each interactive message interaction will have its own response URL. The new ephemeral message won't have a response_url you can use until the end user presses a button, selects a menu item, etc.
response_url will eventually expire ("using the response_url, your app can continue interacting with users up to 5 times within 30 minutes of the action invocation.") If the original message is non-ephemeral, using chat.update is a better strategy for longer timelines. With ephemeral messages, it's more of a "do your best" strategy. They'll eventually get cleaned up for the user after a refresh.
I think you have a good handle on what's best. Personally, I think it's easier to kick off a new "in_channel" message by using chat.postMessage instead of as a chain effect directly from a slash command or interaction.
The Kotlin/Java version for this solution using the Bolt API as shown below
import com.slack.api.bolt.handler.builtin.BlockActionHandler
import com.slack.api.bolt.request.builtin.BlockActionRequest
import com.slack.api.app_backend.interactive_components.response.ActionResponse
import com.slack.api.bolt.response.Response
import com.slack.api.bolt.context.builtin.ActionContext
object Handler : BlockActionHandler {
override fun apply(req: BlockActionRequest,
context: ActionContext): Response {
val response = ActionResponse
.builder()
.deleteOriginal(true)
.replaceOriginal(true)
.responseType("ephemeral")
.blocks(listOf())
.text("")
.build()
context.respond(response)
return context.ack()
}
}
If you are using Python and Flask the following code should work when you respond to a button click in the ephemeral message:
from flask import jsonify
response = jsonify({
'response_type': 'ephemeral',
'text': '',
'replace_original': 'true',
'delete_original':'true'
})
return make_response(response, 200)

Handling of batch requests in SAPUI5 with sap.ui.model.odata.v2.ODataModel

If I change a property of an OData entity to an invalid value (SAPUI5 client) and send that value to SAP Gateway Server using submitChanges I got the following message in the log file:
Service returned messages for entities that were not requested. This
might lead to wrong message processing and loss of messages
Now I would expect that the callback for "error" would be called but it is always "success".
Inside the callback for success I have a list of responses (in this case with an error).
Now I am asking me, why the error callback is not called?
I assume because the overall batch response is most of the time "OK" also if one request of the batch contains an error?
So do I have to implement error handling in the success callback? Or should the server send an overall error response?
I am using SAPUI5 1.28.15 (with 1.30.6 at least the cited message seems to be removed) and switched batch mode to "on" (if batch mode is off, callback will not be called!).

Best way to handle backed out message in WMB

I have a backout queue for my queue manager.
I want to build a message flow which will read this queue and if any message comes to the queue it should take the message and wrap it in a specially formatted XML message and put it in the normal exception queue which gets the handled exceptions.
But, the message coming to the backout queue can be in any format and I have to make an xml where that message is going be a field.
So, what could be the best settings for my flow(Regarding MQMD properties like CCSID, format etc) and which parser should I use (DFDL or BLOB or MRM)?
Kindly advice.
Since you don't know what kind of message arrived to backout queue, you should not parse it with specific parsers (like XMLNSC etc). Probably the more generic params you will set on MQInput, the better you will do further down the flow to determine what's inside the message.
So, I would start with default Message domain (BLOB) and leave other params untouched as well. Connect some logging node (e.g. Trace node) to Catch and Failure terminals. Connect Out terminal to a Compute node which includes ESQL to determine error type and decide on further actions (e.g. route to label). Then in each label decide what part of the message should be mapped to final exception message and to the mapping.
If you need those MQMD properties of the message currently in backout queue in your resulting message, just extract the values and put/concatenate/whatever to resulting message XML part. I don't think you should copy MQMD (and other) headers to result message as is, because these might be the reason why original message got into backout queue and your resulting message will get there again. Construct resulting message headers from scratch.
If something bad happens while doing these transformations, you will see the problem in Trace. Then modify error handling logic appropriately to avoid mishandling in the future.

Erlang message loops

How does message loops in erlang work, are they sync when it comes to processing messages?
As far as I understand, the loop will start by "receive"ing a message and then perform something and hit another iteration of the loop.
So that has to be sync? right?
If multiple clients send messages to the same message loop, then all those messages are queued and performed one after another, or?
To process multiple messages in parallell, you would have to spawn multiple message loops in different processes, right?
Or did I misunderstand all of it?
Sending a message is asynchronous. Processing a message is synchronous - one message is receive'd at a time - because each process has its own (and only one) mailbox.
From the manual (Erlang concurrency
Each process has its own input queue for messages it receives. New messages received are put at the end of the queue. When a process executes a receive, the first message in the queue is matched against the first pattern in the receive, if this matches, the message is removed from the queue and the actions corresponding to the the pattern are executed.
However, if the first pattern does not match, the second pattern is tested, if this matches the message is removed from the queue and the actions corresponding to the second pattern are executed. If the second pattern does not match the third is tried and so on until there are no more pattern to test. If there are no more patterns to test, the first message is kept in the queue and we try the second message instead. If this matches any pattern, the appropriate actions are executed and the second message is removed from the queue (keeping the first message and any other messages in the queue). If the second message does not match we try the third message and so on until we reach the end of the queue. If we reach the end of the queue, the process blocks (stops execution) and waits until a new message is received and this procedure is repeated.Of course the Erlang implementation is "clever" and minimizes the number of times each message is tested against the patterns in each receive.
So you could create prios with the regex, but the concurrency is done via multiple processes.

Resources