I am trying to write the first time of my life test based on BDD style as the following:
final class SapRsSpec extends FeatureSpec
with Matchers
with GivenWhenThen {
feature("KAFKA") {
scenario("Technical user starts SAP RS") {
Given("Consumer client gets started")
When("KAFKA server is not active")
Then("message `Can not connect ot KAFKA` appears.")
}
}
}
I was trying to write as a technical user perspective.
Is it correct?
When clause should ideally describe the action and not the state, so writing
When("consumer client gets started")
instead of When("Kafka server is not active") is more idiomatic. Thinking of Given-When-Then as the Hoare triple might be helpful, where we first specify state before the action (Given), then the action that mutates the sate (When), and finally the expected sate after the action (Then).
feature and scenario clauses should ideally make sense on their own even when leaving out Given-When-Then body. Just stating feature("Kafka") seems too broad. The feature being specified is actually the relationship between Kafka and replication server, not just Kafka by itself.
Say the feature being specified is replication server's distribution to Kafka under two scenarios, when Kafka is up and when it is down, then we might refine the spec as follows:
feature("Replication server's distribution to Kafka") {
scenario("Replication server's distribution when Kafka is DOWN") {
Given("Kafka server is NOT active")
When("consumer client gets started")
Then("print message 'Failed to connect to Kafka'")
}
scenario("Replication server's distribution when Kafka is UP") {
Given("Kafka server is active")
When("consumer client gets started")
Then("print message 'Successfully connected to Kafka'")
}
}
Related
I'm trying to use Ktor for my new backend, and I have a question about how can I launch periodic consumer for kafka or redis inside Ktor backend application.
In very simple way, I thought that I make a single backend application configurable to enable routing and consuming, thus some of instance will support both, and some of instance will support only routing to ensure availability.
But, I'm not sure how can I trigger consumer application from ktor. From the code I tested with this,
fun main() {
embeddedServer(Netty, port = 8080, host = "127.0.0.1") {
configureDependencyInjection()
configureRouting()
configureSecurity()
configureSerialization()
configureExceptionHandling()
configureMonitoring()
consumerStarting() // this is consumer starting.
}.start(wait = true)
}
#OptIn(ExperimentalTime::class)
fun Application.consumerStarting() {
CoroutineScope(Dispatchers.IO).launch {
// todo: make this in to rule activator initializer
println("TEST")
delay(3.seconds)
consumerStarting()
}
}
And, when I tested this, I can see that "TEST" will be printed every 3 seconds.
Similar to this way, I thought that I can start monitoring instances from Application.consumerStarting() (e.g. periodically fetch stream from redis, consume it we coroutine, etc.).
But I'm not sure it is right way because I cannot find any references for this situation with Ktor.
Any comment will be welcome.
I would like to know, if the following Gherkin phrase correspond to BDD rules:
final class KafkaSpec extends BddSpec {
feature("Kafka distribution to SAP server via websocket") {
scenario("Kafka consumer does not receive messages from Kafka server") {
Given("Kafka server is NOT active")
When("consumer client get started")
val ex = SenderActor.run
Then("print message `Failed to connect to Kafka`")
ex.failed map { ex =>
assertThrows[ConnectException](ex)
}
}
scenario("Kafka consumer receives messages from Kafka server") {
Given("Kafka server is ACTIVE")
When("consumer client get started")
Then("print message `Successfully connected to Kafka`")
succeed
}
}
}
Do I use the right tense? Do I use the Given-When-Then correctly?
The Givens (contexts) are fine; we normally use either continuous present or past tense for those:
Given the kafka server is active <-- continuous present
Given the kafka server was started <-- past tense
For the Whens (events), it's better if you can use an active voice. Active voice starts with who did it. Who started the server? (I've corrected the English a bit here too.)
When the consumer client was started <-- passive voice
When our consumer starts their client <-- active voice
For the Thens (outcomes), I really like the word "should". It encourages people to question it; should it really happen? Now? In this release? Is there any context for which this shouldn't happen or something different should happen? Should it still happen, or has this scenario changed?
Then the consumer interface should print the message, `Successfully connected to Kafka`.
One other thing though: the detail in that last step feels a bit too much to me. If the message changed, you'd have to change it everywhere. Instead I keep that in the code (you can abstract the step out) and would say something like:
Then the interface should tell the consumer that the connection was successful.
This is something we usually call "declarative over imperative". It's also OK to have the passive voice here:
Then the consumer should be told that the connection was successful.
Using the word "should" also helps differentiate between the outcomes of one scenario and the givens of another; often these overlap with an outcome forming the context for another scenario:
Given Priscilla has an account
When she enters her username and password correctly
Then she should be on her home page.
Given Priscilla is on her home page...
I wrote more about tenses and language of BDD here, where you'll also find tons of other resources for new BDDers under the BDD category.
I've created an actor to send messages to a chat server. However, the chat server only permits 5 connections per user. If I hammer my scala server I get error messages because my chat clients get disconnected.
So how can I configure akka so that my XmppSenderActors only use a maximum of 5 threads? I don't want to restrict the rest of the actor system, only this object (at the path /XmppSenderActor/).
I'm trying this config since I think it's the dispatcher I need to configure, but I'm not sure:
akka.actor.deployment {
/XmppSenderActor {
dispatcher = xmpp-dispatcher
}
xmpp-dispatcher {
fork-join-executor.parallelism-min = 2
fork-join-executor.parallelism-max = 3
}
}
This gives me an error though: akka.ConfigurationException: Dispatcher [xmpp-dispatcher] not configured for path akka://sangria-server/user/XmppSenderActor
I would probably try to configure a Router instead.
http://doc.akka.io/docs/akka/2.0/scala/routing.html
A dispatcher seems to deal with sending messages to the inbox rather than the actual number or Actor targets.
That configuration in particular could work for you:
akka.actor.deployment {
/router {
router = round-robin
nr-of-instances = 5
}
}
The nr-of-instances will create 5 childrens from the get going and therefore fill your needs.
You might need to find the right Router implementation though.
I have an Unfiltered Netty server that I need to shutdown and restart after every test.
val mockService = unfiltered.netty.Server.http(mockServicePort).handler(mockServicePlan)
before {
proxyServer.start()
}
after {
proxyServer.stop()
}
Currently, this is not working, and I am fairly certain that is because the stop() function is non-blocking and so the following start() function gets called to early.
I looked for a way to block or get notified on server closure, but it would not appear to be surfaced through the current API.
Is there a better way of achieving what I am trying to achieve?
Easy answer: replace your Unfiltered Netty server with a HTTP4S Blaze server.
var server: org.http4s.server.Server = null
val go: Task[Server] = org.http4s.server.blaze.BlazeBuilder
.bindHttp(mockServicePort)
.mountService(mockService)
.start
before {
server = go.run
}
after {
server.shutdown.run
}
There's also an awaitShutdown that blocks until the server shuts down. But since shutdown is a Task, it's easy to get notified when it has finished. Just flatMap that shit.
I currently have a couple of Grails applications using a single MongoDB replica set for some shared information. Recently, a race condition reproducibly occurred where:
A user performed an action on a front-end that started a back-end process
Part of the back-end process involved saving a new status on two domain objects
The back-end process generated a message to an outside server notifying of the event
The outside server generated a request for more details on the relevant domain objects after receiving the message
My app responded with stale data for one resource and accurate(up-to-date) data for the other.
On retry, the outside server generated an identical request and received the expected(accurate) data for both resources.
Neither save was called with flush:true, however the 1st resources save occurs two lines before the 2nd resources save, and the line in between is the change to the second resource. It may be the case that flush will resolve this issue, but I'd like to implement a solution that will guarantee the specific situation doesn't arise again.
My somewhat naive/1st thrust implementation of a solution involves get & release semaphore methods:
public synchronized boolean releaseSemaphore(Thing thing){
if(thing.semaphore==true){
thing.semaphore=false
if(thing.save(failOnError:true, flush:true)){
return true
}
else{
log.warn "releasing thing semaphore, thing: "+thing.id+", failed on thing.save()"
return false
}
}
else{
log.error "releaseThingSemaphore called with thing: "+thing.id+" when semaphore not held."
return false
}
}
public synchronized getThingWithSemaphore(String thingId){
def thing = Thing.get(thingId)
if(thing){
if(thing.semaphore==false){
thing.semaphore=true
if(thing.save(failOnError:true, flush:true)){
return [thing, true]
}
else{
log.debug "Failed to get lock on thing: "+thingId
return [null, false]
}
}
else{
log.warn "Thing: "+thingId+" was locked when getThingWithSemaphore was called"
return [null, false]
}
}
else{
return [null, false]
}
}
Would the GORM API's Thing.lock(thingId) {(http://grails.github.io/grails-doc/3.0.x/guide/GORM.html#locking) .lock()} accomplish the same guarantees I've tried to achieve in my above implementation here (when getting the semaphore prior to writing or reading for a significant action)?
http://www.anyware.co.uk/2005/2012/11/12/the-false-optimism-of-gorm-and-hibernate/ (while I realize its old) claims the .lock() method used to fail silently when outside of a transaction, not actually locking anything. Is this still the case?
(I also have concerns around MongoDB's general level ofsupport for transactions, and the impact this would have on a GORM .lock() call)
If I were to deploy multiple instances of the identical app in different data-centers requiring cross app-instance locking (or cross non-identical app sharing the same MongoDB replication set datasource), would I be able to leverage anything in the GORM API to enable cross-app document locking?