2014-12-19 13:09:35 +01:00
|
|
|
/**
|
2016-02-23 12:58:39 +01:00
|
|
|
* Copyright (C) 2014-2016 Lightbend Inc. <http://www.lightbend.com>
|
2014-12-19 13:09:35 +01:00
|
|
|
*/
|
|
|
|
|
package docs.stream
|
|
|
|
|
|
2016-01-20 10:00:37 +02:00
|
|
|
import akka.NotUsed
|
2015-06-23 18:28:53 +02:00
|
|
|
import akka.stream.ActorMaterializer
|
2016-01-20 10:00:37 +02:00
|
|
|
import akka.stream.scaladsl.{ Flow, Sink, Source }
|
2015-04-24 11:45:03 +03:00
|
|
|
import akka.stream.testkit._
|
2015-07-09 13:36:54 +02:00
|
|
|
import org.reactivestreams.Processor
|
2016-02-25 14:27:45 +01:00
|
|
|
import akka.testkit.AkkaSpec
|
2014-12-19 13:09:35 +01:00
|
|
|
|
|
|
|
|
class ReactiveStreamsDocSpec extends AkkaSpec {
|
|
|
|
|
import TwitterStreamQuickstartDocSpec._
|
|
|
|
|
|
2015-12-11 14:45:24 +01:00
|
|
|
implicit val materializer = ActorMaterializer()
|
2014-12-19 13:09:35 +01:00
|
|
|
|
|
|
|
|
//#imports
|
|
|
|
|
import org.reactivestreams.Publisher
|
|
|
|
|
import org.reactivestreams.Subscriber
|
|
|
|
|
//#imports
|
|
|
|
|
|
|
|
|
|
trait Fixture {
|
|
|
|
|
//#authors
|
|
|
|
|
val authors = Flow[Tweet]
|
2014-12-25 11:33:42 +01:00
|
|
|
.filter(_.hashtags.contains(akka))
|
2014-12-19 13:09:35 +01:00
|
|
|
.map(_.author)
|
|
|
|
|
|
|
|
|
|
//#authors
|
|
|
|
|
|
|
|
|
|
//#tweets-publisher
|
|
|
|
|
def tweets: Publisher[Tweet]
|
|
|
|
|
//#tweets-publisher
|
|
|
|
|
|
|
|
|
|
//#author-storage-subscriber
|
|
|
|
|
def storage: Subscriber[Author]
|
|
|
|
|
//#author-storage-subscriber
|
|
|
|
|
|
|
|
|
|
//#author-alert-subscriber
|
|
|
|
|
def alert: Subscriber[Author]
|
|
|
|
|
//#author-alert-subscriber
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val impl = new Fixture {
|
|
|
|
|
override def tweets: Publisher[Tweet] =
|
2016-01-20 21:01:27 +01:00
|
|
|
TwitterStreamQuickstartDocSpec.tweets.runWith(Sink.asPublisher(fanout = false))
|
2014-12-19 13:09:35 +01:00
|
|
|
|
2015-04-24 11:45:03 +03:00
|
|
|
override def storage = TestSubscriber.manualProbe[Author]
|
2014-12-19 13:09:35 +01:00
|
|
|
|
2015-04-24 11:45:03 +03:00
|
|
|
override def alert = TestSubscriber.manualProbe[Author]
|
2014-12-19 13:09:35 +01:00
|
|
|
}
|
|
|
|
|
|
2015-04-24 11:45:03 +03:00
|
|
|
def assertResult(storage: TestSubscriber.ManualProbe[Author]): Unit = {
|
2014-12-19 13:09:35 +01:00
|
|
|
val sub = storage.expectSubscription()
|
|
|
|
|
sub.request(10)
|
|
|
|
|
storage.expectNext(Author("rolandkuhn"))
|
|
|
|
|
storage.expectNext(Author("patriknw"))
|
|
|
|
|
storage.expectNext(Author("bantonsson"))
|
|
|
|
|
storage.expectNext(Author("drewhk"))
|
|
|
|
|
storage.expectNext(Author("ktosopl"))
|
|
|
|
|
storage.expectNext(Author("mmartynas"))
|
|
|
|
|
storage.expectNext(Author("akkateam"))
|
|
|
|
|
storage.expectComplete()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"reactive streams publisher via flow to subscriber" in {
|
|
|
|
|
import impl._
|
|
|
|
|
val storage = impl.storage
|
|
|
|
|
|
|
|
|
|
//#connect-all
|
2015-12-17 11:48:30 +02:00
|
|
|
Source.fromPublisher(tweets).via(authors).to(Sink.fromSubscriber(storage)).run()
|
2014-12-19 13:09:35 +01:00
|
|
|
//#connect-all
|
|
|
|
|
|
|
|
|
|
assertResult(storage)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"flow as publisher and subscriber" in {
|
|
|
|
|
import impl._
|
|
|
|
|
val storage = impl.storage
|
|
|
|
|
|
|
|
|
|
//#flow-publisher-subscriber
|
2015-07-09 13:36:54 +02:00
|
|
|
val processor: Processor[Tweet, Author] = authors.toProcessor.run()
|
2014-12-19 13:09:35 +01:00
|
|
|
|
2015-07-09 13:36:54 +02:00
|
|
|
tweets.subscribe(processor)
|
|
|
|
|
processor.subscribe(storage)
|
2014-12-19 13:09:35 +01:00
|
|
|
//#flow-publisher-subscriber
|
|
|
|
|
|
|
|
|
|
assertResult(storage)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"source as publisher" in {
|
|
|
|
|
import impl._
|
|
|
|
|
val storage = impl.storage
|
|
|
|
|
|
|
|
|
|
//#source-publisher
|
|
|
|
|
val authorPublisher: Publisher[Author] =
|
2015-12-17 11:48:30 +02:00
|
|
|
Source.fromPublisher(tweets).via(authors).runWith(Sink.asPublisher(fanout = false))
|
2014-12-19 13:09:35 +01:00
|
|
|
|
|
|
|
|
authorPublisher.subscribe(storage)
|
|
|
|
|
//#source-publisher
|
|
|
|
|
|
|
|
|
|
assertResult(storage)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"source as fanoutPublisher" in {
|
|
|
|
|
import impl._
|
|
|
|
|
val storage = impl.storage
|
|
|
|
|
val alert = impl.alert
|
|
|
|
|
|
|
|
|
|
//#source-fanoutPublisher
|
|
|
|
|
val authorPublisher: Publisher[Author] =
|
2015-12-17 11:48:30 +02:00
|
|
|
Source.fromPublisher(tweets).via(authors)
|
|
|
|
|
.runWith(Sink.asPublisher(fanout = true))
|
2014-12-19 13:09:35 +01:00
|
|
|
|
|
|
|
|
authorPublisher.subscribe(storage)
|
|
|
|
|
authorPublisher.subscribe(alert)
|
|
|
|
|
//#source-fanoutPublisher
|
|
|
|
|
|
|
|
|
|
// this relies on fanoutPublisher buffer size > number of authors
|
|
|
|
|
assertResult(storage)
|
|
|
|
|
assertResult(alert)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"sink as subscriber" in {
|
|
|
|
|
import impl._
|
|
|
|
|
val storage = impl.storage
|
|
|
|
|
|
|
|
|
|
//#sink-subscriber
|
|
|
|
|
val tweetSubscriber: Subscriber[Tweet] =
|
2015-12-17 11:48:30 +02:00
|
|
|
authors.to(Sink.fromSubscriber(storage)).runWith(Source.asSubscriber[Tweet])
|
2014-12-19 13:09:35 +01:00
|
|
|
|
|
|
|
|
tweets.subscribe(tweetSubscriber)
|
|
|
|
|
//#sink-subscriber
|
|
|
|
|
|
|
|
|
|
assertResult(storage)
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-09 13:36:54 +02:00
|
|
|
"use a processor" in {
|
|
|
|
|
|
|
|
|
|
//#use-processor
|
|
|
|
|
// An example Processor factory
|
|
|
|
|
def createProcessor: Processor[Int, Int] = Flow[Int].toProcessor.run()
|
|
|
|
|
|
2016-01-20 10:00:37 +02:00
|
|
|
val flow: Flow[Int, Int, NotUsed] = Flow.fromProcessor(() => createProcessor)
|
2015-07-09 13:36:54 +02:00
|
|
|
//#use-processor
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-19 13:09:35 +01:00
|
|
|
}
|