cats.effect.IO Scala Examples
The following examples show how to use cats.effect.IO.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example.
Example 1
Source File: ClientApp.scala From fs2-chat with MIT License | 6 votes |
package fs2chat package client import cats.effect.{Blocker, ExitCode, IO, IOApp} import cats.implicits._ import com.comcast.ip4s._ import com.monovore.decline._ import fs2.io.tcp.SocketGroup object ClientApp extends IOApp { private val argsParser: Command[(Username, SocketAddress[IpAddress])] = Command("fs2chat-client", "FS2 Chat Client") { ( Opts .option[String]("username", "Desired username", "u") .map(Username.apply), Opts .option[String]("address", "Address of chat server") .withDefault("127.0.0.1") .mapValidated(p => IpAddress(p).toValidNel("Invalid IP address")), Opts .option[Int]("port", "Port of chat server") .withDefault(5555) .mapValidated(p => Port(p).toValidNel("Invalid port number")) ).mapN { case (desiredUsername, ip, port) => desiredUsername -> SocketAddress(ip, port) } } def run(args: List[String]): IO[ExitCode] = argsParser.parse(args) match { case Left(help) => IO(System.err.println(help)).as(ExitCode.Error) case Right((desiredUsername, address)) => Blocker[IO] .use { blocker => Console[IO](blocker).flatMap { console => SocketGroup[IO](blocker).use { socketGroup => Client .start[IO](console, socketGroup, address, desiredUsername) .compile .drain } } } .as(ExitCode.Success) } }
Example 2
Source File: MySqlZoneChangeRepository.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.mysql.repository import cats.effect.IO import org.joda.time.DateTime import org.slf4j.LoggerFactory import scalikejdbc._ import vinyldns.core.domain.zone._ import vinyldns.core.protobuf._ import vinyldns.core.route.Monitored import vinyldns.proto.VinylDNSProto class MySqlZoneChangeRepository extends ZoneChangeRepository with ProtobufConversions with Monitored { private final val logger = LoggerFactory.getLogger(classOf[MySqlZoneChangeRepository]) private final val PUT_ZONE_CHANGE = sql""" |REPLACE INTO zone_change (change_id, zone_id, data, created_timestamp) | VALUES ({change_id}, {zone_id}, {data}, {created_timestamp}) """.stripMargin private final val LIST_ZONES_CHANGES = sql""" |SELECT zc.data | FROM zone_change zc | WHERE zc.zone_id = {zoneId} AND zc.created_timestamp <= {startFrom} | ORDER BY zc.created_timestamp DESC | LIMIT {maxItems} """.stripMargin override def save(zoneChange: ZoneChange): IO[ZoneChange] = monitor("repo.ZoneChange.save") { IO { logger.info(s"Saving zone change ${zoneChange.id}") DB.localTx { implicit s => PUT_ZONE_CHANGE .bindByName( 'change_id -> zoneChange.id, 'zone_id -> zoneChange.zoneId, 'data -> toPB(zoneChange).toByteArray, 'created_timestamp -> zoneChange.created.getMillis ) .update() .apply() zoneChange } } } override def listZoneChanges( zoneId: String, startFrom: Option[String], maxItems: Int ): IO[ListZoneChangesResults] = // sorted from most recent, startFrom is an offset from the most recent change monitor("repo.ZoneChange.listZoneChanges") { IO { logger.info(s"Getting zone changes for zone $zoneId") DB.readOnly { implicit s => val startValue = startFrom.getOrElse(DateTime.now().getMillis.toString) // maxItems gets a plus one to know if the table is exhausted so we can conditionally give a nextId val queryResult = LIST_ZONES_CHANGES .bindByName( 'zoneId -> zoneId, 'startFrom -> startValue, 'maxItems -> (maxItems + 1) ) .map(extractZoneChange(1)) .list() .apply() val maxQueries = queryResult.take(maxItems) // nextId is Option[String] to maintains backwards compatibility // earlier maxItems was incremented, if the (maxItems + 1) size is not reached then pages are exhausted val nextId = queryResult match { case _ if queryResult.size <= maxItems | queryResult.isEmpty => None case _ => Some(queryResult.last.created.getMillis.toString) } ListZoneChangesResults(maxQueries, nextId, startFrom, maxItems) } } } private def extractZoneChange(colIndex: Int): WrappedResultSet => ZoneChange = res => { fromPB(VinylDNSProto.ZoneChange.parseFrom(res.bytes(colIndex))) } }
Example 3
Source File: MySqlUserChangeRepository.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.mysql.repository import cats.effect.IO import org.slf4j.LoggerFactory import scalikejdbc._ import vinyldns.core.domain.membership.{UserChange, UserChangeRepository} import vinyldns.core.protobuf.ProtobufConversions import vinyldns.core.route.Monitored import vinyldns.proto.VinylDNSProto class MySqlUserChangeRepository extends UserChangeRepository with Monitored with ProtobufConversions { private final val logger = LoggerFactory.getLogger(classOf[MySqlUserChangeRepository]) private final val PUT_USER_CHANGE = sql""" | INSERT INTO user_change (change_id, user_id, data, created_timestamp) | VALUES ({changeId}, {userId}, {data}, {createdTimestamp}) ON DUPLICATE KEY | UPDATE user_id=VALUES(user_id), | data=VALUES(data), | created_timestamp=VALUES(created_timestamp) """.stripMargin private final val GET_USER_CHANGE_BY_ID = sql""" | SELECT data | FROM user_change | WHERE change_id = ? """.stripMargin def get(changeId: String): IO[Option[UserChange]] = monitor("repo.UserChange.get") { logger.info(s"Getting user change with id: $changeId") IO { DB.readOnly { implicit s => GET_USER_CHANGE_BY_ID .bind(changeId) .map(toUserChange(1)) .first() .apply() } } } def save(change: UserChange): IO[UserChange] = monitor("repo.UserChange.save") { logger.info(s"Saving user change: $change") IO { DB.localTx { implicit s => PUT_USER_CHANGE .bindByName( 'changeId -> change.id, 'userId -> change.madeByUserId, 'data -> toPb(change).toByteArray, 'createdTimestamp -> change.created.getMillis ) .update() .apply() } change } } private def toUserChange(colIndex: Int): WrappedResultSet => UserChange = res => { fromPb(VinylDNSProto.UserChange.parseFrom(res.bytes(colIndex))) } }
Example 4
Source File: MySqlMessageQueueProvider.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.mysql.queue import cats.effect.IO import org.slf4j.LoggerFactory import pureconfig._ import pureconfig.generic.auto._ import pureconfig.module.catseffect.syntax._ import scalikejdbc.{ConnectionPool, DataSourceConnectionPool} import scalikejdbc.config.DBs import vinyldns.core.queue.{MessageQueue, MessageQueueConfig, MessageQueueProvider} import vinyldns.mysql.{HikariCloser, MySqlConnectionConfig, MySqlDataSourceSettings} import vinyldns.mysql.MySqlConnector._ import cats.effect.ContextShift import cats.effect.Blocker class MySqlMessageQueueProvider extends MessageQueueProvider { private val logger = LoggerFactory.getLogger(classOf[MySqlMessageQueueProvider]) implicit val mySqlPropertiesReader: ConfigReader[Map[String, AnyRef]] = MySqlConnectionConfig.mySqlPropertiesReader private implicit val cs: ContextShift[IO] = IO.contextShift(scala.concurrent.ExecutionContext.global) def load(config: MessageQueueConfig): IO[MessageQueue] = for { connectionSettings <- Blocker[IO].use( ConfigSource.fromConfig(config.settings).loadF[IO, MySqlConnectionConfig](_) ) _ <- runDBMigrations(connectionSettings) _ <- setupQueueConnection(connectionSettings) } yield new MySqlMessageQueue(config.maxRetries) def setupQueueConnection(config: MySqlConnectionConfig): IO[Unit] = { val queueConnectionSettings = MySqlDataSourceSettings(config, "mysqlQueuePool") getDataSource(queueConnectionSettings).map { dataSource => logger.error("configuring connection pool for queue") // note this is being called 2x in the case you use the mysql datastores and // loader. That should be ok DBs.loadGlobalSettings() // Configure the connection pool ConnectionPool.add( MySqlMessageQueue.QUEUE_CONNECTION_NAME, new DataSourceConnectionPool(dataSource, closer = new HikariCloser(dataSource)) ) logger.error("queue connection pool init complete") } } }
Example 5
Source File: DataStore.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.core.repository import cats.effect.IO import vinyldns.core.domain.batch.BatchChangeRepository import vinyldns.core.domain.membership._ import vinyldns.core.domain.record.{RecordChangeRepository, RecordSetRepository} import vinyldns.core.domain.zone.{ZoneChangeRepository, ZoneRepository} import vinyldns.core.repository.RepositoryName.RepositoryName import vinyldns.core.health.HealthCheck.HealthCheck import vinyldns.core.task.TaskRepository import scala.reflect.ClassTag class LoadedDataStore( val dataStore: DataStore, val shutdownHook: IO[Unit], val healthCheck: HealthCheck ) object DataStore { def apply( userRepository: Option[UserRepository] = None, groupRepository: Option[GroupRepository] = None, membershipRepository: Option[MembershipRepository] = None, groupChangeRepository: Option[GroupChangeRepository] = None, recordSetRepository: Option[RecordSetRepository] = None, recordChangeRepository: Option[RecordChangeRepository] = None, zoneChangeRepository: Option[ZoneChangeRepository] = None, zoneRepository: Option[ZoneRepository] = None, batchChangeRepository: Option[BatchChangeRepository] = None, userChangeRepository: Option[UserChangeRepository] = None, taskRepository: Option[TaskRepository] = None ): DataStore = new DataStore( userRepository, groupRepository, membershipRepository, groupChangeRepository, recordSetRepository, recordChangeRepository, zoneChangeRepository, zoneRepository, batchChangeRepository, userChangeRepository, taskRepository ) } class DataStore( userRepository: Option[UserRepository] = None, groupRepository: Option[GroupRepository] = None, membershipRepository: Option[MembershipRepository] = None, groupChangeRepository: Option[GroupChangeRepository] = None, recordSetRepository: Option[RecordSetRepository] = None, recordChangeRepository: Option[RecordChangeRepository] = None, zoneChangeRepository: Option[ZoneChangeRepository] = None, zoneRepository: Option[ZoneRepository] = None, batchChangeRepository: Option[BatchChangeRepository] = None, userChangeRepository: Option[UserChangeRepository] = None, taskRepository: Option[TaskRepository] = None ) { lazy val dataStoreMap: Map[RepositoryName, Repository] = List( userRepository.map(RepositoryName.user -> _), groupRepository.map(RepositoryName.group -> _), membershipRepository.map(RepositoryName.membership -> _), groupChangeRepository.map(RepositoryName.groupChange -> _), recordSetRepository.map(RepositoryName.recordSet -> _), recordChangeRepository.map(RepositoryName.recordChange -> _), zoneChangeRepository.map(RepositoryName.zoneChange -> _), zoneRepository.map(RepositoryName.zone -> _), batchChangeRepository.map(RepositoryName.batchChange -> _), userChangeRepository.map(RepositoryName.userChange -> _), taskRepository.map(RepositoryName.task -> _) ).flatten.toMap def keys: Set[RepositoryName] = dataStoreMap.keySet def get[A <: Repository: ClassTag](name: RepositoryName): Option[A] = dataStoreMap.get(name).flatMap { case a: A => Some(a) case _ => None } }
Example 6
Source File: CryptoAlgebra.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.core.crypto import cats.effect.IO import com.typesafe.config.Config trait CryptoAlgebra { def encrypt(value: String): String def decrypt(value: String): String } object CryptoAlgebra { def load(cryptoConfig: Config): IO[CryptoAlgebra] = for { className <- IO(cryptoConfig.getString("type")) classInstance <- IO( Class .forName(className) .getDeclaredConstructor(classOf[Config]) .newInstance(cryptoConfig) .asInstanceOf[CryptoAlgebra] ) } yield classInstance }
Example 7
Source File: HealthCheck.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.core.health import cats.effect.IO import org.slf4j.LoggerFactory object HealthCheck { type HealthCheck = IO[Either[HealthCheckError, Unit]] case class HealthCheckError(message: String) extends Throwable(message) private val logger = LoggerFactory.getLogger("HealthCheck") implicit class HealthCheckImprovements(io: IO[Either[Throwable, _]]) { def asHealthCheck(caller: Class[_]): HealthCheck = io.map { case Left(err) => logger.error(s"HealthCheck for ${caller.getCanonicalName} Failed", err) val msg = Option(err.getMessage).getOrElse("no message from error") Left( HealthCheckError(s"${caller.getCanonicalName} health check failed with msg='${msg}'") ) case _ => Right(()) } } }
Example 8
Source File: HealthService.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.core.health import cats.effect.{ContextShift, IO} import cats.implicits._ import org.slf4j.LoggerFactory import vinyldns.core.health.HealthCheck.{HealthCheck, HealthCheckError} class HealthService(healthChecks: List[HealthCheck]) { private val logger = LoggerFactory.getLogger(classOf[HealthService]) private implicit val cs: ContextShift[IO] = IO.contextShift(scala.concurrent.ExecutionContext.global) def checkHealth(): IO[List[HealthCheckError]] = healthChecks.parSequence .map { _.collect { case Left(err) => logger.error(s"Health Check Failure: ${err.message}") err } } }
Example 9
Source File: AllNotifiers.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.core.notifier import cats.effect.{ContextShift, IO} import cats.implicits._ import org.slf4j.LoggerFactory import vinyldns.core.route.Monitored final case class AllNotifiers(notifiers: List[Notifier])(implicit val cs: ContextShift[IO]) extends Monitored { private val logger = LoggerFactory.getLogger("AllNotifiers") def notify(notification: Notification[_]): IO[Unit] = for { _ <- notifiers.parTraverse(notify(_, notification)) } yield () def notify(notifier: Notifier, notification: Notification[_]): IO[Unit] = monitor(notifier.getClass.getSimpleName) { notifier.notify(notification).handleErrorWith { e => IO { logger.error(s"Notifier ${notifier.getClass.getSimpleName} failed.", e) } } } }
Example 10
Source File: NotifierLoader.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.core.notifier import vinyldns.core.domain.membership.UserRepository import cats.effect.IO import cats.implicits._ import cats.effect.ContextShift object NotifierLoader { def loadAll(configs: List[NotifierConfig], userRepository: UserRepository)( implicit cs: ContextShift[IO] ): IO[AllNotifiers] = for { notifiers <- configs.parTraverse(load(_, userRepository)) } yield AllNotifiers(notifiers) def load(config: NotifierConfig, userRepository: UserRepository): IO[Notifier] = for { provider <- IO( Class .forName(config.className) .getDeclaredConstructor() .newInstance() .asInstanceOf[NotifierProvider] ) notifier <- provider.load(config, userRepository) } yield notifier }
Example 11
Source File: MessageQueueLoader.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.core.queue import cats.effect.IO import org.slf4j.LoggerFactory object MessageQueueLoader { private val logger = LoggerFactory.getLogger("MessageQueueLoader") def load(config: MessageQueueConfig): IO[MessageQueue] = for { _ <- IO(logger.error(s"Attempting to load queue ${config.className}")) provider <- IO( Class .forName(config.className) .getDeclaredConstructor() .newInstance() .asInstanceOf[MessageQueueProvider] ) queue <- provider.load(config) } yield queue }
Example 12
Source File: MockDataStoreProvider.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.core.repository import cats.effect.IO import org.scalatestplus.mockito.MockitoSugar import vinyldns.core.crypto.CryptoAlgebra import vinyldns.core.domain.batch.BatchChangeRepository import vinyldns.core.domain.membership.{ GroupChangeRepository, GroupRepository, MembershipRepository, UserRepository } import vinyldns.core.domain.record.{RecordChangeRepository, RecordSetRepository} import vinyldns.core.domain.zone.{ZoneChangeRepository, ZoneRepository} import vinyldns.core.health.HealthCheck.HealthCheck class MockDataStoreProvider extends DataStoreProvider with MockitoSugar { def load(config: DataStoreConfig, crypto: CryptoAlgebra): IO[LoadedDataStore] = { val repoConfig = config.repositories val user = repoConfig.user.map(_ => mock[UserRepository]) val group = repoConfig.group.map(_ => mock[GroupRepository]) val membership = repoConfig.membership.map(_ => mock[MembershipRepository]) val groupChange = repoConfig.groupChange.map(_ => mock[GroupChangeRepository]) val recordSet = repoConfig.recordSet.map(_ => mock[RecordSetRepository]) val recordChange = repoConfig.recordChange.map(_ => mock[RecordChangeRepository]) val zoneChange = repoConfig.zoneChange.map(_ => mock[ZoneChangeRepository]) val zone = repoConfig.zone.map(_ => mock[ZoneRepository]) val batchChange = repoConfig.batchChange.map(_ => mock[BatchChangeRepository]) IO.pure( new LoadedDataStore( DataStore( user, group, membership, groupChange, recordSet, recordChange, zoneChange, zone, batchChange ), IO.unit, checkHealth() ) ) } def checkHealth(): HealthCheck = IO.pure(Right((): Unit)) } class AlternateMockDataStoreProvider extends MockDataStoreProvider { override def load(config: DataStoreConfig, crypto: CryptoAlgebra): IO[LoadedDataStore] = IO.pure(new LoadedDataStore(DataStore(), shutdown(), checkHealth())) def shutdown(): IO[Unit] = IO.raiseError(new RuntimeException("oh no")) } class FailDataStoreProvider extends DataStoreProvider { def load(config: DataStoreConfig, crypto: CryptoAlgebra): IO[LoadedDataStore] = IO.raiseError(new RuntimeException("ruh roh")) }
Example 13
Source File: AllNotifiersSpec.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.core.notifier import cats.scalatest.{EitherMatchers, EitherValues, ValidatedMatchers} import org.scalatestplus.mockito.MockitoSugar import org.mockito.Mockito._ import cats.effect.IO import org.scalatest.BeforeAndAfterEach import cats.effect.ContextShift import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec class AllNotifiersSpec extends AnyWordSpec with Matchers with MockitoSugar with EitherValues with EitherMatchers with ValidatedMatchers with BeforeAndAfterEach { implicit val cs: ContextShift[IO] = IO.contextShift(scala.concurrent.ExecutionContext.global) val mockNotifiers = List.fill(3)(mock[Notifier]) val notification = Notification("anything") override def beforeEach: Unit = mockNotifiers.foreach { mock => reset(mock) when(mock.notify(notification)).thenReturn(IO.unit) } "notifier" should { "notify all contained notifiers" in { val notifier = AllNotifiers(mockNotifiers) notifier.notify(notification) mockNotifiers.foreach(verify(_).notify(notification)) } "suppress errors from notifiers" in { val notifier = AllNotifiers(mockNotifiers) when(mockNotifiers(2).notify(notification)).thenReturn(IO.raiseError(new Exception("fail"))) notifier.notify(notification).unsafeRunSync() mockNotifiers.foreach(verify(_).notify(notification)) } } }
Example 14
Source File: MessageQueueLoaderSpec.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.core.queue import cats.effect.IO import com.typesafe.config.{Config, ConfigFactory} import org.scalatestplus.mockito.MockitoSugar import scala.concurrent.duration._ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec object MockMessageQueueProvider extends MockitoSugar { val mockMessageQueue: MessageQueue = mock[MessageQueue] } class MockMessageQueueProvider extends MessageQueueProvider { def load(config: MessageQueueConfig): IO[MessageQueue] = IO.pure(MockMessageQueueProvider.mockMessageQueue) } class FailMessageQueueProvider extends MessageQueueProvider { def load(config: MessageQueueConfig): IO[MessageQueue] = IO.raiseError(new RuntimeException("boo")) } class MessageQueueLoaderSpec extends AnyWordSpec with Matchers { val placeholderConfig: Config = ConfigFactory.parseString("{}") private val pollingInterval = 250.millis private val messagesPerPoll = 10 "load" should { "return the correct queue if properly configured" in { val config = MessageQueueConfig( "vinyldns.core.queue.MockMessageQueueProvider", pollingInterval, messagesPerPoll, placeholderConfig, 100 ) val loadCall = MessageQueueLoader.load(config) loadCall.unsafeRunSync() shouldBe MockMessageQueueProvider.mockMessageQueue } "Error if the configured provider cannot be found" in { val config = MessageQueueConfig("bad.class", pollingInterval, messagesPerPoll, placeholderConfig, 100) val loadCall = MessageQueueLoader.load(config) a[ClassNotFoundException] shouldBe thrownBy(loadCall.unsafeRunSync()) } "Error if an error is returned from external load" in { val config = MessageQueueConfig( "vinyldns.core.queue.FailMessageQueueProvider", pollingInterval, messagesPerPoll, placeholderConfig, 100 ) val loadCall = MessageQueueLoader.load(config) a[RuntimeException] shouldBe thrownBy(loadCall.unsafeRunSync()) } } }
Example 15
Source File: TaskSchedulerSpec.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.core.task import cats.effect.{ContextShift, IO, Timer} import org.mockito.Mockito import org.mockito.Mockito._ import org.scalatestplus.mockito.MockitoSugar import org.scalatest.BeforeAndAfterEach import scala.concurrent.duration._ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec class TaskSchedulerSpec extends AnyWordSpec with Matchers with MockitoSugar with BeforeAndAfterEach { private implicit val cs: ContextShift[IO] = IO.contextShift(scala.concurrent.ExecutionContext.global) private implicit val timer: Timer[IO] = IO.timer(scala.concurrent.ExecutionContext.global) private val mockRepo = mock[TaskRepository] class TestTask( val name: String, val timeout: FiniteDuration, val runEvery: FiniteDuration, val checkInterval: FiniteDuration, testResult: IO[Unit] = IO.unit ) extends Task { def run(): IO[Unit] = testResult } override def beforeEach() = Mockito.reset(mockRepo) "TaskScheduler" should { "run a scheduled task" in { val task = new TestTask("test", 5.seconds, 500.millis, 500.millis) val spied = spy(task) doReturn(IO.unit).when(mockRepo).saveTask(task.name) doReturn(IO.pure(true)).when(mockRepo).claimTask(task.name, task.timeout, task.runEvery) doReturn(IO.unit).when(mockRepo).releaseTask(task.name) TaskScheduler.schedule(spied, mockRepo).take(1).compile.drain.unsafeRunSync() // We run twice because we run once on start up verify(spied, times(2)).run() verify(mockRepo, times(2)).claimTask(task.name, task.timeout, task.runEvery) verify(mockRepo, times(2)).releaseTask(task.name) } "release the task even on error" in { val task = new TestTask( "test", 5.seconds, 500.millis, 500.millis, IO.raiseError(new RuntimeException("fail")) ) doReturn(IO.unit).when(mockRepo).saveTask(task.name) doReturn(IO.pure(true)).when(mockRepo).claimTask(task.name, task.timeout, task.runEvery) doReturn(IO.unit).when(mockRepo).releaseTask(task.name) TaskScheduler.schedule(task, mockRepo).take(1).compile.drain.unsafeRunSync() // We release the task twice, once on start and once on the run verify(mockRepo, times(2)).releaseTask(task.name) } "fail to start if the task cannot be saved" in { val task = new TestTask("test", 5.seconds, 500.millis, 500.millis) val spied = spy(task) doReturn(IO.raiseError(new RuntimeException("fail"))).when(mockRepo).saveTask(task.name) a[RuntimeException] should be thrownBy TaskScheduler .schedule(task, mockRepo) .take(1) .compile .drain .unsafeRunSync() verify(spied, never()).run() } } }
Example 16
Source File: KafkaTest.scala From aecor with MIT License | 5 votes |
package aecor.kafkadistributedprocessing import java.util.Properties import aecor.kafkadistributedprocessing.internal.Kafka.UnitDeserializer import aecor.kafkadistributedprocessing.internal.RebalanceEvents.RebalanceEvent import aecor.kafkadistributedprocessing.internal.RebalanceEvents.RebalanceEvent.{ PartitionsAssigned, PartitionsRevoked } import aecor.kafkadistributedprocessing.internal.{ Kafka, KafkaConsumer } import cats.effect.IO import cats.implicits._ import fs2.Stream import fs2.concurrent.Queue import org.apache.kafka.clients.consumer.ConsumerConfig import org.scalatest.funsuite.AnyFunSuite import scala.concurrent.duration._ class KafkaTest extends AnyFunSuite with IOSupport with KafkaSupport { val topic = "test" val partitionCount = 4 createCustomTopic(topic, partitions = partitionCount) val createConsumerAccess = { val properties = new Properties() properties.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, brokers.mkString(",")) properties.setProperty(ConsumerConfig.GROUP_ID_CONFIG, "test") KafkaConsumer.create[IO](properties, new UnitDeserializer, new UnitDeserializer) } val watchRebalanceEvents = Stream .resource(createConsumerAccess) .flatMap(Kafka.watchRebalanceEvents(_, topic, 500.millis, 50.millis)) test("Rebalance event stream") { val program = for { queue <- Queue.unbounded[IO, (Int, RebalanceEvent)] run = (n: Int) => watchRebalanceEvents .evalMap { x => val e = n -> x.value queue.enqueue1(e) >> x.commit } .compile .drain .start p1 <- run(1) l1 <- queue.dequeue.take(2).compile.toList p2 <- run(2) l2 <- queue.dequeue.take(4).compile.toList _ <- p1.cancel l3 <- queue.dequeue.take(2).compile.toList _ <- p2.cancel } yield (l1, l2, l3) val (l1, l2, l3) = program.unsafeRunTimed(40.seconds).get def fold(list: List[(Int, RebalanceEvent)]): Map[Int, Set[Int]] = list.foldLeft(Map.empty[Int, Set[Int]]) { case (s, (c, e)) => e match { case PartitionsRevoked(partitions) => s.updated(c, s.getOrElse(c, Set.empty[Int]) -- partitions.map(_.partition())) case PartitionsAssigned(partitions) => s.updated(c, s.getOrElse(c, Set.empty[Int]) ++ partitions.map(_.partition())) } } assert(fold(l1) == Map(1 -> Set(1, 0, 3, 2))) assert(fold(l2) == Map(1 -> Set(1, 0), 2 -> Set(2, 3))) assert(fold(l3) == Map(2 -> Set(1, 0, 3, 2))) } test("Topic partitions query works before subscription") { val program = createConsumerAccess.use(_.partitionsFor(topic)) val result = program.unsafeRunTimed(2.seconds).get assert(result.size == partitionCount) } }
Example 17
Source File: ChannelTest.scala From aecor with MIT License | 5 votes |
package aecor.kafkadistributedprocessing import aecor.kafkadistributedprocessing.internal.Channel import cats.effect.IO import cats.implicits._ import fs2.concurrent.Queue import org.scalatest.funsuite.AnyFunSuite import scala.concurrent.duration._ class ChannelTest extends AnyFunSuite with IOSupport { test("Channel#call completes only after completion callback") { val out = Channel .create[IO] .flatMap { case Channel(watch, _, call) => Queue.unbounded[IO, String].flatMap { queue => for { fiber <- watch.flatMap { callback => queue.enqueue1("before callback") >> callback }.start _ <- queue.enqueue1("before call") >> call >> queue.enqueue1("after call") _ <- fiber.join out <- queue.dequeue.take(3).compile.toList } yield out } } .unsafeRunTimed(1.seconds) .get assert(out == List("before call", "before callback", "after call")) } test("Channel#call does not wait for completion callback if channel is closed") { Channel .create[IO] .flatMap { case Channel(watch, close, call) => for { w <- watch.start c <- call.start _ <- close _ <- c.join _ <- w.cancel } yield () } .replicateA(100) .unsafeRunTimed(10.seconds) .get assert(true) } }
Example 18
Source File: KafkaDistributedProcessingTest.scala From aecor with MIT License | 5 votes |
package aecor.kafkadistributedprocessing import cats.effect.concurrent.{ Deferred, Ref } import cats.effect.{ ExitCase, IO } import cats.implicits._ import fs2.concurrent.Queue import org.apache.kafka.clients.consumer.ConsumerConfig import org.scalatest.funsuite.AnyFunSuiteLike import scala.concurrent.duration._ class KafkaDistributedProcessingTest extends AnyFunSuiteLike with KafkaSupport with IOSupport { val topicName = "process-distribution" createCustomTopic(topicName, partitions = 4) val settings = DistributedProcessingSettings(Set(s"localhost:${kafkaConfig.kafkaPort}"), topicName) test("Process error propagation") { val exception = new RuntimeException("Oops!") val result = DistributedProcessing(settings) .start("Process error propagation", List(IO.raiseError[Unit](exception))) .attempt .timeout(20.seconds) .unsafeRunSync() assert(result == Left(exception)) } test("Process lifecycle") { val test = Ref.of[IO, (Boolean, Boolean)]((false, false)).flatMap { ref => Deferred[IO, Unit] .flatMap { done => val process = ref.set((true, false)) >> done.complete(()) >> IO.never.guaranteeCase { case ExitCase.Canceled => ref.set((true, true)) case _ => IO.unit }.void val run = DistributedProcessing(settings) .start("Process lifecycle", List(process)) IO.race(run, done.get) >> ref.get } } val (started, finished) = test.timeout(20.seconds).unsafeRunSync() assert(started) assert(finished) } test("Process distribution") { val test = Queue.unbounded[IO, Int].flatMap { queue => def run(client: Int) = DistributedProcessing( settings.withConsumerSetting(ConsumerConfig.CLIENT_ID_CONFIG, client.toString) ).start( "Process distribution", Stream .from(0) .take(8) .map { n => val idx = client * 10 + n (queue.enqueue1(idx) >> IO.cancelBoundary <* IO.never) .guarantee(queue.enqueue1(-idx)) } .toList ) def dequeue(size: Long): IO[List[Int]] = queue.dequeue.take(size).compile.to[List] for { d1 <- run(1).start s1 <- dequeue(8) d2 <- run(2).start s2 <- dequeue(16) _ <- d1.cancel s3 <- dequeue(16) _ <- d2.cancel s4 <- dequeue(8) } yield (s1, s2, s3, s4) } val (s1, s2, s3, s4) = test.timeout(20.seconds).unsafeRunSync() assert(s1.toSet == Set(10, 11, 12, 13, 14, 15, 16, 17)) assert((s1 ++ s2 ++ s3 ++ s4).sum == 0) } }
Example 19
Source File: E2eSupport.scala From aecor with MIT License | 5 votes |
package aecor.testkit import aecor.data.{ EventsourcedBehavior, _ } import aecor.runtime.{ EventJournal, Eventsourced } import cats.data.StateT import cats.effect.{ IO, Sync } import cats.implicits._ import cats.mtl.MonadState import cats.tagless.FunctorK import cats.tagless.syntax.functorK._ import cats.~> import fs2.Stream import monocle.Lens import scala.collection.immutable._ object E2eSupport { final class Runtime[F[_]] { def deploy[M[_[_]]: FunctorK, S, E, K]( behavior: EventsourcedBehavior[M, F, S, E], journal: EventJournal[F, K, E] )(implicit F: Sync[F]): K => M[F] = Eventsourced[M, F, S, E, K](behavior, journal) } abstract class Processes[F[_]](items: Vector[F[Unit]]) { protected type S protected implicit def F: MonadState[F, S] final private implicit val monad = F.monad final def runProcesses: F[Unit] = for { stateBefore <- F.get _ <- items.sequence stateAfter <- F.get _ <- if (stateAfter == stateBefore) { ().pure[F] } else { runProcesses } } yield () final def wireK[I, M[_[_]]: FunctorK](behavior: I => M[F]): I => M[F] = i => behavior(i).mapK(new (F ~> F) { override def apply[A](fa: F[A]): F[A] = fa <* runProcesses }) final def wire[A, B](f: F[B]): F[B] = f <* runProcesses } object Processes { def apply[F[_], S0](items: F[Unit]*)(implicit F0: MonadState[F, S0]): Processes[F] = new Processes[F](items.toVector) { final override type S = S0 override implicit def F: MonadState[F, S] = F0 } } } trait E2eSupport { import cats.mtl.instances.state._ type SpecState type F[A] = StateT[IO, SpecState, A] final def mkJournal[I, E](lens: Lens[SpecState, StateEventJournal.State[I, E]], tagging: Tagging[I]): StateEventJournal[F, I, SpecState, E] = StateEventJournal[F, I, SpecState, E](lens, tagging) final def wireProcess[In](process: In => F[Unit], source: Stream[F, Committable[F, In]], sources: Stream[F, Committable[F, In]]*)(implicit F: Sync[F]): F[Unit] = sources .fold(source)(_ ++ _) .evalMap(_.process(process)) .compile .drain val runtime = new E2eSupport.Runtime[F] }
Example 20
Source File: AkkaPersistenceRuntimeSpec.scala From aecor with MIT License | 5 votes |
package aecor.tests import aecor.data.Tagging import aecor.runtime.akkapersistence.{ AkkaPersistenceRuntime, CassandraJournalAdapter } import aecor.tests.e2e._ import akka.actor.ActorSystem import akka.stream.ActorMaterializer import akka.stream.scaladsl.Sink import akka.testkit.TestKit import cats.effect.IO import cats.implicits._ import com.typesafe.config.{ Config, ConfigFactory } import org.scalatest.matchers.should.Matchers import org.scalatest.concurrent.ScalaFutures import org.scalatest.funsuite.AnyFunSuiteLike import scala.concurrent.duration._ object AkkaPersistenceRuntimeSpec { def conf: Config = ConfigFactory.parseString(s""" akka { cluster { seed-nodes = [ "akka.tcp://[email protected]:52000" ] } actor.provider = cluster remote { netty.tcp { hostname = 127.0.0.1 port = 52000 bind.hostname = "0.0.0.0" bind.port = 52000 } } } aecor.generic-akka-runtime.idle-timeout = 1s """).withFallback(CassandraLifecycle.config).withFallback(ConfigFactory.load()) } class AkkaPersistenceRuntimeSpec extends TestKit(ActorSystem("test", AkkaPersistenceRuntimeSpec.conf)) with AnyFunSuiteLike with Matchers with ScalaFutures with CassandraLifecycle { override def systemName = system.name override implicit val patienceConfig = PatienceConfig(30.seconds, 150.millis) val timer = IO.timer(system.dispatcher) implicit val contextShift = IO.contextShift(system.dispatcher) override def afterAll(): Unit = { TestKit.shutdownActorSystem(system) super.afterAll() } val runtime = AkkaPersistenceRuntime(system, CassandraJournalAdapter(system)) test("Runtime should work") { val deployCounters: IO[CounterId => Counter[IO]] = runtime.deploy( "Counter", CounterBehavior.instance[IO], Tagging.const[CounterId](CounterEvent.tag) ) val program = for { counters <- deployCounters first = counters(CounterId("1")) second = counters(CounterId("2")) _ <- first.increment _ <- second.increment _2 <- second.value _ <- first.decrement _1 <- first.value afterPassivation <- timer.sleep(2.seconds) >> second.value } yield (_1, _2, afterPassivation) program.unsafeRunSync() shouldEqual ((0L, 1L, 1L)) } test("Journal should work") { implicit val materializer = ActorMaterializer() val journal = runtime.journal[CounterId, CounterEvent] val entries = journal.currentEventsByTag(CounterEvent.tag, None).runWith(Sink.seq).futureValue val map = entries.map(_.event).groupBy(_.entityKey) map(CounterId("1")).size shouldBe 2 map(CounterId("2")).size shouldBe 1 } }
Example 21
Source File: GenericRuntimeSpec.scala From aecor with MIT License | 5 votes |
package aecor.runtime.akkageneric import akka.actor.ActorSystem import akka.testkit.TestKit import cats.effect.IO import cats.implicits._ import com.typesafe.config.{ Config, ConfigFactory } import org.scalatest.concurrent.ScalaFutures import org.scalatest.funsuite.AnyFunSuiteLike import org.scalatest.BeforeAndAfterAll import org.scalatest.matchers.should.Matchers import scala.concurrent.duration._ object GenericRuntimeSpec { def conf: Config = ConfigFactory.parseString(s""" cluster.system-name=test cluster.port = 51001 aecor.generic-akka-runtime.idle-timeout = 1s """).withFallback(ConfigFactory.load()) } class GenericRuntimeSpec extends TestKit(ActorSystem("test", GenericRuntimeSpec.conf)) with AnyFunSuiteLike with Matchers with ScalaFutures with BeforeAndAfterAll { implicit val contextShift = IO.contextShift(system.dispatcher) override implicit val patienceConfig = PatienceConfig(15.seconds, 150.millis) val timer = IO.timer(system.dispatcher) override def afterAll: Unit = TestKit.shutdownActorSystem(system) def runCounters(name: String): IO[CounterId => Counter[IO]] = GenericAkkaRuntime(system) .runBehavior[CounterId, Counter, IO](name, (_: CounterId) => Counter.inmem[IO]) test("routing") { val program = for { counters <- runCounters("CounterFoo") first = counters(CounterId("1")) second = counters(CounterId("2")) _ <- first.increment _2 <- second.increment _1 <- first.increment } yield (_1, _2) val (first, second) = program.unsafeRunSync() first shouldBe 2L second shouldBe 1L } test("passivation") { val program = for { counters <- runCounters("CounterBar") first = counters(CounterId("1")) _1 <- first.increment afterPassivation <- timer.sleep(2.seconds) >> first.value } yield (_1, afterPassivation) val (beforePassivation, afterPassivation) = program.unsafeRunSync() beforePassivation shouldBe 1 afterPassivation shouldBe 0 } }
Example 22
Source File: effect.scala From aecor with MIT License | 5 votes |
package aecor.util import cats.effect.{ Async, Effect, IO } import scala.concurrent.{ Future, Promise } object effect { implicit final class AecorEffectOps[F[_], A](val self: F[A]) extends AnyVal { @inline final def unsafeToFuture()(implicit F: Effect[F]): Future[A] = { val p = Promise[A] F.runAsync(self) { case Right(a) => IO { p.success(a); () } case Left(e) => IO { p.failure(e); () } } .unsafeRunSync() p.future } } implicit final class AecorLiftIOOps[F[_]](val self: Async[F]) extends AnyVal { def fromFuture[A](future: => Future[A]): F[A] = IO.fromFuture(IO(future))(IO.contextShift(scala.concurrent.ExecutionContext.global)).to(self) } }
Example 23
Source File: JobsApiTest.scala From kubernetes-client with Apache License 2.0 | 5 votes |
package com.goyeau.kubernetes.client.api import cats.effect.{ConcurrentEffect, IO} import com.goyeau.kubernetes.client.operation._ import com.goyeau.kubernetes.client.KubernetesClient import io.chrisdavenport.log4cats.Logger import io.chrisdavenport.log4cats.slf4j.Slf4jLogger import io.k8s.api.batch.v1.{Job, JobList, JobSpec} import io.k8s.api.core.v1._ import io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta import org.scalatest.OptionValues import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers class JobsApiTest extends AnyFlatSpec with Matchers with OptionValues with CreatableTests[IO, Job] with GettableTests[IO, Job] with ListableTests[IO, Job, JobList] with ReplaceableTests[IO, Job] with DeletableTests[IO, Job, JobList] with DeletableTerminatedTests[IO, Job, JobList] with WatchableTests[IO, Job] with ContextProvider { implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect implicit lazy val logger: Logger[IO] = Slf4jLogger.getLogger[IO] lazy val resourceName = classOf[Job].getSimpleName override def api(implicit client: KubernetesClient[IO]) = client.jobs override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) = client.jobs.namespace(namespaceName) override def sampleResource(resourceName: String, labels: Map[String, String]) = Job( metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))), spec = Option( JobSpec( template = PodTemplateSpec( metadata = Option(ObjectMeta(name = Option(resourceName))), spec = Option( PodSpec(containers = Seq(Container("test", image = Option("docker"))), restartPolicy = Option("Never")) ) ) ) ) ) val labels = Map("app" -> "test") override def modifyResource(resource: Job) = resource.copy( metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name), labels = Option(labels))) ) override def checkUpdated(updatedResource: Job) = (updatedResource.metadata.value.labels.value.toSeq should contain).allElementsOf(labels.toSeq) override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] = client.jobs.namespace(namespaceName) override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, Job] = client.jobs.namespace(namespaceName) }
Example 24
Source File: DeploymentsApiTest.scala From kubernetes-client with Apache License 2.0 | 5 votes |
package com.goyeau.kubernetes.client.api import cats.effect.{ConcurrentEffect, IO} import com.goyeau.kubernetes.client.operation._ import com.goyeau.kubernetes.client.{IntValue, KubernetesClient, StringValue} import io.chrisdavenport.log4cats.Logger import io.chrisdavenport.log4cats.slf4j.Slf4jLogger import io.k8s.api.apps.v1._ import io.k8s.api.core.v1._ import io.k8s.apimachinery.pkg.apis.meta.v1.{LabelSelector, ObjectMeta} import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.OptionValues import org.scalatest.matchers.should.Matchers class DeploymentsApiTest extends AnyFlatSpec with Matchers with OptionValues with CreatableTests[IO, Deployment] with GettableTests[IO, Deployment] with ListableTests[IO, Deployment, DeploymentList] with ReplaceableTests[IO, Deployment] with DeletableTests[IO, Deployment, DeploymentList] with DeletableTerminatedTests[IO, Deployment, DeploymentList] with WatchableTests[IO, Deployment] with ContextProvider { implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect implicit lazy val logger: Logger[IO] = Slf4jLogger.getLogger[IO] lazy val resourceName = classOf[Deployment].getSimpleName override def api(implicit client: KubernetesClient[IO]) = client.deployments override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) = client.deployments.namespace(namespaceName) override def sampleResource(resourceName: String, labels: Map[String, String]) = { val label = Option(Map("app" -> "test")) Deployment( metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))), spec = Option( DeploymentSpec( selector = LabelSelector(matchLabels = label), template = PodTemplateSpec( metadata = Option(ObjectMeta(name = Option(resourceName), labels = label)), spec = Option(PodSpec(containers = Seq(Container("test", image = Option("docker"))))) ) ) ) ) } val strategy = Option( DeploymentStrategy( `type` = Option("RollingUpdate"), rollingUpdate = Option(RollingUpdateDeployment(maxSurge = Option(StringValue("25%")), maxUnavailable = Option(IntValue(10)))) ) ) override def modifyResource(resource: Deployment) = resource.copy( metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name))), spec = resource.spec.map(_.copy(strategy = strategy)) ) override def checkUpdated(updatedResource: Deployment) = updatedResource.spec.value.strategy shouldBe strategy override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] = client.deployments.namespace(namespaceName) override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, Deployment] = client.deployments.namespace(namespaceName) }
Example 25
Source File: CronJobsApiTest.scala From kubernetes-client with Apache License 2.0 | 5 votes |
package com.goyeau.kubernetes.client.api import cats.effect.{ConcurrentEffect, IO} import com.goyeau.kubernetes.client.operation._ import com.goyeau.kubernetes.client.KubernetesClient import io.chrisdavenport.log4cats.Logger import io.chrisdavenport.log4cats.slf4j.Slf4jLogger import io.k8s.api.batch.v1.JobSpec import io.k8s.api.batch.v1beta1.{CronJob, CronJobList, CronJobSpec, JobTemplateSpec} import io.k8s.api.core.v1._ import io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.OptionValues import org.scalatest.matchers.should.Matchers class CronJobsApiTest extends AnyFlatSpec with Matchers with OptionValues with CreatableTests[IO, CronJob] with GettableTests[IO, CronJob] with ListableTests[IO, CronJob, CronJobList] with ReplaceableTests[IO, CronJob] with DeletableTests[IO, CronJob, CronJobList] with DeletableTerminatedTests[IO, CronJob, CronJobList] with WatchableTests[IO, CronJob] with ContextProvider { implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect implicit lazy val logger: Logger[IO] = Slf4jLogger.getLogger[IO] lazy val resourceName = classOf[CronJob].getSimpleName override def api(implicit client: KubernetesClient[IO]) = client.cronJobs override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) = client.cronJobs.namespace(namespaceName) override def sampleResource(resourceName: String, labels: Map[String, String]) = CronJob( metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))), spec = Option( CronJobSpec( schedule = "1 * * * *", jobTemplate = JobTemplateSpec( spec = Option( JobSpec( template = PodTemplateSpec( metadata = Option(ObjectMeta(name = Option(resourceName))), spec = Option( PodSpec( containers = Seq(Container("test", image = Option("docker"))), restartPolicy = Option("Never") ) ) ) ) ) ) ) ) ) val schedule = "2 * * * *" override def modifyResource(resource: CronJob) = resource.copy( metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name))), spec = resource.spec.map(_.copy(schedule = schedule)) ) override def checkUpdated(updatedResource: CronJob) = updatedResource.spec.value.schedule shouldBe schedule override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] = client.cronJobs.namespace(namespaceName) override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, CronJob] = client.cronJobs.namespace(namespaceName) }
Example 26
Source File: ReplicaSetsApiTest.scala From kubernetes-client with Apache License 2.0 | 5 votes |
package com.goyeau.kubernetes.client.api import cats.effect.{ConcurrentEffect, IO} import com.goyeau.kubernetes.client.KubernetesClient import com.goyeau.kubernetes.client.operation._ import io.chrisdavenport.log4cats.Logger import io.chrisdavenport.log4cats.slf4j.Slf4jLogger import io.k8s.api.apps.v1._ import io.k8s.api.core.v1._ import io.k8s.apimachinery.pkg.apis.meta.v1.{LabelSelector, ObjectMeta} import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.OptionValues import org.scalatest.matchers.should.Matchers class ReplicaSetsApiTest extends AnyFlatSpec with Matchers with OptionValues with CreatableTests[IO, ReplicaSet] with GettableTests[IO, ReplicaSet] with ListableTests[IO, ReplicaSet, ReplicaSetList] with ReplaceableTests[IO, ReplicaSet] with DeletableTests[IO, ReplicaSet, ReplicaSetList] with DeletableTerminatedTests[IO, ReplicaSet, ReplicaSetList] with WatchableTests[IO, ReplicaSet] with ContextProvider { implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect implicit lazy val logger: Logger[IO] = Slf4jLogger.getLogger[IO] lazy val resourceName = classOf[ReplicaSet].getSimpleName override def api(implicit client: KubernetesClient[IO]) = client.replicaSets override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) = client.replicaSets.namespace(namespaceName) override def sampleResource(resourceName: String, labels: Map[String, String]) = { val label = Option(Map("app" -> "test")) ReplicaSet( metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))), spec = Option( ReplicaSetSpec( selector = LabelSelector(matchLabels = label), template = Option( PodTemplateSpec( metadata = Option(ObjectMeta(name = Option(resourceName), labels = label)), spec = Option(PodSpec(containers = Seq(Container("test", image = Option("docker"))))) ) ) ) ) ) } val replicas = Option(5) override def modifyResource(resource: ReplicaSet) = resource.copy( metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name))), spec = resource.spec.map(_.copy(replicas = replicas)) ) override def checkUpdated(updatedResource: ReplicaSet) = updatedResource.spec.value.replicas shouldBe replicas override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] = client.replicaSets.namespace(namespaceName) override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, ReplicaSet] = client.replicaSets.namespace(namespaceName) }
Example 27
Source File: StatefulSetsApiTest.scala From kubernetes-client with Apache License 2.0 | 5 votes |
package com.goyeau.kubernetes.client.api import cats.effect.{ConcurrentEffect, IO} import com.goyeau.kubernetes.client.KubernetesClient import com.goyeau.kubernetes.client.operation._ import io.chrisdavenport.log4cats.Logger import io.chrisdavenport.log4cats.slf4j.Slf4jLogger import io.k8s.api.apps.v1._ import io.k8s.api.core.v1._ import io.k8s.apimachinery.pkg.apis.meta.v1.{LabelSelector, ObjectMeta} import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.OptionValues import org.scalatest.matchers.should.Matchers class StatefulSetsApiTest extends AnyFlatSpec with Matchers with OptionValues with CreatableTests[IO, StatefulSet] with GettableTests[IO, StatefulSet] with ListableTests[IO, StatefulSet, StatefulSetList] with ReplaceableTests[IO, StatefulSet] with DeletableTests[IO, StatefulSet, StatefulSetList] with DeletableTerminatedTests[IO, StatefulSet, StatefulSetList] with WatchableTests[IO, StatefulSet] with ContextProvider { implicit lazy val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect implicit lazy val logger: Logger[IO] = Slf4jLogger.getLogger[IO] lazy val resourceName = classOf[StatefulSet].getSimpleName override def api(implicit client: KubernetesClient[IO]) = client.statefulSets override def namespacedApi(namespaceName: String)(implicit client: KubernetesClient[IO]) = client.statefulSets.namespace(namespaceName) override def sampleResource(resourceName: String, labels: Map[String, String]) = { val label = Option(Map("app" -> "test")) StatefulSet( metadata = Option(ObjectMeta(name = Option(resourceName), labels = Option(labels))), spec = Option( StatefulSetSpec( serviceName = "service-name", selector = LabelSelector(matchLabels = label), template = PodTemplateSpec( metadata = Option(ObjectMeta(name = Option(resourceName), labels = label)), spec = Option(PodSpec(containers = Seq(Container("test", image = Option("docker"))))) ) ) ) ) } val updateStrategy = Option( StatefulSetUpdateStrategy( `type` = Option("RollingUpdate"), rollingUpdate = Option(RollingUpdateStatefulSetStrategy(partition = Option(10))) ) ) override def modifyResource(resource: StatefulSet) = resource.copy( metadata = Option(ObjectMeta(name = resource.metadata.flatMap(_.name))), spec = resource.spec.map(_.copy(updateStrategy = updateStrategy)) ) override def checkUpdated(updatedResource: StatefulSet) = updatedResource.spec.value.updateStrategy shouldBe updateStrategy override def deleteApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Deletable[IO] = client.statefulSets.namespace(namespaceName) override def watchApi(namespaceName: String)(implicit client: KubernetesClient[IO]): Watchable[IO, StatefulSet] = client.statefulSets.namespace(namespaceName) }
Example 28
Source File: EmbeddableLogHandler.scala From tofu with Apache License 2.0 | 5 votes |
package tofu.doobie.log import _root_.doobie.LogHandler import cats.effect.IO import cats.tagless.FunctorK import cats.tagless.syntax.functorK._ import cats.{Applicative, FlatMap, Functor, ~>} import tofu.higherKind.Embed import tofu.lift.{Lift, UnliftIO} import tofu.syntax.embed._ import tofu.syntax.monadic._ def nop[F[_]: Applicative]: EmbeddableLogHandler[F] = new EmbeddableLogHandler(LogHandler.nop.pure[F]) private def fromLogHandlerF[F[_]: Functor]( logHandlerF: LogHandlerF[F] )(unsafeRunIO_ : IO[_] => Unit)(implicit U: UnliftIO[F]): EmbeddableLogHandler[F] = new EmbeddableLogHandler(U.unlift.map(toIO => LogHandler(event => unsafeRunIO_(toIO(logHandlerF.run(event)))))) implicit val embeddableLogHandlerFunctorK: FunctorK[EmbeddableLogHandler] = new FunctorK[EmbeddableLogHandler] { def mapK[F[_], G[_]](af: EmbeddableLogHandler[F])(fk: F ~> G): EmbeddableLogHandler[G] = new EmbeddableLogHandler(fk(af.self)) } }
Example 29
Source File: implicits.scala From tofu with Apache License 2.0 | 5 votes |
package tofu.doobie.instances import cats.effect.{Effect, IO, SyncEffect} import doobie.ConnectionIO import tofu.lift.Lift object implicits extends DoobieImplicits1 private[instances] trait DoobieImplicits1 extends DoobieImplicits2 { @inline final implicit def liftToConnectionIOViaIOImplicit[F[_]: Lift[*[_], IO]]: LiftToConnectionIOViaIO[F] = liftToConnectionIOViaIO } private[instances] trait DoobieImplicits2 extends DoobieImplicitsScalaVersionSpecific { @inline final implicit def liftEffectToConnectionIOImplicit[F[_]: Effect]: LiftEffectToConnectionIO[F] = liftEffectToConnectionIO @inline final implicit def liftSyncEffectToConnectionIOImplicit[F[_]: SyncEffect]: LiftSyncEffectToConnectionIO[F] = liftSyncEffectToConnectionIO @inline final implicit def liftToConnectionRIOImplicit[F[_], R](implicit L: Lift[F, ConnectionIO] ): LiftToConnectionRIO[F, R] = liftToConnectionRIO }
Example 30
Source File: DoobieInstances.scala From tofu with Apache License 2.0 | 5 votes |
package tofu.doobie.instances import cats.data.ReaderT import cats.effect.{Effect, IO, SyncEffect} import cats.effect.syntax.effect._ import cats.effect.syntax.syncEffect._ import doobie.ConnectionIO import doobie.free.connection.AsyncConnectionIO import tofu.HasProvide import tofu.doobie.ConnectionRIO import tofu.lift.Lift private[instances] trait DoobieInstances { final def liftToConnectionIOViaIO[F[_]: Lift[*[_], IO]]: LiftToConnectionIOViaIO[F] = new LiftToConnectionIOViaIO final def liftEffectToConnectionIO[F[_]: Effect]: LiftEffectToConnectionIO[F] = new LiftEffectToConnectionIO final def liftSyncEffectToConnectionIO[F[_]: SyncEffect]: LiftSyncEffectToConnectionIO[F] = new LiftSyncEffectToConnectionIO final def liftToConnectionRIO[F[_], R](implicit L: Lift[F, ConnectionIO]): LiftToConnectionRIO[F, R] = new LiftToConnectionRIO final def liftProvideToConnectionRIO[F[_], G[_], R](implicit HP: HasProvide[G, F, R], L: Lift[F, ConnectionIO] ): LiftProvideToConnectionRIO[F, G, R] = new LiftProvideToConnectionRIO } final class LiftToConnectionIOViaIO[F[_]](implicit L: Lift[F, IO]) extends Lift[F, ConnectionIO] { def lift[A](fa: F[A]): ConnectionIO[A] = AsyncConnectionIO.liftIO(L.lift(fa)) } final class LiftEffectToConnectionIO[F[_]: Effect] extends Lift[F, ConnectionIO] { def lift[A](fa: F[A]): ConnectionIO[A] = AsyncConnectionIO.liftIO(fa.toIO) } final class LiftSyncEffectToConnectionIO[F[_]: SyncEffect] extends Lift[F, ConnectionIO] { def lift[A](fa: F[A]): ConnectionIO[A] = fa.runSync[ConnectionIO] } final class LiftToConnectionRIO[F[_], R](implicit L: Lift[F, ConnectionIO]) extends Lift[F, ConnectionRIO[R, *]] { def lift[A](fa: F[A]): ConnectionRIO[R, A] = ReaderT.liftF(L.lift(fa)) } final class LiftProvideToConnectionRIO[F[_], G[_], R](implicit HP: HasProvide[G, F, R], L: Lift[F, ConnectionIO]) extends Lift[G, ConnectionRIO[R, *]] { def lift[A](fa: G[A]): ConnectionRIO[R, A] = ReaderT(ctx => L.lift(HP.runContext(fa)(ctx))) }
Example 31
Source File: DoobieInstancesSuite.scala From tofu with Apache License 2.0 | 5 votes |
package tofu.doobie import cats.Applicative import cats.data.ReaderT import cats.effect.{IO, SyncIO} import com.github.ghik.silencer.silent import doobie.ConnectionIO import monix.eval.{Coeval, Task} import monix.execution.Scheduler import tofu.doobie.instances.implicits._ import tofu.env.Env import tofu.lift.Lift import tofu.zioInstances.implicits._ import zio.interop.catz._ object DoobieInstancesSuite { def summonImplicitsViaLiftToIO[F[_]: Applicative, R](implicit L: Lift[F, IO]): Unit = { Lift[F, ConnectionIO] Lift[F, ConnectionRIO[R, *]] Lift[ReaderT[F, R, *], ConnectionRIO[R, *]] () } def summonCatsEffectImplicits[R](): Unit = { Lift[SyncIO, ConnectionIO] Lift[SyncIO, ConnectionRIO[R, *]] Lift[ReaderT[SyncIO, R, *], ConnectionRIO[R, *]] Lift[IO, ConnectionIO] Lift[IO, ConnectionRIO[R, *]] Lift[ReaderT[IO, R, *], ConnectionRIO[R, *]] () } def summonMonixImplicitsViaScheduler[R](implicit sc: Scheduler): Unit = { Lift[Coeval, ConnectionIO] Lift[Coeval, ConnectionRIO[R, *]] Lift[ReaderT[Coeval, R, *], ConnectionRIO[R, *]] Lift[Task, ConnectionIO] Lift[Task, ConnectionRIO[R, *]] Lift[ReaderT[Task, R, *], ConnectionRIO[R, *]] Lift[Env[R, *], ConnectionRIO[R, *]] () } def summonMonixImplicitsUnambiguously[R](implicit @silent sc: Scheduler, L: Lift[Task, IO]): Unit = { Lift[Task, ConnectionIO] Lift[Task, ConnectionRIO[R, *]] Lift[ReaderT[Task, R, *], ConnectionRIO[R, *]] () } def summonZioImplicits[R](): zio.Task[Unit] = zio.Task.concurrentEffect.map { implicit CE => Lift[zio.Task, ConnectionIO] Lift[zio.Task, ConnectionRIO[R, *]] Lift[zio.RIO[R, *], ConnectionRIO[R, *]] () } def summonLiftConnectionIO[R](): Unit = { LiftConnectionIO[ConnectionIO] LiftConnectionIO[ConnectionRIO[R, *]] () } }
Example 32
Source File: EnvInstances.scala From tofu with Apache License 2.0 | 5 votes |
package tofu.env import cats.arrow.{ArrowChoice, FunctionK, Profunctor} import cats.effect.IO import cats.{Applicative, Monad, Parallel, ~>} import monix.eval.{Task, TaskLift} import monix.execution.Scheduler import tofu.lift.{UnliftIO, UnsafeExecFuture} import tofu.optics.Contains import tofu.syntax.funk._ import scala.concurrent.Future private[env] trait EnvInstances { self: Env.type => private object anyEnvInstance extends EnvFunctorstance[Any] final implicit def envInstance[E]: EnvFunctorstance[E] = anyEnvInstance.asInstanceOf[EnvFunctorstance[E]] private object envParallelInstance extends Applicative[Env[Any, *]] { override def pure[A](x: A): Env[Any, A] = Env.pure(x) override def ap[A, B](ff: Env[Any, A => B])(fa: Env[Any, A]): Env[Any, B] = Env.parMap2(ff, fa)(_.apply(_)) override def map2[A, B, Z](fa: Env[Any, A], fb: Env[Any, B])(f: (A, B) => Z): Env[Any, Z] = Env.parMap2(fa, fb)(f) override val unit: Env[Any, Unit] = Env.unit override def map[A, B](fa: Env[Any, A])(f: A => B): Env[Any, B] = fa.map(f) override def replicateA[A](n: Int, fa: Env[Any, A]): Env[Any, List[A]] = fa.mapTask(t => Task.parSequence(Iterable.fill(n)(t)).map(_.toList)) } private object anyEnvParallelInstance extends Parallel[Env[Any, *]] { type F[a] = Env[Any, a] override def applicative: Applicative[Env[Any, *]] = envParallelInstance override def monad: Monad[Env[Any, *]] = anyEnvInstance override val sequential: ~>[Env[Any, *], Env[Any, *]] = FunctionK.id override val parallel: ~>[Env[Any, *], Env[Any, *]] = FunctionK.id } final implicit def envParallelInstance[E]: Parallel[Env[E, *]] = anyEnvParallelInstance.asInstanceOf[Parallel[Env[E, *]]] final implicit val envProfuctorInstance: Profunctor[Env] with ArrowChoice[Env] = new Profunctor[Env] with ArrowChoice[Env] { override def choose[A, B, C, D](f: Env[A, C])(g: Env[B, D]): Env[Either[A, B], Either[C, D]] = Env { case Left(a) => f.run(a).map(Left(_)) case Right(b) => g.run(b).map(Right(_)) } override def lift[A, B](f: A => B): Env[A, B] = Env(a => Task.pure(f(a))) override def first[A, B, C](fa: Env[A, B]): Env[(A, C), (B, C)] = fa.first[C] override def second[A, B, C](fa: Env[A, B]): Env[(C, A), (C, B)] = fa.second[C] override def compose[A, B, C](f: Env[B, C], g: Env[A, B]): Env[A, C] = f.compose(g) override def rmap[A, B, C](fab: Env[A, B])(f: B => C): Env[A, C] = fab.map(f) override def lmap[A, B, C](fab: Env[A, B])(f: C => A): Env[C, B] = fab.localP(f) override def id[A]: Env[A, A] = Env.context override def dimap[A, B, C, D](fab: Env[A, B])(f: C => A)(g: B => D): Env[C, D] = fab.dimap(f)(g) override def split[A, B, C, D](f: Env[A, B], g: Env[C, D]): Env[(A, C), (B, D)] = f.split(g) override def left[A, B, C](fab: Env[A, B]): Env[Either[A, C], Either[B, C]] = fab.left[C] override def right[A, B, C](fab: Env[A, B]): Env[Either[C, A], Either[C, B]] = fab.right[C] override def choice[A, B, C](f: Env[A, C], g: Env[B, C]): Env[Either[A, B], C] = f.choice(g) override def merge[A, B, C](f: Env[A, B], g: Env[A, C]): Env[A, (B, C)] = Env.parZip2(f, g) } final implicit def envUnliftSubContext[E, E1: E Contains *]: EnvUnliftSubContext[E, E1] = new EnvUnliftSubContext def envUnsafeExecFuture[E](implicit sc: Scheduler): UnsafeExecFuture[Env[E, *]] = new UnsafeExecFuture[Env[E, *]] { def lift[A](fa: Future[A]): Env[E, A] = Env.fromFuture(fa) def unlift: Env[E, Env[E, *] ~> Future] = Env.fromFunc(r => makeFunctionK(_.run(r).runToFuture)) } implicit def envUnliftIO[E](implicit toIO: TaskLift[IO]): UnliftIO[Env[E, *]] = new UnliftIO[Env[E, *]] { def lift[A](fa: IO[A]): Env[E, A] = Env.fromIO(fa) def unlift: Env[E, Env[E, *] ~> IO] = Env.fromFunc(r => funK(_.run(r).to[IO])) } }
Example 33
Source File: Timeout.scala From tofu with Apache License 2.0 | 5 votes |
package tofu import cats.effect.{Concurrent, ContextShift, IO, Timer} import simulacrum.typeclass import tofu.syntax.feither._ import tofu.internal.NonTofu import scala.concurrent.duration.FiniteDuration @typeclass trait Timeout[F[_]] { def timeoutTo[A](fa: F[A], after: FiniteDuration, fallback: F[A]): F[A] } object Timeout extends LowPriorTimeoutImplicits { implicit def io(implicit timer: Timer[IO], cs: ContextShift[IO]): Timeout[IO] = new Timeout[IO] { override def timeoutTo[A](fa: IO[A], after: FiniteDuration, fallback: IO[A]): IO[A] = fa.timeoutTo(after, fallback) } } trait LowPriorTimeoutImplicits { self: Timeout.type => implicit def concurrent[F[_]: NonTofu](implicit F: Concurrent[F], timer: Timer[F]): Timeout[F] = new Timeout[F] { override def timeoutTo[A](fa: F[A], after: FiniteDuration, fallback: F[A]): F[A] = F.race(timer.sleep(after), fa).getOrElseF(fallback) } }
Example 34
Source File: unlift.scala From tofu with Apache License 2.0 | 5 votes |
package tofu.syntax import cats.effect.{CancelToken, ConcurrentEffect, Effect, ExitCase, Fiber, IO, SyncIO} import cats.{FlatMap, Functor, ~>} import tofu.lift.Unlift object unlift { implicit final class UnliftEffectOps[F[_], G[_]](private val U: Unlift[F, G]) extends AnyVal { def effect(implicit G: Functor[G], E: Effect[F]): G[Effect[G]] = G.map(U.unlift) { unliftF => new EffectInstance[F, G] { def toG: F ~> G = U.liftF def toF: G ~> F = unliftF implicit def F: Effect[F] = E } } def effectWith[A](f: Effect[G] => G[A])(implicit G: FlatMap[G], E: Effect[F]): G[A] = G.flatMap(U.unlift) { unliftF => val eff = new EffectInstance[F, G] { def toG: F ~> G = U.liftF def toF: G ~> F = unliftF implicit def F: Effect[F] = E } f(eff) } def concurrentEffect(implicit G: Functor[G], CE: ConcurrentEffect[F]): G[ConcurrentEffect[G]] = G.map(U.unlift) { unliftF => new ConcurrentEffectInstance[F, G] { def toG: F ~> G = U.liftF def toF: G ~> F = unliftF implicit def F: ConcurrentEffect[F] = CE } } def concurrentEffectWith[A](f: ConcurrentEffect[G] => G[A])(implicit G: FlatMap[G], CE: ConcurrentEffect[F]): G[A] = G.flatMap(U.unlift) { unliftF => val ce = new ConcurrentEffectInstance[F, G] { def toG: F ~> G = U.liftF def toF: G ~> F = unliftF implicit def F: ConcurrentEffect[F] = CE } f(ce) } } private[unlift] trait EffectInstance[F[_], G[_]] extends Effect[G] { def toG: F ~> G def toF: G ~> F implicit def F: Effect[F] def pure[A](x: A): G[A] = toG(F.pure(x)) def flatMap[A, B](ga: G[A])(f: A => G[B]): G[B] = toG(F.flatMap(toF(ga))(a => toF(f(a)))) def tailRecM[A, B](a: A)(f: A => G[Either[A, B]]): G[B] = toG(F.tailRecM(a)(a => toF(f(a)))) def raiseError[A](e: Throwable): G[A] = toG(F.raiseError(e)) def handleErrorWith[A](ga: G[A])(f: Throwable => G[A]): G[A] = toG(F.handleErrorWith(toF(ga))(t => toF(f(t)))) def bracketCase[A, B](acquire: G[A])(use: A => G[B])(release: (A, ExitCase[Throwable]) => G[Unit]): G[B] = toG(F.bracketCase(toF(acquire))(a => toF(use(a)))((a, e) => toF(release(a, e)))) def suspend[A](thunk: => G[A]): G[A] = toG(F.suspend(toF(thunk))) def async[A](k: (Either[Throwable, A] => Unit) => Unit): G[A] = toG(F.async(k)) def asyncF[A](k: (Either[Throwable, A] => Unit) => G[Unit]): G[A] = toG(F.asyncF[A](cb => toF(k(cb)))) def runAsync[A](ga: G[A])(cb: Either[Throwable, A] => IO[Unit]): SyncIO[Unit] = F.runAsync(toF(ga))(cb) } private[unlift] trait ConcurrentEffectInstance[F[_], G[_]] extends EffectInstance[F, G] with ConcurrentEffect[G] { implicit def F: ConcurrentEffect[F] def start[A](ga: G[A]): G[Fiber[G, A]] = toG(F.map(F.start(toF(ga)))(_.mapK(toG))) def racePair[A, B](ga: G[A], gb: G[B]): G[Either[(A, Fiber[G, B]), (Fiber[G, A], B)]] = toG(F.map(F.racePair(toF(ga), toF(gb))) { case Left((a, fb)) => Left((a, fb.mapK(toG))) case Right((fa, b)) => Right((fa.mapK(toG), b)) }) def runCancelable[A](ga: G[A])(cb: Either[Throwable, A] => IO[Unit]): SyncIO[CancelToken[G]] = F.runCancelable(toF(ga))(cb).map(toG(_)) } }
Example 35
Source File: PrometheusMetricsReporterApiSpec.scala From kafka4s with Apache License 2.0 | 5 votes |
package com.banno.kafka.metrics.prometheus import scala.collection.compat._ import cats.implicits._ import cats.effect.IO import com.banno.kafka._ import com.banno.kafka.producer._ import com.banno.kafka.consumer._ import org.apache.kafka.clients.producer.ProducerRecord import org.apache.kafka.common.TopicPartition import io.prometheus.client.CollectorRegistry import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import scala.jdk.CollectionConverters._ import scala.concurrent.ExecutionContext import scala.concurrent.duration._ class PrometheusMetricsReporterApiSpec extends AnyFlatSpec with Matchers with InMemoryKafka { implicit val defaultContextShift = IO.contextShift(ExecutionContext.global) implicit val defaultConcurrent = IO.ioConcurrentEffect(defaultContextShift) implicit val defaultTimer = IO.timer(ExecutionContext.global) //when kafka clients change their metrics, this test will help identify the changes we need to make "Prometheus reporter" should "register Prometheus collectors for all known Kafka metrics" in { val topic = createTopic(2) val records = List(new ProducerRecord(topic, 0, "a", "a"), new ProducerRecord(topic, 1, "b", "b")) ProducerApi .resource[IO, String, String]( BootstrapServers(bootstrapServer), MetricReporters[ProducerPrometheusReporter] ) .use( p => ConsumerApi .resource[IO, String, String]( BootstrapServers(bootstrapServer), ClientId("c1"), MetricReporters[ConsumerPrometheusReporter] ) .use( c1 => ConsumerApi .resource[IO, String, String]( BootstrapServers(bootstrapServer), ClientId("c2"), MetricReporters[ConsumerPrometheusReporter] ) .use( c2 => for { _ <- p.sendSyncBatch(records) _ <- c1.assign(topic, Map.empty[TopicPartition, Long]) _ <- c1.poll(1 second) _ <- c1.poll(1 second) _ <- c2.assign(topic, Map.empty[TopicPartition, Long]) _ <- c2.poll(1 second) _ <- c2.poll(1 second) _ <- IO.sleep(PrometheusMetricsReporterApi.defaultUpdatePeriod + (1 second)) _ <- p.close _ <- c1.close _ <- c2.close } yield { val registry = CollectorRegistry.defaultRegistry registry.metricFamilySamples.asScala .count(_.name.startsWith("kafka_producer")) should ===(56) registry.metricFamilySamples.asScala .find(_.name == "kafka_producer_record_send_total") .map(_.samples.asScala.map(_.value)) should ===(Some(List(2))) registry.metricFamilySamples.asScala .count(_.name.startsWith("kafka_consumer")) should ===(50) registry.metricFamilySamples.asScala .find(_.name == "kafka_consumer_records_consumed_total") .map(_.samples.asScala.map(_.value)) should ===(Some(List(2, 2))) registry.metricFamilySamples.asScala .find(_.name == "kafka_consumer_topic_records_consumed_total") .map(_.samples.asScala.map(_.value)) should ===(Some(List(2, 2))) } ) ) ) .unsafeRunSync() } }
Example 36
Source File: InMemoryKafka.scala From kafka4s with Apache License 2.0 | 5 votes |
package com.banno.kafka import org.scalatest.{BeforeAndAfterAll, Suite} import org.scalacheck.Gen import com.banno.kafka.admin.AdminApi import cats.effect.IO import io.chrisdavenport.log4cats.slf4j.Slf4jLogger import org.apache.kafka.clients.admin.NewTopic trait InMemoryKafka extends BeforeAndAfterAll { this: Suite => val log = Slf4jLogger.getLoggerFromClass[IO](this.getClass) val bootstrapServer = "localhost:9092" // val bootstrapServer = "kafka.local:9092" val schemaRegistryUrl = "http://localhost:8081" // val schemaRegistryUrl = "http://kafka.local:8081" override def beforeAll(): Unit = log.info(s"Using docker-machine Kafka cluster for ${getClass.getName}").unsafeRunSync() override def afterAll(): Unit = log.info(s"Used docker-machine Kafka cluster for ${getClass.getName}").unsafeRunSync() def randomId: String = Gen.listOfN(10, Gen.alphaChar).map(_.mkString).sample.get def genGroupId: String = randomId def genTopic: String = randomId def createTopic(partitionCount: Int = 1): String = { val topic = genTopic AdminApi .createTopicsIdempotent[IO]( bootstrapServer, List(new NewTopic(topic, partitionCount, 1.toShort)) ) .unsafeRunSync() topic } }
Example 37
Source File: ServerApp.scala From fs2-chat with MIT License | 5 votes |
package fs2chat package server import cats.effect.{Blocker, ExitCode, IO, IOApp} import cats.implicits._ import com.comcast.ip4s._ import com.monovore.decline._ import fs2.io.tcp.SocketGroup import io.chrisdavenport.log4cats.slf4j.Slf4jLogger object ServerApp extends IOApp { private val argsParser: Command[Port] = Command("fs2chat-server", "FS2 Chat Server") { Opts .option[Int]("port", "Port to bind for connection requests") .withDefault(5555) .mapValidated(p => Port(p).toValidNel("Invalid port number")) } def run(args: List[String]): IO[ExitCode] = argsParser.parse(args) match { case Left(help) => IO(System.err.println(help)).as(ExitCode.Error) case Right(port) => Blocker[IO] .use { blocker => SocketGroup[IO](blocker).use { socketGroup => Slf4jLogger.create[IO].flatMap { implicit logger => Server.start[IO](socketGroup, port).compile.drain } } } .as(ExitCode.Success) } }
Example 38
Source File: ProfileCtrl.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.web.pages.user.profile import cats.effect.IO import com.mohiva.play.silhouette.api.Silhouette import gospeak.core.domain.User import gospeak.core.services.storage.{UserGroupRepo, UserProposalRepo, UserTalkRepo, UserUserRepo} import gospeak.web.AppConf import gospeak.web.auth.domain.CookieEnv import gospeak.web.domain.Breadcrumb import gospeak.web.pages.published.speakers.routes.{SpeakerCtrl => PublishedSpeakerRoutes} import gospeak.web.pages.user.UserCtrl import gospeak.web.pages.user.profile.ProfileCtrl._ import gospeak.web.utils.{GsForms, UICtrl, UserReq} import play.api.data.Form import play.api.mvc.{Action, AnyContent, ControllerComponents, Result} class ProfileCtrl(cc: ControllerComponents, silhouette: Silhouette[CookieEnv], conf: AppConf, groupRepo: UserGroupRepo, proposalRepo: UserProposalRepo, talkRepo: UserTalkRepo, userRepo: UserUserRepo) extends UICtrl(cc, silhouette, conf) { def edit(): Action[AnyContent] = UserAction { implicit req => editView(GsForms.user) } def doEdit(): Action[AnyContent] = UserAction { implicit req => GsForms.user.bindFromRequest.fold( formWithErrors => editView(formWithErrors), data => userRepo.edit(data) .map(_ => Redirect(PublishedSpeakerRoutes.detail(req.user.slug)).flashing("success" -> "Profile updated")) ) } private def editView(form: Form[User.Data])(implicit req: UserReq[AnyContent]): IO[Result] = { val filledForm = if (form.hasErrors) form else form.fill(req.user.data) IO(Ok(html.edit(filledForm)(editBreadcrumb))) } } object ProfileCtrl { def breadcrumb(implicit req: UserReq[AnyContent]): Breadcrumb = UserCtrl.breadcrumb.add("Profile" -> PublishedSpeakerRoutes.detail(req.user.slug)) def editBreadcrumb(implicit req: UserReq[AnyContent]): Breadcrumb = breadcrumb.add("Edit" -> routes.ProfileCtrl.edit()) }
Example 39
Source File: HomeCtrl.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.web.pages.published import cats.effect.IO import com.mohiva.play.silhouette.api.Silhouette import gospeak.core.services.storage._ import gospeak.web.AppConf import gospeak.web.auth.domain.CookieEnv import gospeak.web.domain.Breadcrumb import gospeak.web.pages.published.HomeCtrl._ import gospeak.web.utils.UICtrl import play.api.mvc._ class HomeCtrl(cc: ControllerComponents, silhouette: Silhouette[CookieEnv], conf: AppConf, userRepo: PublicUserRepo, talkRepo: PublicTalkRepo, groupRepo: PublicGroupRepo, cfpRepo: PublicCfpRepo, eventRepo: PublicEventRepo, proposalRepo: PublicProposalRepo, externalCfpRepo: PublicExternalCfpRepo, externalEvent: PublicExternalEventRepo, externalProposal: PublicExternalProposalRepo) extends UICtrl(cc, silhouette, conf) { def index(): Action[AnyContent] = UserAwareAction { implicit req => IO.pure(Ok(html.index()(breadcrumb()))) } def why(): Action[AnyContent] = UserAwareAction { implicit req => IO.pure(Ok(html.why()(breadcrumb().add("Why use Gospeak" -> routes.HomeCtrl.why())))) } def videoNewsletter(): Action[AnyContent] = UserAwareAction { implicit req => IO.pure(Ok(html.videoNewsletter()(breadcrumb().add("Video newsletter" -> routes.HomeCtrl.videoNewsletter())))) } def sitemap(): Action[AnyContent] = UserAwareAction { implicit req => for { users <- userRepo.listAllPublicSlugs().map(_.toMap) talks <- talkRepo.listAllPublicSlugs() groups <- groupRepo.listAllSlugs().map(_.toMap) events <- eventRepo.listAllPublishedSlugs() proposals <- proposalRepo.listAllPublicIds() cfps <- cfpRepo.listAllPublicSlugs() extCfps <- externalCfpRepo.listAllIds() extEvents <- externalEvent.listAllIds() extProposals <- externalProposal.listAllPublicIds() } yield Ok(html.sitemap(users, talks, groups, events, proposals, cfps, extCfps, extEvents, extProposals)).as("text/xml") } } object HomeCtrl { def breadcrumb(): Breadcrumb = Breadcrumb("Home", routes.HomeCtrl.index()) }
Example 40
Source File: SpeakerCtrl.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.web.pages.published.speakers import cats.data.OptionT import cats.effect.IO import com.mohiva.play.silhouette.api.Silhouette import gospeak.core.domain.{Proposal, Talk, User} import gospeak.core.services.email.EmailSrv import gospeak.core.services.storage._ import gospeak.libs.scala.domain.Page import gospeak.web.AppConf import gospeak.web.auth.domain.CookieEnv import gospeak.web.domain.Breadcrumb import gospeak.web.emails.Emails import gospeak.web.pages.published.HomeCtrl import gospeak.web.pages.published.speakers.SpeakerCtrl._ import gospeak.web.utils._ import play.api.mvc._ class SpeakerCtrl(cc: ControllerComponents, silhouette: Silhouette[CookieEnv], conf: AppConf, userRepo: PublicUserRepo, talkRepo: PublicTalkRepo, externalProposalRepo: PublicExternalProposalRepo, groupRepo: PublicGroupRepo, emailSrv: EmailSrv) extends UICtrl(cc, silhouette, conf) { def list(params: Page.Params): Action[AnyContent] = UserAwareAction { implicit req => userRepo.listPublic(params).map(speakers => Ok(html.list(speakers)(listBreadcrumb()))) } def detail(user: User.Slug): Action[AnyContent] = UserAwareAction { implicit req => (for { speakerElt <- OptionT(userRepo.findPublic(user)) groups <- OptionT.liftF(groupRepo.listFull(speakerElt.id)) talks <- OptionT.liftF(talkRepo.listAll(speakerElt.id, Talk.Status.Public)) proposals <- OptionT.liftF(externalProposalRepo.listAllCommon(speakerElt.id, Proposal.Status.Accepted)) users <- OptionT.liftF(userRepo.list((groups.flatMap(_.owners.toList) ++ talks.flatMap(_.users)).distinct)) res = Ok(html.detail(speakerElt, groups, talks, proposals.groupBy(_.talk.id), users)(breadcrumb(speakerElt))) } yield res).value.map(_.getOrElse(publicUserNotFound(user))) } def talk(user: User.Slug, talk: Talk.Slug): Action[AnyContent] = UserAwareAction { implicit req => (for { userElt <- OptionT(userRepo.findPublic(user)) talkElt <- OptionT(talkRepo.findPublic(talk, userElt.id)) proposals <- OptionT.liftF(externalProposalRepo.listAllCommon(talkElt.id, Proposal.Status.Accepted)) users <- OptionT.liftF(userRepo.list((talkElt.users ++ proposals.flatMap(_.users)).distinct)) res = Ok(html.talk(userElt, talkElt, proposals, users)(breadcrumb(userElt, talkElt))) } yield res).value.map(_.getOrElse(publicTalkNotFound(user, talk))) } def contactSpeaker(user: User.Slug): Action[AnyContent] = UserAction { implicit req => val next = Redirect(routes.SpeakerCtrl.detail(user)) GsForms.speakerContact.bindFromRequest.fold( formWithErrors => IO.pure(next.flashing(formWithErrors.flash)), data => (for { speakerElt <- OptionT(userRepo.findPublic(user)(req.userAware)) _ <- OptionT.liftF(emailSrv.send(Emails.contactSpeaker(data.subject, data.content, speakerElt.user))) res = next.flashing("success" -> "The message has been sent!") } yield res).value.map(_.getOrElse(publicUserNotFound(user)))) } } object SpeakerCtrl { def listBreadcrumb(): Breadcrumb = HomeCtrl.breadcrumb().add("Speakers" -> routes.SpeakerCtrl.list()) def breadcrumb(speaker: User.Full): Breadcrumb = listBreadcrumb().add(speaker.name.value -> routes.SpeakerCtrl.detail(speaker.slug)) def breadcrumb(speaker: User.Full, talk: Talk): Breadcrumb = breadcrumb(speaker).add("Talks" -> routes.SpeakerCtrl.detail(speaker.slug)).add(talk.title.value -> routes.SpeakerCtrl.talk(speaker.slug, talk.slug)) }
Example 41
Source File: CfpCtrl.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.web.pages.orga.cfps import cats.data.OptionT import cats.effect.IO import com.mohiva.play.silhouette.api.Silhouette import gospeak.core.domain.utils.OrgaCtx import gospeak.core.domain.{Cfp, Event, Group} import gospeak.core.services.storage._ import gospeak.web.AppConf import gospeak.web.auth.domain.CookieEnv import gospeak.web.domain.Breadcrumb import gospeak.web.pages.orga.GroupCtrl import gospeak.web.pages.orga.cfps.CfpCtrl._ import gospeak.web.pages.orga.events.routes.{EventCtrl => EventRoutes} import gospeak.web.utils.{GsForms, OrgaReq, UICtrl} import gospeak.libs.scala.domain.Page import play.api.data.Form import play.api.mvc.{Action, AnyContent, ControllerComponents, Result} class CfpCtrl(cc: ControllerComponents, silhouette: Silhouette[CookieEnv], conf: AppConf, userRepo: OrgaUserRepo, val groupRepo: OrgaGroupRepo, cfpRepo: OrgaCfpRepo, eventRepo: OrgaEventRepo, proposalRepo: OrgaProposalRepo) extends UICtrl(cc, silhouette, conf) with UICtrl.OrgaAction { def list(group: Group.Slug, params: Page.Params): Action[AnyContent] = OrgaAction(group) { implicit req => val customParams = params.withNullsFirst cfpRepo.list(customParams).map(cfps => Ok(html.list(cfps)(listBreadcrumb))) // TODO listWithProposalCount } def create(group: Group.Slug, event: Option[Event.Slug]): Action[AnyContent] = OrgaAction(group) { implicit req => createView(group, GsForms.cfp, event) } def doCreate(group: Group.Slug, event: Option[Event.Slug]): Action[AnyContent] = OrgaAction(group) { implicit req => GsForms.cfp.bindFromRequest.fold( formWithErrors => createView(group, formWithErrors, event), data => (for { // TODO check if slug not already exist cfpElt <- OptionT.liftF(cfpRepo.create(data)) redirect <- OptionT.liftF(event.map { e => eventRepo.attachCfp(e, cfpElt.id) .map(_ => Redirect(EventRoutes.detail(group, e))) // TODO recover and redirect to cfp detail }.getOrElse { IO.pure(Redirect(routes.CfpCtrl.detail(group, data.slug))) }) } yield redirect).value.map(_.getOrElse(groupNotFound(group))) ) } private def createView(group: Group.Slug, form: Form[Cfp.Data], event: Option[Event.Slug])(implicit req: OrgaReq[AnyContent]): IO[Result] = { val b = listBreadcrumb.add("New" -> routes.CfpCtrl.create(group)) IO.pure(Ok(html.create(form, event)(b))) } def detail(group: Group.Slug, cfp: Cfp.Slug, params: Page.Params): Action[AnyContent] = OrgaAction(group) { implicit req => (for { cfpElt <- OptionT(cfpRepo.find(cfp)) proposals <- OptionT.liftF(proposalRepo.listFull(cfp, params)) speakers <- OptionT.liftF(userRepo.list(proposals.items.flatMap(_.users).distinct)) userRatings <- OptionT.liftF(proposalRepo.listRatings(cfp)) b = breadcrumb(cfpElt) } yield Ok(html.detail(cfpElt, proposals, speakers, userRatings)(b))).value.map(_.getOrElse(cfpNotFound(group, cfp))) } def edit(group: Group.Slug, cfp: Cfp.Slug, redirect: Option[String]): Action[AnyContent] = OrgaAction(group) { implicit req => editView(group, cfp, GsForms.cfp, redirect) } def doEdit(group: Group.Slug, cfp: Cfp.Slug, redirect: Option[String]): Action[AnyContent] = OrgaAction(group) { implicit req => GsForms.cfp.bindFromRequest.fold( formWithErrors => editView(group, cfp, formWithErrors, redirect), data => (for { cfpOpt <- OptionT.liftF(cfpRepo.find(data.slug)) res <- OptionT.liftF(cfpOpt match { case Some(duplicate) if data.slug != cfp => editView(group, cfp, GsForms.cfp.fillAndValidate(data).withError("slug", s"Slug already taken by cfp: ${duplicate.name.value}"), redirect) case _ => cfpRepo.edit(cfp, data).map { _ => redirectOr(redirect, routes.CfpCtrl.detail(group, data.slug)) } }) } yield res).value.map(_.getOrElse(groupNotFound(group))) ) } private def editView(group: Group.Slug, cfp: Cfp.Slug, form: Form[Cfp.Data], redirect: Option[String])(implicit req: OrgaReq[AnyContent], ctx: OrgaCtx): IO[Result] = { (for { cfpElt <- OptionT(cfpRepo.find(cfp)) filledForm = if (form.hasErrors) form else form.fill(cfpElt.data) b = breadcrumb(cfpElt).add("Edit" -> routes.CfpCtrl.edit(group, cfp)) } yield Ok(html.edit(cfpElt, filledForm, redirect)(b))).value.map(_.getOrElse(cfpNotFound(group, cfp))) } } object CfpCtrl { def listBreadcrumb(implicit req: OrgaReq[AnyContent]): Breadcrumb = GroupCtrl.breadcrumb.add("CFPs" -> routes.CfpCtrl.list(req.group.slug)) def breadcrumb(cfp: Cfp)(implicit req: OrgaReq[AnyContent]): Breadcrumb = listBreadcrumb.add(cfp.name.value -> routes.CfpCtrl.detail(req.group.slug, cfp.slug)) }
Example 42
Source File: SwaggerCtrl.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.web.api.swagger import cats.effect.IO import com.mohiva.play.silhouette.api.Silhouette import gospeak.web.AppConf import gospeak.web.auth.domain.CookieEnv import gospeak.web.utils.{OpenApiUtils, UICtrl} import play.api.mvc.{Action, AnyContent, ControllerComponents} class SwaggerCtrl(cc: ControllerComponents, silhouette: Silhouette[CookieEnv], conf: AppConf) extends UICtrl(cc, silhouette, conf) { private val spec = OpenApiUtils.loadSpec().get // to fail app on start def getSpec: Action[AnyContent] = UserAwareAction { implicit req => IO.pure(Ok(spec)) } def getUi: Action[AnyContent] = UserAwareAction { implicit req => IO.pure(Ok(html.swaggerUi())) } }
Example 43
Source File: UtilsCtrl.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.web.api.ui import cats.effect.IO import com.mohiva.play.silhouette.api.Silhouette import gospeak.core.domain.ExternalCfp import gospeak.core.domain.messages.Message import gospeak.core.services.cloudinary.CloudinarySrv import gospeak.core.services.slack.SlackSrv import gospeak.core.services.slack.domain.SlackToken import gospeak.core.services.storage.PublicExternalCfpRepo import gospeak.infra.services.EmbedSrv import gospeak.libs.scala.Extensions._ import gospeak.libs.scala.domain.{Html, Markdown, Mustache, Url} import gospeak.web.AppConf import gospeak.web.api.domain.ApiExternalCfp import gospeak.web.api.domain.utils.ApiResult import gospeak.web.api.ui.helpers.JsonFormats._ import gospeak.web.auth.domain.CookieEnv import gospeak.web.services.MessageSrv import gospeak.web.utils.ApiCtrl import play.api.libs.json._ import play.api.mvc._ import play.twirl.api.HtmlFormat import scala.util.control.NonFatal case class ValidationResult(valid: Boolean, message: String) case class TemplateDataResponse(data: JsValue) case class TemplateRequest(template: Mustache.Markdown[Any], ref: Option[Message.Ref], markdown: Boolean) case class TemplateResponse(result: Option[Html], error: Option[String]) class UtilsCtrl(cc: ControllerComponents, silhouette: Silhouette[CookieEnv], conf: AppConf, externalCfpRepo: PublicExternalCfpRepo, cloudinarySrv: CloudinarySrv, slackSrv: SlackSrv, ms: MessageSrv) extends ApiCtrl(cc, silhouette, conf) { def cloudinarySignature(): Action[AnyContent] = UserAction[String] { implicit req => val queryParams = req.queryString.flatMap { case (key, values) => values.headOption.map(value => (key, value)) } IO.pure(cloudinarySrv.signRequest(queryParams) match { case Right(signature) => ApiResult.of(signature) case Left(error) => ApiResult.badRequest(error) }) } def validateSlackToken(token: String): Action[AnyContent] = UserAction[ValidationResult] { implicit req => SlackToken.from(token, conf.app.aesKey).toIO.flatMap(slackSrv.getInfos(_, conf.app.aesKey)) .map(infos => ValidationResult(valid = true, s"Token for ${infos.teamName} team, created by ${infos.userName}")) .recover { case NonFatal(e) => ValidationResult(valid = false, s"Invalid token: ${e.getMessage}") } .map(ApiResult.of(_)) } def duplicatesExtCfp(params: ExternalCfp.DuplicateParams): Action[AnyContent] = UserAction[Seq[ApiExternalCfp.Published]] { implicit req => externalCfpRepo.listDuplicatesFull(params).map(cfps => ApiResult.of(cfps.map(ApiExternalCfp.published))) } def embed(url: Url): Action[AnyContent] = UserAwareAction { implicit req => EmbedSrv.embedCode(url).map(_.value).map(ApiResult.of(_)) } def markdownToHtml(): Action[JsValue] = UserAwareActionJson[String, String] { implicit req => val html = Markdown(req.body).toHtml IO.pure(ApiResult.of(html.value)) } def templateData(ref: Message.Ref): Action[AnyContent] = UserAction[TemplateDataResponse] { implicit req => val data = circeToPlay(ms.sample(Some(ref))) IO.pure(ApiResult.of(TemplateDataResponse(data))) } def renderTemplate(): Action[JsValue] = UserActionJson[TemplateRequest, TemplateResponse] { implicit req => val data = ms.sample(req.body.ref)(req.withBody(AnyContent())) val tmpl = req.body.template.render(data) val res = tmpl match { case Left(err) => TemplateResponse(None, Some(err.message)) case Right(tmpl) if req.body.markdown => TemplateResponse(Some(tmpl.toHtml), None) case Right(tmpl) => TemplateResponse(Some(Html(s"<pre>${HtmlFormat.escape(tmpl.value)}</pre>")), None) } IO.pure(ApiResult.of(res)) } private def circeToPlay(json: io.circe.Json): JsValue = { json.fold( jsonNull = JsNull, jsonBoolean = (b: Boolean) => JsBoolean(b), jsonNumber = (n: io.circe.JsonNumber) => JsNumber(n.toBigDecimal.getOrElse(BigDecimal(n.toDouble))), jsonString = (s: String) => JsString(s), jsonArray = (v: Vector[io.circe.Json]) => JsArray(v.map(circeToPlay)), jsonObject = (o: io.circe.JsonObject) => JsObject(o.toMap.mapValues(circeToPlay)) ) } }
Example 44
Source File: SchedulerSrv.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.web.services import java.time.Instant import cats.effect.{IO, Timer} import cron4s.CronExpr import eu.timepit.fs2cron.awakeEveryCron import fs2.Stream import gospeak.core.domain.utils.{AdminCtx, Constants} import gospeak.core.services.storage.AdminVideoRepo import gospeak.core.services.twitter.TwitterSrv import gospeak.libs.scala.Extensions._ import gospeak.libs.scala.TimeUtils import gospeak.web.services.SchedulerSrv.{Conf, Exec, Scheduler} import scala.collection.mutable import scala.concurrent.ExecutionContext import scala.concurrent.duration.FiniteDuration import scala.util.control.NonFatal class SchedulerSrv(videoRepo: AdminVideoRepo, twitterSrv: TwitterSrv)(implicit ec: ExecutionContext) { implicit private val timer: Timer[IO] = IO.timer(ec) private val schedulers = mutable.ListBuffer[Scheduler]() private val execs: mutable.ListBuffer[Exec] = mutable.ListBuffer[Exec]() def getSchedulers: List[Scheduler] = schedulers.toList def getExecs: List[Exec] = execs.toList def init(conf: Conf): Unit = { schedule("tweet random video", conf.tweetRandomVideo, tweetRandomVideo()) } def exec(name: String)(implicit ctx: AdminCtx): IO[Option[Exec]] = schedulers.find(_.name == name).map(exec(_, s"manual (${ctx.user.name.value})")).sequence private def tweetRandomVideo(): IO[(String, Option[String])] = for { video <- videoRepo.findRandom() tweet <- (for { v <- video.toRight("No video available") } yield twitterSrv.tweet(s"#OneDayOneTalk [${v.lang}] ${v.title} on ${v.channel.name} in ${v.publishedAt.getYear(Constants.defaultZoneId)} ${v.url.value}")).sequence } yield (tweet.map(t => s"Tweet sent: ${t.text}").getOrElse("Tweet not sent"), tweet.swap.toOption) // TODO be able to stop/start a scheduler private def schedule(name: String, cron: CronExpr, task: IO[(String, Option[String])]): Unit = { schedulers.find(_.name == name).map(_ => ()).getOrElse { val scheduler = Scheduler(name, cron, Some(Instant.now()), task) schedulers += scheduler val stream = awakeEveryCron[IO](cron).flatMap { _ => Stream.eval(exec(scheduler, "auto")) } stream.compile.drain.unsafeRunAsyncAndForget } } private def exec(s: Scheduler, source: String): IO[Exec] = IO(Instant.now()).flatMap { start => s.task.map { case (res, None) => Exec(s.name, source, start, Instant.now(), res, None) case (res, Some(err)) => Exec(s.name, source, start, Instant.now(), res, Some(err)) }.recover { case NonFatal(e) => Exec(s.name, source, start, Instant.now(), s"Finished with ${e.getClass.getSimpleName}", Some(e.getMessage)) }.map { e => execs += e e } } } object SchedulerSrv { final case class Conf(tweetRandomVideo: CronExpr) final case class Scheduler(name: String, schedule: CronExpr, started: Option[Instant], private[SchedulerSrv] val task: IO[(String, Option[String])]) final case class Exec(name: String, source: String, started: Instant, finished: Instant, result: String, error: Option[String]) { def duration: FiniteDuration = TimeUtils.toFiniteDuration(started, finished) } }
Example 45
Source File: MessageHandler.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.web.services import java.time.LocalDateTime import cats.data.OptionT import cats.effect.IO import gospeak.core.ApplicationConf import gospeak.core.domain.Group import gospeak.core.domain.Group.Settings.Action import gospeak.core.domain.Group.Settings.Action.Trigger import gospeak.core.domain.messages.Message import gospeak.core.domain.utils.Constants import gospeak.core.services.email.EmailSrv import gospeak.core.services.slack.SlackSrv import gospeak.core.services.storage.{OrgaGroupRepo, OrgaGroupSettingsRepo} import gospeak.core.services.twitter.{Tweets, TwitterSrv} import gospeak.libs.scala.Extensions._ import gospeak.libs.scala.domain.{CustomException, EmailAddress} import gospeak.web.services.MessageSrv._ import io.circe.Json import org.slf4j.LoggerFactory import scala.util.control.NonFatal class MessageHandler(appConf: ApplicationConf, groupRepo: OrgaGroupRepo, groupSettingsRepo: OrgaGroupSettingsRepo, emailSrv: EmailSrv, slackSrv: SlackSrv, twitterSrv: TwitterSrv) { private val logger = LoggerFactory.getLogger(this.getClass) def groupActionHandler(msg: Message): IO[Unit] = (msg match { case m: Message.GroupMessage => handleGroupAction(m.group.slug, m, eMessage(m)) case _ => IO.pure(0) }).map(_ => ()).recover { case NonFatal(_) => () } def gospeakHandler(msg: Message): IO[Unit] = (msg match { case m: Message.ExternalCfpCreated => gospeakTwitt(m) case _ => IO.pure(0) }).map(_ => ()).recover { case NonFatal(_) => () } def logHandler(msg: Message): IO[Unit] = IO.pure(logger.info(s"Message sent: $msg")) private def handleGroupAction(group: Group.Slug, msg: Message.GroupMessage, data: Json): IO[Int] = (for { groupElt <- OptionT(groupRepo.find(group)) actions <- OptionT.liftF(groupSettingsRepo.findActions(groupElt.id)) accounts <- OptionT.liftF(groupSettingsRepo.findAccounts(groupElt.id)) actionsToExec = Trigger.all.filter(_.message == msg.ref).flatMap(actions.getOrElse(_, Seq())) results <- OptionT.liftF(actionsToExec.map(execGroupAction(accounts, _, data)).sequence) } yield results.length).value.map(_.getOrElse(0)) private def execGroupAction(accounts: Group.Settings.Accounts, action: Action, data: Json): IO[Unit] = action match { case email: Action.Email => (for { to <- email.to.render(data).left.map(e => CustomException(e.message)).flatMap(EmailAddress.from).map(EmailAddress.Contact(_)) subject <- email.subject.render(data).left.map(e => CustomException(e.message)) content <- email.content.render(data).map(_.toHtml).leftMap(e => CustomException(e.message)) } yield emailSrv.send(EmailSrv.Email( from = Constants.Gospeak.noreplyEmail, to = Seq(to), subject = subject, content = EmailSrv.HtmlContent(content.value) ))).toIO.flatMap(identity).map(_ => ()) case Action.Slack(slack) => accounts.slack.map(slackSrv.exec(slack, data, _, appConf.aesKey)).getOrElse(IO.raiseError(CustomException("No credentials for Slack"))) } private def gospeakTwitt(msg: Message.ExternalCfpCreated): IO[Int] = { if (msg.cfp.isActive(LocalDateTime.now())) { twitterSrv.tweet(Tweets.externalCfpCreated(msg)).map(_ => 1) } else { IO.pure(0) } } }
Example 46
Source File: SendGridEmailSrv.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.infra.services.email import cats.effect.IO import gospeak.core.services.email.EmailSrv.{Email, HtmlContent, TextContent} import gospeak.core.services.email.{EmailConf, EmailSrv} import gospeak.libs.scala.Extensions._ import gospeak.libs.scala.domain.Done import gospeak.libs.scala.domain.EmailAddress.Contact class SendGridEmailSrv private(client: com.sendgrid.SendGrid) extends EmailSrv { import com.sendgrid.helpers.mail.{objects => sgO} import com.sendgrid.helpers.{mail => sgM} import com.{sendgrid => sg} override def send(email: Email): IO[Done] = { // https://github.com/sendgrid/sendgrid-java/blob/master/examples/helpers/mail/Example.java#L30 val mail = buildMail(email) val request = new sg.Request() request.setMethod(sg.Method.POST) request.setEndpoint("mail/send") for { body <- IO(mail.build) _ = request.setBody(body) _ <- IO(client.api(request)).filter(_.getStatusCode == 202) } yield Done } private def buildMail(email: Email): sgM.Mail = { val mail = new sgM.Mail() mail.setFrom(buildEmail(email.from)) val personalization = new sgO.Personalization() email.to.foreach(to => personalization.addTo(buildEmail(to))) mail.addPersonalization(personalization) mail.setSubject(email.subject) email.content match { case TextContent(text) => mail.addContent(new sgO.Content("text/plain", text)) case HtmlContent(html) => mail.addContent(new sgO.Content("text/html", html)) } mail } private def buildEmail(contact: Contact): sgO.Email = contact.name.map { name => new sgO.Email(contact.address.value, name) }.getOrElse { new sgO.Email(contact.address.value) } } object SendGridEmailSrv { def apply(conf: EmailConf.SendGrid): SendGridEmailSrv = new SendGridEmailSrv(new com.sendgrid.SendGrid(conf.apiKey.decode)) }
Example 47
Source File: ConsoleEmailSrv.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.infra.services.email import cats.effect.IO import gospeak.core.services.email.EmailSrv import gospeak.core.services.email.EmailSrv.Email import gospeak.libs.scala.domain.Done // useful for dev class ConsoleEmailSrv extends EmailSrv { override def send(email: Email): IO[Done] = IO { println( s"""EmailSrv.send( | from: ${email.from.format}, | to: ${email.to.map(_.format).mkString(", ")}, | subject: ${email.subject}, | content: |${email.content.value} |)""".stripMargin) Done } }
Example 48
Source File: CloudinarySrvImpl.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.infra.services.cloudinary import cats.effect.IO import gospeak.core.domain.{ExternalEvent, Group, Partner, User} import gospeak.core.services.cloudinary.CloudinarySrv import gospeak.core.services.upload.UploadConf import gospeak.libs.cloudinary.CloudinaryClient import gospeak.libs.cloudinary.domain.CloudinaryUploadRequest import gospeak.libs.scala.Extensions._ import gospeak.libs.scala.domain.{Avatar, Banner, Logo} class CloudinarySrvImpl(client: CloudinaryClient) extends CloudinarySrv { override def signRequest(params: Map[String, String]): Either[String, String] = client.sign(params) override def uploadAvatar(user: User): IO[Avatar] = { client.upload(CloudinaryUploadRequest( file = user.avatar.value, folder = CloudinarySrvImpl.userFolder(user), publicId = CloudinarySrvImpl.userAvatarFile )).flatMap(_.toIO(new IllegalStateException(_))) .flatMap(_.toUrl.toIO) .map(_.transform(Seq("ar_1", "c_crop")).toUrl).map(Avatar) } override def uploadGroupLogo(group: Group, logo: Logo): IO[Logo] = { client.upload(CloudinaryUploadRequest( file = logo.value, folder = CloudinarySrvImpl.groupFolder(group), publicId = CloudinarySrvImpl.groupLogoFile )).flatMap(_.toIO(new IllegalStateException(_))) .flatMap(_.toUrl.toIO) .map(_.transform(Seq("ar_1", "c_crop")).toUrl).map(Logo) } override def uploadGroupBanner(group: Group, banner: Banner): IO[Banner] = { client.upload(CloudinaryUploadRequest( file = banner.value, folder = CloudinarySrvImpl.groupFolder(group), publicId = CloudinarySrvImpl.groupBannerFile )).flatMap(_.toIO(new IllegalStateException(_))) .flatMap(_.toUrl.toIO) .map(_.transform(Seq("ar_3", "c_crop")).toUrl).map(Banner) } override def uploadPartnerLogo(group: Group, partner: Partner): IO[Logo] = { client.upload(CloudinaryUploadRequest( file = partner.logo.value, folder = CloudinarySrvImpl.groupPartnerFolder(group), publicId = CloudinarySrvImpl.groupPartnerFile(Some(partner.slug.value)) )).flatMap(_.toIO(new IllegalStateException(_))) .flatMap(_.toUrl.toIO) .map(_.transform(Seq("ar_1", "c_crop")).toUrl).map(Logo) } override def uploadExternalEventLogo(event: ExternalEvent, logo: Logo): IO[Logo] = { client.upload(CloudinaryUploadRequest( file = logo.value, folder = CloudinarySrvImpl.extEventFolder(), publicId = CloudinarySrvImpl.extEventLogoFile(Some(event.name.value)) )).flatMap(_.toIO(new IllegalStateException(_))) .flatMap(_.toUrl.toIO) .map(_.transform(Seq("ar_1", "c_crop")).toUrl).map(Logo) } } object CloudinarySrvImpl { def from(conf: UploadConf.Cloudinary): CloudinarySrvImpl = new CloudinarySrvImpl(new CloudinaryClient(CloudinaryClient.Conf( cloudName = conf.cloudName, uploadPreset = conf.uploadPreset, creds = conf.creds))) def userAvatarFile: Option[String] = Some("avatar") def groupLogoFile: Option[String] = Some("logo") def groupBannerFile: Option[String] = Some("banner") def groupPartnerFile(partnerSlug: Option[String]): Option[String] = partnerSlug.filter(_.nonEmpty) def groupSlackBotFile: Option[String] = Some("slack-bot-avatar") def extEventLogoFile(eventName: Option[String]): Option[String] = eventName.filter(_.nonEmpty) def userFolder(user: User): Option[String] = Some(s"users/${user.slug.value}_${user.id.value}") def groupFolder(group: Group): Option[String] = Some(s"groups/${group.slug.value}_${group.id.value}") def groupPartnerFolder(group: Group): Option[String] = groupFolder(group).map(_ + "/partners") def extEventFolder(): Option[String] = Some(s"ext-events") }
Example 49
Source File: SlackSrvImpl.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.infra.services.slack import cats.data.EitherT import cats.effect.IO import gospeak.core.services.slack.SlackSrv import gospeak.core.services.slack.domain.SlackAction.PostMessage import gospeak.core.services.slack.domain._ import gospeak.infra.services.slack.SlackSrvImpl._ import gospeak.libs.scala.Crypto.AesSecretKey import gospeak.libs.scala.Extensions._ import gospeak.libs.scala.domain.{CustomException, Markdown} import gospeak.libs.slack.{SlackClient, domain => api} import io.circe.Json import scala.util.Try // SlackSrv should not use Slack classes in the API, it's independent and the implementation should do the needed conversion class SlackSrvImpl(client: SlackClient) extends SlackSrv { override def getInfos(token: SlackToken, key: AesSecretKey): IO[SlackTokenInfo] = toSlack(token, key).toIO.flatMap(client.info).map(_.map(toGospeak)).flatMap(toIO) override def exec(action: SlackAction, data: Json, creds: SlackCredentials, key: AesSecretKey): IO[Unit] = action match { case a: PostMessage => postMessage(a, data, creds, key).map(_ => ()) } private def postMessage(action: PostMessage, data: Json, creds: SlackCredentials, key: AesSecretKey): IO[Either[api.SlackError, api.SlackMessage]] = { val sender = api.SlackSender.Bot(creds.name, creds.avatar.map(_.value)) for { token <- toSlack(creds.token, key).toIO channel <- action.channel.render(data).map(toSlackName).toIO(e => CustomException(e.message)) message <- action.message.render(data).map(toSlack).toIO(e => CustomException(e.message)) attempt1 <- client.postMessage(token, sender, channel, message) attempt2 <- attempt1 match { case Left(api.SlackError(false, "channel_not_found", _, _)) if action.createdChannelIfNotExist => (for { createdChannel <- EitherT(client.createChannel(token, channel)) invitedUsers <- EitherT.liftF(if (action.inviteEverybody) { client.listUsers(token).flatMap(_.getOrElse(Seq()).map(_.id).map(client.inviteToChannel(token, createdChannel.id, _)).sequence) } else { IO.pure(Seq()) }) attempt2 <- EitherT(client.postMessage(token, sender, createdChannel.id, message)) } yield attempt2).value case _ => IO.pure(attempt1) } } yield attempt2 } private def toSlack(token: SlackToken, key: AesSecretKey): Try[api.SlackToken] = token.decode(key).map(api.SlackToken) private def toSlack(md: Markdown): api.SlackContent.Markdown = api.SlackContent.Markdown(md.value) private def toSlackName(name: String): api.SlackChannel.Name = api.SlackChannel.Name(name) private def toGospeak(id: api.SlackUser.Id): SlackUser.Id = SlackUser.Id(id.value) private def toGospeak(info: api.SlackTokenInfo): SlackTokenInfo = SlackTokenInfo(SlackTeam.Id(info.team_id.value), info.team, info.url, toGospeak(info.user_id), info.user) private def toIO[A](e: Either[api.SlackError, A]): IO[A] = e.toIO(e => CustomException(format(e))) } object SlackSrvImpl { private[slack] def format(err: api.SlackError): String = err.error + err.needed.map(" " + _).getOrElse("") + err.provided.map(" (provided: " + _ + ")").getOrElse("") }
Example 50
Source File: TwitterSrvImpl.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.infra.services.twitter import cats.effect.{ContextShift, IO} import com.danielasfregola.twitter4s.TwitterRestClient import com.danielasfregola.twitter4s.entities.{AccessToken, ConsumerToken, Tweet} import gospeak.core.services.twitter.{TwitterConf, TwitterSrv, domain => gs} import scala.concurrent.ExecutionContext class TwitterSrvImpl(conf: TwitterConf) extends TwitterSrv { implicit private val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global) private val consumerToken = ConsumerToken(key = conf.consumerKey, secret = conf.consumerSecret.decode) private val accessToken = AccessToken(key = conf.accessKey, secret = conf.accessSecret.decode) private val restClient = TwitterRestClient(consumerToken, accessToken) def tweet(msg: String): IO[gs.Tweet] = IO.fromFuture(IO(restClient.createTweet(trim(msg)))).map(fromLib) private def fromLib(t: Tweet): gs.Tweet = gs.Tweet( id = t.id, text = t.text) }
Example 51
Source File: SponsorRepoSql.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.infra.services.storage.sql import java.time.Instant import cats.effect.IO import doobie.implicits._ import doobie.util.fragment.Fragment import gospeak.core.domain._ import gospeak.core.domain.utils.OrgaCtx import gospeak.core.services.storage.SponsorRepo import gospeak.infra.services.storage.sql.SponsorRepoSql._ import gospeak.infra.services.storage.sql.utils.DoobieUtils.Mappings._ import gospeak.infra.services.storage.sql.utils.DoobieUtils._ import gospeak.infra.services.storage.sql.utils.GenericRepo import gospeak.libs.scala.Extensions._ import gospeak.libs.scala.domain.{Done, Page} class SponsorRepoSql(protected[sql] val xa: doobie.Transactor[IO]) extends GenericRepo with SponsorRepo { override def create(data: Sponsor.Data)(implicit ctx: OrgaCtx): IO[Sponsor] = insert(Sponsor(ctx.group.id, data, ctx.info)).run(xa) override def edit(sponsor: Sponsor.Id, data: Sponsor.Data)(implicit ctx: OrgaCtx): IO[Done] = update(ctx.group.id, sponsor)(data, ctx.user.id, ctx.now).run(xa) override def remove(sponsor: Sponsor.Id)(implicit ctx: OrgaCtx): IO[Done] = delete(ctx.group.id, sponsor).run(xa) override def find(sponsor: Sponsor.Id)(implicit ctx: OrgaCtx): IO[Option[Sponsor]] = selectOne(ctx.group.id, sponsor).runOption(xa) override def listFull(params: Page.Params)(implicit ctx: OrgaCtx): IO[Page[Sponsor.Full]] = selectPage(params).run(xa) override def listCurrentFull(group: Group.Id, now: Instant): IO[Seq[Sponsor.Full]] = selectCurrent(group, now).runList(xa) override def listAll(implicit ctx: OrgaCtx): IO[Seq[Sponsor]] = selectAll(ctx.group.id).runList(xa) override def listAll(contact: Contact.Id)(implicit ctx: OrgaCtx): IO[Seq[Sponsor]] = selectAll(ctx.group.id, contact).runList(xa) override def listAllFull(partner: Partner.Id)(implicit ctx: OrgaCtx): IO[Seq[Sponsor.Full]] = selectAllFull(ctx.group.id, partner).runList(xa) } object SponsorRepoSql { private val _ = sponsorIdMeta // for intellij not remove DoobieUtils.Mappings import private val table = Tables.sponsors val tableFull: Table = table .join(Tables.sponsorPacks, _.sponsor_pack_id -> _.id).get .join(Tables.partners, _.partner_id -> _.id).get .joinOpt(Tables.contacts, _.contact_id -> _.id).get .copy(filters = Seq( Filter.Bool.fromNow("active", "Is active", "s.start", "s.finish"))) private[sql] def insert(e: Sponsor): Insert[Sponsor] = { val values = fr0"${e.id}, ${e.group}, ${e.partner}, ${e.pack}, ${e.contact}, ${e.start}, ${e.finish}, ${e.paid}, ${e.price.amount}, ${e.price.currency}, ${e.info.createdAt}, ${e.info.createdBy}, ${e.info.updatedAt}, ${e.info.updatedBy}" table.insert(e, _ => values) } private[sql] def update(group: Group.Id, sponsor: Sponsor.Id)(data: Sponsor.Data, by: User.Id, now: Instant): Update = { val fields = fr0"partner_id=${data.partner}, sponsor_pack_id=${data.pack}, contact_id=${data.contact}, start=${data.start}, finish=${data.finish}, paid=${data.paid}, price=${data.price.amount}, currency=${data.price.currency}, updated_at=$now, updated_by=$by" table.update(fields, where(group, sponsor)) } private[sql] def delete(group: Group.Id, sponsor: Sponsor.Id): Delete = table.delete(where(group, sponsor)) private[sql] def selectOne(group: Group.Id, pack: Sponsor.Id): Select[Sponsor] = table.select[Sponsor](where(group, pack)) private[sql] def selectPage(params: Page.Params)(implicit ctx: OrgaCtx): SelectPage[Sponsor.Full, OrgaCtx] = tableFull.selectPage[Sponsor.Full, OrgaCtx](params, fr0"WHERE s.group_id=${ctx.group.id}") private[sql] def selectCurrent(group: Group.Id, now: Instant): Select[Sponsor.Full] = tableFull.select[Sponsor.Full](fr0"WHERE s.group_id=$group AND s.start < $now AND s.finish > $now") private[sql] def selectAll(group: Group.Id): Select[Sponsor] = table.select[Sponsor](fr0"WHERE s.group_id=$group") private[sql] def selectAll(group: Group.Id, contact: Contact.Id): Select[Sponsor] = table.select[Sponsor](fr0"WHERE s.group_id=$group AND s.contact_id=$contact") private[sql] def selectAllFull(group: Group.Id, partner: Partner.Id): Select[Sponsor.Full] = tableFull.select[Sponsor.Full](fr0"WHERE s.group_id=$group AND s.partner_id=$partner") private def where(group: Group.Id, sponsor: Sponsor.Id): Fragment = fr0"WHERE s.group_id=$group AND s.id=$sponsor" }
Example 52
Source File: ContactRepoSql.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.infra.services.storage.sql import java.time.Instant import cats.effect.IO import doobie.implicits._ import doobie.util.fragment.Fragment import gospeak.core.domain._ import gospeak.core.domain.utils.OrgaCtx import gospeak.core.services.storage.ContactRepo import gospeak.infra.services.storage.sql.ContactRepoSql._ import gospeak.infra.services.storage.sql.utils.DoobieUtils.Mappings._ import gospeak.infra.services.storage.sql.utils.DoobieUtils.{Delete, Insert, Select, Update} import gospeak.infra.services.storage.sql.utils.GenericRepo import gospeak.libs.scala.domain.{Done, EmailAddress} class ContactRepoSql(protected[sql] val xa: doobie.Transactor[IO]) extends GenericRepo with ContactRepo { override def create(data: Contact.Data)(implicit ctx: OrgaCtx): IO[Contact] = insert(Contact(data, ctx.info)).run(xa) override def edit(contact: Contact.Id, data: Contact.Data)(implicit ctx: OrgaCtx): IO[Done] = update(contact, data)(ctx.user.id, ctx.now).run(xa) override def remove(partner: Partner.Id, contact: Contact.Id)(implicit ctx: OrgaCtx): IO[Done] = delete(ctx.group.id, partner, contact)(ctx.user.id, ctx.now).run(xa) override def find(id: Contact.Id): IO[Option[Contact]] = selectOne(id).runOption(xa) override def list(partner: Partner.Id): IO[Seq[Contact]] = selectAll(partner).runList(xa) override def exists(partner: Partner.Id, email: EmailAddress): IO[Boolean] = selectOne(partner, email).runExists(xa) } object ContactRepoSql { private val _ = contactIdMeta // for intellij not remove DoobieUtils.Mappings import private val table = Tables.contacts private[sql] def insert(e: Contact): Insert[Contact] = { val values = fr0"${e.id}, ${e.partner}, ${e.firstName}, ${e.lastName}, ${e.email}, ${e.notes}, ${e.info.createdAt}, ${e.info.createdBy}, ${e.info.updatedAt}, ${e.info.updatedBy}" table.insert[Contact](e, _ => values) } private[sql] def update(contact: Contact.Id, data: Contact.Data)(by: User.Id, now: Instant): Update = { val fields = fr0"first_name=${data.firstName}, last_name=${data.lastName}, email=${data.email}, notes=${data.notes}, updated_at=$now, updated_by=$by" table.update(fields, where(contact)) } private[sql] def delete(group: Group.Id, partner: Partner.Id, contact: Contact.Id)(by: User.Id, now: Instant): Delete = table.delete(where(contact)) private[sql] def selectAll(partner: Partner.Id): Select[Contact] = table.select[Contact](where(partner)) private[sql] def selectOne(id: Contact.Id): Select[Contact] = table.select[Contact](where(id)) private[sql] def selectOne(partner: Partner.Id, email: EmailAddress): Select[Contact] = table.select[Contact](where(partner, email)) private def where(partner: Partner.Id): Fragment = fr0"WHERE ct.partner_id=$partner" private def where(partner: Partner.Id, email: EmailAddress): Fragment = fr0"WHERE ct.partner_id=$partner AND ct.email=$email" private def where(id: Contact.Id): Fragment = fr0"WHERE ct.id=$id" }
Example 53
Source File: CommentRepoSql.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.infra.services.storage.sql import cats.effect.IO import doobie.implicits._ import gospeak.core.domain.utils.{OrgaCtx, UserCtx} import gospeak.core.domain.{Comment, Event, Proposal} import gospeak.core.services.storage.CommentRepo import gospeak.infra.services.storage.sql.CommentRepoSql._ import gospeak.infra.services.storage.sql.utils.DoobieUtils.Mappings._ import gospeak.infra.services.storage.sql.utils.DoobieUtils.{Insert, Select} import gospeak.infra.services.storage.sql.utils.GenericRepo import gospeak.libs.scala.Extensions._ class CommentRepoSql(protected[sql] val xa: doobie.Transactor[IO]) extends GenericRepo with CommentRepo { override def addComment(event: Event.Id, data: Comment.Data)(implicit ctx: UserCtx): IO[Comment] = insert(event, Comment.create(data, Comment.Kind.Event, ctx.user.id, ctx.now)).run(xa) override def addComment(proposal: Proposal.Id, data: Comment.Data)(implicit ctx: UserCtx): IO[Comment] = insert(proposal, Comment.create(data, Comment.Kind.Proposal, ctx.user.id, ctx.now)).run(xa) override def addOrgaComment(proposal: Proposal.Id, data: Comment.Data)(implicit ctx: OrgaCtx): IO[Comment] = insert(proposal, Comment.create(data, Comment.Kind.ProposalOrga, ctx.user.id, ctx.now)).run(xa) override def getComments(event: Event.Id): IO[Seq[Comment.Full]] = selectAll(event, Comment.Kind.Event).runList(xa) override def getComments(proposal: Proposal.Id)(implicit ctx: UserCtx): IO[Seq[Comment.Full]] = selectAll(proposal, Comment.Kind.Proposal).runList(xa) override def getOrgaComments(proposal: Proposal.Id)(implicit ctx: OrgaCtx): IO[Seq[Comment.Full]] = selectAll(proposal, Comment.Kind.ProposalOrga).runList(xa) } object CommentRepoSql { private val _ = commentIdMeta // for intellij not remove DoobieUtils.Mappings import private val table = Tables.comments private val tableFull = table .join(Tables.users, _.created_by -> _.id) .flatMap(_.dropField(_.event_id)) .flatMap(_.dropField(_.proposal_id)).get private[sql] def insert(e: Event.Id, c: Comment): Insert[Comment] = { val values = fr0"$e, ${Option.empty[Proposal.Id]}, ${c.id}, ${c.kind}, ${c.answers}, ${c.text}, ${c.createdAt}, ${c.createdBy}" table.insert(c, _ => values) } private[sql] def insert(e: Proposal.Id, c: Comment): Insert[Comment] = { val values = fr0"${Option.empty[Event.Id]}, $e, ${c.id}, ${c.kind}, ${c.answers}, ${c.text}, ${c.createdAt}, ${c.createdBy}" table.insert(c, _ => values) } private[sql] def selectAll(event: Event.Id, kind: Comment.Kind): Select[Comment.Full] = tableFull.select[Comment.Full](fr0"WHERE co.event_id=$event AND co.kind=$kind") private[sql] def selectAll(proposal: Proposal.Id, kind: Comment.Kind): Select[Comment.Full] = tableFull.select[Comment.Full](fr0"WHERE co.proposal_id=$proposal AND co.kind=$kind") }
Example 54
Source File: ExternalCfpRepoSql.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.infra.services.storage.sql import java.time.Instant import cats.data.NonEmptyList import cats.effect.IO import doobie.implicits._ import gospeak.core.domain._ import gospeak.core.domain.utils.{Info, UserAwareCtx, UserCtx} import gospeak.core.services.storage.ExternalCfpRepo import gospeak.infra.services.storage.sql.ExternalCfpRepoSql._ import gospeak.infra.services.storage.sql.utils.DoobieUtils.Mappings._ import gospeak.infra.services.storage.sql.utils.DoobieUtils._ import gospeak.infra.services.storage.sql.utils.GenericRepo import gospeak.libs.scala.Extensions._ import gospeak.libs.scala.domain.{Done, Page} class ExternalCfpRepoSql(protected[sql] val xa: doobie.Transactor[IO]) extends GenericRepo with ExternalCfpRepo { override def create(event: ExternalEvent.Id, data: ExternalCfp.Data)(implicit ctx: UserCtx): IO[ExternalCfp] = insert(ExternalCfp(data, event, Info(ctx.user.id, ctx.now))).run(xa) override def edit(cfp: ExternalCfp.Id)(data: ExternalCfp.Data)(implicit ctx: UserCtx): IO[Done] = update(cfp)(data, ctx.user.id, ctx.now).run(xa) override def listAllIds(): IO[Seq[ExternalCfp.Id]] = selectAllIds().runList(xa) override def listAll(event: ExternalEvent.Id): IO[Seq[ExternalCfp]] = selectAll(event).runList(xa) override def listIncoming(params: Page.Params)(implicit ctx: UserAwareCtx): IO[Page[CommonCfp]] = selectCommonPageIncoming(params).run(xa) override def listDuplicatesFull(p: ExternalCfp.DuplicateParams): IO[Seq[ExternalCfp.Full]] = selectDuplicatesFull(p).runList(xa) override def findFull(cfp: ExternalCfp.Id): IO[Option[ExternalCfp.Full]] = selectOneFull(cfp).runOption(xa) override def findCommon(cfp: Cfp.Slug): IO[Option[CommonCfp]] = selectOneCommon(cfp).runOption(xa) override def findCommon(cfp: ExternalCfp.Id): IO[Option[CommonCfp]] = selectOneCommon(cfp).runOption(xa) } object ExternalCfpRepoSql { private val _ = externalCfpIdMeta // for intellij not remove DoobieUtils.Mappings import private val table = Tables.externalCfps private val tableFull = table .join(Tables.externalEvents.dropFields(_.name.startsWith("location_")), _.event_id -> _.id).get private val commonTable = Table( name = "((SELECT c.name, g.logo, c.begin, c.close, g.location, c.description, c.tags, null as ext_id, null as ext_url, null as ext_event_start, null as ext_event_finish, null as ext_event_url, null as ext_tickets_url, null as ext_videos_url, null as twitter_account, null as twitter_hashtag, c.slug as int_slug, g.id as group_id, g.slug as group_slug FROM cfps c INNER JOIN groups g ON c.group_id=g.id) " + "UNION (SELECT e.name, e.logo, c.begin, c.close, e.location, c.description, e.tags, c.id as ext_id, c.url as ext_url, e.start as ext_event_start, e.finish as ext_event_finish, e.url as ext_event_url, e.tickets_url as ext_tickets_url, e.videos_url as ext_videos_url, e.twitter_account, e.twitter_hashtag, null as int_slug, null as group_id, null as group_slug FROM external_cfps c INNER JOIN external_events e ON c.event_id=e.id))", prefix = "c", joins = Seq(), fields = Seq( "name", "logo", "begin", "close", "location", "description", "tags", "ext_id", "ext_url", "ext_event_start", "ext_event_finish", "ext_event_url", "ext_tickets_url", "ext_videos_url", "twitter_account", "twitter_hashtag", "int_slug", "group_id", "group_slug").map(Field(_, "c")), aggFields = Seq(), customFields = Seq(), sorts = Sorts("close", "close date", Field("close", "c"), Field("name", "c")), search = Seq("name", "description", "tags").map(Field(_, "c")), filters = Seq()) private[sql] def insert(e: ExternalCfp): Insert[ExternalCfp] = { val values = fr0"${e.id}, ${e.event}, ${e.description}, ${e.begin}, ${e.close}, ${e.url}, ${e.info.createdAt}, ${e.info.createdBy}, ${e.info.updatedAt}, ${e.info.updatedBy}" table.insert[ExternalCfp](e, _ => values) } private[sql] def update(id: ExternalCfp.Id)(e: ExternalCfp.Data, by: User.Id, now: Instant): Update = { val fields = fr0"description=${e.description}, begin=${e.begin}, close=${e.close}, url=${e.url}, updated_at=$now, updated_by=$by" table.update(fields, fr0"WHERE id=$id") } private[sql] def selectAllIds(): Select[ExternalCfp.Id] = table.select[ExternalCfp.Id](Seq(Field("id", "ec"))) private[sql] def selectAll(id: ExternalEvent.Id): Select[ExternalCfp] = table.select[ExternalCfp](fr0"WHERE ec.event_id=$id") private[sql] def selectOneFull(id: ExternalCfp.Id): Select[ExternalCfp.Full] = tableFull.selectOne[ExternalCfp.Full](fr0"WHERE ec.id=$id") private[sql] def selectOneCommon(slug: Cfp.Slug): Select[CommonCfp] = commonTable.selectOne[CommonCfp](fr0"WHERE c.slug=$slug") private[sql] def selectOneCommon(id: ExternalCfp.Id): Select[CommonCfp] = commonTable.selectOne[CommonCfp](fr0"WHERE c.id=$id") private[sql] def selectCommonPageIncoming(params: Page.Params)(implicit ctx: UserAwareCtx): SelectPage[CommonCfp, UserAwareCtx] = commonTable.selectPage[CommonCfp, UserAwareCtx](params, fr0"WHERE (c.close IS NULL OR c.close >= ${ctx.now})") private[sql] def selectDuplicatesFull(p: ExternalCfp.DuplicateParams): Select[ExternalCfp.Full] = { val filters = Seq( p.cfpUrl.map(v => fr0"ec.url LIKE ${"%" + v + "%"}"), p.cfpEndDate.map(v => fr0"ec.close=$v") ).flatten if (filters.isEmpty) { tableFull.select[ExternalCfp.Full](fr0"WHERE ec.id='no-match'") } else { tableFull.select[ExternalCfp.Full](fr0"WHERE " ++ filters.reduce(_ ++ fr0" OR " ++ _)) } } }
Example 55
Source File: ExternalEventRepoSql.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.infra.services.storage.sql import java.time.Instant import cats.effect.IO import doobie.implicits._ import gospeak.core.domain.utils.{Info, UserAwareCtx, UserCtx} import gospeak.core.domain.{CommonEvent, Event, ExternalEvent, User} import gospeak.core.services.storage.ExternalEventRepo import gospeak.infra.services.storage.sql.ExternalEventRepoSql._ import gospeak.infra.services.storage.sql.utils.DoobieUtils.Mappings._ import gospeak.infra.services.storage.sql.utils.DoobieUtils._ import gospeak.infra.services.storage.sql.utils.{GenericQuery, GenericRepo} import gospeak.libs.scala.domain.{Done, Logo, Page, Tag} class ExternalEventRepoSql(protected[sql] val xa: doobie.Transactor[IO]) extends GenericRepo with ExternalEventRepo { override def create(data: ExternalEvent.Data)(implicit ctx: UserCtx): IO[ExternalEvent] = insert(ExternalEvent(data, Info(ctx.user.id, ctx.now))).run(xa) override def edit(id: ExternalEvent.Id)(data: ExternalEvent.Data)(implicit ctx: UserCtx): IO[Done] = update(id)(data, ctx.user.id, ctx.now).run(xa) override def listAllIds()(implicit ctx: UserAwareCtx): IO[Seq[ExternalEvent.Id]] = selectAllIds().runList(xa) override def list(params: Page.Params)(implicit ctx: UserCtx): IO[Page[ExternalEvent]] = selectPage(params).run(xa) override def listCommon(params: Page.Params)(implicit ctx: UserAwareCtx): IO[Page[CommonEvent]] = selectPageCommon(params).run(xa) override def find(id: ExternalEvent.Id): IO[Option[ExternalEvent]] = selectOne(id).runOption(xa) override def listTags(): IO[Seq[Tag]] = selectTags().runList(xa).map(_.flatten.distinct) override def listLogos(): IO[Seq[Logo]] = selectLogos().runList(xa).map(_.flatten.distinct) } object ExternalEventRepoSql { import GenericQuery._ private val _ = externalEventIdMeta // for intellij not remove DoobieUtils.Mappings import val table: Table = Tables.externalEvents.copy(filters = Seq( Filter.Enum.fromEnum("type", "Type", "ee.kind", Seq( "conference" -> Event.Kind.Conference.value, "meetup" -> Event.Kind.Meetup.value, "training" -> Event.Kind.Training.value, "private event" -> Event.Kind.PrivateEvent.value)), Filter.Bool.fromNullable("video", "With video", "ee.videos_url"))) private val tableSelect = table.dropFields(_.name.startsWith("location_")) val commonTable: Table = Table( name = "((SELECT e.name, e.kind, e.start, v.address as location, g.social_twitter as twitter_account, null as twitter_hashtag, e.tags, null as ext_id, null as ext_logo, null as ext_description, null as ext_url, null as ext_tickets, null as ext_videos, e.id as int_id, e.slug as int_slug, e.description as int_description, g.id as int_group_id, g.slug as int_group_slug, g.name as int_group_name, g.logo as int_group_logo, c.id as int_cfp_id, c.slug as int_cfp_slug, c.name as int_cfp_name, v.id as int_venue_id, p.name as int_venue_name, p.logo as int_venue_logo, e.created_at, e.created_by, e.updated_at, e.updated_by FROM events e INNER JOIN groups g ON e.group_id=g.id LEFT OUTER JOIN cfps c ON e.cfp_id=c.id LEFT OUTER JOIN venues v ON e.venue=v.id LEFT OUTER JOIN partners p ON v.partner_id=p.id WHERE e.published IS NOT NULL) " + "UNION (SELECT e.name, e.kind, e.start, e.location, e.twitter_account, e.twitter_hashtag, e.tags, e.id as ext_id, e.logo as ext_logo, e.description as ext_description, e.url as ext_url, e.tickets_url as ext_tickets, e.videos_url as ext_videos, null as int_id, null as int_slug, null as int_description, null as int_group_id, null as int_group_slug, null as int_group_name, null as int_group_logo, null as int_cfp_id, null as int_cfp_slug, null as int_cfp_name, null as int_venue_id, null as int_venue_name, null as int_venue_logo, e.created_at, e.created_by, e.updated_at, e.updated_by FROM external_events e))", prefix = "e", joins = Seq(), fields = Seq( "name", "kind", "start", "location", "twitter_account", "twitter_hashtag", "tags", "ext_id", "ext_logo", "ext_description", "ext_url", "ext_tickets", "ext_videos", "int_id", "int_slug", "int_description", "int_group_id", "int_group_slug", "int_group_name", "int_group_logo", "int_cfp_id", "int_cfp_slug", "int_cfp_name", "int_venue_id", "int_venue_name", "int_venue_logo", "created_at", "created_by", "updated_at", "updated_by").map(Field(_, "e")), aggFields = Seq(), customFields = Seq(), sorts = Sorts("start", Field("-start", "e"), Field("-created_at", "e")), search = Seq("name", "kind", "location", "twitter_account", "tags", "int_group_name", "int_cfp_name", "int_description", "ext_description").map(Field(_, "e")), filters = Seq( Filter.Enum.fromEnum("type", "Type", "e.kind", Seq( "conference" -> Event.Kind.Conference.value, "meetup" -> Event.Kind.Meetup.value, "training" -> Event.Kind.Training.value, "private event" -> Event.Kind.PrivateEvent.value)), Filter.Bool.fromNullable("video", "With video", "e.ext_videos"), Filter.Bool("past", "Is past", aggregation = false, ctx => fr0"e.start < ${ctx.now}", ctx => fr0"e.start > ${ctx.now}"))) private[sql] def insert(e: ExternalEvent): Insert[ExternalEvent] = { val values = fr0"${e.id}, ${e.name}, ${e.kind}, ${e.logo}, ${e.description}, ${e.start}, ${e.finish}, " ++ insertLocation(e.location) ++ fr0", ${e.url}, ${e.tickets}, ${e.videos}, ${e.twitterAccount}, ${e.twitterHashtag}, ${e.tags}, " ++ insertInfo(e.info) table.insert[ExternalEvent](e, _ => values) } private[sql] def update(id: ExternalEvent.Id)(e: ExternalEvent.Data, by: User.Id, now: Instant): Update = { val fields = fr0"name=${e.name}, kind=${e.kind}, logo=${e.logo}, description=${e.description}, start=${e.start}, finish=${e.finish}, " ++ updateLocation(e.location) ++ fr0", url=${e.url}, tickets_url=${e.tickets}, videos_url=${e.videos}, twitter_account=${e.twitterAccount}, twitter_hashtag=${e.twitterHashtag}, tags=${e.tags}, updated_at=$now, updated_by=$by" table.update(fields, fr0"WHERE id=$id") } private[sql] def selectOne(id: ExternalEvent.Id): Select[ExternalEvent] = tableSelect.selectOne[ExternalEvent](fr0"WHERE ee.id=$id") private[sql] def selectAllIds()(implicit ctx: UserAwareCtx): Select[ExternalEvent.Id] = table.select[ExternalEvent.Id](Seq(Field("id", "ee"))) private[sql] def selectPage(params: Page.Params)(implicit ctx: UserCtx): SelectPage[ExternalEvent, UserCtx] = tableSelect.selectPage[ExternalEvent, UserCtx](params) private[sql] def selectPageCommon(params: Page.Params)(implicit ctx: UserAwareCtx): SelectPage[CommonEvent, UserAwareCtx] = commonTable.selectPage[CommonEvent, UserAwareCtx](params) private[sql] def selectTags(): Select[Seq[Tag]] = table.select[Seq[Tag]](Seq(Field("tags", "ee"))) private[sql] def selectLogos(): Select[Option[Logo]] = table.select[Option[Logo]](Seq(Field("logo", "ee")), fr0"WHERE ee.logo IS NOT NULL") }
Example 56
Source File: SponsorPackRepoSql.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.infra.services.storage.sql import java.time.Instant import cats.data.NonEmptyList import cats.effect.IO import doobie.Fragments import doobie.implicits._ import doobie.util.fragment.Fragment import gospeak.core.domain.utils.OrgaCtx import gospeak.core.domain.{Group, SponsorPack, User} import gospeak.core.services.storage.SponsorPackRepo import gospeak.infra.services.storage.sql.SponsorPackRepoSql._ import gospeak.infra.services.storage.sql.utils.DoobieUtils.Mappings._ import gospeak.infra.services.storage.sql.utils.DoobieUtils.{Insert, Select, Update} import gospeak.infra.services.storage.sql.utils.GenericRepo import gospeak.libs.scala.domain.{CustomException, Done} class SponsorPackRepoSql(protected[sql] val xa: doobie.Transactor[IO]) extends GenericRepo with SponsorPackRepo { override def create(data: SponsorPack.Data)(implicit ctx: OrgaCtx): IO[SponsorPack] = insert(SponsorPack(ctx.group.id, data, ctx.info)).run(xa) override def edit(pack: SponsorPack.Slug, data: SponsorPack.Data)(implicit ctx: OrgaCtx): IO[Done] = { if (data.slug != pack) { find(data.slug).flatMap { case None => update(ctx.group.id, pack)(data, ctx.user.id, ctx.now).run(xa) case _ => IO.raiseError(CustomException(s"You already have a sponsor pack with slug ${data.slug}")) } } else { update(ctx.group.id, pack)(data, ctx.user.id, ctx.now).run(xa) } } override def disable(pack: SponsorPack.Slug)(implicit ctx: OrgaCtx): IO[Done] = setActive(ctx.group.id, pack)(active = false, ctx.user.id, ctx.now).run(xa) override def enable(pack: SponsorPack.Slug)(implicit ctx: OrgaCtx): IO[Done] = setActive(ctx.group.id, pack)(active = true, ctx.user.id, ctx.now).run(xa) override def find(pack: SponsorPack.Slug)(implicit ctx: OrgaCtx): IO[Option[SponsorPack]] = selectOne(ctx.group.id, pack).runOption(xa) override def listAll(group: Group.Id): IO[Seq[SponsorPack]] = selectAll(group).runList(xa) override def listAll(implicit ctx: OrgaCtx): IO[Seq[SponsorPack]] = selectAll(ctx.group.id).runList(xa) override def listActives(group: Group.Id): IO[Seq[SponsorPack]] = selectActives(group).runList(xa) override def listActives(implicit ctx: OrgaCtx): IO[Seq[SponsorPack]] = selectActives(ctx.group.id).runList(xa) } object SponsorPackRepoSql { private val _ = sponsorPackIdMeta // for intellij not remove DoobieUtils.Mappings import private val table = Tables.sponsorPacks private[sql] def insert(e: SponsorPack): Insert[SponsorPack] = { val values = fr0"${e.id}, ${e.group}, ${e.slug}, ${e.name}, ${e.description}, ${e.price.amount}, ${e.price.currency}, ${e.duration}, ${e.active}, ${e.info.createdAt}, ${e.info.createdBy}, ${e.info.updatedAt}, ${e.info.updatedBy}" table.insert(e, _ => values) } private[sql] def update(group: Group.Id, pack: SponsorPack.Slug)(data: SponsorPack.Data, by: User.Id, now: Instant): Update = { val fields = fr0"slug=${data.slug}, name=${data.name}, description=${data.description}, price=${data.price.amount}, currency=${data.price.currency}, duration=${data.duration}, updated_at=$now, updated_by=$by" table.update(fields, where(group, pack)) } private[sql] def setActive(group: Group.Id, pack: SponsorPack.Slug)(active: Boolean, by: User.Id, now: Instant): Update = table.update(fr0"active=$active, updated_at=$now, updated_by=$by", where(group, pack)) private[sql] def selectOne(group: Group.Id, pack: SponsorPack.Slug): Select[SponsorPack] = table.select[SponsorPack](where(group, pack)) private[sql] def selectAll(ids: NonEmptyList[SponsorPack.Id]): Select[SponsorPack] = table.select[SponsorPack](fr0"WHERE " ++ Fragments.in(fr"sp.id", ids)) private[sql] def selectAll(group: Group.Id): Select[SponsorPack] = table.select[SponsorPack](where(group)) private[sql] def selectActives(group: Group.Id): Select[SponsorPack] = { val active = true table.select[SponsorPack](where(group) ++ fr0" AND sp.active=$active") } private def where(group: Group.Id, slug: SponsorPack.Slug): Fragment = fr0"WHERE sp.group_id=$group AND sp.slug=$slug" private def where(group: Group.Id): Fragment = fr0"WHERE sp.group_id=$group" }
Example 57
Source File: VideoSrvImpl.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.infra.services.video import cats.effect.IO import gospeak.core.domain.Video import gospeak.core.domain.Video.PlaylistRef import gospeak.core.services.video.{VideoSrv, YoutubeConf} import gospeak.libs.scala.Cache import gospeak.libs.scala.Extensions._ import gospeak.libs.scala.domain.{CustomException, Url} import gospeak.libs.youtube.YoutubeClient import gospeak.libs.youtube.domain.{YoutubeErrors, YoutubePlaylist} import scala.util.Try class VideoSrvImpl(youtubeOpt: Option[YoutubeClient]) extends VideoSrv { private val getChannelIdCache: Url.Videos.Channel => IO[Url.Videos.Channel.Id] = Cache.memoizeIO { case u: Url.YouTube.Channel => withYoutube(_.getChannelId(u).flatMap(formatError)) case _: Url.Vimeo.Channel => withVimeo() } override val youtube: Boolean = youtubeOpt.isDefined override val vimeo: Boolean = false override val infoq: Boolean = false override def getChannelId(url: Url.Videos.Channel): IO[Url.Videos.Channel.Id] = getChannelIdCache(url) override def listVideos(url: Url.Videos): IO[List[Video.Data]] = url match { case u: Url.YouTube.Channel => withYoutube(c => c.getChannelId(u).flatMap(formatError).flatMap(id => listYoutubeChannelVideos(c, id))) case u: Url.YouTube.Playlist => withYoutube(c => c.getPlaylist(u).flatMap(formatError).flatMap(p => listYoutubePlaylistVideos(c, p))) case _: Url.Vimeo.Channel => withVimeo() case _: Url.Vimeo.Showcase => withVimeo() case _: Url.Infoq.Topic => withInfoq() } private def listYoutubeChannelVideos(client: YoutubeClient, channelId: Url.Videos.Channel.Id, pageToken: String = ""): IO[List[Video.Data]] = for { page <- client.listChannelVideos(channelId, pageToken).flatMap(formatError) videos <- getYoutubeVideoDetails(page.items.map(_.id), None)(client) allPages <- page.nextPageToken.map(listYoutubeChannelVideos(client, channelId, _).map(nextPage => videos ++ nextPage)).getOrElse(IO.pure(videos)) } yield allPages private def listYoutubePlaylistVideos(client: YoutubeClient, playlist: YoutubePlaylist, pageToken: String = ""): IO[List[Video.Data]] = for { videoPage <- client.listPlaylistVideos(playlist.id, pageToken).flatMap(formatError) videoDetails <- getYoutubeVideoDetails(videoPage.items.map(_.id), Some(playlist))(client) allPages <- videoPage.nextPageToken.map(listYoutubePlaylistVideos(client, playlist, _).map(nextPage => videoDetails ++ nextPage)).getOrElse(IO.pure(videoDetails)) } yield allPages private def getYoutubeVideoDetails(videoIds: Seq[Url.Video.Id], playlist: Option[YoutubePlaylist])(client: YoutubeClient): IO[List[Video.Data]] = client.getVideoDetails(videoIds).flatMap(formatError).map(_.map(Video.Data.from(_, playlist.map(p => PlaylistRef(p.id, p.title)))).sequence).flatMap(_.toIO) private def formatError[A](errors: Either[YoutubeErrors, A]): IO[A] = errors.toIO(e => CustomException(s"YouTube error ${e.code}: ${e.message.getOrElse("")}" + e.errors.map("\n" + _).mkString)) private def withYoutube[T](f: YoutubeClient => IO[T]): IO[T] = youtubeOpt.map(f).getOrElse(IO.raiseError(CustomException("YoutubeClient not available"))) private def withVimeo[T](): IO[T] = IO.raiseError(CustomException("VimeoClient not available")) private def withInfoq[T](): IO[T] = IO.raiseError(CustomException("InfoqClient not available")) } object VideoSrvImpl { def from(appName: String, youtubeConf: YoutubeConf): Try[VideoSrvImpl] = for { youtubeClient <- youtubeConf.secret.map(YoutubeClient.create(_, appName)).sequence } yield new VideoSrvImpl(youtubeClient) }
Example 58
Source File: CloudinaryClient.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.libs.cloudinary import java.time.Instant import cats.effect.IO import gospeak.libs.cloudinary.CloudinaryJson._ import gospeak.libs.cloudinary.domain.{CloudinaryUploadRequest, CloudinaryUploadResponse} import gospeak.libs.http.HttpClient import gospeak.libs.scala.Crypto import gospeak.libs.scala.Extensions._ import gospeak.libs.scala.domain.Creds import io.circe.parser.decode class CloudinaryClient(conf: CloudinaryClient.Conf) { private val baseUrl = "https://api.cloudinary.com/v1_1" private val ignoreOnSign = Set("api_key", "file") // see https://cloudinary.com/documentation/upload_images#generating_authentication_signatures def sign(params: Map[String, String]): Either[String, String] = withCreds((_, creds) => sign(creds, params)) // see https://cloudinary.com/documentation/upload_images#uploading_with_a_direct_call_to_the_api def upload(req: CloudinaryUploadRequest): IO[Either[String, CloudinaryUploadResponse]] = { withCreds { (cloudName, creds) => val uploadUrl = s"$baseUrl/$cloudName/image/upload" val allParams = req.toMap ++ Map( "api_key" -> creds.key, "timestamp" -> Instant.now().getEpochSecond.toString) val signature = sign(creds, allParams) HttpClient.postForm(uploadUrl, allParams ++ Map("signature" -> signature)) .map(r => decode[CloudinaryUploadResponse](r.body).leftMap(_.getMessage)) }.sequence.map(_.flatMap(identity)) } private def sign(creds: Creds, queryParams: Map[String, String]): String = { val params = queryParams .filterKeys(!ignoreOnSign.contains(_)) .toList.sortBy(_._1) .map { case (key, value) => s"$key=$value" }.mkString("&") Crypto.sha1(params + creds.secret.decode) } private def withCreds[A](block: (String, Creds) => A): Either[String, A] = conf match { case CloudinaryClient.Conf(cloudName, _, Some(creds)) => Right(block(cloudName, creds)) case _: CloudinaryClient.Conf => Left("No credentials defined for cloudinary") } } object CloudinaryClient { final case class Conf(cloudName: String, uploadPreset: Option[String], creds: Option[Creds]) }
Example 59
Source File: SlackClient.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.libs.slack import cats.effect.IO import gospeak.libs.slack.SlackJson._ import gospeak.libs.slack.domain._ import gospeak.libs.http.HttpClient import gospeak.libs.http.HttpClient.Response import io.circe.Decoder import io.circe.parser._ // SlackClient should not depend on core module, it's an independent lib // scala lib: https://github.com/slack-scala-client/slack-scala-client class SlackClient { private val baseUrl = "https://slack.com/api" // cf https://api.slack.com/methods/auth.test def info(token: SlackToken): IO[Either[SlackError, SlackTokenInfo]] = HttpClient.get(s"$baseUrl/auth.test", query = Map("token" -> token.value)) .flatMap(parse[SlackTokenInfo]) // cf https://api.slack.com/methods/channels.create def createChannel(token: SlackToken, name: SlackChannel.Name): IO[Either[SlackError, SlackChannel]] = HttpClient.get(s"$baseUrl/channels.create", query = Map( "token" -> token.value, "name" -> name.value )).flatMap(parse[SlackChannel.Single]).map(_.map(_.channel)) // cf https://api.slack.com/methods/channels.invite def inviteToChannel(token: SlackToken, channel: SlackChannel.Id, user: SlackUser.Id): IO[Either[SlackError, SlackChannel]] = HttpClient.get(s"$baseUrl/channels.invite", query = Map( "token" -> token.value, "channel" -> channel.value, "user" -> user.value )).flatMap(parse[SlackChannel.Single]).map(_.map(_.channel)) // cf https://api.slack.com/methods/channels.list def listChannels(token: SlackToken): IO[Either[SlackError, Seq[SlackChannel]]] = HttpClient.get(s"$baseUrl/channels.list", query = Map("token" -> token.value)) .flatMap(parse[SlackChannel.List]).map(_.map(_.channels)) // cf https://api.slack.com/methods/users.list def listUsers(token: SlackToken): IO[Either[SlackError, Seq[SlackUser]]] = HttpClient.get(s"$baseUrl/users.list", query = Map("token" -> token.value)) .flatMap(parse[SlackUser.List]).map(_.map(_.members)) // cf https://api.slack.com/methods/chat.postMessage def postMessage(token: SlackToken, sender: SlackSender, channel: SlackChannel.Ref, msg: SlackContent): IO[Either[SlackError, SlackMessage]] = HttpClient.get(s"$baseUrl/chat.postMessage", query = sender.toOpts ++ msg.toOpts ++ Map( "token" -> token.value, "channel" -> channel.value )).flatMap(parse[SlackMessage.Posted]).map(_.map(_.message)) private def parse[A](res: Response)(implicit d: Decoder[A]): IO[Either[SlackError, A]] = { decode[A](res.body) match { case Right(info) => IO.pure(Right(info)) case Left(err) => decode[SlackError](res.body) match { case Right(fail) => IO.pure(Left(fail)) case Left(_) => IO.raiseError(err) } } } }
Example 60
Source File: HttpClient.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.libs.http import java.net.URLEncoder import java.nio.charset.StandardCharsets import cats.effect.IO import gospeak.libs.scala.domain.CustomException import hammock.apache.ApacheInterpreter import hammock.{Encoder, Entity, Hammock, HttpResponse, InterpTrans, Method, Uri} object HttpClient { final case class Request(url: String, query: Map[String, String] = Map(), headers: Map[String, String] = Map()) final case class Response(status: Int, body: String, headers: Map[String, String]) { def isOk: Boolean = 200 <= status && status < 400 } object Response { def from(res: HttpResponse): Response = Response( status = res.status.code, headers = res.headers, body = res.entity match { case Entity.EmptyEntity => "" case e: Entity.StringEntity => e.body case e: Entity.ByteArrayEntity => new String(e.body, StandardCharsets.UTF_8) }) } private implicit val interpreter: InterpTrans[IO] = ApacheInterpreter.instance[IO] private implicit val stringEncoder: Encoder[String] = (value: String) => Entity.StringEntity(value) def get(url: String, query: Map[String, String] = Map(), headers: Map[String, String] = Map()): IO[Response] = buildUri(url, query)(request(Method.GET, _, headers)) def postJson(url: String, body: String, query: Map[String, String] = Map(), headers: Map[String, String] = Map()): IO[Response] = sendJson(method = Method.POST, url = url, body = body, query = query, headers = headers) def putJson(url: String, body: String, query: Map[String, String] = Map(), headers: Map[String, String] = Map()): IO[Response] = sendJson(method = Method.PUT, url = url, body = body, query = query, headers = headers) def patchJson(url: String, body: String, query: Map[String, String] = Map(), headers: Map[String, String] = Map()): IO[Response] = sendJson(method = Method.PATCH, url = url, body = body, query = query, headers = headers) def deleteJson(url: String, body: String, query: Map[String, String] = Map(), headers: Map[String, String] = Map()): IO[Response] = sendJson(method = Method.DELETE, url = url, body = body, query = query, headers = headers) def postForm(url: String, body: Map[String, String], query: Map[String, String] = Map(), headers: Map[String, String] = Map()): IO[Response] = sendForm(method = Method.POST, url = url, body = body, query = query, headers = headers) def putForm(url: String, body: Map[String, String], query: Map[String, String] = Map(), headers: Map[String, String] = Map()): IO[Response] = sendForm(method = Method.PUT, url = url, body = body, query = query, headers = headers) def patchForm(url: String, body: Map[String, String], query: Map[String, String] = Map(), headers: Map[String, String] = Map()): IO[Response] = sendForm(method = Method.PATCH, url = url, body = body, query = query, headers = headers) def deleteForm(url: String, body: Map[String, String], query: Map[String, String] = Map(), headers: Map[String, String] = Map()): IO[Response] = sendForm(method = Method.DELETE, url = url, body = body, query = query, headers = headers) private def sendJson(method: Method, url: String, body: String, query: Map[String, String] = Map(), headers: Map[String, String] = Map()): IO[Response] = buildUri(url, query)(request(method, _, headers + ("Content-Type" -> "application/json"), Some(body))) private def sendForm(method: Method, url: String, body: Map[String, String], query: Map[String, String], headers: Map[String, String]): IO[Response] = buildUri(url, query)(request(method, _, headers + ("Content-Type" -> "application/x-www-form-urlencoded"), Some(buildParams(body)))) private def buildUri(url: String, query: Map[String, String])(callback: Uri => IO[Response]): IO[Response] = Uri.fromString(buildUrl(url, query)).map(callback).getOrElse(IO.raiseError(CustomException(s"Invalid URI '${buildUrl(url, query)}'"))) private def request(method: Method, uri: Uri, headers: Map[String, String], body: Option[String] = None): IO[Response] = { // def requestInfo: String = s"HttpClient.$method ${uri.path}\n headers: $headers" + body.map(b => s"\n body: $b").getOrElse("") Hammock.request(method, uri, headers, body).exec[IO].map(Response.from) // .map { r => println(s"\n$requestInfo\n response: ${r.status} ${r.body}"); r } // .recoverWith { case e => println(s"\n$requestInfo\n response: ${e.getClass.getSimpleName}: ${e.getMessage}"); IO.raiseError(e) } } def buildUrl(url: String, query: Map[String, String]): String = { if (query.isEmpty) { url } else if (url.contains("?")) { url + "&" + buildParams(query) } else { url + "?" + buildParams(query) } } private def buildParams(params: Map[String, String]): String = params.map { case (key, value) => s"$key=${URLEncoder.encode(value, "UTF8")}" }.mkString("&") }
Example 61
Source File: MessageBus.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.libs.scala import cats.effect.IO import Extensions._ import scala.collection.mutable import scala.reflect.ClassTag trait MessageBus[A] { def subscribe[B <: A : ClassTag](f: B => IO[Unit]) // not used // like subscribe but with a partial function // def when[B <: A : ClassTag](pf: PartialFunction[B, IO[Unit]]): Unit // returns the number of called subscribers def publish[B <: A](msg: B): IO[Int] // not used // like 'publish' with 'msg' param lazy evaluated but will call only T handlers, not 'msg' concrete type handlers // def publishLazy[B <: A : ClassTag](msg: => B): IO[Int] } class BasicMessageBus[A] extends MessageBus[A] { private val eventHandlers = mutable.Map[Class[_], List[_ => IO[Unit]]]() override def subscribe[B <: A : ClassTag](f: B => IO[Unit]): Unit = { val key = implicitly[ClassTag[B]].runtimeClass eventHandlers.put(key, eventHandlers.getOrElse(key, Nil) :+ f) } private def getClasses(clazz: Class[_]): List[Class[_]] = { val parents = Option(clazz.getSuperclass).toList ++ clazz.getInterfaces.toList clazz :: parents.flatMap(getClasses) } }
Example 62
Source File: MessageBusSpec.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.libs.scala import cats.effect.IO import gospeak.libs.scala.MessageBusSpec._ import gospeak.libs.testingutils.BaseSpec class MessageBusSpec extends BaseSpec { describe("MessageBus") { it("should be specialized for a message type") { val mb = create[MyEvents]() mb.publish(Event1("a")) // mb.publish(Message("a")) // should not compile } describe("subscribe") { it("should register a handler based on message type") { val mb = create[Any]() var tmp = "" mb.subscribe[Event1](e => IO { tmp = e.msg }) mb.publish(Event1("a")).unsafeRunSync() shouldBe 1 tmp shouldBe "a" mb.publish(Msg("b")).unsafeRunSync() shouldBe 0 tmp shouldBe "a" mb.publish(Event1("c")).unsafeRunSync() shouldBe 1 tmp shouldBe "c" } it("should work with parent types") { val mb = create[Any]() var tmp = "" mb.subscribe[MyEvents] { case e: Event1 => IO { tmp = e.msg } case e: Event2 => IO { tmp = e.count.toString } } mb.publish(Event1("a")).unsafeRunSync() shouldBe 1 tmp shouldBe "a" mb.publish(Event2(2)).unsafeRunSync() shouldBe 1 tmp shouldBe "2" mb.publish(Event1("c"): MyEvents).unsafeRunSync() shouldBe 1 tmp shouldBe "c" } } } } object MessageBusSpec { sealed trait MyEvents case class Event1(msg: String) extends MyEvents case class Event2(count: Int) extends MyEvents case class Msg(info: String) def create[A](): MessageBus[A] = { new BasicMessageBus[A] } }
Example 63
Source File: CacheSpec.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.libs.scala import cats.effect.IO import gospeak.libs.testingutils.BaseSpec class CacheSpec extends BaseSpec { describe("Cache") { describe("memoize") { it("should compute value once") { var call = 0 val mem = Cache.memoize((n: Int) => { call += 1 n.toString }) mem(1) shouldBe "1" call shouldBe 1 mem(2) shouldBe "2" call shouldBe 2 mem(1) shouldBe "1" call shouldBe 2 } } describe("memoizeIO") { it("should compute value once") { var call = 0 val mem = Cache.memoizeIO((n: Int) => { call += 1 IO.pure(n.toString) }) mem(1).unsafeRunSync() shouldBe "1" call shouldBe 1 mem(2).unsafeRunSync() shouldBe "2" call shouldBe 2 mem(1).unsafeRunSync() shouldBe "1" call shouldBe 2 } } } }
Example 64
Source File: EmailSrv.scala From gospeak with Apache License 2.0 | 5 votes |
package gospeak.core.services.email import cats.effect.IO import gospeak.core.services.email.EmailSrv.Email import gospeak.libs.scala.domain.Done import gospeak.libs.scala.domain.EmailAddress.Contact trait EmailSrv { def send(email: Email): IO[Done] } object EmailSrv { final case class Email(from: Contact, to: Seq[Contact], subject: String, content: Content) sealed trait Content { def value: String } final case class TextContent(text: String) extends Content { override def value: String = text } final case class HtmlContent(html: String) extends Content { override def value: String = html } }
Example 65
Source File: InternalSpec.scala From fs2-aws with MIT License | 5 votes |
package fs2.aws.core import cats.effect.{ ContextShift, IO } import fs2.Stream import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import scala.concurrent.ExecutionContext class InternalSpec extends AnyFlatSpec with Matchers { implicit val ec: ExecutionContext = ExecutionContext.global implicit val ioContextShift: ContextShift[IO] = IO.contextShift(ec) "groupBy" should "create K substreams based on K selector outputs" in { val k = 30 val streams = Stream .emits(1 to 100000) .through(groupBy(i => IO(i % k))) .compile .toVector .unsafeRunSync streams.size shouldBe k } it should "split stream elements into respective substreams" in { val streams = Stream .emits(1 to 10) .through(groupBy(i => IO(i % 2))) .compile .toVector .unsafeRunSync streams.filter(_._1 == 0).head._2.compile.toVector.unsafeRunSync shouldBe List(2, 4, 6, 8, 10) streams.filter(_._1 == 1).head._2.compile.toVector.unsafeRunSync shouldBe List(1, 3, 5, 7, 9) } it should "fail on exception" in { val streams = Stream .emits(1 to 10) .through(groupBy(i => IO(throw new Exception()))) .attempt .compile .toVector .unsafeRunSync streams.size shouldBe 1 streams.head.isLeft shouldBe true } }
Example 66
Source File: DynamoDBStreamer.scala From fs2-aws with MIT License | 5 votes |
import cats.effect.{ ExitCode, IO, IOApp } import fs2.aws.dynamodb import fs2.aws.dynamodb.parsers import io.chrisdavenport.log4cats.SelfAwareStructuredLogger import io.chrisdavenport.log4cats.slf4j.Slf4jLogger import io.circe.Json import io.github.howardjohn.scanamo.CirceDynamoFormat._ object DynamoDBStreamer extends IOApp { override def run(args: List[String]): IO[ExitCode] = for { implicit0(logger: SelfAwareStructuredLogger[IO]) <- Slf4jLogger.fromName[IO]("example") _ <- dynamodb .readFromDynamDBStream[IO]( "dynamo_db_example", "arn:aws:dynamodb:us-east-1:023006903388:table/nightly-sync-events-Production/stream/2020-01-27T22:49:13.204" ) .evalMap(cr => parsers.parseDynamoEvent[IO, Json](cr.record)) .evalTap(msg => logger.info(s"received $msg")) .compile .drain } yield ExitCode.Success }
Example 67
Source File: CirisDecoderSpec.scala From fs2-aws with MIT License | 5 votes |
package fs2.aws.ciris; import java.util.Date import cats.effect.{ ContextShift, IO } import ciris.{ ConfigException, ConfigValue } import org.scalatest.Assertion import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec import software.amazon.kinesis.common.InitialPositionInStream import scala.concurrent.ExecutionContext.Implicits.global; class CirisDecoderSpec extends AnyWordSpec with Matchers { implicit val cs: ContextShift[IO] = IO.contextShift(global) "InitialPositionDecoderSpec" should { "when decoding Either[InitialPositionInStream, Date]" can { // same package, so `import fs2.aws.ciris._` not necessary here def decode(testStr: String): Either[InitialPositionInStream, Date] = ConfigValue .default(testStr) .as[Either[InitialPositionInStream, Date]] .load[IO] .unsafeRunSync() def expectDecodeFailure(testString: String): Assertion = intercept[ConfigException] { decode(testString) }.getMessage should include( s"Unable to convert value $testString to InitialPositionInStream" ) "decode supported strings as initial offsets" in { decode("LATEST") should equal(Left(InitialPositionInStream.LATEST)) decode("TRIM_HORIZON") should equal(Left(InitialPositionInStream.TRIM_HORIZON)) decode("TS_1592404273000") should equal(Right(new Date(1592404273000L))) } "fail to decode valid strings" in { expectDecodeFailure("FOOBAR") expectDecodeFailure("TS_FOO") expectDecodeFailure("TS_") expectDecodeFailure("_1592404273000") } } } }
Example 68
Source File: package.scala From fs2-aws with MIT License | 5 votes |
package fs2 import cats.effect.concurrent.Deferred import cats.effect.{ ConcurrentEffect, IO } import fs2.aws.sqs.{ ConsumerBuilder, ReceiverCallback, SqsConfig } import fs2.concurrent.Queue import javax.jms.{ Message, MessageListener } package object aws { def sqsStream[F[_], O]( sqsConfig: SqsConfig, builder: (SqsConfig, MessageListener) => ConsumerBuilder[F], d: Option[Deferred[F, MessageListener]] = None )(implicit F: ConcurrentEffect[F], decoder: Message => Either[Throwable, O]): fs2.Stream[F, O] = for { q <- fs2.Stream.eval(Queue.unbounded[F, Either[Throwable, O]]) callback <- fs2.Stream.eval(callback(q)) _ <- fs2.Stream.eval(d.map(_.complete(callback)).getOrElse(F.unit)) item <- builder(sqsConfig, callback).serve(q.dequeue.rethrow) } yield item def callback[F[_], O](queue: Queue[F, Either[Throwable, O]])( implicit F: ConcurrentEffect[F], decoder: Message => Either[Throwable, O] ): F[ReceiverCallback[Either[Throwable, O]]] = F.delay( new ReceiverCallback[Either[Throwable, O]](r => F.runAsync(queue.enqueue1(r))(_ => IO.unit).unsafeRunSync() ) ) }
Example 69
Source File: SqsSpec.scala From fs2-aws with MIT License | 5 votes |
package fs2.aws import cats.effect.concurrent.Deferred import cats.effect.{ ContextShift, IO } import com.amazon.sqs.javamessaging.SQSConnection import com.amazon.sqs.javamessaging.message.SQSTextMessage import eu.timepit.refined.auto._ import fs2.aws import fs2.aws.sqs.{ ConsumerBuilder, SQSConsumer, SqsConfig } import javax.jms.{ Message, MessageListener, TextMessage } import org.mockito.scalatest.MockitoSugar import org.scalatest.flatspec.AsyncFlatSpec import org.scalatest.matchers.should.Matchers import scala.concurrent.ExecutionContext class SqsSpec extends AsyncFlatSpec with Matchers with MockitoSugar { implicit val ec: ExecutionContext = ExecutionContext.global implicit val ioContextShift: ContextShift[IO] = IO.contextShift(ec) implicit val messageDecoder: Message => Either[Throwable, Int] = { sqs_msg => val text = sqs_msg.asInstanceOf[TextMessage].getText if ("fail" == text) Left(intercept[Exception](())) else Right(text.toInt) } "SQS endpoint" should "stream messages" in { def stream(d: Deferred[IO, MessageListener]) = aws .sqsStream[IO, Int]( SqsConfig("dummy"), (_, listener) => new ConsumerBuilder[IO] { override def start: IO[SQSConsumer] = IO.delay(new SQSConsumer { override def callback: MessageListener = listener override def startConsumer(): Unit = () override def shutdown(): Unit = () override def connection: SQSConnection = mock[SQSConnection] }) }, Some(d) ) .take(4) .compile .toList val r = for { d <- Deferred[IO, MessageListener] res <- IO.racePair(stream(d), d.get).flatMap { case Right((streamFiber, listener)) => listener.onMessage(new SQSTextMessage("1")) listener.onMessage(new SQSTextMessage("2")) listener.onMessage(new SQSTextMessage("fail")) listener.onMessage(new SQSTextMessage("4")) listener.onMessage(new SQSTextMessage("5")) streamFiber.join case _ => IO(Nil) } } yield res val future = r.unsafeToFuture() future.map(_ should be(List(1, 2, 4, 5))) } }
Example 70
Source File: package.scala From fs2-aws with MIT License | 5 votes |
package fs2.aws import java.io._ import cats.effect.{ Effect, IO } import com.amazonaws.SdkClientException import com.amazonaws.services.s3.AmazonS3 import com.amazonaws.services.s3.model.{ AmazonS3Exception, GetObjectRequest, S3ObjectInputStream } import fs2.aws.internal._ import org.apache.http.client.methods.HttpRequestBase import scala.io.Source package object utils { val s3TestClient: S3Client[IO] = new S3Client[IO] { override def client: AmazonS3 = throw new NotImplementedError("s3 client shouldn't be used in this test client") override def getObjectContentOrError( getObjectRequest: GetObjectRequest )(implicit e: Effect[IO]): IO[Either[Throwable, InputStream]] = getObjectRequest match { case goe: GetObjectRequest => { IO[Either[Throwable, ByteArrayInputStream]] { val fileContent: Array[Byte] = try { Source.fromResource(goe.getKey).mkString.getBytes } catch { case _: FileNotFoundException => throw new AmazonS3Exception("File not found") case e: Throwable => throw e } goe.getRange match { case Array(x, y) => if (y > fileContent.length) Right(new ByteArrayInputStream(fileContent.slice(x.toInt, fileContent.length))) else Right(new ByteArrayInputStream(fileContent.slice(x.toInt, y.toInt))) } } map { case Left(e) => Left(e) case Right(is) => Thread.sleep(500) // simulate a call to S3 Right(new S3ObjectInputStream(is, new HttpRequestBase { def getMethod = "" })) } } case _ => throw new SdkClientException("Invalid GetObjectRequest") } override def getObjectContent( getObjectRequest: GetObjectRequest )(implicit e: Effect[IO]): IO[InputStream] = IO[ByteArrayInputStream] { val fileContent: Array[Byte] = try { val testS3Resource = Option(getObjectRequest.getVersionId) match { case Some(version) => s"${getObjectRequest.getKey}_v$version" case None => getObjectRequest.getKey } Source.fromResource(testS3Resource).mkString.getBytes } catch { case _: FileNotFoundException => throw new AmazonS3Exception("File not found") case e: Throwable => throw e } new ByteArrayInputStream(fileContent) }.map { is => Thread.sleep(500) // simulate a call to S3 new S3ObjectInputStream(is, new HttpRequestBase { def getMethod = "" }) } } }
Example 71
Source File: S3Spec.scala From fs2-aws with MIT License | 5 votes |
package fs2 package aws import java.util.concurrent.Executors import cats.effect.{ ContextShift, IO } import com.amazonaws.services.s3.AmazonS3 import fs2.aws.internal.S3Client import fs2.aws.s3._ import org.mockito.MockitoSugar._ import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import scala.concurrent.ExecutionContext class S3Spec extends AnyFlatSpec with Matchers { private val blockingEC = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(6)) implicit val ec: ExecutionContext = ExecutionContext.global implicit val ioContextShift: ContextShift[IO] = IO.contextShift(ec) implicit val s3Client: S3Client[IO] = fs2.aws.utils.s3TestClient val mockS3 = mock[AmazonS3] ignore should "stdout the jsonfile" in { readS3FileMultipart[IO]("resources", "jsontest.json", 25, mockS3).compile.toVector.unsafeRunSync should be( Vector() ) } "Downloading the JSON test file by chunks" should "return the same content" in { readS3FileMultipart[IO]("resources", "jsontest.json", 25, mockS3) .through(fs2.text.utf8Decode) .through(fs2.text.lines) .compile .toVector .unsafeRunSync .reduce(_ + _) .concat("") should be( """{"test": 1}{"test": 2}{"test": 3}{"test": 4}{"test": 5}{"test": 6}{"test": 7}{"test": 8}""" ) } "Downloading the JSON test file" should "return the same content" in { readS3File[IO]("resources", "jsontest.json", blockingEC, mockS3) .through(fs2.text.utf8Decode) .through(fs2.text.lines) .compile .toVector .unsafeRunSync .reduce(_ + _) .concat("") should be( """{"test": 1}{"test": 2}{"test": 3}{"test": 4}{"test": 5}{"test": 6}{"test": 7}{"test": 8}""" ) } "Downloading the versioned JSON test file" should "return the same content" in { readS3VersionedFile[IO]("resources", "jsontest.json", version = "ABC", blockingEC, mockS3) .through(fs2.text.utf8Decode) .through(fs2.text.lines) .compile .toVector .unsafeRunSync .reduce(_ + _) .concat("") should be( """{"this": 1}{"is": 2}{"versioned": 3}{"content": 4}""" ) } "big chunk size but small entire text" should "be trimmed to content" in { readS3FileMultipart[IO]("resources", "jsontest1.json", 25, mockS3) .through(fs2.text.utf8Decode) .through(fs2.text.lines) .compile .toVector .unsafeRunSync .reduce(_ + _) .concat("") should be("""{"test": 1}""") } }
Example 72
Source File: DynamoEventParserSpec.scala From fs2-aws with MIT License | 5 votes |
package fs2.aws.dynamodb.parsers import java.util import cats.effect.IO import com.amazonaws.services.dynamodbv2.model.{ AttributeValue, OperationType, Record, StreamRecord, StreamViewType } import com.amazonaws.services.dynamodbv2.streamsadapter.model.RecordAdapter import io.circe.Json import org.scalatest.wordspec.AnyWordSpec import io.github.howardjohn.scanamo.CirceDynamoFormat._ import org.scalatest.matchers.should.Matchers class DynamoEventParserSpec extends AnyWordSpec with Matchers { "Dynamo Event Parser" should { "parse insert event type" in { val sr = new StreamRecord() sr.setStreamViewType(StreamViewType.NEW_IMAGE) val newImage = new util.HashMap[String, AttributeValue]() newImage.put("name", new AttributeValue().withS("Barry")) sr.setNewImage(newImage) val r = new Record() r.setEventName(OperationType.INSERT) r.withDynamodb(sr) parseDynamoEvent[IO, Json](new RecordAdapter(r)).unsafeRunSync() should be( Insert(Json.obj("name" -> Json.fromString("Barry"))) ) } "parse modify event type" in { val sr = new StreamRecord() sr.setStreamViewType(StreamViewType.NEW_AND_OLD_IMAGES) val oldImage = new util.HashMap[String, AttributeValue]() oldImage.put("name", new AttributeValue().withS("Dmytro")) sr.setOldImage(oldImage) val newImage = new util.HashMap[String, AttributeValue]() newImage.put("name", new AttributeValue().withS("Barry")) sr.setNewImage(newImage) val r = new Record() r.setEventName(OperationType.MODIFY) r.withDynamodb(sr) parseDynamoEvent[IO, Json](new RecordAdapter(r)).unsafeRunSync() should be( Update( Json.obj("name" -> Json.fromString("Dmytro")), Json.obj("name" -> Json.fromString("Barry")) ) ) } "parse delete event type" in { val sr = new StreamRecord() sr.setStreamViewType(StreamViewType.NEW_AND_OLD_IMAGES) val oldImage = new util.HashMap[String, AttributeValue]() oldImage.put("name", new AttributeValue().withS("Dmytro")) sr.setOldImage(oldImage) val r = new Record() r.setEventName(OperationType.REMOVE) r.withDynamodb(sr) parseDynamoEvent[IO, Json](new RecordAdapter(r)).unsafeRunSync() should be( Delete( Json.obj("name" -> Json.fromString("Dmytro")) ) ) } "parse modify event type with NewImage view only as Insert" in { val sr = new StreamRecord() sr.setStreamViewType(StreamViewType.NEW_IMAGE) val newImage = new util.HashMap[String, AttributeValue]() newImage.put("name", new AttributeValue().withS("Barry")) sr.setNewImage(newImage) val r = new Record() r.setEventName(OperationType.MODIFY) r.withDynamodb(sr) parseDynamoEvent[IO, Json](new RecordAdapter(r)).unsafeRunSync() should be( Insert(Json.obj("name" -> Json.fromString("Barry"))) ) } "do not support NEW_IMAGE view type with REMOVE operation type" in { val sr = new StreamRecord() sr.setStreamViewType(StreamViewType.NEW_IMAGE) val oldImage = new util.HashMap[String, AttributeValue]() oldImage.put("name", new AttributeValue().withS("Barry")) sr.setNewImage(oldImage) val r = new Record() r.setEventName(OperationType.REMOVE) r.withDynamodb(sr) parseDynamoEvent[IO, Json](new RecordAdapter(r)).unsafeRunSync() should be( Unsupported("NEW_IMAGE is not supported with REMOVE") ) } } }
Example 73
Source File: CatsHelpers.scala From nelson with Apache License 2.0 | 5 votes |
package nelson import cats.Eval import cats.effect.{Effect, IO, Timer} import cats.free.Cofree import cats.syntax.functor._ import cats.syntax.monadError._ import fs2.{Pipe, Sink, Stream} import quiver.{Context, Decomp, Graph} import java.util.concurrent.TimeoutException import scala.concurrent.ExecutionContext import scala.concurrent.duration.FiniteDuration import scala.collection.immutable.{Stream => SStream} object CatsHelpers { implicit class NelsonEnrichedIO[A](val io: IO[A]) extends AnyVal { private type Tree[A] = Cofree[SStream, A] private def flattenTree[A](tree: Tree[A]): SStream[A] = { def go(tree: Tree[A], xs: SStream[A]): SStream[A] = SStream.cons(tree.head, tree.tail.value.foldRight(xs)(go(_, _))) go(tree, SStream.Empty) } private def Node[A](root: A, forest: => SStream[Tree[A]]): Tree[A] = Cofree[SStream, A](root, Eval.later(forest)) implicit class NelsonEnrichedGraph[N, A, B](val graph: Graph[N, A, B]) extends AnyVal { def reachable(v: N): Vector[N] = xdfWith(Seq(v), _.successors, _.vertex)._1.flatMap(flattenTree) def xdfWith[C](vs: Seq[N], d: Context[N, A, B] => Seq[N], f: Context[N, A, B] => C): (Vector[Tree[C]], Graph[N, A, B]) = if (vs.isEmpty || graph.isEmpty) (Vector(), graph) else graph.decomp(vs.head) match { case Decomp(None, g) => g.xdfWith(vs.tail, d, f) case Decomp(Some(c), g) => val (xs, _) = g.xdfWith(d(c), d, f) val (ys, g3) = g.xdfWith(vs.tail, d, f) (Node(f(c), xs.toStream) +: ys, g3) } } }
Example 74
Source File: KubernetesHealthClient.scala From nelson with Apache License 2.0 | 5 votes |
package nelson package health import nelson.health.HealthCheckOp._ import nelson.CatsHelpers._ import cats.~> import cats.effect.IO import scala.concurrent.duration.FiniteDuration import scala.concurrent.ExecutionContext final class KubernetesHealthClient( kubectl: Kubectl, timeout: FiniteDuration, executionContext: ExecutionContext ) extends (HealthCheckOp ~> IO) { private implicit val kubernetesShellExecutionContext = executionContext def apply[A](fa: HealthCheckOp[A]): IO[A] = fa match { case Health(_, ns, stackName) => kubectl.getPods(ns, stackName).timed(timeout) } }
Example 75
Source File: KubernetesShell.scala From nelson with Apache License 2.0 | 5 votes |
package nelson package scheduler import nelson.Datacenter.{Deployment, StackName} import nelson.Kubectl.{DeploymentStatus, JobStatus, KubectlError} import nelson.scheduler.SchedulerOp._ import nelson.CatsHelpers._ import cats.~> import cats.effect.IO import cats.implicits._ import scala.concurrent.ExecutionContext import scala.concurrent.duration.FiniteDuration import java.util.concurrent.ScheduledExecutorService final class KubernetesShell( kubectl: Kubectl, timeout: FiniteDuration, scheduler: ScheduledExecutorService, executionContext: ExecutionContext ) extends (SchedulerOp ~> IO) { import KubernetesShell._ private implicit val kubernetesShellExecutionContext = executionContext def apply[A](fa: SchedulerOp[A]): IO[A] = fa match { case Delete(_, deployment) => delete(deployment) .retryExponentially(limit = 3)(scheduler, kubernetesShellExecutionContext) .timed(timeout) case Launch(_, _, _, _, _, _, bp) => kubectl.apply(bp) .retryExponentially(limit = 3)(scheduler, kubernetesShellExecutionContext) .timed(timeout) case Summary(_, ns, stackName) => summary(ns, stackName) .retryExponentially(limit = 3)(scheduler, kubernetesShellExecutionContext) .timed(timeout) } def delete(deployment: Deployment): IO[Unit] = { val ns = deployment.namespace.name val stack = deployment.stackName // We don't have enough information here to determine what exactly // we're trying to delete so try each one in turn.. val fallback = kubectl.deleteService(ns, stack).void.recoverWith { case err@KubectlError(_) if notFound(err) => kubectl.deleteCronJob(ns, stack).void.recoverWith { case err@KubectlError(_) if notFound(err) => kubectl.deleteJob(ns, stack).void.recover { case err@KubectlError(_) if notFound(err) => () } } } deployment.renderedBlueprint.fold(fallback)(spec => kubectl.delete(spec).void) } // Janky heuristic to see if an attempted (legacy) deletion failed because // it was not found as opposed to some other reason like RBAC permissions private def notFound(error: KubectlError): Boolean = error.stderr.exists(_.startsWith("Error from server (NotFound)")) def summary(ns: NamespaceName, stackName: StackName): IO[Option[DeploymentSummary]] = deploymentSummary(ns, stackName).recoverWith { case _ => cronJobSummary(ns, stackName).recoverWith { case _ => jobSummary(ns, stackName).recover { case _ => None } } } def deploymentSummary(ns: NamespaceName, stackName: StackName): IO[Option[DeploymentSummary]] = kubectl.getDeployment(ns, stackName).map { case DeploymentStatus(available, unavailable) => Some(DeploymentSummary( running = available, pending = unavailable, completed = None, failed = None )) } def cronJobSummary(ns: NamespaceName, stackName: StackName): IO[Option[DeploymentSummary]] = kubectl.getCronJob(ns, stackName).map(js => Some(jobStatusToSummary(js))) def jobSummary(ns: NamespaceName, stackName: StackName): IO[Option[DeploymentSummary]] = kubectl.getJob(ns, stackName).map(js => Some(jobStatusToSummary(js))) } object KubernetesShell { private def jobStatusToSummary(js: JobStatus): DeploymentSummary = DeploymentSummary( running = js.active, pending = None, // Doesn't seem like K8s API gives this info completed = js.succeeded, failed = js.failed ) }
Example 76
Source File: StubbedConsulClient.scala From nelson with Apache License 2.0 | 5 votes |
package nelson import cats.~> import cats.effect.IO import helm.ConsulOp import scala.collection.immutable.Set object StubbedConsulClient extends (ConsulOp ~> IO) { def apply[A](fa: ConsulOp[A]): IO[A] = fa match { case ConsulOp.KVGet(_) => IO.pure(None) case ConsulOp.KVSet(_, _) => IO.unit case ConsulOp.KVListKeys(_) => IO.pure(Set.empty) case ConsulOp.KVDelete(_) => IO.unit case ConsulOp.HealthListChecksForService(_, _, _, _) => IO.pure(List.empty) case ConsulOp.HealthListChecksForNode(_, _) => IO.pure(List.empty) case ConsulOp.HealthListChecksInState(_, _, _, _) => IO.pure(List.empty) case ConsulOp.HealthListNodesForService(_, _, _, _, _, _) => IO.pure(List.empty) case ConsulOp.AgentRegisterService(_, _, _, _, _, _, _, _) => IO.unit case ConsulOp.AgentDeregisterService(_) => IO.unit case ConsulOp.AgentListServices => IO.pure(Map.empty) case ConsulOp.AgentEnableMaintenanceMode(_, _, _) => IO.unit } }
Example 77
Source File: DefaultBlueprints.scala From nelson with Apache License 2.0 | 5 votes |
package nelson package blueprint import cats.effect.IO import fs2.{io, text} object DefaultBlueprints { private def templateFromClasspath(path: String): IO[Template] = io.readInputStream(IO(getClass.getClassLoader.getResourceAsStream(path)), 4096) .through(text.utf8Decode) .through(text.lines) .compile .toList .map(lines => Template.load(s"nelson-default-${path}", lines.mkString("\n"))) object canopus { val service = templateFromClasspath("nelson/canopus_service.mustache") val cronJob = templateFromClasspath("nelson/canopus_cron_job.mustache") val job = templateFromClasspath("nelson/canopus_job.mustache") } }
Example 78
Source File: hikari.scala From nelson with Apache License 2.0 | 5 votes |
package nelson package storage import doobie.hikari._ import cats.effect.IO object Hikari { def build(db: DatabaseConfig): HikariTransactor[IO] = { val trans = for { xa <- HikariTransactor.newHikariTransactor[IO](db.driver, db.connection, db.username.getOrElse(""), db.password.getOrElse("")) _ <- xa.configure(hx => IO(db.maxConnections.foreach(max => hx.setMaximumPoolSize(max)))) } yield xa trans.unsafeRunSync() } }
Example 79
Source File: Migrate.scala From nelson with Apache License 2.0 | 5 votes |
package nelson package storage import cats.effect.IO import org.flywaydb.core.Flyway import journal.Logger object Migrate { val log = Logger[Migrate.type] def migrate(cfg: DatabaseConfig): IO[Unit] = IO { val flyway = new Flyway flyway.setDataSource( cfg.connection, cfg.username.getOrElse(""), cfg.password.getOrElse("")) try { log.info("Conducting database schema migrations if needed.") val completed = flyway.migrate() log.info(s"Completed $completed succsessful migrations.") } catch { case e: Throwable => { // attempt a repair (useful for local debugging) log.error(s"Failed to migrate database. ${e.getMessage}") log.info("Repairing database before retrying migration") flyway.repair() val completed = flyway.migrate() log.info(s"After repair, completed $completed succsessful migrations.") } } } }
Example 80
Source File: Math2.scala From skunk with MIT License | 5 votes |
// Copyright (c) 2018-2020 by Rob Norris // This software is licensed under the MIT License (MIT). // For more information see LICENSE or https://opensource.org/licenses/MIT package example import cats.Monad import cats.effect.{ ExitCode, IO, IOApp, Resource } import skunk.Session import skunk.implicits._ import skunk.codec.numeric.{ int4, float8 } import natchez.Trace.Implicits.noop object Math2 extends IOApp { val session: Resource[IO, Session[IO]] = Session.single( host = "localhost", port = 5432, user = "jimmy", database = "world", password = Some("banana"), debug = true ) // An algebra for doing math. trait Math[F[_]] { def add(a: Int, b: Int): F[Int] def sqrt(d: Double): F[Double] } object Math { object Statements { val add = sql"select $int4 + $int4".query(int4) val sqrt = sql"select sqrt($float8)".query(float8) } def fromSession[F[_]: Monad](sess: Session[F]): Resource[F, Math[F]] = for { pAdd <- sess.prepare(Statements.add) pSqrt <- sess.prepare(Statements.sqrt) } yield new Math[F] { def add(a: Int, b: Int) = pAdd.unique(a ~ b) def sqrt(d: Double) = pSqrt.unique(d) } } def run(args: List[String]): IO[ExitCode] = session.flatMap(Math.fromSession(_)).use { m => for { n <- m.add(42, 71) d <- m.sqrt(2) d2 <- m.sqrt(42) _ <- IO(println(s"The answers were $n and $d and $d2")) } yield ExitCode.Success } }
Example 81
Source File: Math1.scala From skunk with MIT License | 5 votes |
// Copyright (c) 2018-2020 by Rob Norris // This software is licensed under the MIT License (MIT). // For more information see LICENSE or https://opensource.org/licenses/MIT package example import cats.effect.{ Bracket, ExitCode, IO, IOApp, Resource } import skunk.Session import skunk.implicits._ import skunk.codec.numeric.{ int4, float8 } import natchez.Trace.Implicits.noop object Math1 extends IOApp { val session: Resource[IO, Session[IO]] = Session.single( host = "localhost", port = 5432, user = "jimmy", database = "world", password = Some("banana") ) // An algebra for doing math. trait Math[F[_]] { def add(a: Int, b: Int): F[Int] def sqrt(d: Double): F[Double] } object Math { object Statements { val add = sql"select $int4 + $int4".query(int4) val sqrt = sql"select sqrt($float8)".query(float8) } // `Math` implementation that delegates its work to Postgres. def fromSession[F[_]: Bracket[?[_], Throwable]](sess: Session[F]): Math[F] = new Math[F] { def add(a: Int, b: Int) = sess.prepare(Statements.add).use(_.unique(a ~ b)) def sqrt(d: Double) = sess.prepare(Statements.sqrt).use(_.unique(d)) } } def run(args: List[String]): IO[ExitCode] = session.map(Math.fromSession(_)).use { m => for { n <- m.add(42, 71) d <- m.sqrt(2) d2 <- m.sqrt(42) _ <- IO(println(s"The answers were $n and $d and $d2")) } yield ExitCode.Success } }
Example 82
Source File: SkunkTest.scala From skunk with MIT License | 5 votes |
// Copyright (c) 2018-2020 by Rob Norris // This software is licensed under the MIT License (MIT). // For more information see LICENSE or https://opensource.org/licenses/MIT package tests import cats.effect.{ IO, Resource } import cats.implicits._ import skunk.Session import skunk.data._ import skunk.codec.all._ import skunk.implicits._ import skunk.util.Typer import natchez.Trace.Implicits.noop abstract class SkunkTest(debug: Boolean = false, strategy: Typer.Strategy = Typer.Strategy.BuiltinsOnly) extends ffstest.FTest { val session: Resource[IO, Session[IO]] = Session.single( host = "localhost", port = 5432, user = "jimmy", database = "world", password = Some("banana"), strategy = strategy, debug = debug ) def sessionTest[A](name: String)(fa: Session[IO] => IO[A]): Unit = test(name)(session.use(fa)) implicit class SkunkTestSessionOps(s: Session[IO]) { def assertTransactionStatus(msg: String, xas: TransactionStatus): IO[Unit] = s.transactionStatus.get.flatMap(a => assert(s"$msg (expected $xas, got $a)", a === xas)) def assertHealthy: IO[Unit] = for { _ <- assertTransactionStatus("sanity check", TransactionStatus.Idle) n <- s.unique(sql"select 'SkunkTest Health Check'::varchar".query(varchar)) _ <- assert("sanity check", n == "SkunkTest Health Check") } yield () } }
Example 83
Source File: ErrorResponseTest.scala From skunk with MIT License | 5 votes |
// Copyright (c) 2018-2020 by Rob Norris // This software is licensed under the MIT License (MIT). // For more information see LICENSE or https://opensource.org/licenses/MIT package tests import cats.effect.IO import skunk.codec.all._ import skunk.exception.PostgresErrorException import skunk.implicits._ case object ErrorResponseTest extends SkunkTest { sessionTest("simple command, syntax error") { s => for { _ <- s.execute(sql"foo?".command).assertFailsWith[PostgresErrorException] _ <- s.assertHealthy } yield "ok" } sessionTest("simple query, syntax error") { s => for { _ <- s.execute(sql"foo?".query(int4)).assertFailsWith[PostgresErrorException] _ <- s.assertHealthy } yield "ok" } sessionTest("prepared query, syntax error") { s => for { _ <- s.prepare(sql"foo?".query(int4)).use(_ => IO.unit).assertFailsWith[PostgresErrorException] _ <- s.assertHealthy } yield "ok" } sessionTest("prepared command, syntax error") { s => for { _ <- s.prepare(sql"foo?".command).use(_ => IO.unit).assertFailsWith[PostgresErrorException] _ <- s.assertHealthy } yield "ok" } // test("prepared query, bind error") { // fail("Not implemented.") // } // test("prepared query, bind error") { // fail("Not implemented.") // } }
Example 84
Source File: Integration.scala From helm with Apache License 2.0 | 5 votes |
package helm package http4s import scala.concurrent.duration.DurationInt import cats.effect.IO import cats.implicits._ import com.github.dockerjava.core.DefaultDockerClientConfig import com.github.dockerjava.netty.NettyDockerCmdExecFactory import com.whisk.docker._ import com.whisk.docker.impl.dockerjava.{Docker, DockerJavaExecutorFactory} import com.whisk.docker.scalatest._ import journal.Logger import org.http4s._ import org.http4s.client.blaze._ import org.scalacheck._ import org.scalatest._ import org.scalatest.enablers.CheckerAsserting import org.scalatest.prop._ // This is how we use docker-kit. Nothing specific to helm in this trait. trait DefaultDockerKit extends DockerKit { override implicit val dockerFactory: DockerFactory = new DockerJavaExecutorFactory( new Docker(DefaultDockerClientConfig.createDefaultConfigBuilder().build(), factory = new NettyDockerCmdExecFactory())) lazy val dockerHost: String = { // i'm expecting protocol://ip:port sys.env.get("DOCKER_HOST").flatMap { url => val parts = url.split(":") if (parts.length == 3) Some(parts(1).substring(2)) else None }.getOrElse("127.0.0.1") } } trait DockerConsulService extends DefaultDockerKit { private[this] val logger = Logger[DockerConsulService] override implicit val dockerFactory: DockerFactory = new DockerJavaExecutorFactory( new Docker(DefaultDockerClientConfig.createDefaultConfigBuilder().build(), factory = new NettyDockerCmdExecFactory())) val ConsulPort = 18512 val consulContainer = DockerContainer("consul:0.7.0", name = Some("consul")) .withPorts(8500 -> Some(ConsulPort)) .withLogLineReceiver(LogLineReceiver(true, s => logger.debug(s"consul: $s"))) .withReadyChecker(DockerReadyChecker.LogLineContains("agent: Synced")) abstract override def dockerContainers: List[DockerContainer] = consulContainer :: super.dockerContainers } class IntegrationSpec extends FlatSpec with Matchers with Checkers with BeforeAndAfterAll with DockerConsulService with DockerTestKit { val client = Http1Client[IO]().unsafeRunSync val baseUrl: Uri = Uri.fromString(s"http://${dockerHost}:${ConsulPort}").valueOr(throw _) val interpreter = new Http4sConsulClient(baseUrl, client) "consul" should "work" in check { (k: String, v: Array[Byte]) => scala.concurrent.Await.result(dockerContainers.head.isReady(), 20.seconds) helm.run(interpreter, ConsulOp.kvSet(k, v)).unsafeRunSync // Equality comparison for Option[Array[Byte]] doesn't work properly. Since we expect the value to always be Some making a custom matcher doesn't seem worthwhile, so call .get on the Option // See https://github.com/scalatest/scalatest/issues/491 helm.run(interpreter, ConsulOp.kvGetRaw(k, None, None)).unsafeRunSync.value.get should be (v) helm.run(interpreter, ConsulOp.kvListKeys("")).unsafeRunSync should contain (k) helm.run(interpreter, ConsulOp.kvDelete(k)).unsafeRunSync helm.run(interpreter, ConsulOp.kvListKeys("")).unsafeRunSync should not contain (k) true }(implicitly, implicitly, Arbitrary(Gen.alphaStr suchThat(_.size > 0)), implicitly, implicitly, Arbitrary.arbContainer[Array, Byte], implicitly, implicitly, implicitly[CheckerAsserting[EntityDecoder[IO, Array[Byte]]]], implicitly, implicitly) }
Example 85
Source File: ConsulOpTests.scala From helm with Apache License 2.0 | 5 votes |
package helm import argonaut._, Argonaut._ import cats.effect.IO import org.scalatest.{FlatSpec, Matchers} import org.scalactic.TypeCheckedTripleEquals import ConsulOp._ class ConsulOpTests extends FlatSpec with Matchers with TypeCheckedTripleEquals { val I = Interpreter.prepare[ConsulOp, IO] "getJson" should "return none right when get returns None" in { val interp = for { _ <- I.expectU[QueryResponse[Option[Array[Byte]]]] { case ConsulOp.KVGetRaw("foo", None, None) => IO.pure(QueryResponse(None, -1, true, -1)) } } yield () interp.run(kvGetJson[Json]("foo", None, None)).unsafeRunSync should equal(Right(QueryResponse(None, -1, true, -1))) } it should "return a value when get returns a decodeable value" in { val interp = for { _ <- I.expectU[QueryResponse[Option[Array[Byte]]]] { case ConsulOp.KVGetRaw("foo", None, None) => IO.pure(QueryResponse(Some("42".getBytes), -1, true, -1)) } } yield () interp.run(kvGetJson[Json]("foo", None, None)).unsafeRunSync should equal(Right(QueryResponse(Some(jNumber(42)), -1, true, -1))) } it should "return an error when get returns a non-decodeable value" in { val interp = for { _ <- I.expectU[QueryResponse[Option[Array[Byte]]]] { case ConsulOp.KVGetRaw("foo", None, None) => IO.pure(QueryResponse(Some("{".getBytes), -1, true, -1)) } } yield () interp.run(kvGetJson[Json]("foo", None, None)).unsafeRunSync should equal(Left("JSON terminates unexpectedly.")) } }
Example 86
Source File: AuthQueryTypeCheckSpec.scala From scala-pet-store with Apache License 2.0 | 5 votes |
package io.github.pauljamescleary.petstore package infrastructure.repository.doobie import cats.effect.IO import doobie.scalatest.IOChecker import org.scalatest.funsuite.AnyFunSuite import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import PetStoreArbitraries._ import tsec.mac.jca.HMACSHA256 import tsec.authentication.AugmentedJWT import tsec.common.SecureRandomId import org.scalatest.matchers.should.Matchers class AuthQueryTypeCheckSpec extends AnyFunSuite with Matchers with ScalaCheckPropertyChecks with IOChecker { override def transactor: doobie.Transactor[IO] = testTransactor import AuthSQL._ test("Typecheck auth queries") { forAll { jwt: AugmentedJWT[HMACSHA256, Long] => check(insert(jwt)) } forAll { jwt: AugmentedJWT[HMACSHA256, Long] => check(update(jwt)) } forAll { id: SecureRandomId => check(select(id)) } forAll { id: SecureRandomId => check(delete(id)) } } }
Example 87
Source File: PetQueryTypeCheckSpec.scala From scala-pet-store with Apache License 2.0 | 5 votes |
package io.github.pauljamescleary.petstore package infrastructure.repository.doobie import cats.data.NonEmptyList import cats.effect.IO import cats.syntax.applicative._ import doobie.scalatest.IOChecker import doobie.util.transactor.Transactor import org.scalatest.funsuite.AnyFunSuite import PetStoreArbitraries.pet import org.scalatest.matchers.should.Matchers class PetQueryTypeCheckSpec extends AnyFunSuite with Matchers with IOChecker { override val transactor: Transactor[IO] = testTransactor import PetSQL._ test("Typecheck pet queries") { pet.arbitrary.sample.map { p => check(selectByStatus(p.status.pure[NonEmptyList])) check(insert(p)) p.id.foreach(id => check(PetSQL.update(p, id))) } check(selectTagLikeString("example".pure[NonEmptyList])) check(select(1L)) check(selectAll) check(delete(1L)) check(selectByNameAndCategory("name", "category")) } }
Example 88
Source File: UserQueryTypeCheckSpec.scala From scala-pet-store with Apache License 2.0 | 5 votes |
package io.github.pauljamescleary.petstore package infrastructure.repository.doobie import org.scalatest.funsuite.AnyFunSuite import cats.effect.IO import doobie.scalatest.IOChecker import doobie.util.transactor.Transactor import PetStoreArbitraries.user import org.scalatest.matchers.should.Matchers class UserQueryTypeCheckSpec extends AnyFunSuite with Matchers with IOChecker { override val transactor: Transactor[IO] = testTransactor import UserSQL._ test("Typecheck user queries") { user.arbitrary.sample.map { u => check(insert(u)) check(byUserName(u.userName)) u.id.foreach(id => check(update(u, id))) } check(selectAll) check(select(1L)) check(delete(1L)) } }
Example 89
Source File: package.scala From scala-pet-store with Apache License 2.0 | 5 votes |
package io.github.pauljamescleary.petstore package infrastructure.repository import cats.implicits._ import cats.effect.{Async, ContextShift, Effect, IO} import config._ import _root_.doobie.Transactor import io.circe.config.parser import scala.concurrent.ExecutionContext package object doobie { def getTransactor[F[_]: Async: ContextShift](cfg: DatabaseConfig): Transactor[F] = Transactor.fromDriverManager[F]( cfg.driver, // driver classname cfg.url, // connect URL (driver-specific) cfg.user, // user cfg.password, // password ) def initializedTransactor[F[_]: Effect: Async: ContextShift]: F[Transactor[F]] = for { petConfig <- parser.decodePathF[F, PetStoreConfig]("petstore") _ <- DatabaseConfig.initializeDb(petConfig.db) } yield getTransactor(petConfig.db) lazy val testEc = ExecutionContext.Implicits.global implicit lazy val testCs = IO.contextShift(testEc) lazy val testTransactor = initializedTransactor[IO].unsafeRunSync() }
Example 90
Source File: LoginTest.scala From scala-pet-store with Apache License 2.0 | 5 votes |
package io.github.pauljamescleary.petstore package infrastructure.endpoint import cats.data.Kleisli import cats.effect.IO import domain.authentication.{LoginRequest, SignupRequest} import domain.users.{Role, User} import org.http4s.circe.{jsonEncoderOf, jsonOf} import org.http4s.client.dsl.Http4sClientDsl import org.http4s.{EntityDecoder, EntityEncoder, HttpApp, Request, Response} import org.http4s.implicits._ import org.http4s.headers.Authorization import io.circe.generic.auto._ import org.http4s.dsl.Http4sDsl trait LoginTest extends Http4sClientDsl[IO] with Http4sDsl[IO] { implicit val userEnc: EntityEncoder[IO, User] = jsonEncoderOf implicit val userDec: EntityDecoder[IO, User] = jsonOf implicit val signUpRequestEnc: EntityEncoder[IO, SignupRequest] = jsonEncoderOf implicit val signUpRequestDec: EntityDecoder[IO, SignupRequest] = jsonOf implicit val loginRequestEnc: EntityEncoder[IO, LoginRequest] = jsonEncoderOf implicit val loginRequestDec: EntityDecoder[IO, LoginRequest] = jsonOf def signUpAndLogIn( userSignUp: SignupRequest, userEndpoint: HttpApp[IO], ): IO[(User, Option[Authorization])] = for { signUpRq <- POST(userSignUp, uri"/users") signUpResp <- userEndpoint.run(signUpRq) user <- signUpResp.as[User] loginBody = LoginRequest(userSignUp.userName, userSignUp.password) loginRq <- POST(loginBody, uri"/users/login") loginResp <- userEndpoint.run(loginRq) } yield { user -> loginResp.headers.get(Authorization) } def signUpAndLogInAsAdmin( userSignUp: SignupRequest, userEndpoint: Kleisli[IO, Request[IO], Response[IO]], ): IO[(User, Option[Authorization])] = signUpAndLogIn(userSignUp.copy(role = Role.Admin), userEndpoint) def signUpAndLogInAsCustomer( userSignUp: SignupRequest, userEndpoint: Kleisli[IO, Request[IO], Response[IO]], ): IO[(User, Option[Authorization])] = signUpAndLogIn(userSignUp.copy(role = Role.Customer), userEndpoint) }
Example 91
Source File: AsyncHttpClientLowLevelFs2WebsocketTest.scala From sttp with Apache License 2.0 | 5 votes |
package sttp.client.asynchttpclient.fs2 import cats.effect.IO import org.asynchttpclient.ws.{WebSocketListener, WebSocket => AHCWebSocket} import sttp.client._ import sttp.client.asynchttpclient.WebSocketHandler import sttp.client.impl.cats.CatsTestBase import sttp.client.testing.websocket.LowLevelListenerWebSocketTest class AsyncHttpClientLowLevelFs2WebsocketTest extends LowLevelListenerWebSocketTest[IO, AHCWebSocket, WebSocketHandler] with CatsTestBase { implicit val backend: SttpBackend[IO, Nothing, WebSocketHandler] = AsyncHttpClientFs2Backend[IO]().unsafeRunSync() override def createHandler(_onTextFrame: String => Unit): WebSocketHandler[AHCWebSocket] = WebSocketHandler.fromListener(new WebSocketListener { override def onOpen(websocket: AHCWebSocket): Unit = {} override def onClose(websocket: AHCWebSocket, code: Int, reason: String): Unit = {} override def onError(t: Throwable): Unit = {} override def onTextFrame(payload: String, finalFragment: Boolean, rsv: Int): Unit = { _onTextFrame(payload) } }) override def sendText(ws: AHCWebSocket, t: String): Unit = ws.sendTextFrame(t).await() override def sendCloseFrame(ws: AHCWebSocket): Unit = ws.sendCloseFrame() }
Example 92
Source File: AsyncHttpClientPipedFs2WebsocketsTest.scala From sttp with Apache License 2.0 | 5 votes |
package sttp.client.asynchttpclient.fs2 import cats.effect.concurrent.Ref import cats.effect.IO import cats.implicits._ import fs2._ import sttp.client._ import sttp.client.asynchttpclient.WebSocketHandler import sttp.client.impl.cats.CatsTestBase import sttp.client.impl.fs2.Fs2WebSockets import sttp.client.testing.ToFutureWrapper import sttp.client.ws.WebSocket import sttp.model.ws.WebSocketFrame import sttp.client.testing.HttpTest.wsEndpoint import scala.collection.immutable.Queue import org.scalatest.flatspec.AsyncFlatSpec import org.scalatest.matchers.should.Matchers class AsyncHttpClientPipedFs2WebsocketsTest extends AsyncFlatSpec with Matchers with ToFutureWrapper with CatsTestBase { implicit val backend: SttpBackend[IO, Nothing, WebSocketHandler] = AsyncHttpClientFs2Backend[IO]().unsafeRunSync() def createHandler: Option[Int] => IO[WebSocketHandler[WebSocket[IO]]] = Fs2WebSocketHandler[IO](_) it should "run a simple echo pipe" in { basicRequest .get(uri"$wsEndpoint/ws/echo") .openWebsocketF(createHandler(None)) .product(Ref.of[IO, Queue[String]](Queue.empty)) .flatMap { case (response, results) => Fs2WebSockets.handleSocketThroughTextPipe(response.result) { in => val receive = in.evalMap(m => results.update(_.enqueue(m))) val send = Stream("Message 1".asRight, "Message 2".asRight, WebSocketFrame.close.asLeft) send merge receive.drain } >> results.get.map(_ should contain theSameElementsInOrderAs List("echo: Message 1", "echo: Message 2")) } .toFuture() } it should "run a simple read-only client" in { basicRequest .get(uri"$wsEndpoint/ws/send_and_wait") .openWebsocketF(createHandler(None)) .product(Ref.of[IO, Queue[String]](Queue.empty)) .flatMap { case (response, results) => Fs2WebSockets.handleSocketThroughTextPipe(response.result) { in => in.evalMap(m => results.update(_.enqueue(m)).flatMap(_ => results.get.map(_.size))).flatMap { case 2 => Stream(None) // terminating the stream case _ => Stream.empty // waiting for more messages }.unNoneTerminate } >> results.get.map(_ should contain theSameElementsInOrderAs List("test10", "test20")) } .toFuture() } }
Example 93
Source File: AsyncHttpClientHighLevelFs2WebsocketTest.scala From sttp with Apache License 2.0 | 5 votes |
package sttp.client.asynchttpclient.fs2 import cats.effect.IO import sttp.client._ import sttp.client.asynchttpclient.{AsyncHttpClientHighLevelWebsocketTest, WebSocketHandler} import sttp.client.impl.cats.CatsTestBase import sttp.client.ws.WebSocket import scala.concurrent.duration._ import cats.implicits._ class AsyncHttpClientHighLevelFs2WebsocketTest extends AsyncHttpClientHighLevelWebsocketTest[IO] with CatsTestBase { implicit val backend: SttpBackend[IO, Nothing, WebSocketHandler] = AsyncHttpClientFs2Backend[IO]().unsafeRunSync() override def createHandler: Option[Int] => IO[WebSocketHandler[WebSocket[IO]]] = Fs2WebSocketHandler[IO](_) override def eventually[T](interval: FiniteDuration, attempts: Int)(f: => IO[T]): IO[T] = { def tryWithCounter(i: Int): IO[T] = { (IO.sleep(interval) >> f).recoverWith { case _: Exception if i < attempts => tryWithCounter(i + 1) } } tryWithCounter(0) } }
Example 94
Source File: AsyncHttpClientCatsHttpTest.scala From sttp with Apache License 2.0 | 5 votes |
package sttp.client.asynchttpclient.cats import java.util.concurrent.TimeoutException import cats.effect.IO import sttp.client._ import sttp.client.impl.cats.CatsTestBase import sttp.client.testing.{CancelTest, HttpTest} import scala.concurrent.duration._ class AsyncHttpClientCatsHttpTest extends HttpTest[IO] with CancelTest[IO, Nothing] with CatsTestBase { override implicit val backend: SttpBackend[IO, Nothing, NothingT] = AsyncHttpClientCatsBackend[IO]().unsafeRunSync() "illegal url exceptions" - { "should be wrapped in the effect wrapper" in { basicRequest.get(uri"ps://sth.com").send().toFuture().failed.map { e => e shouldBe a[IllegalArgumentException] } } } override def timeoutToNone[T](t: IO[T], timeoutMillis: Int): IO[Option[T]] = t.map(Some(_)) .timeout(timeoutMillis.milliseconds) .handleErrorWith { case _: TimeoutException => IO(None) case e => throw e } override def throwsExceptionOnUnsupportedEncoding = false }
Example 95
Source File: StreamFs2.scala From sttp with Apache License 2.0 | 5 votes |
package sttp.client.examples object StreamFs2 extends App { import sttp.client._ import sttp.client.asynchttpclient.fs2.AsyncHttpClientFs2Backend import cats.effect.{ContextShift, IO} import cats.instances.string._ import fs2.{Stream, text} implicit val cs: ContextShift[IO] = IO.contextShift(scala.concurrent.ExecutionContext.global) def streamRequestBody(implicit backend: SttpBackend[IO, Stream[IO, Byte], NothingT]): IO[Unit] = { val stream: Stream[IO, Byte] = Stream.emits("Hello, world".getBytes) basicRequest .streamBody(stream) .post(uri"https://httpbin.org/post") .send() .map { response => println(s"RECEIVED:\n${response.body}") } } def streamResponseBody(implicit backend: SttpBackend[IO, Stream[IO, Byte], NothingT]): IO[Unit] = { basicRequest .body("I want a stream!") .post(uri"https://httpbin.org/post") .response(asStreamAlways[Stream[IO, Byte]]) .send() .flatMap { response => response.body.chunks .through(text.utf8DecodeC) .compile .foldMonoid } .map { body => println(s"RECEIVED:\n$body") } } val effect = AsyncHttpClientFs2Backend[IO]().flatMap { implicit backend => streamRequestBody.flatMap(_ => streamResponseBody).guarantee(backend.close()) } effect.unsafeRunSync() }
Example 96
Source File: HttpClientHighLevelFs2WebsocketTest.scala From sttp with Apache License 2.0 | 5 votes |
package sttp.client.httpclient.fs2 import cats.effect.IO import cats.implicits._ import sttp.client._ import sttp.client.httpclient.WebSocketHandler import sttp.client.testing.websocket.HighLevelWebsocketTest import sttp.client.ws.WebSocket import sttp.client.testing.HttpTest.wsEndpoint import scala.concurrent.duration._ class HttpClientHighLevelFs2WebsocketTest extends HighLevelWebsocketTest[IO, WebSocketHandler] with HttpClientFs2TestBase { override def createHandler: Option[Int] => IO[WebSocketHandler[WebSocket[IO]]] = Fs2WebSocketHandler[IO](_) it should "handle backpressure correctly" in { basicRequest .get(uri"$wsEndpoint/ws/echo") .openWebsocketF(createHandler(Some(3))) .flatMap { response => val ws = response.result send(ws, 1000) >> eventually(10.millis, 500) { ws.isOpen.map(_ shouldBe true) } } .toFuture() } override def eventually[T](interval: FiniteDuration, attempts: Int)(f: => IO[T]): IO[T] = { def tryWithCounter(i: Int): IO[T] = { (IO.sleep(interval) >> f).recoverWith { case _: Exception if i < attempts => tryWithCounter(i + 1) } } tryWithCounter(0) } }
Example 97
Source File: Fs2AsyncQueue.scala From sttp with Apache License 2.0 | 5 votes |
package sttp.client.impl.fs2 import cats.effect.{Effect, IO} import fs2.concurrent.InspectableQueue import sttp.client.ws.internal.AsyncQueue import sttp.model.ws.WebSocketBufferFull import scala.language.higherKinds class Fs2AsyncQueue[F[_], A](queue: InspectableQueue[F, A])(implicit F: Effect[F]) extends AsyncQueue[F, A] { override def offer(t: A): Unit = { F.toIO(queue.offer1(t)) .flatMap { case true => IO.unit case false => IO.raiseError(new WebSocketBufferFull()) } .unsafeRunSync() } override def poll: F[A] = queue.dequeue1 }
Example 98
Source File: Launcher.scala From slab with Apache License 2.0 | 5 votes |
// Example: A Slab server // // Guide for creating a Slab server package com.criteo.slab.example import java.net.URLDecoder import cats.effect.IO import com.criteo.slab.app.StateService.NotFoundError import com.criteo.slab.app.WebServer import com.criteo.slab.lib.InMemoryStore import lol.http._ import org.slf4j.LoggerFactory object Launcher { import SimpleBoard._ import scala.concurrent.ExecutionContext.Implicits.global private val logger = LoggerFactory.getLogger(this.getClass) def main(args: Array[String]): Unit = { require(args.length == 1, "you must supply a port!") val port = args(0).toInt // You should provide codec for checked value types for values to be persistent in a store import InMemoryStore.codec // Define a value store for uploading and restoring history implicit val store = new InMemoryStore // Create a web server WebServer() // You can define custom routes, Slab web server is built with [lolhttp](https://github.com/criteo/lolhttp) .withRoutes(stateService => { case GET at "/api/heartbeat" => Ok("ok") case GET at url"/api/boards/$board/status" => IO.fromFuture(IO( stateService .current(URLDecoder.decode(board, "UTF-8")).map(view => Ok(view.status.name)) .recover { case NotFoundError(message) => NotFound(message) case e => logger.error(e.getMessage, e) InternalServerError } )) }) // Attach a board to the server .attach(board) // Launch the server at port .apply(port) } }
Example 99
Source File: Stryker4sMain.scala From stryker4s with Apache License 2.0 | 5 votes |
package stryker4s.command import pureconfig.error.ConfigReaderException import stryker4s.command.config.ProcessRunnerConfig import stryker4s.config.ConfigReader import stryker4s.run.threshold.ErrorStatus import pureconfig.generic.auto._ import cats.effect.IOApp import cats.effect.{ExitCode, IO} object Stryker4sMain extends IOApp { override def run(args: List[String]): IO[ExitCode] = IO { Stryker4sArgumentHandler.handleArgs(args) val processRunnerConfig: ProcessRunnerConfig = ConfigReader.readConfigOfType[ProcessRunnerConfig]() match { case Left(failures) => throw ConfigReaderException(failures) case Right(config) => config } val result = new Stryker4sCommandRunner(processRunnerConfig).run() result match { case ErrorStatus => ExitCode.Error case _ => ExitCode.Success } } }
Example 100
Source File: Stryker4sMain.scala From stryker4s with Apache License 2.0 | 5 votes |
package stryker4s.maven import javax.inject.Inject import org.apache.maven.plugin.{AbstractMojo, MojoFailureException} import org.apache.maven.plugins.annotations.{Mojo, Parameter} import org.apache.maven.project.MavenProject import stryker4s.run.threshold.ErrorStatus import scala.concurrent.ExecutionContext.Implicits.global import cats.effect.{ContextShift, IO} import scala.concurrent.ExecutionContext @Mojo(name = "run") class Stryker4sMain @Inject() (@Parameter(defaultValue = "${project}") project: MavenProject) extends AbstractMojo { override def execute(): Unit = { implicit val cs: ContextShift[IO] = IO.contextShift(implicitly[ExecutionContext]) new Stryker4sMavenRunner(project).run() match { case ErrorStatus => throw new MojoFailureException("Mutation score was below configured threshold") case _ => } } }
Example 101
Source File: JsonReporter.scala From stryker4s with Apache License 2.0 | 5 votes |
package stryker4s.report import grizzled.slf4j.Logging import stryker4s.config.Config import stryker4s.files.FileIO import mutationtesting.MutationTestReport import cats.effect.IO import java.nio.file.Path class JsonReporter(fileIO: FileIO)(implicit config: Config) extends FinishedRunReporter with Logging { def writeReportJsonTo(file: Path, report: MutationTestReport): IO[Unit] = { import io.circe.syntax._ import mutationtesting.MutationReportEncoder._ val json = report.asJson.noSpaces fileIO.createAndWrite(file, json) } override def reportRunFinished(runReport: FinishedRunReport): IO[Unit] = { val targetLocation = config.baseDir / s"target/stryker4s-report-${runReport.timestamp}/" val resultLocation = targetLocation / "report.json" writeReportJsonTo(resultLocation.path, runReport.report) *> IO(info(s"Written JSON report to $resultLocation")) } }
Example 102
Source File: HtmlReporter.scala From stryker4s with Apache License 2.0 | 5 votes |
package stryker4s.report import grizzled.slf4j.Logging import mutationtesting._ import stryker4s.config.Config import stryker4s.files.FileIO import cats.effect.IO import cats.Parallel import java.nio.file.Path class HtmlReporter(fileIO: FileIO)(implicit config: Config, p: Parallel[IO]) extends FinishedRunReporter with Logging { private val title = "Stryker4s report" private val mutationTestElementsName = "mutation-test-elements.js" private val htmlReportResource = s"/mutation-testing-elements/$mutationTestElementsName" private val reportFilename = "report.js" private val indexHtml: String = s"""<!DOCTYPE html> |<html lang="en"> |<head> | <meta charset="UTF-8"> | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | <script src="mutation-test-elements.js"></script> |</head> |<body> | <mutation-test-report-app title-postfix="$title"> | Your browser doesn't support <a href="https://caniuse.com/#search=custom%20elements">custom elements</a>. | Please use a latest version of an evergreen browser (Firefox, Chrome, Safari, Opera, etc). | </mutation-test-report-app> | <script src="$reportFilename"></script> |</body> |</html>""".stripMargin def writeMutationTestElementsJsTo(file: Path): IO[Unit] = fileIO.createAndWriteFromResource(file, htmlReportResource) def writeIndexHtmlTo(file: Path): IO[Unit] = fileIO.createAndWrite(file, indexHtml) def writeReportJsTo(file: Path, report: MutationTestReport): IO[Unit] = { import io.circe.syntax._ import mutationtesting.MutationReportEncoder._ val json = report.asJson.noSpaces val reportContent = s"document.querySelector('mutation-test-report-app').report = $json" fileIO.createAndWrite(file, reportContent) } override def reportRunFinished(runReport: FinishedRunReport): IO[Unit] = { val targetLocation = config.baseDir / s"target/stryker4s-report-${runReport.timestamp}/" val mutationTestElementsLocation = targetLocation / mutationTestElementsName val indexLocation = targetLocation / "index.html" val reportLocation = targetLocation / reportFilename val reportsWriting = writeIndexHtmlTo(indexLocation.path) &> writeReportJsTo(reportLocation.path, runReport.report) &> writeMutationTestElementsJsTo(mutationTestElementsLocation.path) reportsWriting *> IO(info(s"Written HTML report to $indexLocation")) } }
Example 103
Source File: MutationRunReporter.scala From stryker4s with Apache License 2.0 | 5 votes |
package stryker4s.report import mutationtesting._ import stryker4s.model.{Mutant, MutantRunResult} import cats.effect.IO sealed trait MutationRunReporter trait ProgressReporter extends MutationRunReporter { def reportMutationStart(mutant: Mutant): IO[Unit] def reportMutationComplete(result: MutantRunResult, totalMutants: Int): IO[Unit] } trait FinishedRunReporter extends MutationRunReporter { def reportRunFinished(runReport: FinishedRunReport): IO[Unit] } final case class FinishedRunReport(report: MutationTestReport, metrics: MetricsResult) { @transient val timestamp: Long = System.currentTimeMillis() }
Example 104
Source File: DashboardReporter.scala From stryker4s with Apache License 2.0 | 5 votes |
package stryker4s.report import grizzled.slf4j.Logging import mutationtesting.{MetricsResult, MutationTestReport} import stryker4s.report.dashboard.DashboardConfigProvider import stryker4s.report.model._ import stryker4s.config.Full import stryker4s.config.MutationScoreOnly import sttp.client._ import sttp.client.circe._ import sttp.model.MediaType import sttp.model.StatusCode import cats.effect.IO class DashboardReporter(dashboardConfigProvider: DashboardConfigProvider)(implicit httpBackend: SttpBackend[IO, Nothing, NothingT] ) extends FinishedRunReporter with Logging { override def reportRunFinished(runReport: FinishedRunReport): IO[Unit] = dashboardConfigProvider.resolveConfig() match { case Left(configKey) => IO { warn(s"Could not resolve dashboard configuration key '$configKey', not sending report") } case Right(dashboardConfig) => val request = buildRequest(dashboardConfig, runReport.report, runReport.metrics) request .send() .map(response => logResponse(response)) } def buildRequest(dashConfig: DashboardConfig, report: MutationTestReport, metrics: MetricsResult) = { import io.circe.{Decoder, Encoder} implicit val decoder: Decoder[DashboardPutResult] = Decoder.forProduct1("href")(DashboardPutResult.apply) // Separate so any slashes won't be escaped in project or version val baseUrl = s"${dashConfig.baseUrl}/api/reports/${dashConfig.project}/${dashConfig.version}" val uri = uri"$baseUrl?module=${dashConfig.module}" val request = basicRequest .header("X-Api-Key", dashConfig.apiKey) .contentType(MediaType.ApplicationJson) .response(asJson[DashboardPutResult]) .put(uri) dashConfig.reportType match { case Full => import mutationtesting.MutationReportEncoder._ request .body(report) case MutationScoreOnly => implicit val encoder: Encoder[ScoreOnlyReport] = Encoder.forProduct1("mutationScore")(r => r.mutationScore) request .body(ScoreOnlyReport(metrics.mutationScore)) } } def logResponse(response: Response[Either[ResponseError[io.circe.Error], DashboardPutResult]]): Unit = response.body match { case Left(HttpError(errorBody)) => response.code match { case StatusCode.Unauthorized => error( s"Error HTTP PUT '$errorBody'. Status code 401 Unauthorized. Did you provide the correct api key in the 'STRYKER_DASHBOARD_API_KEY' environment variable?" ) case statusCode => error( s"Failed to PUT report to dashboard. Response status code: ${statusCode.code}. Response body: '${errorBody}'" ) } case Left(DeserializationError(original, error)) => warn(s"Dashboard report was sent successfully, but could not decode the response: '$original'. Error:", error) case Right(DashboardPutResult(href)) => info(s"Sent report to dashboard. Available at $href") } }
Example 105
Source File: Reporter.scala From stryker4s with Apache License 2.0 | 5 votes |
package stryker4s.report import grizzled.slf4j.Logging import stryker4s.config._ import stryker4s.files.DiskFileIO import stryker4s.model.{Mutant, MutantRunResult} import stryker4s.report.dashboard.DashboardConfigProvider import cats.implicits._ import cats.effect.IO import sttp.client.asynchttpclient.cats.AsyncHttpClientCatsBackend import cats.effect.ContextShift class Reporter(implicit config: Config, cs: ContextShift[IO]) extends FinishedRunReporter with ProgressReporter with Logging { lazy val reporters: Iterable[MutationRunReporter] = config.reporters map { case Console => new ConsoleReporter() case Html => new HtmlReporter(new DiskFileIO()) case Json => new JsonReporter(new DiskFileIO()) case Dashboard => AsyncHttpClientCatsBackend[IO]() .map { implicit backend => new DashboardReporter(new DashboardConfigProvider(sys.env)) } // TODO: Figure out some other way to do this? .unsafeRunSync() } private[this] lazy val progressReporters = reporters collect { case r: ProgressReporter => r } private[this] lazy val finishedRunReporters = reporters collect { case r: FinishedRunReporter => r } override def reportMutationStart(mutant: Mutant): IO[Unit] = reportAll[ProgressReporter]( progressReporters, _.reportMutationStart(mutant) ) override def reportMutationComplete(result: MutantRunResult, totalMutants: Int): IO[Unit] = reportAll[ProgressReporter]( progressReporters, _.reportMutationComplete(result, totalMutants) ) override def reportRunFinished(runReport: FinishedRunReport): IO[Unit] = { reportAll[FinishedRunReporter]( finishedRunReporters, reporter => reporter.reportRunFinished(runReport) ) } private def reportAll[T](reporters: Iterable[T], reportF: T => IO[Unit]): IO[Unit] = { reporters.toList .parTraverse { reporter => reportF(reporter).attempt } .map { _ collect { case Left(f) => f } } .flatMap { failed => if (failed.nonEmpty) IO { warn(s"${failed.size} reporter(s) failed to report:") failed.foreach(warn(_)) } else IO.unit } } }
Example 106
Source File: fileIO.scala From stryker4s with Apache License 2.0 | 5 votes |
package stryker4s.files import cats.effect.IO import fs2._ import fs2.io.readInputStream import fs2.io.file._ import cats.effect.Blocker import cats.effect.ContextShift import cats.effect.Sync import java.nio.file.Path sealed trait FileIO { def createAndWriteFromResource(file: Path, resource: String): IO[Unit] def createAndWrite(file: Path, content: String): IO[Unit] } class DiskFileIO()(implicit cs: ContextShift[IO], s: Sync[IO]) extends FileIO { override def createAndWriteFromResource(file: Path, resourceName: String): IO[Unit] = Blocker[IO].use { blocker => val stream = IO { getClass().getResourceAsStream(resourceName) } createDirectories(blocker, file.getParent()) *> readInputStream(stream, 8192, blocker) .through(writeAll(file, blocker)) .compile .drain } override def createAndWrite(file: Path, content: String): IO[Unit] = Blocker[IO].use { blocker => createDirectories(blocker, file.getParent()) *> Stream(content) .through(text.utf8Encode) .through(writeAll(file, blocker)) .compile .drain } }
Example 107
Source File: Stryker4sRunner.scala From stryker4s with Apache License 2.0 | 5 votes |
package stryker4s.run import stryker4s.Stryker4s import stryker4s.config.{Config, ConfigReader} import stryker4s.mutants.Mutator import stryker4s.mutants.applymutants.ActiveMutationContext.ActiveMutationContext import stryker4s.mutants.applymutants.{MatchBuilder, StatementTransformer} import stryker4s.mutants.findmutants.{FileCollector, MutantFinder, MutantMatcher, SourceCollector} import stryker4s.report.Reporter import stryker4s.run.process.ProcessRunner import stryker4s.run.threshold.ScoreStatus import cats.effect.ContextShift import cats.effect.IO trait Stryker4sRunner { def run()(implicit cs: ContextShift[IO]): ScoreStatus = { implicit val config: Config = ConfigReader.readConfig() val collector = new FileCollector(ProcessRunner()) val stryker4s = new Stryker4s( collector, new Mutator(new MutantFinder(new MutantMatcher), new StatementTransformer, new MatchBuilder(mutationActivation)), resolveRunner(collector, new Reporter()) ) stryker4s.run() } def resolveRunner(collector: SourceCollector, reporter: Reporter)(implicit config: Config): MutantRunner def mutationActivation: ActiveMutationContext }
Example 108
Source File: ProcessRunner.scala From stryker4s with Apache License 2.0 | 5 votes |
package stryker4s.run.process import better.files.File import grizzled.slf4j.Logging import scala.concurrent.duration.{Duration, MINUTES} import scala.sys.process.{Process, ProcessLogger} import scala.util.Try import cats.effect.IO trait ProcessRunner extends Logging { def apply(command: Command, workingDir: File): Try[Seq[String]] = { Try { Process(s"${command.command} ${command.args}", workingDir.toJava) .!!<(ProcessLogger(debug(_))) .linesIterator .toSeq } } def apply(command: Command, workingDir: File, envVar: (String, String)): Try[Int] = { val mutantProcess = Process(s"${command.command} ${command.args}", workingDir.toJava, envVar) .run(ProcessLogger(debug(_))) val exitCodeFuture = IO(mutantProcess.exitValue()) // TODO: Maybe don't use unsafeRunTimed // TODO: Use timeout decided by initial test-run duration Try(exitCodeFuture.unsafeRunTimed(Duration(2, MINUTES)).get) } } object ProcessRunner { private def isWindows: Boolean = sys.props("os.name").toLowerCase.contains("windows") def apply(): ProcessRunner = { if (isWindows) new WindowsProcessRunner else new UnixProcessRunner } }
Example 109
Source File: JsonReporterTest.scala From stryker4s with Apache License 2.0 | 5 votes |
package stryker4s.report import mutationtesting.{Metrics, MutationTestReport, Thresholds} import org.mockito.captor.ArgCaptor import stryker4s.config.Config import stryker4s.files.FileIO import stryker4s.scalatest.LogMatchers import stryker4s.testutil.{MockitoSuite, Stryker4sSuite} import java.nio.file.Path import cats.effect.IO class JsonReporterTest extends Stryker4sSuite with MockitoSuite with LogMatchers { describe("reportJson") { it("should contain the report") { implicit val config: Config = Config.default val mockFileIO = mock[FileIO] when(mockFileIO.createAndWrite(any[Path], any[String])).thenReturn(IO.unit) val sut = new JsonReporter(mockFileIO) val testFile = (config.baseDir / "foo.bar").path val report = MutationTestReport(thresholds = Thresholds(100, 0), files = Map.empty) sut .writeReportJsonTo(testFile, report) .unsafeRunSync() verify(mockFileIO).createAndWrite(eqTo(testFile), any[String]) } } describe("reportRunFinished") { implicit val config: Config = Config.default val stryker4sReportFolderRegex = ".*target(/|\\\\)stryker4s-report-(\\d*)(/|\\\\)[a-z-]*\\.[a-z]*$" it("should write the report file to the report directory") { val mockFileIO = mock[FileIO] when(mockFileIO.createAndWrite(any[Path], any[String])).thenReturn(IO.unit) val sut = new JsonReporter(mockFileIO) val report = MutationTestReport(thresholds = Thresholds(100, 0), files = Map.empty) val metrics = Metrics.calculateMetrics(report) sut .reportRunFinished(FinishedRunReport(report, metrics)) .unsafeRunSync() val writtenFilesCaptor = ArgCaptor[Path] verify(mockFileIO, times(1)).createAndWrite(writtenFilesCaptor, any[String]) val paths = writtenFilesCaptor.values.map(_.toString()) all(paths) should fullyMatch regex stryker4sReportFolderRegex writtenFilesCaptor.values.map(_.getFileName().toString()) should contain only "report.json" } it("should info log a message") { val mockFileIO = mock[FileIO] when(mockFileIO.createAndWrite(any[Path], any[String])).thenReturn(IO.unit) val sut = new JsonReporter(mockFileIO) val report = MutationTestReport(thresholds = Thresholds(100, 0), files = Map.empty) val metrics = Metrics.calculateMetrics(report) val captor = ArgCaptor[Path] sut .reportRunFinished(FinishedRunReport(report, metrics)) .unsafeRunSync() verify(mockFileIO).createAndWrite(captor.capture, any[String]) s"Written JSON report to ${captor.value}" shouldBe loggedAsInfo } } }
Example 110
Source File: EffectInstancesLawsSuite.scala From meow-mtl with MIT License | 5 votes |
package com.olegpy.meow.effects import cats.effect.IO import cats.effect.concurrent.Ref import cats.effect.laws.util.TestContext import cats.implicits._ import cats.effect.laws.discipline.arbitrary._ import cats.effect.laws.util.TestInstances._ import cats.mtl.laws.discipline._ import minitest.SimpleTestSuite import minitest.laws.Checkers import org.typelevel.discipline.Laws import scala.concurrent.duration._ object EffectInstancesLawsSuite extends SimpleTestSuite with Checkers { private def checkAll(name: String)(ruleSet: TestContext => Laws#RuleSet) = { implicit val ctx = TestContext() for ((id, prop) <- ruleSet(ctx).all.properties) test(name + "." + id) { ctx.tick(1.day) check(prop) } } checkAll("Ref.runAsk") { implicit ctx => Ref.unsafe[IO, Int](0).runAsk(ev => ApplicativeAskTests(ev).applicativeAsk[Int] ) } checkAll("Ref.runState") { implicit ctx => Ref.unsafe[IO, Int](0).runState(ev => MonadStateTests(ev).monadState[Int] ) } checkAll("Ref.runTell") { implicit ctx => Ref.unsafe[IO, Int](0).runTell(ev => FunctorTellTests(ev).functorTell[Int] ) } checkAll("Consumer.runTell") { implicit ctx => case object DummyErr extends Throwable def fun(x: Int) = if (x == 1) IO.raiseError[Unit](DummyErr) else IO.unit Consumer(fun _).runTell(ev => FunctorTellTests(ev).functorTell[Int] ) } }
Example 111
Source File: FS2CronTest.scala From fs2-cron with Apache License 2.0 | 5 votes |
package eu.timepit.fs2cron import cats.effect.{ContextShift, IO, Timer} import cron4s.Cron import cron4s.expr.CronExpr import scala.concurrent.ExecutionContext import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers class FS2CronTest extends AnyFunSuite with Matchers { implicit val timer: Timer[IO] = IO.timer(ExecutionContext.global) val evenSeconds: CronExpr = Cron.unsafeParse("*/2 * * ? * *") def isEven(i: Int): Boolean = i % 2 == 0 test("awakeEveryCron") { val s1 = awakeEveryCron[IO](evenSeconds) >> evalNow[IO] val s2 = s1.map(_.getSecond).take(2).forall(isEven) s2.compile.last.map(_.getOrElse(false)).unsafeRunSync() } test("sleepCron") { val s1 = sleepCron[IO](evenSeconds) >> evalNow[IO] val s2 = s1.map(_.getSecond).forall(isEven) s2.compile.last.map(_.getOrElse(false)).unsafeRunSync() } test("schedule") { implicit val ctxShift: ContextShift[IO] = IO.contextShift(ExecutionContext.global) val everySecond: CronExpr = Cron.unsafeParse("* * * ? * *") val s1 = schedule(List(everySecond -> evalNow[IO], evenSeconds -> evalNow[IO])).map(_.getSecond) val seconds = s1.take(3).compile.toList.unsafeRunSync() seconds.count(isEven) shouldBe 2 seconds.count(!isEven(_)) shouldBe 1 } }
Example 112
Source File: DownloadableFile.scala From polynote with Apache License 2.0 | 5 votes |
package polynote.kernel.util import java.io.{File, FileInputStream, InputStream} import java.net.{HttpURLConnection, URI} import java.util.ServiceLoader import scala.collection.JavaConverters._ import cats.effect.IO import zio.{RIO, ZIO} import zio.blocking.{Blocking, effectBlocking} trait DownloadableFile { def openStream: IO[InputStream] def size: IO[Long] } trait DownloadableFileProvider { def getFile(uri: URI): Option[DownloadableFile] = provide.lift(uri) def provide: PartialFunction[URI, DownloadableFile] def protocols: Seq[String] object Supported { def unapply(arg: URI): Option[URI] = { Option(arg.getScheme).flatMap(scheme => protocols.find(_ == scheme)).map(_ => arg) } } } object DownloadableFileProvider { private lazy val unsafeLoad = ServiceLoader.load(classOf[DownloadableFileProvider]).iterator.asScala.toList def isSupported(uri: URI): RIO[Blocking, Boolean] = effectBlocking(unsafeLoad).map { providers => Option(uri.getScheme).exists(providers.flatMap(_.protocols).contains) } def getFile(uri: URI): ZIO[Blocking, Throwable, DownloadableFile] = { effectBlocking(unsafeLoad).map { providers => for { scheme <- Option(uri.getScheme) provider <- providers.find(_.protocols.contains(scheme)) file <- provider.getFile(uri) } yield file }.someOrFail(new Exception(s"Unable to find provider for uri $uri")) } } class HttpFileProvider extends DownloadableFileProvider { override def protocols: Seq[String] = Seq("http", "https") override def provide: PartialFunction[URI, DownloadableFile] = { case Supported(uri) => HTTPFile(uri) } } case class HTTPFile(uri: URI) extends DownloadableFile { override def openStream: IO[InputStream] = IO(uri.toURL.openStream()) override def size: IO[Long] = IO(uri.toURL.openConnection().asInstanceOf[HttpURLConnection]).bracket { conn => IO { conn.setRequestMethod("HEAD") conn.getContentLengthLong } } { conn => IO(conn.disconnect())} } class LocalFileProvider extends DownloadableFileProvider { override def protocols: Seq[String] = Seq("file") override def provide: PartialFunction[URI, DownloadableFile] = { case Supported(uri) => LocalFile(uri) } } case class LocalFile(uri: URI) extends DownloadableFile { lazy val file = new File(uri) override def openStream: IO[InputStream] = IO(new FileInputStream(file)) override def size: IO[Long] = IO.pure(file.length()) }
Example 113
Source File: CatsImplicitsSpec.scala From neotypes with MIT License | 5 votes |
package neotypes.cats.effect import cats.{Applicative, Monad} import cats.effect.{Async, IO, Resource} import cats.effect.implicits._ import cats.implicits._ import neotypes.{BaseIntegrationSpec, Driver, Session} import neotypes.cats.effect.implicits._ import neotypes.implicits.all._ import org.neo4j.driver.v1.exceptions.ClientException final class CatsImplicitsSpec extends BaseIntegrationSpec[IO](IOTestkit) { it should "work with cats implicits and neotypes implicits" in { def test1[F[_]: Applicative]: F[Unit] = Applicative[F].unit def test2[F[_]: Monad]: F[Unit] = ().pure[F] def makeSession[F[_]: Async]: Resource[F, Session[F]] = Resource .make(Async[F].delay(new Driver[F](this.driver)))(_.close) .flatMap(_.session) def useSession[F[_]: Async]: F[String] = makeSession[F].use { s => (test1[F] *> test2[F]).flatMap { _=> """match (p:Person {name: "Charlize Theron"}) return p.name""" .query[String] .single(s) } } useSession[IO].unsafeToFuture().map { name => assert(name == "Charlize Theron") } } override val initQuery: String = BaseIntegrationSpec.DEFAULT_INIT_QUERY }
Example 114
Source File: DeepBindBenchmark.scala From cats-effect with Apache License 2.0 | 5 votes |
package cats.effect.benchmarks import java.util.concurrent.TimeUnit import cats.effect.{ContextShift, IO} import org.openjdk.jmh.annotations._ import scala.concurrent.ExecutionContext.Implicits @State(Scope.Thread) @BenchmarkMode(Array(Mode.Throughput)) @OutputTimeUnit(TimeUnit.SECONDS) class DeepBindBenchmark { implicit val cs: ContextShift[IO] = IO.contextShift(Implicits.global) @Param(Array("3000")) var size: Int = _ @Benchmark def pure(): Int = { def loop(i: Int): IO[Int] = for { j <- IO.pure(i) _ <- if (j > size) IO.pure(j) else loop(j + 1) } yield j loop(0).unsafeRunSync() } @Benchmark def delay(): Int = { def loop(i: Int): IO[Int] = for { j <- IO(i) _ <- if (j > size) IO(j) else loop(j + 1) } yield j loop(0).unsafeRunSync() } @Benchmark def async(): Int = { def loop(i: Int): IO[Int] = for { j <- IO(i) _ <- IO.shift _ <- if (j > size) IO(j) else loop(j + 1) } yield j loop(0).unsafeRunSync() } }
Example 115
Source File: AttemptBenchmark.scala From cats-effect with Apache License 2.0 | 5 votes |
package cats.effect.benchmarks import java.util.concurrent.TimeUnit import cats.effect.IO import org.openjdk.jmh.annotations._ @State(Scope.Thread) @BenchmarkMode(Array(Mode.Throughput)) @OutputTimeUnit(TimeUnit.SECONDS) class AttemptBenchmark { @Param(Array("10000")) var size: Int = _ @Benchmark def happyPath(): Int = { def loop(i: Int): IO[Int] = if (i < size) IO.pure(i + 1).attempt.flatMap(_.fold(IO.raiseError, loop)) else IO.pure(i) loop(0).unsafeRunSync() } @Benchmark def errorRaised(): Int = { val dummy = new RuntimeException("dummy") val id = IO.pure[Int] _ def loop(i: Int): IO[Int] = if (i < size) IO.raiseError[Int](dummy) .flatMap(x => IO.pure(x + 1)) .attempt .flatMap(_.fold(_ => loop(i + 1), id)) else IO.pure(i) loop(0).unsafeRunSync() } }
Example 116
Source File: MapStreamBenchmark.scala From cats-effect with Apache License 2.0 | 5 votes |
package cats.effect.benchmarks import java.util.concurrent.TimeUnit import cats.effect.IO import org.openjdk.jmh.annotations._ @State(Scope.Thread) @BenchmarkMode(Array(Mode.Throughput)) @OutputTimeUnit(TimeUnit.SECONDS) class MapStreamBenchmark { import MapStreamBenchmark.streamTest @Benchmark def one(): Long = streamTest(12000, 1) @Benchmark def batch30(): Long = streamTest(1000, 30) @Benchmark def batch120(): Long = streamTest(100, 120) } object MapStreamBenchmark { def streamTest(times: Int, batchSize: Int): Long = { var stream = range(0, times) var i = 0 while (i < batchSize) { stream = mapStream(addOne)(stream) i += 1 } sum(0)(stream).unsafeRunSync() } final case class Stream(value: Int, next: IO[Option[Stream]]) val addOne = (x: Int) => x + 1 def range(from: Int, until: Int): Option[Stream] = if (from < until) Some(Stream(from, IO(range(from + 1, until)))) else None def mapStream(f: Int => Int)(box: Option[Stream]): Option[Stream] = box match { case Some(Stream(value, next)) => Some(Stream(f(value), next.map(mapStream(f)))) case None => None } def sum(acc: Long)(box: Option[Stream]): IO[Long] = box match { case Some(Stream(value, next)) => next.flatMap(sum(acc + value)) case None => IO.pure(acc) } }
Example 117
Source File: MapCallsBenchmark.scala From cats-effect with Apache License 2.0 | 5 votes |
package cats.effect.benchmarks import java.util.concurrent.TimeUnit import cats.effect.IO import org.openjdk.jmh.annotations._ @State(Scope.Thread) @BenchmarkMode(Array(Mode.Throughput)) @OutputTimeUnit(TimeUnit.SECONDS) class MapCallsBenchmark { import MapCallsBenchmark.test @Benchmark def one(): Long = test(12000, 1) @Benchmark def batch30(): Long = test(12000 / 30, 30) @Benchmark def batch120(): Long = test(12000 / 120, 120) } object MapCallsBenchmark { def test(iterations: Int, batch: Int): Long = { val f = (x: Int) => x + 1 var io = IO(0) var j = 0 while (j < batch) { io = io.map(f); j += 1 } var sum = 0L var i = 0 while (i < iterations) { sum += io.unsafeRunSync() i += 1 } sum } }
Example 118
Source File: CpgServerMain.scala From codepropertygraph with Apache License 2.0 | 5 votes |
package io.shiftleft.cpgserver import cats.effect.{ExitCode, IO, IOApp} import cats.implicits._ import org.http4s.implicits._ import org.http4s.server.blaze.BlazeServerBuilder import io.shiftleft.cpgserver.config.ServerConfiguration import io.shiftleft.cpgserver.cpg.DummyCpgProvider import io.shiftleft.cpgserver.query.{DefaultAmmoniteExecutor, ServerAmmoniteExecutor} import io.shiftleft.cpgserver.route.{CpgRoute, HttpErrorHandler, SwaggerRoute} object CpgServerMain extends IOApp { private val banner: String = """| ██████╗██████╗ ██████╗ ███████╗███████╗██████╗ ██╗ ██╗███████╗██████╗ |██╔════╝██╔══██╗██╔════╝ ██╔════╝██╔════╝██╔══██╗██║ ██║██╔════╝██╔══██╗ |██║ ██████╔╝██║ ███╗ ███████╗█████╗ ██████╔╝██║ ██║█████╗ ██████╔╝ |██║ ██╔═══╝ ██║ ██║ ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██╔══╝ ██╔══██╗ |╚██████╗██║ ╚██████╔╝ ███████║███████╗██║ ██║ ╚████╔╝ ███████╗██║ ██║ | ╚═════╝╚═╝ ╚═════╝ ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝╚═╝ ╚═╝ |""".stripMargin private val cpgProvider: DummyCpgProvider = new DummyCpgProvider private val ammoniteExecutor: ServerAmmoniteExecutor = new DefaultAmmoniteExecutor private implicit val httpErrorHandler: HttpErrorHandler = CpgRoute.CpgHttpErrorHandler private val serverConfig: ServerConfiguration = ServerConfiguration.config.getOrElse(ServerConfiguration.default) private val httpRoutes = CpgRoute(cpgProvider, ammoniteExecutor, serverConfig.files).routes <+> SwaggerRoute().routes override def run(args: List[String]): IO[ExitCode] = { BlazeServerBuilder[IO] .withBanner(List(banner)) .bindHttp(serverConfig.port, serverConfig.host) .withHttpApp(httpRoutes.orNotFound) .serve .compile .drain .as(ExitCode.Success) } }
Example 119
Source File: SwaggerRoute.scala From codepropertygraph with Apache License 2.0 | 5 votes |
package io.shiftleft.cpgserver.route import java.util.concurrent.Executors import scala.concurrent.ExecutionContext import cats.data.OptionT import cats.effect.{Blocker, ContextShift, IO} import io.circe.generic.auto._ import io.circe.syntax._ import org.http4s._ import org.http4s.circe._ import org.http4s.dsl.io._ import org.http4s.headers.Location import org.webjars.WebJarAssetLocator import io.shiftleft.cpgserver.route.CpgRoute.ApiError final class SwaggerRoute { private val blockingEc = ExecutionContext.fromExecutor(Executors.newSingleThreadExecutor) private val blocker = Blocker.liftExecutionContext(blockingEc) private implicit val blockingCs: ContextShift[IO] = IO.contextShift(blockingEc) private val swaggerUiVersion = IO { new WebJarAssetLocator().getWebJars.get("swagger-ui") } private val swaggerUiResources = swaggerUiVersion.map { ver => s"/META-INF/resources/webjars/swagger-ui/$ver" } private val swaggerUiPath = Path("swagger-ui") val routes: HttpRoutes[IO] = HttpRoutes.of { case GET -> Root / ("swagger-ui" | "docs") => PermanentRedirect(Location(Uri.unsafeFromString("swagger-ui/index.html"))) // TODO discuss with jacob: according to scalac this is unreachable... commenting for now since it probably never worked anyway case req @ GET -> (Root | `swaggerUiPath`) / "swagger.yaml" => StaticFile .fromResource("/swagger.yaml", blocker, Some(req)) .getOrElseF(InternalServerError(ApiError("Swagger documentation is missing.").asJson)) case req @ GET -> path if path.startsWith(swaggerUiPath) => { val file = path.toList.tail.mkString("/", "/", "") match { case f if f == "/index.html" => StaticFile.fromResource[IO]("/swagger-ui/index.html", blocker, Some(req)) case f => OptionT.liftF(swaggerUiResources).flatMap { resources => StaticFile.fromResource[IO](resources + f, blocker, Some(req)) } } file.getOrElseF(InternalServerError(ApiError(s"Requested file [$file] is missing.").asJson)) } } } object SwaggerRoute { def apply(): SwaggerRoute = new SwaggerRoute }
Example 120
Source File: HttpErrorHandler.scala From codepropertygraph with Apache License 2.0 | 5 votes |
package io.shiftleft.cpgserver.route import cats.data.{Kleisli, OptionT} import cats.effect.IO import org.http4s.{HttpRoutes, Request, Response} trait HttpErrorHandler { def handle(routes: HttpRoutes[IO]): HttpRoutes[IO] } object HttpErrorHandler { def apply(routes: HttpRoutes[IO])(handler: PartialFunction[Throwable, IO[Response[IO]]]): HttpRoutes[IO] = { Kleisli { req: Request[IO] => OptionT { routes.run(req).value.handleErrorWith { e => if (handler.isDefinedAt(e)) handler(e).map(Option(_)) else IO.raiseError(e) } } } } }
Example 121
Source File: DummyCpgProviderSpec.scala From codepropertygraph with Apache License 2.0 | 5 votes |
package io.shiftleft.cpgserver.cpg import java.util.UUID import scala.concurrent.ExecutionContext import cats.data.OptionT import cats.effect.{ContextShift, IO} import org.scalatest.concurrent.Eventually import io.shiftleft.codepropertygraph.Cpg import io.shiftleft.cpgserver.BaseSpec import io.shiftleft.cpgserver.query.CpgOperationResult import scala.concurrent.duration._ import scala.language.postfixOps class DummyCpgProviderSpec extends BaseSpec with Eventually { private implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global) private def withNewCpgProvider[T](f: DummyCpgProvider => T): T = { f(new DummyCpgProvider) } "Creating a CPG" should { "return a UUID referencing the eventual CPG" in withNewCpgProvider { cpgProvider => noException should be thrownBy cpgProvider.createCpg(Set.empty).unsafeRunSync() } } "Retrieving a CPG" should { "return a success if the CPG was created successfully" in withNewCpgProvider { cpgProvider => val cpgId = cpgProvider.createCpg(Set.empty).unsafeRunSync() eventually(timeout(10 seconds), interval(1 seconds)) { cpgProvider.retrieveCpg(cpgId).value.unsafeRunSync() shouldBe defined } } "return an empty OptionT if the CPG does not exist" in withNewCpgProvider { cpgProvider => cpgProvider.retrieveCpg(UUID.randomUUID) shouldBe OptionT.none[IO, CpgOperationResult[Cpg]] } } }
Example 122
Source File: ServerAmmoniteExecutorSpec.scala From codepropertygraph with Apache License 2.0 | 5 votes |
package io.shiftleft.cpgserver.query import cats.effect.{ContextShift, IO} import org.scalatest.{Matchers, WordSpec} import io.shiftleft.codepropertygraph.Cpg class ServerAmmoniteExecutorSpec extends WordSpec with Matchers { private implicit val cs: ContextShift[IO] = IO.contextShift(scala.concurrent.ExecutionContext.global) private class DummyServerAmmoniteExecutor extends ServerAmmoniteExecutor { override protected def predef: String = "import io.shiftleft.semanticcpg.language._" } private def withServerExecutor[T](f: ServerAmmoniteExecutor => T): T = { f(new DummyServerAmmoniteExecutor) } "A ServerAmmoniteExecutor" should { "run a query synchronously" in withServerExecutor { executor => executor.executeQuerySync(Cpg.emptyCpg, "cpg.method.l").unsafeRunSync() should matchPattern { case CpgOperationSuccess("List()") => } } } }
Example 123
Source File: Http4sSpec.scala From codepropertygraph with Apache License 2.0 | 5 votes |
package io.shiftleft.cpgserver.route import cats.effect.IO import org.http4s.{EntityDecoder, Response, Status} import io.shiftleft.cpgserver.BaseSpec trait Http4sSpec extends BaseSpec { // Helpfully lifted from https://http4s.org/v0.20/testing/ def check[A](actual: IO[Response[IO]], expectedStatus: Status, expectedBody: Option[A] = None)( implicit ev: EntityDecoder[IO, A] ): Boolean = { val actualResp = actual.unsafeRunSync val statusCheck = actualResp.status == expectedStatus val bodyCheck = expectedBody.fold[Boolean](actualResp.body.compile.toVector.unsafeRunSync.isEmpty)( // Verify Response's body is empty. expected => actualResp.as[A].unsafeRunSync == expected) statusCheck && bodyCheck } }
Example 124
Source File: ScriptManagerTest.scala From codepropertygraph with Apache License 2.0 | 5 votes |
package io.shiftleft.console.scripting import better.files.File import cats.effect.IO import org.scalatest.{Inside, Matchers, WordSpec} import io.shiftleft.codepropertygraph.Cpg import io.shiftleft.console.scripting.ScriptManager.{ScriptCollections, ScriptDescription, ScriptDescriptions} import java.nio.file.{FileSystemNotFoundException, NoSuchFileException, Path} import scala.io.Source import scala.util.Try class ScriptManagerTest extends WordSpec with Matchers with Inside { private object TestScriptExecutor extends AmmoniteExecutor { override protected def predef: String = "" override def runScript(scriptPath: Path, parameters: Map[String, String], cpg: Cpg): IO[Any] = IO.fromTry( Try { val source = Source.fromFile(scriptPath.toFile) val result = source.getLines.mkString(System.lineSeparator()) source.close() result } ) } private object TestScriptManager extends ScriptManager(TestScriptExecutor) protected val DEFAULT_CPG_NAME: String = { if (File(".").name == "console") { (File("..") / "resources" / "testcode" / "cpgs" / "method" / "cpg.bin.zip").pathAsString } else { (File("resources") / "testcode" / "cpgs" / "method" / "cpg.bin.zip").pathAsString } } def withScriptManager(f: ScriptManager => Unit): Unit = { f(TestScriptManager) } "listing scripts" should { "be correct" in withScriptManager { scriptManager => val scripts = scriptManager.scripts() val expected = List( ScriptCollections("general", ScriptDescriptions( "A collection of general purpose scripts.", List(ScriptDescription("list-funcs.sc", "Lists all functions.")) )), ScriptCollections("java", ScriptDescriptions( "A collection of java-specific scripts.", List(ScriptDescription("list-sl-ns.sc", "Lists all shiftleft namespaces.")) )), ScriptCollections("general/general_plus", ScriptDescriptions( "Even more general purpose scripts.", List.empty )) ) scripts should contain theSameElementsAs expected } } "running scripts" should { "be correct when explicitly specifying a CPG" in withScriptManager { scriptManager => val expected = """|@main def main() = { | cpg.method.name.l |}""".stripMargin scriptManager.runScript("general/list-funcs.sc", Map.empty, Cpg.emptyCpg) shouldBe expected } "be correct when specifying a CPG filename" in withScriptManager { scriptManager => val expected = """|@main def main() = { | cpg.method.name.l |}""".stripMargin scriptManager.runScript("general/list-funcs.sc", Map.empty, DEFAULT_CPG_NAME) shouldBe expected } "throw an exception if the specified CPG can not be found" in withScriptManager { scriptManager => intercept[FileSystemNotFoundException] { scriptManager.runScript("general/list-funcs.sc", Map.empty, "cake.bin.zip") } } "throw an exception if the specified script can not be found" in withScriptManager { scriptManager => intercept[NoSuchFileException] { scriptManager.runScript("list-funcs.sc", Map.empty, Cpg.emptyCpg) } } } }
Example 125
Source File: ResilientStreamSpec.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.resiliency import cats.effect.IO import cats.effect.concurrent.Ref import cats.implicits._ import dev.profunktor.fs2rabbit.BaseSpec import fs2._ import scala.concurrent.duration._ import org.scalatest.compatible.Assertion class ResilientStreamSpec extends BaseSpec { private val sink: Pipe[IO, Int, Unit] = _.evalMap(putStrLn) val emptyAssertion: Assertion = true shouldBe true it should "run a stream until it's finished" in { val program = Stream(1, 2, 3).covary[IO].through(sink) ResilientStream.run(program).as(emptyAssertion).unsafeToFuture } it should "run a stream and recover in case of failure" in { val errorProgram = Stream.raiseError[IO](new Exception("on purpose")).through(sink) def p(ref: Ref[IO, Int]): Stream[IO, Unit] = errorProgram.handleErrorWith { t => Stream.eval(ref.get) flatMap { n => if (n == 0) Stream.eval(IO.unit) else Stream.eval(ref.update(_ - 1) *> IO.raiseError(t)) } } Ref.of[IO, Int](2).flatMap(r => ResilientStream.run(p(r), 1.second)).as(emptyAssertion).unsafeToFuture } }
Example 126
Source File: RabbitSuite.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.interpreter import cats.effect.{ContextShift, IO} import cats.implicits._ import dev.profunktor.fs2rabbit.BaseSpec import dev.profunktor.fs2rabbit.config.Fs2RabbitConfig import scala.concurrent.ExecutionContext class RabbitSuite extends BaseSpec with Fs2RabbitSpec { override implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global) override val config: Fs2RabbitConfig = Fs2RabbitConfig( host = "localhost", port = 5672, virtualHost = "/", connectionTimeout = 30, ssl = false, username = "guest".some, password = "guest".some, requeueOnNack = false, requeueOnReject = false, internalQueueSize = 500.some ) }
Example 127
Source File: EnvelopeDecoderSpec.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.effects import java.nio.charset.StandardCharsets import cats.data.EitherT import cats.effect.{IO, SyncIO} import cats.instances.either._ import cats.instances.try_._ import dev.profunktor.fs2rabbit.model.{AmqpEnvelope, AmqpProperties, DeliveryTag, ExchangeName, RoutingKey} import org.scalatest.funsuite.AsyncFunSuite import scala.util.Try class EnvelopeDecoderSpec extends AsyncFunSuite { // Available instances of EnvelopeDecoder for any ApplicativeError[F, Throwable] EnvelopeDecoder[Either[Throwable, ?], String] EnvelopeDecoder[SyncIO, String] EnvelopeDecoder[EitherT[IO, String, ?], String] EnvelopeDecoder[Try, String] test("should decode a UTF-8 string") { val msg = "hello world!" val raw = msg.getBytes(StandardCharsets.UTF_8) EnvelopeDecoder[IO, String] .run( AmqpEnvelope(DeliveryTag(0L), raw, AmqpProperties.empty, ExchangeName("test"), RoutingKey("test.route"), false)) .flatMap { result => IO(assert(result == msg)) } .unsafeToFuture() } test("should decode payload with the given content encoding") { val msg = "hello world!" val raw = msg.getBytes(StandardCharsets.UTF_8) EnvelopeDecoder[IO, String] .run( AmqpEnvelope(DeliveryTag(0L), raw, AmqpProperties.empty.copy(contentEncoding = Some("UTF-16")), ExchangeName("test"), RoutingKey("test.route"), false)) .flatMap { result => IO(assert(result != msg)) } .unsafeToFuture() } test("should decode a UTF-16 string into a UTF-8 (default)") { val msg = "hello world!" val raw = msg.getBytes(StandardCharsets.UTF_16) EnvelopeDecoder[IO, String] .run( AmqpEnvelope(DeliveryTag(0L), raw, AmqpProperties.empty, ExchangeName("test"), RoutingKey("test.route"), false)) .flatMap { result => IO(assert(result != msg)) } .unsafeToFuture() } }
Example 128
Source File: FileChecks.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.convert import java.nio.charset.StandardCharsets import java.nio.file.{Files, Path} import cats.data.Kleisli import cats.effect.IO import fs2.{Pipe, Stream} import docspell.common.MimeType import docspell.convert.ConversionResult.Handler import docspell.files.TikaMimetype trait FileChecks { implicit class FileCheckOps(p: Path) { def isNonEmpty: Boolean = Files.exists(p) && Files.size(p) > 0 def isType(mime: MimeType): Boolean = TikaMimetype.detect[IO](p).map(_ == mime).unsafeRunSync def isPDF: Boolean = isType(MimeType.pdf) def isPlainText: Boolean = isType(MimeType.text("plain")) } def storeFile(file: Path): Pipe[IO, Byte, Path] = in => Stream.eval(in.compile.to(Array).flatMap(bytes => IO(Files.write(file, bytes)))) def storePdfHandler(file: Path): Handler[IO, Path] = storePdfTxtHandler(file, file.resolveSibling("unexpected.txt")).map(_._1) def storePdfTxtHandler(filePdf: Path, fileTxt: Path): Handler[IO, (Path, Path)] = Kleisli({ case ConversionResult.SuccessPdfTxt(pdf, txt) => for { pout <- pdf.through(storeFile(filePdf)).compile.lastOrError str <- txt tout <- IO(Files.write(fileTxt, str.getBytes(StandardCharsets.UTF_8))) } yield (pout, tout) case ConversionResult.SuccessPdf(pdf) => pdf.through(storeFile(filePdf)).compile.lastOrError.map(p => (p, fileTxt)) case ConversionResult.Failure(ex) => throw new Exception(s"Unexpected result (failure: ${ex.getMessage})", ex) case cr => throw new Exception(s"Unexpected result: $cr") }) def commandExists(cmd: String): Boolean = Runtime.getRuntime.exec(Array("which", cmd)).waitFor() == 0 }
Example 129
Source File: TextExtractionSuite.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.extract.ocr import cats.effect.IO import docspell.common.Logger import docspell.files.TestFiles import minitest.SimpleTestSuite object TextExtractionSuite extends SimpleTestSuite { import TestFiles._ val logger = Logger.log4s[IO](org.log4s.getLogger) test("extract english pdf") { ignore() val text = TextExtract .extract[IO](letterSourceEN, blocker, logger, "eng", OcrConfig.default) .compile .lastOrError .unsafeRunSync() println(text) } test("extract german pdf") { ignore() val expect = TestFiles.letterDEText val extract = TextExtract .extract[IO](letterSourceDE, blocker, logger, "deu", OcrConfig.default) .compile .lastOrError .unsafeRunSync() assertEquals(extract.value, expect) } }
Example 130
Source File: TestFiles.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.files import cats.effect.{Blocker, IO} import fs2.Stream import scala.concurrent.ExecutionContext object TestFiles { val blocker = Blocker.liftExecutionContext(ExecutionContext.global) implicit val CS = IO.contextShift(ExecutionContext.global) val letterSourceDE: Stream[IO, Byte] = ExampleFiles.letter_de_pdf .readURL[IO](8 * 1024, blocker) val letterSourceEN: Stream[IO, Byte] = ExampleFiles.letter_en_pdf .readURL[IO](8 * 1024, blocker) lazy val letterDEText = ExampleFiles.letter_de_txt .readText[IO](8 * 1024, blocker) .unsafeRunSync lazy val letterENText = ExampleFiles.letter_en_txt .readText[IO](8 * 1024, blocker) .unsafeRunSync }
Example 131
Source File: Playing.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.files import cats.effect.{Blocker, ExitCode, IO, IOApp} import docspell.common.MimeTypeHint import scala.concurrent.ExecutionContext object Playing extends IOApp { val blocker = Blocker.liftExecutionContext(ExecutionContext.global) def run(args: List[String]): IO[ExitCode] = IO { //val ods = ExampleFiles.examples_sample_ods.readURL[IO](8192, blocker) //val odt = ExampleFiles.examples_sample_odt.readURL[IO](8192, blocker) val rtf = ExampleFiles.examples_sample_rtf.readURL[IO](8192, blocker) val x = for { odsm1 <- TikaMimetype .detect( rtf, MimeTypeHint.filename(ExampleFiles.examples_sample_rtf.path.segments.last) ) odsm2 <- TikaMimetype.detect(rtf, MimeTypeHint.none) } yield (odsm1, odsm2) println(x.unsafeRunSync()) ExitCode.Success } }
Example 132
Source File: ImageSizeTest.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.files import cats.implicits._ import cats.effect.{Blocker, IO} import minitest.SimpleTestSuite import scala.concurrent.ExecutionContext import scala.util.Using object ImageSizeTest extends SimpleTestSuite { val blocker = Blocker.liftExecutionContext(ExecutionContext.global) implicit val CS = IO.contextShift(ExecutionContext.global) //tiff files are not supported on the jdk by default //requires an external library val files = List( ExampleFiles.camera_letter_en_jpg -> Dimension(1695, 2378), ExampleFiles.camera_letter_en_png -> Dimension(1695, 2378), // ExampleFiles.camera_letter_en_tiff -> Dimension(1695, 2378), ExampleFiles.scanner_jfif_jpg -> Dimension(2480, 3514), ExampleFiles.bombs_20K_gray_jpeg -> Dimension(20000, 20000), ExampleFiles.bombs_20K_gray_png -> Dimension(20000, 20000), ExampleFiles.bombs_20K_rgb_jpeg -> Dimension(20000, 20000), ExampleFiles.bombs_20K_rgb_png -> Dimension(20000, 20000) ) test("get sizes from input-stream") { files.foreach { case (uri, expect) => val url = uri.toJavaUrl.fold(sys.error, identity) Using.resource(url.openStream()) { in => val dim = ImageSize.get(in) assertEquals(dim, expect.some) } } } test("get sizes from stream") { files.foreach { case (uri, expect) => val stream = uri.readURL[IO](8192, blocker) val dim = ImageSize.get(stream).unsafeRunSync() assertEquals(dim, expect.some) } } }
Example 133
Source File: JsonLogEncodingTest.scala From cedi-dtrace with Apache License 2.0 | 5 votes |
package com.ccadllc.cedi.dtrace package logging import cats.effect.{ IO, Effect } import io.circe._ import io.circe.syntax._ import org.scalacheck.Arbitrary import org.scalatest.wordspec.AnyWordSpec import json.encoding._ class JsonLogEncodingTests extends AnyWordSpec with TestSupport { // format: OFF val calculateQuarterlySalesTraceContextJson = Json.obj( "where" -> calculateQuarterlySalesTraceContext.system.data.allValues.asJson, "root" -> calculateQuarterlySalesTraceContext.currentSpan.root.asJson, "trace-id" -> calculateQuarterlySalesTraceContext.currentSpan.spanId.traceId.asJson, "span-id" -> calculateQuarterlySalesTraceContext.currentSpan.spanId.spanId.asJson, "parent-id" -> calculateQuarterlySalesTraceContext.currentSpan.spanId.parentSpanId.asJson, "span-name" -> calculateQuarterlySalesTraceContext.currentSpan.spanName.value.asJson, "start-time" -> calculateQuarterlySalesTraceContext.currentSpan.startTime.asJson, "span-success" -> calculateQuarterlySalesTraceContext.currentSpan.failure.isEmpty.asJson, "failure-detail" -> calculateQuarterlySalesTraceContext.currentSpan.failure.map(_.render).asJson, "span-duration" -> calculateQuarterlySalesTraceContext.currentSpan.duration.toMicros.asJson, "notes" -> Map( quarterlySalesUnitsNote.name.value -> quarterlySalesUnitsNoteValue.value.toString, quarterlySalesGoalReachedNote.name.value -> quarterlySalesGoalReachedNoteValue.value.toString, salesRegionNote.name.value -> salesRegionNoteValue.value, quarterlySalesTotalNote.name.value -> quarterlySalesTotalNoteValue.value.toString ).asJson ) // format: ON implicit def traceArb[F[_]: Effect]: Arbitrary[TraceContext[F]] = Arbitrary(genTraceContext[F]) "Trace" should { encodeGeneratedJson[TraceContext[IO]] } "Trace" should { encodeSpecificJson(calculateQuarterlySalesTraceContext, calculateQuarterlySalesTraceContextJson) } }
Example 134
Source File: TestSupport.scala From cedi-dtrace with Apache License 2.0 | 5 votes |
package com.ccadllc.cedi.dtrace package logging import cats.effect.{ IO, Sync } import io.circe._ import io.circe.syntax._ import org.scalacheck.Arbitrary import org.scalatest.Suite import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import shapeless.Lazy trait TestSupport extends AnyWordSpecLike with Matchers with ScalaCheckPropertyChecks with TraceGenerators with TestData { self: Suite => override def testEmitter[F[_]: Sync]: F[TraceSystem.Emitter[F]] = Sync[F].pure(LogEmitter.apply) val salesManagementSystem = TraceSystem(testSystemData, testEmitter[IO].unsafeRunSync, TraceSystem.realTimeTimer[IO]) val calculateQuarterlySalesTraceContext = TraceContext(quarterlySalesCalculationSpan, true, salesManagementSystem) def encodeGeneratedJson[A: Arbitrary](implicit encoder: Lazy[Encoder[A]]): Unit = { implicit val e = encoder.value "encode arbitrary instances to JSON" in { forAll { (msg: A) => msg.asJson.noSpaces should not be (None) } } } def encodeSpecificJson[A](a: A, json: Json)(implicit encoder: Lazy[Encoder[A]]): Unit = { implicit val e = encoder.value "encode specific instance to JSON and ensure it matches expected" in { a.asJson shouldBe json } } }
Example 135
Source File: LogstashLogbackEmitterTest.scala From cedi-dtrace with Apache License 2.0 | 5 votes |
package com.ccadllc.cedi.dtrace package logstash import cats.effect.IO import org.scalatest.wordspec.AnyWordSpec class LogstashLogbackEmitterTest extends AnyWordSpec with TestData { "LogstashLogbackEmitterTest" should { "work" in { val system = TraceSystem(testSystemData, new LogstashLogbackEmitter[IO], quarterlySalesCalculationTimer) val spanRoot = Span.root[IO](quarterlySalesCalculationTimer, Span.Name("calculate-quarterly-sales")).unsafeRunSync IO.unit.toTraceT.trace(TraceContext(spanRoot, true, system)).unsafeRunSync } } }
Example 136
Source File: EcsLogstashLogbackEmitterTest.scala From cedi-dtrace with Apache License 2.0 | 5 votes |
package com.ccadllc.cedi.dtrace package logstash import cats.effect.IO import org.scalatest.wordspec.AnyWordSpec class EcsLogstashLogbackEmitterTest extends AnyWordSpec with TestData { "EcsLogstashLogbackEmitterTest" should { "work" in { val system = TraceSystem(testSystemData, new EcsLogstashLogbackEmitter[IO], quarterlySalesCalculationTimer) val spanRoot = Span.root[IO](quarterlySalesCalculationTimer, Span.Name("calculate-quarterly-sales")).unsafeRunSync IO.unit.toTraceT.trace(TraceContext(spanRoot, true, system)).unsafeRunSync } } }
Example 137
Source File: CodeGenWrite.scala From bosatsu with Apache License 2.0 | 5 votes |
package org.bykn.bosatsu import cats.data.NonEmptyList import cats.effect.IO import java.nio.file.Path import java.io.PrintWriter import org.typelevel.paiges.Doc object CodeGenWrite { @annotation.tailrec final def toPath(root: Path, pn: PackageName): Path = pn.parts match { case NonEmptyList(h, Nil) => root.resolve(h).resolve("Values.java") case NonEmptyList(h0, h1 :: tail) => toPath(root.resolve(h0), PackageName(NonEmptyList(h1, tail))) } def writeDoc(p: Path, d: Doc): IO[Unit] = IO { Option(p.getParent).foreach(_.toFile.mkdirs) val pw = new PrintWriter(p.toFile, "UTF-8") try d.renderStream(80).foreach(pw.print(_)) finally { pw.close } } }
Example 138
Source File: Commands.scala From franklin with Apache License 2.0 | 5 votes |
package com.azavea.franklin.api.commands import cats.effect.{ContextShift, ExitCode, IO} import cats.implicits._ import com.azavea.franklin.crawler.StacImport import com.monovore.decline._ import doobie.Transactor import doobie.free.connection.{rollback, setAutoCommit, unit} import doobie.util.transactor.Strategy import org.flywaydb.core.Flyway object Commands { final case class RunMigrations(databaseConfig: DatabaseConfig) final case class RunServer(apiConfig: ApiConfig, dbConfig: DatabaseConfig) final case class RunImport( catalogRoot: String, config: DatabaseConfig, dryRun: Boolean ) private def runImportOpts(implicit cs: ContextShift[IO]): Opts[RunImport] = Opts.subcommand("import", "Import a STAC catalog") { ( Options.catalogRoot, Options.databaseConfig, Options.dryRun ).mapN(RunImport) } private def runMigrationsOpts(implicit cs: ContextShift[IO]): Opts[RunMigrations] = Opts.subcommand("migrate", "Runs migrations against database") { Options.databaseConfig map RunMigrations } private def runServerOpts(implicit cs: ContextShift[IO]): Opts[RunServer] = Opts.subcommand("serve", "Runs web service") { (Options.apiConfig, Options.databaseConfig) mapN RunServer } def runMigrations(dbConfig: DatabaseConfig): IO[ExitCode] = IO { Flyway .configure() .dataSource( s"${dbConfig.jdbcUrl}", dbConfig.dbUser, dbConfig.dbPass ) .locations("classpath:migrations/") .load() .migrate() ExitCode.Success } def runImport( stacCatalog: String, config: DatabaseConfig, dryRun: Boolean )( implicit contextShift: ContextShift[IO] ): IO[Unit] = { val xa = Transactor.strategy.set( Transactor.fromDriverManager[IO]( config.driver, config.jdbcUrl, config.dbUser, config.dbPass ), if (dryRun) { Strategy.default.copy(before = setAutoCommit(false), after = rollback, always = unit) } else { Strategy.default } ) new StacImport(stacCatalog).runIO(xa) } def applicationCommand(implicit cs: ContextShift[IO]): Command[Product] = Command("", "Your Friendly Neighborhood OGC API - Features and STAC Web Service") { runServerOpts orElse runMigrationsOpts orElse runImportOpts } }
Example 139
Source File: CogAssetNodeImplicits.scala From franklin with Apache License 2.0 | 5 votes |
package com.azavea.franklin.tile import cats.effect.ContextShift import cats.effect.IO import geotrellis.proj4.WebMercator import geotrellis.raster._ import geotrellis.raster.io.geotiff.AutoHigherResolution import geotrellis.raster.resample.NearestNeighbor import geotrellis.server.ExtentReification import geotrellis.server.TmsReification import geotrellis.vector.Extent object CogAssetNodeImplicits extends TileUtil { implicit def cogAssetNodeTmsReification: TmsReification[CogAssetNode] = new TmsReification[CogAssetNode] { def tmsReification( self: CogAssetNode, buffer: Int )(implicit cs: ContextShift[IO]): (Int, Int, Int) => IO[ProjectedRaster[MultibandTile]] = (z: Int, x: Int, y: Int) => { def fetch(xCoord: Int, yCoord: Int): IO[Raster[MultibandTile]] = { self.fetchTile(z, xCoord, yCoord, WebMercator).flatMap(a => IO(a)) } fetch(x, y).map { tile => val extent = tmsLevels(z).mapTransform.keyToExtent(x, y) ProjectedRaster(tile.tile, extent, WebMercator) } } } implicit def cogAssetNodeExtentReification: ExtentReification[CogAssetNode] = new ExtentReification[CogAssetNode] { def extentReification( self: CogAssetNode )(implicit cs: ContextShift[IO]): (Extent, CellSize) => IO[ProjectedRaster[MultibandTile]] = (extent: Extent, cs: CellSize) => { self.getRasterSource map { rs => rs.resample( TargetRegion(new GridExtent[Long](extent, cs)), NearestNeighbor, AutoHigherResolution ) .read(extent) .map { ProjectedRaster(_, WebMercator) } match { case Some(mbt) => mbt case _ => throw new Exception( s"No tile available for RasterExtent: ${RasterExtent(extent, cs)}" ) } } } } }
Example 140
Source File: CogAssetNode.scala From franklin with Apache License 2.0 | 5 votes |
package com.azavea.franklin.tile import cats.data.{NonEmptyList => NEL} import cats.effect.IO import com.azavea.franklin.cache._ import com.azavea.stac4s.StacItemAsset import geotrellis.layer._ import geotrellis.proj4._ import geotrellis.raster._ import geotrellis.raster.geotiff.GeoTiffRasterSource import geotrellis.raster.histogram.Histogram import geotrellis.raster.resample._ import scalacache.modes.sync._ import scalacache.{Sync => _, _} case class CogAssetNode(asset: StacItemAsset, bands: Seq[Int]) extends TileUtil { private val histoKey = s"histogram - $bands - ${asset.href}" private val tiffKey = s"tiff - ${asset.href}" def getRasterSource: IO[GeoTiffRasterSource] = { val infoFromCache = sync.get[SerializableGeotiffInfo](tiffKey) val tiffInfoIO = infoFromCache match { case Some(info) => IO.pure(info) case _ => { for { info <- IO.delay(GeotiffReader.getGeotiffInfo(asset.href)) } yield { sync.put(tiffKey)(info) info } } } for { info <- tiffInfoIO byteReader = getByteReader(asset.href) gtiffInfo = info.toGeotiffInfo(byteReader) geotiff = GeotiffReader.readMultibandWithInfo(gtiffInfo) } yield GeoTiffRasterSource(asset.href, baseTiff = Some(geotiff)) } def getHistograms: IO[List[Histogram[Int]]] = { val histogramFromSource = getRasterSource.map { rs => val overviews = rs.tiff.overviews val smallestOverview = overviews.maxBy { overview => val cs = overview.cellSize cs.width } bands.map { b => smallestOverview.tile.band(b).histogram }.toList } sync.get[List[Histogram[Int]]](histoKey) match { case Some(histograms) => IO.pure(histograms) case _ => { for { histograms <- histogramFromSource _ <- IO.pure(sync.put(histoKey)(histograms, None)) } yield histograms } } } def getRasterExtents: IO[NEL[RasterExtent]] = { getRasterSource map { rs => NEL .fromList(rs.resolutions.map { cs => RasterExtent(rs.extent, cs) }) .getOrElse(NEL(rs.gridExtent.toRasterExtent, Nil)) } } def fetchTile( zoom: Int, x: Int, y: Int, crs: CRS = WebMercator, method: ResampleMethod = NearestNeighbor, target: ResampleTarget = DefaultTarget ): IO[Raster[MultibandTile]] = { getRasterSource map { rs => val key = SpatialKey(x, y) val layoutDefinition = tmsLevels(zoom) val rasterSource = rs.reproject(crs, target).tileToLayout(layoutDefinition, method) rasterSource.read(key, bands).map(Raster(_, layoutDefinition.mapTransform(key))) } map { case Some(t) => t case _ => invisiRaster } } }
Example 141
Source File: CollectionsServiceSpec.scala From franklin with Apache License 2.0 | 5 votes |
package com.azavea.franklin.api.services import cats.data.OptionT import cats.effect.IO import cats.implicits._ import com.azavea.franklin.Generators import com.azavea.franklin.api.{TestClient, TestServices} import com.azavea.franklin.database.TestDatabaseSpec import com.azavea.franklin.datamodel.CollectionsResponse import com.azavea.stac4s.StacCollection import com.azavea.stac4s.testing._ import org.http4s.circe.CirceEntityDecoder._ import org.http4s.{Method, Request, Uri} import org.specs2.{ScalaCheck, Specification} import java.net.URLEncoder import java.nio.charset.StandardCharsets class CollectionsServiceSpec extends Specification with ScalaCheck with TestDatabaseSpec with Generators { def is = s2""" This specification verifies that the collections service can run without crashing The collections service should: - create and delete collections $createDeleteCollectionExpectation - list collections $listCollectionsExpectation - get collections by id $getCollectionsExpectation """ val testServices: TestServices[IO] = new TestServices[IO](transactor) val testClient: TestClient[IO] = new TestClient[IO](testServices.collectionsService, testServices.collectionItemsService) def listCollectionsExpectation = prop { (stacCollectionA: StacCollection, stacCollectionB: StacCollection) => { val listIO = ( testClient.getCollectionResource(stacCollectionA), testClient.getCollectionResource(stacCollectionB) ).tupled use { _ => val request = Request[IO](method = Method.GET, Uri.unsafeFromString(s"/collections")) (for { resp <- testServices.collectionsService.routes.run(request) decoded <- OptionT.liftF { resp.as[CollectionsResponse] } } yield decoded).value } val result = listIO.unsafeRunSync.get.collections map { _.id } (result must contain(stacCollectionA.id)) and (result must contain(stacCollectionB.id)) } } def getCollectionsExpectation = prop { (stacCollection: StacCollection) => val fetchIO = testClient.getCollectionResource(stacCollection) use { collection => val encodedId = URLEncoder.encode(collection.id, StandardCharsets.UTF_8.toString) val request = Request[IO](method = Method.GET, Uri.unsafeFromString(s"/collections/$encodedId")) (for { resp <- testServices.collectionsService.routes.run(request) decoded <- OptionT.liftF { resp.as[StacCollection] } } yield (decoded, collection)).value } val (fetched, inserted) = fetchIO.unsafeRunSync.get fetched must beTypedEqualTo(inserted) } // since creation / deletion is a part of the collection resource, and accurate creation is checked // in getCollectionsExpectation, this test just makes sure that if other tests are failing, it's // not because create/delete are broken def createDeleteCollectionExpectation = prop { (stacCollection: StacCollection) => (testClient .getCollectionResource(stacCollection) use { _ => IO.unit }).unsafeRunSync must beTypedEqualTo( () ) } }
Example 142
Source File: TracerSpec.scala From http4s-tracer with Apache License 2.0 | 5 votes |
package dev.profunktor.tracer import cats.effect.IO import dev.profunktor.tracer.instances.tracerlog._ import munit.FunSuite import org.http4s._ import org.http4s.client.dsl.io._ import org.http4s.dsl.io._ import org.http4s.implicits._ class TracerSpec extends FunSuite { // format: off override def munitValueTransforms = super.munitValueTransforms :+ new ValueTransform("IO", { case ioa: IO[_] => IO.suspend(ioa).unsafeToFuture }) // format: on val customHeaderName = "Test-Id" val customHeaderValue = "my-custom-value" val tracer: Tracer[IO] = Tracer.create[IO]() val customTracer: Tracer[IO] = Tracer.create[IO](customHeaderName) val tracerApp: HttpApp[IO] = tracer.middleware(TestHttpRoute.routes(tracer).orNotFound) val customTracerApp: HttpApp[IO] = customTracer.middleware(TestHttpRoute.routes(customTracer).orNotFound) def defaultAssertion(traceHeaderName: String): Response[IO] => IO[Unit] = resp => IO { assert(resp.status == Status.Ok) assert(resp.headers.toList.map(_.name.value).contains(traceHeaderName)) } def customAssertion(traceHeaderName: String): Response[IO] => IO[Unit] = resp => IO { assert(resp.status == Status.Ok) assert(resp.headers.toList.map(_.name.value).contains(traceHeaderName)) assert(resp.headers.toList.map(_.value).contains(customHeaderValue)) } test("Default TraceId header is created") { for { req <- GET(Uri.uri("/")) resp <- tracerApp(req) _ <- defaultAssertion(Tracer.DefaultTraceIdHeader)(resp) } yield () } test("TraceId header is passed in the request (no TraceId created)") { for { req <- GET(Uri.uri("/"), Header(Tracer.DefaultTraceIdHeader, customHeaderValue)) resp <- tracerApp(req) _ <- customAssertion(Tracer.DefaultTraceIdHeader)(resp) } yield () } test("Custom TraceId header (Test-Id) is created") { for { req <- GET(Uri.uri("/")) resp <- customTracerApp(req) _ <- defaultAssertion(customHeaderName)(resp) } yield () } test("TraceId header (Test-Id) is passed in the request") { for { req <- GET(Uri.uri("/"), Header(customHeaderName, customHeaderValue)) resp <- customTracerApp(req) _ <- customAssertion(customHeaderName)(resp) } yield () } } object TestHttpRoute extends Http4sTracerDsl[IO] { def routes(implicit t: Tracer[IO]): HttpRoutes[IO] = TracedHttpRoute[IO] { case GET -> Root using traceId => Ok(traceId.value) } }
Example 143
Source File: CommandExecutor.scala From renku with Apache License 2.0 | 5 votes |
package ch.renku.acceptancetests.tooling.console import java.io.{File, InputStream} import java.nio.file.Path import java.util import java.util.concurrent.ConcurrentLinkedQueue import cats.effect.IO import cats.implicits._ import ch.renku.acceptancetests.model.users.UserCredentials import ch.renku.acceptancetests.tooling.TestLogger.logger import ch.renku.acceptancetests.tooling.console.Command.UserInput import scala.jdk.CollectionConverters._ import scala.language.postfixOps import scala.sys.process._ private class CommandExecutor(command: Command) { def execute(implicit workPath: Path, userCredentials: UserCredentials): String = { implicit val output: util.Collection[String] = new ConcurrentLinkedQueue[String]() IO { executeCommand output.asString } recoverWith consoleException }.unsafeRunSync() def safeExecute(implicit workPath: Path, userCredentials: UserCredentials): String = { implicit val output: util.Collection[String] = new ConcurrentLinkedQueue[String]() IO { executeCommand output.asString } recover outputAsString }.unsafeRunSync() private def executeCommand(implicit workPath: Path, output: util.Collection[String], userCredentials: UserCredentials): Unit = command.userInputs.foldLeft(buildProcess) { (process, userInput) => process #< userInput.asStream } lazyLines ProcessLogger(logLine _) foreach logLine private def buildProcess(implicit workPath: Path) = command.maybeFileName.foldLeft(Process(command.toString.stripMargin, workPath.toFile)) { (process, fileName) => process #>> new File(workPath.toUri resolve fileName.value) } private def logLine( line: String )(implicit output: util.Collection[String], userCredentials: UserCredentials): Unit = line.trim match { case "" => () case line => val obfuscatedLine = line.replace(userCredentials.password.value, "###") output add obfuscatedLine logger debug obfuscatedLine } private def consoleException(implicit output: util.Collection[String]): PartialFunction[Throwable, IO[String]] = { case _ => ConsoleException { s"$command failed with:\n${output.asString}" }.raiseError[IO, String] } private def outputAsString(implicit output: util.Collection[String]): PartialFunction[Throwable, String] = { case _ => output.asString } private implicit class OutputOps(output: util.Collection[String]) { lazy val asString: String = output.asScala.mkString("\n") } private implicit class UserInputOps(userInput: UserInput) { import java.nio.charset.StandardCharsets.UTF_8 lazy val asStream: InputStream = new java.io.ByteArrayInputStream( userInput.value.getBytes(UTF_8.name) ) } }
Example 144
Source File: Main.scala From cats-stm with Apache License 2.0 | 5 votes |
package io.github.timwspence.cats.stm import cats.effect.{ExitCode, IO, IOApp} //import io.github.timwspence.cats.stm.{TVar, STM} import scala.concurrent.duration._ object Main extends IOApp { override def run(args: List[String]): IO[ExitCode] = for { accountForTim <- TVar.of[Long](100).commit[IO] accountForSteve <- TVar.of[Long](0).commit[IO] _ <- printBalances(accountForTim, accountForSteve) _ <- giveTimMoreMoney(accountForTim).start _ <- transfer(accountForTim, accountForSteve) _ <- printBalances(accountForTim, accountForSteve) } yield ExitCode.Success private def transfer(accountForTim: TVar[Long], accountForSteve: TVar[Long]): IO[Unit] = STM.atomically[IO] { for { balance <- accountForTim.get _ <- STM.check(balance > 100) _ <- accountForTim.modify(_ - 100) _ <- accountForSteve.modify(_ + 100) } yield () } private def giveTimMoreMoney(accountForTim: TVar[Long]): IO[Unit] = for { _ <- IO.sleep(5000.millis) _ <- STM.atomically[IO](accountForTim.modify(_ + 1)) } yield () private def printBalances(accountForTim: TVar[Long], accountForSteve: TVar[Long]): IO[Unit] = for { (amountForTim, amountForSteve) <- STM.atomically[IO](for { t <- accountForTim.get s <- accountForSteve.get } yield (t, s)) _ <- IO(println(s"Tim: $amountForTim")) _ <- IO(println(s"Steve: $amountForSteve")) } yield () }
Example 145
Source File: TVarTest.scala From cats-stm with Apache License 2.0 | 5 votes |
package io.github.timwspence.cats.stm import cats.effect.{ContextShift, IO, Timer} import org.scalatest.matchers.should.Matchers import org.scalatest.funsuite.AsyncFunSuite import scala.concurrent.ExecutionContext class TVarTest extends AsyncFunSuite with Matchers { implicit override def executionContext: ExecutionContext = ExecutionContext.Implicits.global implicit val timer: Timer[IO] = IO.timer(executionContext) implicit val cs: ContextShift[IO] = IO.contextShift(executionContext) test("Get returns current value") { val prog: STM[String] = for { tvar <- TVar.of("hello") value <- tvar.get } yield value for (value <- prog.commit[IO].unsafeToFuture) yield { value shouldBe "hello" } } test("Set changes current value") { val prog: STM[String] = for { tvar <- TVar.of("hello") _ <- tvar.set("world") value <- tvar.get } yield value for (value <- prog.commit[IO].unsafeToFuture) yield { value shouldBe "world" value shouldBe "world" } } test("Modify changes current value") { val prog: STM[String] = for { tvar <- TVar.of("hello") _ <- tvar.modify(_.toUpperCase) value <- tvar.get } yield value for (value <- prog.commit[IO].unsafeToFuture) yield { value shouldBe "HELLO" } } test("Pending transaction is removed on success") { val tvar = TVar.of("foo").commit[IO].unsafeRunSync val prog: STM[String] = for { _ <- tvar.modify(_.toUpperCase) value <- tvar.get } yield value for (value <- prog.commit[IO].unsafeToFuture) yield { value shouldBe "FOO" tvar.value shouldBe "FOO" tvar.pending.get.isEmpty shouldBe true } } test("Pending transaction is removed on failure") { val tvar = TVar.of("foo").commit[IO].unsafeRunSync val prog: STM[String] = for { _ <- tvar.modify(_.toUpperCase) _ <- STM.abort[String](new RuntimeException("boom")) value <- tvar.get } yield value for (_ <- prog.commit[IO].attempt.unsafeToFuture) yield { tvar.value shouldBe "foo" tvar.pending.get.isEmpty shouldBe true } } }
Example 146
Source File: PropertyTests.scala From cats-stm with Apache License 2.0 | 5 votes |
package io.github.timwspence.cats.stm import cats.effect.{ContextShift, IO, Timer} import cats.instances.list._ import cats.syntax.functor._ import cats.syntax.traverse._ import org.scalacheck._ import org.scalatest.matchers.should.Matchers import org.scalatest.funsuite.AnyFunSuite import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks import scala.concurrent.ExecutionContext import scala.util.Random class MaintainsInvariants extends AnyFunSuite with ScalaCheckDrivenPropertyChecks with Matchers { implicit val executionContext: ExecutionContext = ExecutionContext.Implicits.global implicit val timer: Timer[IO] = IO.timer(executionContext) implicit val cs: ContextShift[IO] = IO.contextShift(executionContext) val tvarGen: Gen[TVar[Long]] = for { value <- Gen.posNum[Long] } yield TVar.of(value).commit[IO].unsafeRunSync val txnGen: List[TVar[Long]] => Gen[STM[Unit]] = tvars => for { fromIdx <- Gen.choose(0, tvars.length - 1) toIdx <- Gen.choose(0, tvars.length - 1) suchThat (_ != fromIdx) txn <- for { balance <- tvars(fromIdx).get transfer = Math.abs(Random.nextLong()) % balance _ <- tvars(fromIdx).modify(_ - transfer) _ <- tvars(toIdx).modify(_ + transfer) } yield () } yield txn val gen: Gen[(Long, List[TVar[Long]], IO[Unit])] = for { tvars <- Gen.listOfN(50, tvarGen) total = tvars.foldLeft(0L)((acc, tvar) => acc + tvar.value) txns <- Gen.listOf(txnGen(tvars)) commit = txns.traverse(_.commit[IO].start) run = commit.flatMap(l => l.traverse(_.join)).void } yield (total, tvars, run) test("Transactions maintain invariants") { forAll(gen) { g => val total = g._1 val tvars = g._2 val txn = g._3 txn.unsafeRunSync() tvars.map(_.value).sum shouldBe total } } }
Example 147
Source File: TQueueTest.scala From cats-stm with Apache License 2.0 | 5 votes |
package io.github.timwspence.cats.stm import cats.effect.{ContextShift, IO, Timer} import cats.instances.string._ import cats.syntax.semigroup._ import org.scalatest.matchers.should.Matchers import org.scalatest.funsuite.AsyncFunSuite import scala.concurrent.ExecutionContext class TQueueTest extends AsyncFunSuite with Matchers { implicit override def executionContext: ExecutionContext = ExecutionContext.Implicits.global implicit val timer: Timer[IO] = IO.timer(executionContext) implicit val cs: ContextShift[IO] = IO.contextShift(executionContext) test("Read removes the first element") { val prog: STM[(String, Boolean)] = for { tqueue <- TQueue.empty[String] _ <- tqueue.put("hello") value <- tqueue.read empty <- tqueue.isEmpty } yield value -> empty for (value <- prog.commit[IO].unsafeToFuture) yield { value._1 shouldBe "hello" value._2 shouldBe true } } test("Peek does not remove the first element") { val prog: STM[(String, Boolean)] = for { tqueue <- TQueue.empty[String] _ <- tqueue.put("hello") value <- tqueue.peek empty <- tqueue.isEmpty } yield value -> empty for (value <- prog.commit[IO].unsafeToFuture) yield { value._1 shouldBe "hello" value._2 shouldBe false } } test("TQueue is FIFO") { val prog: STM[String] = for { tqueue <- TQueue.empty[String] _ <- tqueue.put("hello") _ <- tqueue.put("world") hello <- tqueue.read world <- tqueue.peek } yield hello |+| world for (value <- prog.commit[IO].unsafeToFuture) yield { value shouldBe "helloworld" } } }
Example 148
Source File: TSemaphoreTest.scala From cats-stm with Apache License 2.0 | 5 votes |
package io.github.timwspence.cats.stm import cats.effect.{ContextShift, IO, Timer} import org.scalatest.matchers.should.Matchers import org.scalatest.funsuite.AsyncFunSuite import scala.concurrent.ExecutionContext class TSemaphoreTest extends AsyncFunSuite with Matchers { implicit override def executionContext: ExecutionContext = ExecutionContext.Implicits.global implicit val timer: Timer[IO] = IO.timer(executionContext) implicit val cs: ContextShift[IO] = IO.contextShift(executionContext) test("Acquire decrements the number of permits") { val prog: STM[Long] = for { tsem <- TSemaphore.make(1) _ <- tsem.acquire value <- tsem.available } yield value for (value <- prog.commit[IO].unsafeToFuture) yield { value shouldBe 0 } } test("Release increments the number of permits") { val prog: STM[Long] = for { tsem <- TSemaphore.make(0) _ <- tsem.release value <- tsem.available } yield value for (value <- prog.commit[IO].unsafeToFuture) yield { value shouldBe 1 } } }
Example 149
Source File: AkkaActorIntermediator.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.sourcing.akka import akka.actor.ActorSystem import akka.pattern.ask import akka.util.Timeout import cats.effect.{ContextShift, Effect, IO, Timer} import cats.syntax.all._ import ch.epfl.bluebrain.nexus.sourcing.akka.Msg._ import retry.CatsEffect._ import retry.syntax.all._ import retry.{RetryDetails, RetryPolicy} import scala.reflect.ClassTag abstract private[akka] class AkkaActorIntermediator[F[_]: Timer]( name: String, selection: ActorRefSelection[F], askTimeout: Timeout )(implicit F: Effect[F], as: ActorSystem, policy: RetryPolicy[F]) { implicit private[akka] val contextShift: ContextShift[IO] = IO.contextShift(as.dispatcher) implicit private[akka] def noop[A]: (A, RetryDetails) => F[Unit] = retry.noop[F, A] implicit private val timeout: Timeout = askTimeout private[akka] def send[M <: Msg, Reply, A](id: String, msg: M, f: Reply => A)(implicit Reply: ClassTag[Reply] ): F[A] = selection(name, id).flatMap { ref => val future = IO(ref ? msg) val fa = IO.fromFuture(future).to[F] fa.flatMap[A] { case Reply(value) => F.pure(f(value)) case te: TypeError => F.raiseError(te) case um: UnexpectedMsgId => F.raiseError(um) case cet: CommandEvaluationTimeout[_] => F.raiseError(cet) case cee: CommandEvaluationError[_] => F.raiseError(cee) case other => F.raiseError(TypeError(id, Reply.runtimeClass.getSimpleName, other)) } .retryingOnAllErrors[Throwable] } }
Example 150
Source File: InMemoryAggregateSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.sourcing import cats.effect.{ContextShift, IO, Timer} import ch.epfl.bluebrain.nexus.sourcing.AggregateFixture._ import ch.epfl.bluebrain.nexus.sourcing.Command.{Increment, IncrementAsync, Initialize} import ch.epfl.bluebrain.nexus.sourcing.Event.{Incremented, Initialized} import ch.epfl.bluebrain.nexus.sourcing.State.Current import scala.concurrent.ExecutionContext import scala.concurrent.duration._ class InMemoryAggregateSpec extends SourcingSpec { implicit val ctx: ContextShift[IO] = IO.contextShift(ExecutionContext.global) implicit val timer: Timer[IO] = IO.timer(ExecutionContext.global) "An InMemoryAggregate" should { val agg = Aggregate .inMemory[IO, Int]("global", initialState, AggregateFixture.next, AggregateFixture.evaluate[IO]) .unsafeRunSync() "return its name" in { agg.name shouldEqual "global" } "update its state when accepting commands" in { agg.evaluateE(1, Increment(0, 2)).unsafeRunSync().rightValue shouldEqual Incremented(1, 2) agg .evaluate(1, IncrementAsync(1, 5, 200.millis)) .unsafeRunSync() .rightValue shouldEqual (Current(2, 7) -> Incremented(2, 5)) agg.currentState(1).unsafeRunSync() shouldEqual Current(2, 7) } "return its current seq nr" in { agg.lastSequenceNr(1).unsafeRunSync() shouldEqual 2L } "test without applying changes" in { agg.test(1, Initialize(0)).unsafeRunSync().leftValue agg.testE(1, Initialize(2)).unsafeRunSync().rightValue shouldEqual Initialized(3) agg.testS(1, Initialize(2)).unsafeRunSync().rightValue shouldEqual Current(3, 0) agg.currentState(1).unsafeRunSync() shouldEqual Current(2, 7) } "not update its state if evaluation fails" in { agg.evaluate(1, Initialize(0)).unsafeRunSync().leftValue agg.currentState(1).unsafeRunSync() shouldEqual Current(2, 7) } "evaluate commands one at a time" in { agg.evaluateS(1, Initialize(2)).unsafeRunSync().rightValue shouldEqual Current(3, 0) agg.currentState(1).unsafeRunSync() shouldEqual Current(3, 0) agg.evaluateS(1, IncrementAsync(3, 2, 300.millis)).unsafeToFuture() agg.evaluateE(1, IncrementAsync(4, 2, 20.millis)).unsafeRunSync().rightValue shouldEqual Incremented(5, 2) agg.currentState(1).unsafeRunSync() shouldEqual Current(5, 4) } "fold over the event stream in order" in { agg .foldLeft(1, (0, true)) { case ((lastRev, succeeded), event) => (event.rev, succeeded && event.rev - lastRev == 1) } .unsafeRunSync() ._2 shouldEqual true } "return all events" in { agg.foldLeft(1, 0) { case (acc, _) => acc + 1 }.unsafeRunSync() shouldEqual 5 } "append events" in { agg.append(2, Incremented(1, 2)).unsafeRunSync() shouldEqual 1L agg.currentState(1).unsafeRunSync() shouldEqual Current(5, 4) } "return true for existing ids" in { agg.exists(1).unsafeRunSync() shouldEqual true } "return false for unknown ids" in { agg.exists(Int.MaxValue).unsafeRunSync() shouldEqual false } "return the sequence number for a snapshot" in { agg.snapshot(1).unsafeRunSync() shouldEqual 5L } } }
Example 151
Source File: ProjectionsSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.sourcing.projections import akka.actor.ActorSystem import akka.persistence.query.Offset import akka.stream.scaladsl.Source import akka.testkit.{TestKit, TestKitBase} import cats.effect.{ContextShift, IO} import ch.epfl.bluebrain.nexus.sourcing.projections.Fixture.memoize import ch.epfl.bluebrain.nexus.sourcing.projections.ProjectionProgress._ import ch.epfl.bluebrain.nexus.sourcing.projections.ProjectionsSpec.SomeEvent import io.circe.generic.auto._ import org.scalatest.concurrent.Eventually import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike import org.scalatest.{BeforeAndAfterAll, DoNotDiscover} import scala.concurrent.duration._ //noinspection TypeAnnotation @DoNotDiscover class ProjectionsSpec extends TestKitBase with AnyWordSpecLike with Matchers with TestHelpers with IOValues with Eventually with BeforeAndAfterAll { implicit override lazy val system: ActorSystem = SystemBuilder.persistence("ProjectionsSpec") implicit private val contextShift: ContextShift[IO] = IO.contextShift(system.dispatcher) override protected def afterAll(): Unit = { TestKit.shutdownActorSystem(system) super.afterAll() } "A Projection" should { val id = genString() val persistenceId = s"/some/${genString()}" val projections = memoize(Projections[IO, SomeEvent]).unsafeRunSync() val progress = OffsetProgress(Offset.sequence(42), 42, 42, 0) "store progress" in { projections.ioValue.recordProgress(id, progress).ioValue } "retrieve stored progress" in { projections.ioValue.progress(id).ioValue shouldEqual progress } "retrieve NoProgress for unknown projections" in { projections.ioValue.progress(genString()).ioValue shouldEqual NoProgress } val firstOffset: Offset = Offset.sequence(42) val secondOffset: Offset = Offset.sequence(98) val firstEvent = SomeEvent(1L, "description") val secondEvent = SomeEvent(2L, "description2") "store an event" in { projections.ioValue.recordFailure(id, persistenceId, 1L, firstOffset, firstEvent).ioValue } "store another event" in { projections.ioValue.recordFailure(id, persistenceId, 2L, secondOffset, secondEvent).ioValue } "retrieve stored events" in { val expected = Seq((firstEvent, firstOffset), (secondEvent, secondOffset)) eventually { logOf(projections.ioValue.failures(id)) should contain theSameElementsInOrderAs expected } } "retrieve empty list of events for unknown failure log" in { eventually { logOf(projections.ioValue.failures(genString())) shouldBe empty } } } private def logOf(source: Source[(SomeEvent, Offset), _]): Vector[(SomeEvent, Offset)] = { val f = source.runFold(Vector.empty[(SomeEvent, Offset)])(_ :+ _) IO.fromFuture(IO(f)).ioValue } implicit override def patienceConfig: PatienceConfig = PatienceConfig(30.seconds, 50.milliseconds) } object ProjectionsSpec { final case class SomeEvent(rev: Long, description: String) }
Example 152
Source File: IOValues.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.sourcing.projections import cats.effect.IO import org.scalactic.source import org.scalatest.matchers.should.Matchers._ import org.scalatest.concurrent.ScalaFutures import scala.reflect.ClassTag trait IOValues extends ScalaFutures { implicit final def ioValues[A](io: IO[A]): IOValuesSyntax[A] = new IOValuesSyntax(io) protected class IOValuesSyntax[A](io: IO[A]) { def failed[Ex <: Throwable: ClassTag](implicit config: PatienceConfig, pos: source.Position): Ex = { val Ex = implicitly[ClassTag[Ex]] io.redeemWith( { case Ex(ex) => IO.pure(ex) case other => IO( fail( s"Wrong throwable type caught, expected: '${Ex.runtimeClass.getName}', actual: '${other.getClass.getName}'" ) ) }, a => IO(fail(s"The IO did not fail as expected, but computed the value '$a'")) ) .ioValue(config, pos) } def ioValue(implicit config: PatienceConfig, pos: source.Position): A = io.unsafeToFuture().futureValue(config, pos) } } object IOValues extends IOValues
Example 153
Source File: Fixture.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.sourcing.projections import akka.persistence.journal.{Tagged, WriteEventAdapter} import cats.effect.{IO, Sync} import cats.effect.concurrent.Ref import scala.annotation.nowarn object Fixture { sealed trait Event final case object Executed extends Event final case object OtherExecuted extends Event final case object AnotherExecuted extends Event final case object YetAnotherExecuted extends Event final case object RetryExecuted extends Event final case object IgnoreExecuted extends Event final case object NotDiscarded extends Event final case object Discarded extends Event sealed trait EventTransform final case object ExecutedTransform extends EventTransform final case object OtherExecutedTransform extends EventTransform final case object AnotherExecutedTransform extends EventTransform final case object YetAnotherExecutedTransform extends EventTransform final case object RetryExecutedTransform extends EventTransform final case object IgnoreExecutedTransform extends EventTransform final case object NotDiscardedTransform extends EventTransform final case object DiscardedTransform extends EventTransform sealed trait Cmd final case object Execute extends Cmd final case object ExecuteOther extends Cmd final case object ExecuteAnother extends Cmd final case object ExecuteYetAnother extends Cmd final case object ExecuteRetry extends Cmd final case object ExecuteIgnore extends Cmd sealed trait State final case object Perpetual extends State sealed trait Rejection final case object Reject extends Rejection class TaggingAdapter extends WriteEventAdapter { override def manifest(event: Any): String = "" override def toJournal(event: Any): Any = event match { case Executed => Tagged(event, Set("executed")) case OtherExecuted => Tagged(event, Set("other")) case AnotherExecuted => Tagged(event, Set("another")) case YetAnotherExecuted => Tagged(event, Set("yetanother")) case RetryExecuted => Tagged(event, Set("retry")) case IgnoreExecuted => Tagged(event, Set("ignore")) case NotDiscarded => Tagged(event, Set("discard")) case Discarded => Tagged(event, Set("discard")) } } val initial: State = Perpetual @nowarn("cat=unused") def next(state: State, event: Event): State = Perpetual @nowarn("cat=unused") def eval(state: State, cmd: Cmd): IO[Either[Rejection, Event]] = cmd match { case Execute => IO.pure(Right(Executed)) case ExecuteOther => IO.pure(Right(OtherExecuted)) case ExecuteAnother => IO.pure(Right(AnotherExecuted)) case ExecuteYetAnother => IO.pure(Right(YetAnotherExecuted)) case ExecuteRetry => IO.pure(Right(RetryExecuted)) case ExecuteIgnore => IO.pure(Right(IgnoreExecuted)) } def memoize[F[_], A](fa: F[A])(implicit F: Sync[F]): F[F[A]] = { import cats.implicits._ for { ref <- Ref[F].of(fa.attempt) _ <- ref.update(_.flatTap(a => ref.set(a.pure[F]))) } yield ref.get.flatten.rethrow } }
Example 154
Source File: InMemoryStateMachineSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.sourcing import cats.effect.{ContextShift, IO, Timer} import ch.epfl.bluebrain.nexus.sourcing.Command.{Increment, IncrementAsync, Initialize} import ch.epfl.bluebrain.nexus.sourcing.State.Current import ch.epfl.bluebrain.nexus.sourcing.StateMachineFixture._ import scala.concurrent.ExecutionContext import scala.concurrent.duration._ class InMemoryStateMachineSpec extends SourcingSpec { implicit val ctx: ContextShift[IO] = IO.contextShift(ExecutionContext.global) implicit val timer: Timer[IO] = IO.timer(ExecutionContext.global) "An InMemoryStateMachine" should { val cache = StateMachine.inMemory[IO, Int]("global", initialState, evaluate[IO]).unsafeRunSync() "return its name" in { cache.name shouldEqual "global" } "update its state when accepting commands" in { cache.evaluate(1, Increment(0, 2)).unsafeRunSync().rightValue shouldEqual Current(1, 2) cache.evaluate(1, IncrementAsync(1, 5, 200.millis)).unsafeRunSync().rightValue shouldEqual Current(2, 7) cache.currentState(1).unsafeRunSync() shouldEqual Current(2, 7) } "test without applying changes" in { cache.test(1, Initialize(0)).unsafeRunSync().leftValue cache.test(1, Initialize(2)).unsafeRunSync().rightValue shouldEqual Current(3, 0) cache.test(1, Initialize(2)).unsafeRunSync().rightValue shouldEqual Current(3, 0) cache.currentState(1).unsafeRunSync() shouldEqual Current(2, 7) } "not update its state if evaluation fails" in { cache.evaluate(1, Initialize(0)).unsafeRunSync().leftValue cache.currentState(1).unsafeRunSync() shouldEqual Current(2, 7) } "evaluate commands one at a time" in { cache.evaluate(1, Initialize(2)).unsafeRunSync().rightValue shouldEqual Current(3, 0) cache.currentState(1).unsafeRunSync() shouldEqual Current(3, 0) cache.evaluate(1, IncrementAsync(3, 2, 300.millis)).unsafeToFuture() cache.evaluate(1, IncrementAsync(4, 2, 20.millis)).unsafeRunSync().rightValue shouldEqual Current(5, 4) cache.currentState(1).unsafeRunSync() shouldEqual Current(5, 4) } } }
Example 155
Source File: EvaluationSyntaxSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.sourcing import cats.effect.IO import org.scalatest.concurrent.ScalaFutures import ch.epfl.bluebrain.nexus.sourcing.syntax._ import org.scalatest.EitherValues class EvaluationSyntaxSpec extends SourcingSpec with ScalaFutures with EitherValues { type State = (Int) type Command = Int "An evaluation syntax" should { "transform a '(state, command) => state' evaluation into a '(state, command) => F(Right(state))'" in { val eval: (State, Command) => State = { case (st, cmd) => (st + cmd) } val evalEitherF = eval.toEitherF[IO] evalEitherF(2, 3).unsafeRunSync().rightValue shouldEqual 5 } "transform a '(state, command) => F(state)' evaluation into a '(state, command) => F(Right(state))'" in { val err = new RuntimeException("error") val eval: (State, Command) => IO[State] = { case (st, cmd) if st < 0 || cmd < 0 => IO.raiseError(err) case (st, cmd) => IO.pure(st + cmd) } val evalEitherF = eval.toEither evalEitherF(1, 2).unsafeRunSync().rightValue shouldEqual 3 evalEitherF(-1, 3).unsafeToFuture().failed.futureValue shouldEqual err evalEitherF(1, -3).unsafeToFuture().failed.futureValue shouldEqual err } } }
Example 156
Source File: ArchiveCacheSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.kg.archives import java.time.{Clock, Instant, ZoneId} import cats.effect.{IO, Timer} import ch.epfl.bluebrain.nexus.admin.client.types.Project import ch.epfl.bluebrain.nexus.commons.test.ActorSystemFixture import ch.epfl.bluebrain.nexus.commons.test.io.IOOptionValues import ch.epfl.bluebrain.nexus.iam.types.Identity.Anonymous import ch.epfl.bluebrain.nexus.kg.TestHelper import ch.epfl.bluebrain.nexus.kg.archives.Archive.{File, Resource, ResourceDescription} import ch.epfl.bluebrain.nexus.kg.resources.Id import ch.epfl.bluebrain.nexus.kg.resources.syntax._ import ch.epfl.bluebrain.nexus.service.config.Settings import org.scalatest.concurrent.Eventually import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike import scala.concurrent.duration._ class ArchiveCacheSpec extends ActorSystemFixture("ArchiveCacheSpec", true) with TestHelper with AnyWordSpecLike with Matchers with IOOptionValues with Eventually { implicit override def patienceConfig: PatienceConfig = PatienceConfig(10.second, 50.milliseconds) private val appConfig = Settings(system).serviceConfig implicit private val config = appConfig.copy(kg = appConfig.kg.copy(archives = appConfig.kg.archives.copy(cacheInvalidateAfter = 500.millis, maxResources = 100)) ) implicit private val timer: Timer[IO] = IO.timer(system.dispatcher) implicit private val archivesCfg = config.kg.archives private val cache: ArchiveCache[IO] = ArchiveCache[IO].unsafeToFuture().futureValue implicit private val clock = Clock.fixed(Instant.EPOCH, ZoneId.systemDefault()) private val instant = clock.instant() def randomProject() = { val instant = Instant.EPOCH // format: off Project(genIri, genString(), genString(), None, genIri, genIri, Map.empty, genUUID, genUUID, 1L, false, instant, genIri, instant, genIri) // format: on } "An archive cache" should { "write and read an Archive" in { val resId = Id(randomProject().ref, genIri) val resource1 = Resource(genIri, randomProject(), None, None, originalSource = true, None) val file1 = File(genIri, randomProject(), None, None, None) val archive = Archive(resId, instant, Anonymous, Set(resource1, file1)) val _ = cache.put(archive).value.some cache.get(archive.resId).value.some shouldEqual archive } "read a non existing resource" in { val resId = Id(randomProject().ref, genIri) cache.get(resId).value.ioValue shouldEqual None } "read after timeout" in { val resId = Id(randomProject().ref, genIri) val set = Set[ResourceDescription](Resource(genIri, randomProject(), None, None, originalSource = true, None)) val archive = Archive(resId, instant, Anonymous, set) val _ = cache.put(archive).value.some val time = System.currentTimeMillis() cache.get(resId).value.some shouldEqual archive eventually { cache.get(resId).value.ioValue shouldEqual None } val diff = System.currentTimeMillis() - time diff should be > config.kg.archives.cacheInvalidateAfter.toMillis diff should be < config.kg.archives.cacheInvalidateAfter.toMillis + 300 } } }
Example 157
Source File: DiskStorageOperationsSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.kg.storage import java.nio.file.Paths import akka.http.scaladsl.model.{ContentTypes, Uri} import cats.effect.IO import ch.epfl.bluebrain.nexus.commons.test._ import ch.epfl.bluebrain.nexus.commons.test.io.IOEitherValues import ch.epfl.bluebrain.nexus.kg.config.KgConfig._ import ch.epfl.bluebrain.nexus.kg.resources.file.File.FileDescription import ch.epfl.bluebrain.nexus.kg.resources.Id import ch.epfl.bluebrain.nexus.kg.resources.ProjectIdentifier.ProjectRef import ch.epfl.bluebrain.nexus.kg.{KgError, TestHelper} import ch.epfl.bluebrain.nexus.service.config.Settings import ch.epfl.bluebrain.nexus.sourcing.RetryStrategyConfig import org.mockito.IdiomaticMockito import org.scalatest.{BeforeAndAfter, OptionValues} import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike import scala.concurrent.duration._ class DiskStorageOperationsSpec extends ActorSystemFixture("DiskStorageOperationsSpec") with AnyWordSpecLike with Matchers with BeforeAndAfter with IdiomaticMockito with IOEitherValues with Resources with TestHelper with OptionValues { implicit private val appConfig = Settings(system).serviceConfig implicit private val sc: StorageConfig = appConfig.kg.storage.copy( DiskStorageConfig(Paths.get("/tmp"), "SHA-256", read, write, false, 1024L), RemoteDiskStorageConfig("http://example.com", "v1", None, "SHA-256", read, write, true, 1024L), S3StorageConfig("MD5", read, write, true, 1024L), "password", "salt", RetryStrategyConfig("linear", 300.millis, 5.minutes, 100, 1.second) ) private val project = ProjectRef(genUUID) private val storage = Storage.DiskStorage.default(project) private val resId = Id(storage.ref, genIri) private val fileDesc = FileDescription("my file.txt", ContentTypes.`text/plain(UTF-8)`) "DiskStorageOperations" should { "verify when the storage exists" in { val verify = new DiskStorageOperations.VerifyDiskStorage[IO](storage) verify.apply.accepted } "save and fetch files" in { val save = new DiskStorageOperations.SaveDiskFile[IO](storage) val fetch = new DiskStorageOperations.FetchDiskFile[IO]() val source = genSource val attr = save.apply(resId, fileDesc, source).ioValue attr.bytes shouldEqual 16L attr.filename shouldEqual fileDesc.filename attr.mediaType shouldEqual fileDesc.mediaType.value attr.location shouldEqual Uri(s"file:///tmp/${mangle(project, attr.uuid, "my%20file.txt")}") attr.path shouldEqual attr.location.path.tail.tail.tail val fetched = fetch.apply(attr).ioValue consume(source) shouldEqual consume(fetched) } "not link files" in { val link = new DiskStorageOperations.LinkDiskFile[IO]() link.apply(resId, fileDesc, Uri.Path("/foo")).failed[KgError] shouldEqual KgError.UnsupportedOperation } } }
Example 158
Source File: RemoteDiskStorageOperationsSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.kg.storage import akka.http.scaladsl.model.ContentTypes._ import akka.http.scaladsl.model.Uri import cats.effect.IO import ch.epfl.bluebrain.nexus.commons.test.io.IOEitherValues import ch.epfl.bluebrain.nexus.commons.test.{ActorSystemFixture, Resources} import ch.epfl.bluebrain.nexus.iam.auth.AccessToken import ch.epfl.bluebrain.nexus.iam.client.types.AuthToken import ch.epfl.bluebrain.nexus.iam.types.Permission import ch.epfl.bluebrain.nexus.kg.TestHelper import ch.epfl.bluebrain.nexus.kg.resources.file.File.{Digest, FileAttributes, FileDescription} import ch.epfl.bluebrain.nexus.kg.resources.Id import ch.epfl.bluebrain.nexus.kg.resources.ProjectIdentifier.ProjectRef import ch.epfl.bluebrain.nexus.kg.storage.Storage.RemoteDiskStorage import ch.epfl.bluebrain.nexus.storage.client.StorageClient import ch.epfl.bluebrain.nexus.storage.client.types.FileAttributes.{Digest => StorageDigest} import ch.epfl.bluebrain.nexus.storage.client.types.{FileAttributes => StorageFileAttributes} import org.mockito.{IdiomaticMockito, Mockito} import org.scalatest.BeforeAndAfter import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike class RemoteDiskStorageOperationsSpec extends ActorSystemFixture("RemoteDiskStorageOperationsSpec") with AnyWordSpecLike with Matchers with BeforeAndAfter with IdiomaticMockito with IOEitherValues with Resources with TestHelper { private val endpoint = "http://nexus.example.com/v1" // TODO: Remove when migrating ADMIN client implicit private def oldTokenConversion(implicit token: Option[AccessToken]): Option[AuthToken] = token.map(t => AuthToken(t.value)) sealed trait Ctx { val cred = genString() implicit val token: Option[AccessToken] = Some(AccessToken(cred)) val path = Uri.Path(s"${genString()}/${genString()}") // format: off val storage = RemoteDiskStorage(ProjectRef(genUUID), genIri, 1L, false, false, "SHA-256", endpoint, Some(cred), genString(), Permission.unsafe(genString()), Permission.unsafe(genString()), 1024L) val attributes = FileAttributes(s"$endpoint/${storage.folder}/$path", path, s"${genString()}.json", `application/json`, 12L, Digest("SHA-256", genString())) // format: on } private val client = mock[StorageClient[IO]] before { Mockito.reset(client) } "RemoteDiskStorageOperations" should { "verify when storage exists" in new Ctx { client.exists(storage.folder) shouldReturn IO(true) val verify = new RemoteDiskStorageOperations.Verify[IO](storage, client) verify.apply.accepted } "verify when storage does not exists" in new Ctx { client.exists(storage.folder) shouldReturn IO(false) val verify = new RemoteDiskStorageOperations.Verify[IO](storage, client) verify.apply .rejected[ String ] shouldEqual s"Folder '${storage.folder}' does not exists on the endpoint '${storage.endpoint}'" } "fetch file" in new Ctx { val source = genSource client.getFile(storage.folder, path) shouldReturn IO(source) val fetch = new RemoteDiskStorageOperations.Fetch[IO](storage, client) val resultSource = fetch.apply(attributes).ioValue consume(resultSource) shouldEqual consume(source) } "link file" in new Ctx { val id = Id(storage.ref, genIri) val sourcePath = Uri.Path(s"${genString()}/${genString()}") val destRelativePath = Uri.Path(mangle(storage.ref, attributes.uuid, attributes.filename)) client.moveFile(storage.folder, sourcePath, destRelativePath) shouldReturn IO( StorageFileAttributes( attributes.location, attributes.bytes, StorageDigest(attributes.digest.algorithm, attributes.digest.value), attributes.mediaType ) ) val link = new RemoteDiskStorageOperations.Link[IO](storage, client) link .apply(id, FileDescription(attributes.uuid, attributes.filename, Some(attributes.mediaType)), sourcePath) .ioValue shouldEqual attributes.copy(path = destRelativePath) } } }
Example 159
Source File: IOValues.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.util import cats.effect.IO import org.scalactic.source import org.scalatest.matchers.should.Matchers._ import org.scalatest.concurrent.ScalaFutures import scala.reflect.ClassTag trait IOValues extends ScalaFutures { implicit final def ioValues[A](io: IO[A]): IOValuesSyntax[A] = new IOValuesSyntax(io) protected class IOValuesSyntax[A](io: IO[A]) { def failed[Ex <: Throwable: ClassTag](implicit config: PatienceConfig, pos: source.Position): Ex = { val Ex = implicitly[ClassTag[Ex]] io.redeemWith( { case Ex(ex) => IO.pure(ex) case other => IO( fail( s"Wrong throwable type caught, expected: '${Ex.runtimeClass.getName}', actual: '${other.getClass.getName}'" ) ) }, a => IO(fail(s"The IO did not fail as expected, but computed the value '$a'")) ) .ioValue(config, pos) } def ioValue(implicit config: PatienceConfig, pos: source.Position): A = io.unsafeToFuture().futureValue(config, pos) } } object IOValues extends IOValues
Example 160
Source File: IOEitherValues.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.util import cats.effect.IO import org.scalactic.source import org.scalatest.matchers.should.Matchers.fail import scala.reflect.ClassTag trait IOEitherValues extends IOValues with EitherValues { implicit final def ioEitherValues[E, A](io: IO[Either[E, A]]): IOEitherValuesSyntax[E, A] = new IOEitherValuesSyntax(io) protected class IOEitherValuesSyntax[E, A](io: IO[Either[E, A]]) { def accepted(implicit config: PatienceConfig, pos: source.Position): A = io.ioValue(config, pos).rightValue def rejected[EE <: E: ClassTag](implicit config: PatienceConfig, pos: source.Position): EE = { val EE = implicitly[ClassTag[EE]] io.ioValue(config, pos).leftValue match { case EE(value) => value case other => fail( s"Wrong throwable type caught, expected: '${EE.runtimeClass.getName}', actual: '${other.getClass.getName}'" ) } } } } object IOEitherValues extends IOEitherValues
Example 161
Source File: InfluxProjectionSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.influx import java.nio.file.Files import cats.effect.{Blocker, IO} import ch.epfl.bluebrain.nexus.cli.Console import ch.epfl.bluebrain.nexus.cli.clients.InfluxClient import ch.epfl.bluebrain.nexus.cli.config.AppConfig import ch.epfl.bluebrain.nexus.cli.modules.influx.InfluxProjection import ch.epfl.bluebrain.nexus.cli.sse.Offset import fs2.io //noinspection SqlNoDataSourceInspection class InfluxProjectionSpec extends AbstractInfluxSpec { "A InfluxProjection" should { val brainParcelationExpected = jsonContentOf("/templates/influxdb-results-brain-parcelation.json") val cellRecordExpected = jsonContentOf("/templates/influxdb-results-cell-record.json") "project distribution sizes" in { (proj: InfluxProjection[IO], client: InfluxClient[IO]) => for { _ <- proj.run brainQueryResult <- client.query("""SELECT * FROM "brainParcelation"""") cellQueryResult <- client.query("""SELECT * FROM "cellRecord"""") _ = brainQueryResult shouldEqual Right(brainParcelationExpected) _ = cellQueryResult shouldEqual Right(cellRecordExpected) } yield () } "save offset" in { (cfg: AppConfig, blocker: Blocker, proj: InfluxProjection[IO], console: Console[IO]) => implicit val b: Blocker = blocker implicit val c: Console[IO] = console for { _ <- proj.run exists <- io.file.exists[IO](blocker, cfg.influx.offsetFile) _ = exists shouldEqual true _ = println(s"Offset file content '${Files.readString(cfg.influx.offsetFile)}'") offset <- Offset.load(cfg.influx.offsetFile) _ = offset.nonEmpty shouldEqual true } yield () } } }
Example 162
Source File: AbstractInfluxSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.influx import cats.effect.{Blocker, IO, Resource} import ch.epfl.bluebrain.nexus.cli.{AbstractCliSpec, Console} import ch.epfl.bluebrain.nexus.cli.clients.InfluxClient import ch.epfl.bluebrain.nexus.cli.config.AppConfig import ch.epfl.bluebrain.nexus.cli.influx.InfluxDocker.InfluxHostConfig import izumi.distage.model.definition.{Module, ModuleDef} import org.http4s.client.blaze.BlazeClientBuilder import scala.concurrent.duration._ class AbstractInfluxSpec extends AbstractCliSpec { override protected def defaultModules: Module = { super.defaultModules ++ new InfluxDocker.Module[IO] } override def testModule: ModuleDef = new ModuleDef { make[AppConfig].fromEffect { host: InfluxHostConfig => copyConfigs.flatMap { case (envFile, _, influxFile) => AppConfig.load[IO](Some(envFile), influxConfigFile = Some(influxFile)).flatMap { case Left(value) => IO.raiseError(value) case Right(value) => val influxOffsetFile = influxFile.getParent.resolve("influx.offset") val cfg = value.copy(influx = value.influx.copy( endpoint = host.endpoint, offsetFile = influxOffsetFile, offsetSaveInterval = 100.milliseconds ) ) IO.pure(cfg) } } } make[InfluxClient[IO]].fromResource { (_: InfluxDocker.Container, cfg: AppConfig, blocker: Blocker, console: Console[IO]) => BlazeClientBuilder[IO](blocker.blockingContext).resource.flatMap { client => val influxClient = InfluxClient(client, cfg, console) waitForInfluxReady(influxClient).map(_ => influxClient) } } } private def waitForInfluxReady( client: InfluxClient[IO], maxDelay: FiniteDuration = 90.seconds ): Resource[IO, Unit] = { import retry.CatsEffect._ import retry.RetryPolicies._ import retry._ val policy = limitRetriesByCumulativeDelay[IO](maxDelay, constantDelay(5.second)) val healthIO = retryingOnAllErrors( policy = policy, onError = (_: Throwable, _) => IO.delay(println("Influx Container not ready, retrying...")) ) { client.health.map { case Left(err) => throw err case Right(_) => () } } Resource.liftF(healthIO) } }
Example 163
Source File: CliSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli import java.nio.file.{Files, Path} import java.util.regex.Pattern.quote import cats.effect.{ExitCode, IO} import ch.epfl.bluebrain.nexus.cli.config.AppConfig import ch.epfl.bluebrain.nexus.cli.dummies.TestConsole class CliSpec extends AbstractCliSpec { "A CLI" should { "show the default config" in { (cli: Cli[IO], console: TestConsole[IO], cfg: AppConfig) => for { code <- cli.command(assemble("config show")) replacements = Map( quote("{postgres-offset-file}") -> cfg.postgres.offsetFile.toString, quote("{influx-offset-file}") -> cfg.influx.offsetFile.toString ) expected = contentOf("cli/config-show.txt", replacements) lines <- console.stdQueue.dequeue1 _ = lines.trim shouldEqual expected.trim _ = code shouldEqual ExitCode.Success } yield () } "show the default help" in { (cli: Cli[IO], console: TestConsole[IO]) => for { code <- cli.command(assemble("--help")) expected = contentOf("cli/help-main.txt") lines <- console.stdQueue.dequeue1 _ = lines.trim shouldEqual expected.trim _ = code shouldEqual ExitCode.Success } yield () } } override def copyConfigs: IO[(Path, Path, Path)] = IO { val parent = Files.createTempDirectory(".nexus") val envFile = parent.resolve("env.conf") val postgresFile = parent.resolve("postgres.conf") val influxFile = parent.resolve("influx.conf") Files.copy(getClass.getClassLoader.getResourceAsStream("env.conf"), envFile) Files.copy(getClass.getClassLoader.getResourceAsStream("postgres-noprojects.conf"), postgresFile) Files.copy(getClass.getClassLoader.getResourceAsStream("influx-noprojects.conf"), influxFile) (envFile, postgresFile, influxFile) } def assemble(string: String): List[String] = string.split(" ").toList }
Example 164
Source File: AbstractPostgresSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.postgres import cats.effect.IO import ch.epfl.bluebrain.nexus.cli.AbstractCliSpec import ch.epfl.bluebrain.nexus.cli.config.AppConfig import ch.epfl.bluebrain.nexus.cli.postgres.PostgresDocker.PostgresHostConfig import doobie.util.transactor.Transactor import izumi.distage.model.definition.{Module, ModuleDef} import scala.concurrent.duration._ class AbstractPostgresSpec extends AbstractCliSpec { override protected def defaultModules: Module = { super.defaultModules ++ new PostgresDocker.Module[IO] } override def testModule: ModuleDef = new ModuleDef { make[AppConfig].fromEffect { host: PostgresHostConfig => copyConfigs.flatMap { case (envFile, postgresFile, _) => AppConfig.load[IO](Some(envFile), Some(postgresFile)).flatMap { case Left(value) => IO.raiseError(value) case Right(value) => val postgresOffsetFile = postgresFile.getParent.resolve("postgres.offset") val cfg = value.copy(postgres = value.postgres.copy( host = host.host, port = host.port, offsetFile = postgresOffsetFile, offsetSaveInterval = 100.milliseconds ) ) IO.pure(cfg) } } } make[Transactor[IO]].fromEffect { (_: PostgresDocker.Container, cfg: AppConfig) => val xa = Transactor.fromDriverManager[IO]( "org.postgresql.Driver", cfg.postgres.jdbcUrl, cfg.postgres.username, cfg.postgres.password ) waitForPostgresReady(xa).as(xa) } } private def waitForPostgresReady(xa: Transactor[IO], maxDelay: FiniteDuration = 30.seconds): IO[Unit] = { import doobie.implicits._ import retry.CatsEffect._ import retry.RetryPolicies._ import retry._ val policy = limitRetriesByCumulativeDelay[IO](maxDelay, constantDelay(1.second)) retryingOnAllErrors( policy = policy, onError = (_: Throwable, _) => IO.delay(println("Postgres Container not ready, retrying...")) ) { sql"select 1;".query[Int].unique.transact(xa) } *> IO.unit } }
Example 165
Source File: PostgresProjectionSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.postgres import java.time.OffsetDateTime import cats.effect.{Blocker, IO} import ch.epfl.bluebrain.nexus.cli.Console import ch.epfl.bluebrain.nexus.cli.config.AppConfig import ch.epfl.bluebrain.nexus.cli.modules.postgres.PostgresProjection import ch.epfl.bluebrain.nexus.cli.modules.postgres.PostgresProjection.TimeMeta.javatime._ import ch.epfl.bluebrain.nexus.cli.sse.Offset import doobie.util.transactor.Transactor import fs2.io //noinspection SqlNoDataSourceInspection class PostgresProjectionSpec extends AbstractPostgresSpec { "A PostgresProjection" should { "project all schemas" in { import doobie.implicits._ (xa: Transactor[IO], proj: PostgresProjection[IO]) => for { _ <- proj.run count <- sql"select count(id) from schemas;".query[Int].unique.transact(xa) _ = count shouldEqual 175 maxImport <- sql"select id, count(import) from schema_imports group by id order by count desc limit 1;" .query[(String, Int)] .unique .transact(xa) (maxImportSchema, maxImportCount) = maxImport _ = maxImportSchema shouldEqual "https://neuroshapes.org/commons/entity" _ = maxImportCount shouldEqual 7 lastUpdated <- sql"select last_updated from schemas where id = 'https://neuroshapes.org/commons/entity'" .query[OffsetDateTime] .unique .transact(xa) _ = lastUpdated.toInstant.toEpochMilli shouldEqual 1584615316089L } yield () } "save offset" in { (cfg: AppConfig, blocker: Blocker, proj: PostgresProjection[IO], console: Console[IO]) => implicit val b: Blocker = blocker implicit val c: Console[IO] = console for { _ <- proj.run exists <- io.file.exists[IO](blocker, cfg.postgres.offsetFile) _ = exists shouldEqual true offset <- Offset.load(cfg.postgres.offsetFile) _ = offset.nonEmpty shouldEqual true } yield () } } }
Example 166
Source File: InfluxPointSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.clients import java.time.Instant import java.util.regex.Pattern.quote import cats.effect.IO import cats.implicits._ import ch.epfl.bluebrain.nexus.cli.config.influx.TypeConfig import ch.epfl.bluebrain.nexus.cli.utils.{Resources, TimeTransformation} import fs2._ import fs2.text._ import org.http4s.EntityEncoder import org.scalatest.Inspectors import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike class InfluxPointSpec extends AnyWordSpecLike with Matchers with Resources with Inspectors with TimeTransformation { private def writeToString[A](a: A)(implicit W: EntityEncoder[IO, A]): String = Stream .emit(W.toEntity(a)) .covary[IO] .flatMap(_.body) .through(utf8Decode) .foldMonoid .compile .last .map(_.getOrElse("")) .unsafeRunSync "An InfluxPoint" should { val created = Instant.now() val updated = created.plusSeconds(5) "be created from SparqlResults" in { val sparqlResults = jsonContentOf( "/templates/sparql-results-influx.json", Map( quote("{created}") -> created.toString, quote("{updated}") -> updated.toString, quote("{bytes}") -> 1234.toString, quote("{project}") -> "myorg/myproject" ) ).as[SparqlResults].getOrElse(throw new IllegalArgumentException) val typeConfig = TypeConfig("https://neuroshapes.org/Subject", "", "datastats", Set("bytes"), "updated") val expected = InfluxPoint( "datastats", Map("created" -> created.toString, "project" -> "myorg/myproject", "deprecated" -> "false"), Map("bytes" -> "1234"), Some(updated) ) InfluxPoint.fromSparqlResults(sparqlResults, typeConfig) shouldEqual List(expected) } "converted to string" in { val point = InfluxPoint( "m1", Map("created" -> created.toString, "project" -> "org/proj", "deprecated" -> "false"), Map("bytes" -> "1234"), Some(updated) ) val pointNoTag = InfluxPoint( "m2", Map.empty, Map("bytes" -> "2345"), Some(updated) ) val list = List( point -> s"m1,created=${created.toString},project=org/proj,deprecated=false bytes=1234 ${toNano(updated)}", pointNoTag -> s"m2 bytes=2345 ${toNano(updated)}" ) forAll(list) { case (point, str) => writeToString(point) shouldEqual str } } } }
Example 167
Source File: SparqlClientSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.clients import cats.effect.IO import cats.implicits._ import ch.epfl.bluebrain.nexus.cli.{AbstractCliSpec, Console} import ch.epfl.bluebrain.nexus.cli.CliError.ClientError.{ClientStatusError, ServerStatusError} import ch.epfl.bluebrain.nexus.cli.config.{AppConfig, EnvConfig} import ch.epfl.bluebrain.nexus.cli.sse._ import ch.epfl.bluebrain.nexus.cli.utils.Http4sExtras import izumi.distage.model.definition.ModuleDef import org.http4s.circe.CirceEntityEncoder._ import org.http4s.client.Client import org.http4s.dsl.io._ import org.http4s.headers.`Content-Type` import org.http4s.{HttpApp, Response, Status, Uri} import org.scalatest.OptionValues class SparqlClientSpec extends AbstractCliSpec with Http4sExtras with OptionValues { private val sparqlResultsJson = jsonContentOf("/templates/sparql-results.json") private val sparqlResults = sparqlResultsJson.as[SparqlResults].toOption.value private val query = "SELECT * {?s ?p ?o} LIMIT 10" override def overrides: ModuleDef = new ModuleDef { include(defaultModules) make[Client[IO]].from { cfg: AppConfig => val token = cfg.env.token val ct = `Content-Type`(SparqlClient.`application/sparql-query`) val view = cfg.env.defaultSparqlView.renderString val httpApp = HttpApp[IO] { // success case req @ POST -> `v1` / "views" / OrgLabelVar(`orgLabel`) / ProjectLabelVar( `projectLabel` ) / `view` / "sparql" contentType `ct` optbearer `token` => req.as[String].flatMap { case `query` => Response[IO](Status.Ok).withEntity(sparqlResultsJson).pure[IO] case _ => Response[IO](Status.BadRequest).pure[IO] } // unknown view id case req @ POST -> `v1` / "views" / OrgLabelVar(`orgLabel`) / ProjectLabelVar( `projectLabel` ) / (_: String) / "sparql" contentType `ct` optbearer `token` => req.as[String].flatMap { case `query` => Response[IO](Status.NotFound).withEntity(notFoundJson).pure[IO] case _ => Response[IO](Status.BadRequest).pure[IO] } // unknown token case req @ POST -> `v1` / "views" / OrgLabelVar(`orgLabel`) / ProjectLabelVar( `projectLabel` ) / `view` / "sparql" contentType `ct` optbearer (_: Option[ BearerToken ]) => req.as[String].flatMap { case `query` => Response[IO](Status.Forbidden).withEntity(authFailedJson).pure[IO] case _ => Response[IO](Status.BadRequest).pure[IO] } // other - internal error case req @ POST -> "v1" /: (_: Path) contentType `ct` optbearer `token` => req.as[String].flatMap { case `query` => Response[IO](Status.InternalServerError).withEntity(internalErrorJson).pure[IO] case _ => Response[IO](Status.BadRequest).pure[IO] } } Client.fromHttpApp(httpApp) } } "A SparqlClient" should { "return sparql results" in { (client: Client[IO], console: Console[IO], env: EnvConfig) => val cl = SparqlClient(client, env, console) for { results <- cl.query(orgLabel, projectLabel, query) _ = results shouldEqual Right(sparqlResults) } yield () } "return not found" in { (client: Client[IO], console: Console[IO], env: EnvConfig) => val cl = SparqlClient(client, env, console) for { results <- cl.query(orgLabel, projectLabel, Uri.unsafeFromString(genString()), query) _ = results shouldEqual Left(ClientStatusError(Status.NotFound, notFoundJson.noSpaces)) } yield () } "return internal error" in { (client: Client[IO], console: Console[IO], env: EnvConfig) => val cl = SparqlClient(client, env, console) for { results <- cl.query(orgLabel, ProjectLabel(genString()), Uri.unsafeFromString(genString()), query) _ = results shouldEqual Left(ServerStatusError(Status.InternalServerError, internalErrorJson.noSpaces)) } yield () } "return bad token" in { (client: Client[IO], console: Console[IO], env: EnvConfig) => val cl = SparqlClient(client, env.copy(token = Some(BearerToken("bad"))), console) for { results <- cl.query(orgLabel, projectLabel, query) _ = results shouldEqual Left(ClientStatusError(Status.Forbidden, authFailedJson.noSpaces)) } yield () } } }
Example 168
Source File: ProjectClientSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.clients import java.util.UUID import cats.effect.IO import cats.effect.concurrent.Ref import cats.implicits._ import ch.epfl.bluebrain.nexus.cli.{AbstractCliSpec, Console} import ch.epfl.bluebrain.nexus.cli.CliError.ClientError.ClientStatusError import ch.epfl.bluebrain.nexus.cli.config.{AppConfig, EnvConfig} import ch.epfl.bluebrain.nexus.cli.sse._ import ch.epfl.bluebrain.nexus.cli.utils.Http4sExtras import izumi.distage.model.definition.ModuleDef import org.http4s.circe.CirceEntityEncoder._ import org.http4s.client.Client import org.http4s.dsl.io._ import org.http4s.{HttpApp, Response, Status} class ProjectClientSpec extends AbstractCliSpec with Http4sExtras { private val projectJson = jsonContentOf("/templates/project.json", replacements) type Cache = Map[(OrgUuid, ProjectUuid), (OrgLabel, ProjectLabel)] type CacheRef = Ref[IO, Cache] override def overrides: ModuleDef = new ModuleDef { include(defaultModules) make[Client[IO]].from { cfg: AppConfig => val token = cfg.env.token val httpApp = HttpApp[IO] { case GET -> `v1` / "projects" / OrgUuidVar(`orgUuid`) / ProjectUuidVar(`projectUuid`) optbearer `token` => Response[IO](Status.Ok).withEntity(projectJson).pure[IO] case GET -> `v1` / "projects" / OrgUuidVar(_) / ProjectUuidVar(_) optbearer `token` => Response[IO](Status.NotFound).withEntity(notFoundJson).pure[IO] case GET -> `v1` / "projects" / OrgUuidVar(_) / ProjectUuidVar(_) bearer (_: BearerToken) => Response[IO](Status.Forbidden).withEntity(authFailedJson).pure[IO] } Client.fromHttpApp(httpApp) } make[CacheRef].fromEffect { Ref.of[IO, Cache](Map.empty) } } "A ProjectClient" should { "resolve a known (orgUuid, projUuid) pair" in { (client: Client[IO], console: Console[IO], cache: CacheRef, env: EnvConfig) => val cl = ProjectClient[IO](client, env, cache, console) for { labels <- cl.labels(orgUuid, projectUuid) _ = labels shouldEqual Right((orgLabel, projectLabel)) } yield () } "resolve from cache a known (orgUuid, projUuid) pair" in { (client: Client[IO], console: Console[IO], cache: CacheRef, env: EnvConfig) => val errClient = Client.fromHttpApp(HttpApp[IO] { case GET -> Root => IO.pure(Response[IO](Status.NotFound)) }) for { _ <- ProjectClient[IO](client, env, cache, console).labels(orgUuid, projectUuid) labels <- ProjectClient[IO](errClient, env, cache, console).labels(orgUuid, projectUuid) _ = labels shouldEqual Right((orgLabel, projectLabel)) } yield () } "fail to resolve an unknown (orgUuid, projUuid) pair" in { (client: Client[IO], console: Console[IO], cache: CacheRef, env: EnvConfig) => val cl = ProjectClient[IO](client, env, cache, console) for { labels <- cl.labels(OrgUuid(UUID.randomUUID()), projectUuid) _ = labels shouldEqual Left(ClientStatusError(Status.NotFound, notFoundJson.noSpaces)) } yield () } "fail to resolve a known (orgUuid, projUuid) pair with bad credentials" in { (client: Client[IO], console: Console[IO], cache: CacheRef, env: EnvConfig) => val cl = ProjectClient[IO](client, env.copy(token = Some(BearerToken("bad"))), cache, console) for { labels <- cl.labels(orgUuid, projectUuid) _ = labels shouldEqual Left(ClientStatusError(Status.Forbidden, authFailedJson.noSpaces)) } yield () } } }
Example 169
Source File: OffsetSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.sse import java.nio.file.{Files, Path} import java.util.UUID import cats.effect.{Blocker, ContextShift, IO} import ch.epfl.bluebrain.nexus.cli.Console import ch.epfl.bluebrain.nexus.cli.dummies.TestConsole import org.scalatest.OptionValues import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike import scala.concurrent.ExecutionContext class OffsetSpec extends AnyWordSpecLike with Matchers with OptionValues { implicit protected val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global) implicit private val blocker: Blocker = Blocker.liftExecutionContext(ExecutionContext.global) implicit private val console: Console[IO] = TestConsole[IO].unsafeRunSync() abstract class Ctx { protected val uuid: UUID = UUID.randomUUID protected val file: Path = Files.createTempFile("offset", ".conf") } "An offset" should { "be loaded from configuration" in new Ctx { Files.writeString(file, uuid.toString) (for { offset <- Offset.load(file) _ = offset.value shouldEqual Offset(uuid) } yield Files.deleteIfExists(file)).unsafeRunSync() } "be loaded from configuration but failed to convert to UUID" in new Ctx { Files.writeString(file, "not-an-uuid") (for { offset <- Offset.load(file) _ = offset shouldEqual None } yield Files.deleteIfExists(file)).unsafeRunSync() } "be written to file" in new Ctx { val offset = Offset(UUID.randomUUID()) (for { _ <- offset.write(file) _ = Files.readString(file) shouldEqual offset.value.toString } yield Files.deleteIfExists(file)).unsafeRunSync() } } }
Example 170
Source File: ConsoleSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli import cats.effect.IO import ch.epfl.bluebrain.nexus.cli.dummies.TestConsole class ConsoleSpec extends AbstractCliSpec { "A TestConsole" should { "record the println" in { (tc: TestConsole[IO], c: Console[IO]) => for { _ <- c.println("line") line <- tc.stdQueue.dequeue1 _ = line shouldEqual "line" } yield () } "record the printlnErr" in { (tc: TestConsole[IO], c: Console[IO]) => for { _ <- c.printlnErr("line") line <- tc.errQueue.dequeue1 _ = line shouldEqual "line" } yield () } } }
Example 171
Source File: AttributesCache.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.storage.attributes import java.nio.file.Path import java.time.Clock import akka.actor.{ActorRef, ActorSystem} import akka.pattern.{ask, AskTimeoutException} import akka.util.Timeout import cats.effect.{ContextShift, Effect, IO} import cats.implicits._ import ch.epfl.bluebrain.nexus.storage.File.FileAttributes import ch.epfl.bluebrain.nexus.storage.StorageError.{InternalError, OperationTimedOut} import ch.epfl.bluebrain.nexus.storage.attributes.AttributesCacheActor.Protocol._ import ch.epfl.bluebrain.nexus.storage.config.AppConfig.DigestConfig import com.typesafe.scalalogging.Logger import scala.util.control.NonFatal trait AttributesCache[F[_]] { def asyncComputePut(filePath: Path, algorithm: String): Unit } object AttributesCache { private[this] val logger = Logger[this.type] def apply[F[_], Source](implicit system: ActorSystem, clock: Clock, tm: Timeout, F: Effect[F], computation: AttributesComputation[F, Source], config: DigestConfig ): AttributesCache[F] = apply(system.actorOf(AttributesCacheActor.props(computation))) private[attributes] def apply[F[_]]( underlying: ActorRef )(implicit system: ActorSystem, tm: Timeout, F: Effect[F]): AttributesCache[F] = new AttributesCache[F] { implicit private val contextShift: ContextShift[IO] = IO.contextShift(system.dispatcher) override def get(filePath: Path): F[FileAttributes] = IO.fromFuture(IO.shift(system.dispatcher) >> IO(underlying ? Get(filePath))) .to[F] .flatMap[FileAttributes] { case attributes: FileAttributes => F.pure(attributes) case other => logger.error(s"Received unexpected reply from the file attributes cache: '$other'") F.raiseError(InternalError("Unexpected reply from the file attributes cache")) } .recoverWith { case _: AskTimeoutException => F.raiseError(OperationTimedOut("reply from the file attributes cache timed out")) case NonFatal(th) => logger.error("Exception caught while exchanging messages with the file attributes cache", th) F.raiseError(InternalError("Exception caught while exchanging messages with the file attributes cache")) } override def asyncComputePut(filePath: Path, algorithm: String): Unit = underlying ! Compute(filePath) } }
Example 172
Source File: IamIdentitiesClient.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.storage import akka.actor.ActorSystem import akka.http.scaladsl.Http import akka.http.scaladsl.client.RequestBuilding.Get import akka.http.scaladsl.model.HttpRequest import akka.http.scaladsl.model.headers.OAuth2BearerToken import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller import akka.util.ByteString import cats.effect.{ContextShift, Effect, IO} import cats.implicits._ import ch.epfl.bluebrain.nexus.rdf.implicits._ import ch.epfl.bluebrain.nexus.storage.IamIdentitiesClient.Identity._ import ch.epfl.bluebrain.nexus.storage.IamIdentitiesClient._ import ch.epfl.bluebrain.nexus.storage.IamIdentitiesClientError.IdentitiesSerializationError import ch.epfl.bluebrain.nexus.storage.config.IamClientConfig import de.heikoseeberger.akkahttpcirce.ErrorAccumulatingCirceSupport.{DecodingFailures => AccDecodingFailures} import io.circe.Decoder.Result import io.circe.{Decoder, DecodingFailure, HCursor} import scala.concurrent.ExecutionContext class IamIdentitiesClient[F[_]](config: IamClientConfig)(implicit F: Effect[F], as: ActorSystem) extends JsonLdCirceSupport { private val um: FromEntityUnmarshaller[Caller] = unmarshaller[Caller] implicit private val ec: ExecutionContext = as.dispatcher implicit private val contextShift: ContextShift[IO] = IO.contextShift(ec) def apply()(implicit credentials: Option[AccessToken]): F[Caller] = credentials match { case Some(token) => execute(Get(config.identitiesIri.asAkka).addCredentials(OAuth2BearerToken(token.value))) case None => F.pure(Caller.anonymous) } private def execute(req: HttpRequest): F[Caller] = { IO.fromFuture(IO(Http().singleRequest(req))).to[F].flatMap { resp => if (resp.status.isSuccess()) IO.fromFuture(IO(um(resp.entity))).to[F].recoverWith { case err: AccDecodingFailures => F.raiseError(IdentitiesSerializationError(err.getMessage)) case err: Error => F.raiseError(IdentitiesSerializationError(err.getMessage)) } else IO.fromFuture(IO(resp.entity.dataBytes.runFold(ByteString(""))(_ ++ _).map(_.utf8String))) .to[F] .flatMap { err => F.raiseError(IamIdentitiesClientError.unsafe(resp.status, err)) } } } } object IamIdentitiesClient { final case class Authenticated(realm: String) extends Identity private def decodeAnonymous(hc: HCursor): Result[Subject] = hc.get[String]("@type").flatMap { case "Anonymous" => Right(Anonymous) case _ => Left(DecodingFailure("Cannot decode Anonymous Identity", hc.history)) } private def decodeUser(hc: HCursor): Result[Subject] = (hc.get[String]("subject"), hc.get[String]("realm")).mapN { case (subject, realm) => User(subject, realm) } private def decodeGroup(hc: HCursor): Result[Identity] = (hc.get[String]("group"), hc.get[String]("realm")).mapN { case (group, realm) => Group(group, realm) } private def decodeAuthenticated(hc: HCursor): Result[Identity] = hc.get[String]("realm").map(Authenticated) private val attempts = List[HCursor => Result[Identity]](decodeAnonymous, decodeUser, decodeGroup, decodeAuthenticated) implicit val identityDecoder: Decoder[Identity] = Decoder.instance { hc => attempts.foldLeft(Left(DecodingFailure("Unexpected", hc.history)): Result[Identity]) { case (acc @ Right(_), _) => acc case (_, f) => f(hc) } } } }
Example 173
Source File: IOValues.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.storage.utils import cats.effect.IO import org.scalactic.source import org.scalatest.matchers.should.Matchers._ import org.scalatest.concurrent.ScalaFutures import scala.reflect.ClassTag trait IOValues extends ScalaFutures { implicit final def ioValues[A](io: IO[A]): IOValuesSyntax[A] = new IOValuesSyntax(io) protected class IOValuesSyntax[A](io: IO[A]) { def failed[Ex <: Throwable: ClassTag](implicit config: PatienceConfig, pos: source.Position): Ex = { val Ex = implicitly[ClassTag[Ex]] io.redeemWith( { case Ex(ex) => IO.pure(ex) case other => IO( fail( s"Wrong throwable type caught, expected: '${Ex.runtimeClass.getName}', actual: '${other.getClass.getName}'" ) ) }, a => IO(fail(s"The IO did not fail as expected, but computed the value '$a'")) ) .ioValue(config, pos) } def ioValue(implicit config: PatienceConfig, pos: source.Position): A = io.unsafeToFuture().futureValue(config, pos) } } object IOValues extends IOValues
Example 174
Source File: IOEitherValues.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.storage.utils import cats.effect.IO import org.scalactic.source import org.scalatest.matchers.should.Matchers.fail import scala.reflect.ClassTag trait IOEitherValues extends IOValues with EitherValues { implicit final def ioEitherValues[E, A](io: IO[Either[E, A]]): IOEitherValuesSyntax[E, A] = new IOEitherValuesSyntax(io) protected class IOEitherValuesSyntax[E, A](io: IO[Either[E, A]]) { def accepted(implicit config: PatienceConfig, pos: source.Position): A = io.ioValue(config, pos).rightValue def rejected[EE <: E: ClassTag](implicit config: PatienceConfig, pos: source.Position): EE = { val EE = implicitly[ClassTag[EE]] io.ioValue(config, pos).leftValue match { case EE(value) => value case other => fail( s"Wrong throwable type caught, expected: '${EE.runtimeClass.getName}', actual: '${other.getClass.getName}'" ) } } } } object IOEitherValues extends IOEitherValues
Example 175
Source File: AttributesComputationSpec.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.storage.attributes import java.nio.charset.StandardCharsets import java.nio.file.{Files, Paths} import akka.actor.ActorSystem import akka.http.scaladsl.model.ContentTypes.`text/plain(UTF-8)` import akka.testkit.TestKit import cats.effect.IO import ch.epfl.bluebrain.nexus.storage.File.{Digest, FileAttributes} import ch.epfl.bluebrain.nexus.storage.StorageError.InternalError import ch.epfl.bluebrain.nexus.storage.utils.IOValues import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike import scala.concurrent.ExecutionContextExecutor class AttributesComputationSpec extends TestKit(ActorSystem("AttributesComputationSpec")) with AnyWordSpecLike with Matchers with IOValues { implicit private val ec: ExecutionContextExecutor = system.dispatcher private trait Ctx { val path = Files.createTempFile("storage-test", ".txt") val (text, digest) = "something" -> "3fc9b689459d738f8c88a3a48aa9e33542016b7a4052e001aaa536fca74813cb" } "Attributes computation computation" should { val computation = AttributesComputation.akkaAttributes[IO] val alg = "SHA-256" "succeed" in new Ctx { Files.write(path, text.getBytes(StandardCharsets.UTF_8)) computation(path, alg).ioValue shouldEqual FileAttributes( s"file://$path", Files.size(path), Digest(alg, digest), `text/plain(UTF-8)` ) Files.deleteIfExists(path) } "fail when algorithm is wrong" in new Ctx { Files.write(path, text.getBytes(StandardCharsets.UTF_8)) computation(path, "wrong-alg").failed[InternalError] } "fail when file does not exists" in new Ctx { computation(Paths.get("/tmp/non/existing"), alg).failed[InternalError] } } }
Example 176
Source File: DoobieSpec.scala From cron4s with Apache License 2.0 | 5 votes |
package cron4s package doobie import cats.effect.{IO, ContextShift} import _root_.doobie._ import _root_.doobie.implicits._ import _root_.doobie.util.invariant._ import org.scalatest.matchers.should.Matchers import org.scalatest.flatspec.AnyFlatSpec import scala.concurrent.ExecutionContext class DoobieSpec extends AnyFlatSpec with Matchers { implicit val contextShift: ContextShift[IO] = IO.contextShift(ExecutionContext.global) val xa = Transactor.fromDriverManager[IO]( "org.h2.Driver", "jdbc:h2:mem:refined;DB_CLOSE_DELAY=-1", "sa", "" ) def insertMeeting(meeting: Meeting) = { val createTable = sql""" create table meeting( meeting_id BIGINT AUTO_INCREMENT PRIMARY KEY, subject VARCHAR(255) NOT NULL, description VARCHAR(255) NOT NULL, frequency VARCHAR(255) NOT NULL ) """ val insertRecord = sql""" insert into meeting(subject, description, frequency) values(${meeting.subject}, ${meeting.description}, ${meeting.frequency}) """ for { _ <- createTable.update.run id <- insertRecord.update.withUniqueGeneratedKeys[Long]("meeting_id") } yield MeetingId(id) } def loadMeeting(meetingId: MeetingId) = sql"select subject, description, frequency from meeting where meeting_id = $meetingId" .query[Meeting] .unique "Doobie" should "store and retrieve a cron expression as a member of a storable data structure" in { val standUpMeeting = Meeting( "Daily stand-up", "Daily team morning stand-up meeting", Cron.unsafeParse("0 0 10 ? * mon-fri") ) val tx = for { meetingId <- insertMeeting(standUpMeeting) loaded <- loadMeeting(meetingId) } yield loaded val loadedMeeting = tx.transact(xa).unsafeRunSync() loadedMeeting shouldBe standUpMeeting } it should "throw a SecondaryValidationFailed in case the cron expression is invalid" in { assertThrows[SecondaryValidationFailed[CronExpr]] { sql"select '0- 0 30 * * ?'".query[CronExpr].unique.transact(xa).unsafeRunSync() } } }
Example 177
Source File: RegressionRun.scala From Conseil with Apache License 2.0 | 5 votes |
package tech.cryptonomic.conseil.smoke.tests import cats.effect.{ExitCode, IO, IOApp} import tech.cryptonomic.conseil.smoke.tests.suites.RegressionSuite override def run(args: List[String]): IO[ExitCode] = { val defaultConfigFileName = "conseil-regression-tests.conf" val (conf, platform, network) = args match { case platform :: network :: configfile :: _ => (configfile, platform, Some(network)) case platform :: configfile :: Nil => (configfile, platform, None) case platform :: Nil => (defaultConfigFileName, platform, None) } val configPrint = IO( println( s"Running with configuration from $conf and ${network.fold("no syncing to tezos")(net => "syncing to tezos " + net)}" ) ) for { _ <- configPrint probe <- RegressionSuite(conf, platform, network) _ <- probe.runRegressionSuite } yield ExitCode.Success } }
Example 178
Source File: Server.scala From typedapi with MIT License | 5 votes |
import typedapi.server._ import typedapi.server.http4s._ import cats.effect.IO import org.http4s._ import org.http4s.circe._ object Server { implicit val decoder = jsonOf[IO, User] implicit val encoder = jsonEncoderOf[IO, User] val get: () => IO[Result[User]] = () => IO.pure(success(User("Joe", 42))) val put: () => IO[Result[User]] = get val post: () => IO[Result[User]] = get val delete: () => IO[Result[User]] = get val path: () => IO[Result[User]] = get val putBody: User => IO[Result[User]] = user => IO.pure(success(user)) val segment: String => IO[Result[User]] = name => IO.pure(success(User(name, 42))) val search: String => IO[Result[User]] = segment val header: String => IO[Result[User]] = consumer => IO.pure(success(User("found: " + consumer, 42))) val fixed: () => IO[Result[User]] = get val client: () => IO[Result[User]] = get val coll: () => IO[Result[User]] = get val matching: Map[String, String] => IO[Result[User]] = matches => IO.pure(success(User(matches.mkString(","), 42))) val endpoints = deriveAll[IO](FromDefinition.MyApi).from( get, put, post, delete, path, putBody, segment, search, header, fixed, client, coll, matching ) def main(args: Array[String]): Unit = { import org.http4s.server.blaze.BlazeBuilder val sm = ServerManager(BlazeBuilder[IO], "localhost", 9000) mount(sm, endpoints).unsafeRunSync() scala.io.StdIn.readLine("Press 'Enter' to stop ...") } }
Example 179
Source File: Client.scala From typedapi with MIT License | 5 votes |
import typedapi.client._ import typedapi.client.http4s._ import cats.effect.IO import org.http4s._ import org.http4s.circe._ object Client { implicit val decoder = jsonOf[IO, User] implicit val encoder = jsonEncoderOf[IO, User] val (get, put, post, delete, path, putBody, segment, search, header, fixed, client, coll, matches) = deriveAll(FromDsl.MyApi) def main(args: Array[String]): Unit = { import User._ import cats.effect.IO import org.http4s.client.blaze.Http1Client val cm = ClientManager(Http1Client[IO]().unsafeRunSync, "http://localhost", 9000) (for { u0 <- putBody(User("joe", 27)).run[IO](cm) u1 <- search("joe").run[IO](cm) } yield { println(u0) println(u1) () }).unsafeRunSync() } }
Example 180
Source File: Http4sClientSupportSpec.scala From typedapi with MIT License | 5 votes |
package http.support.tests.client import http.support.tests.{UserCoding, User, Api} import typedapi.client._ import typedapi.client.http4s._ import cats.effect.IO import org.http4s.client.blaze.Http1Client import org.specs2.mutable.Specification final class Http4sClientSupportSpec extends Specification { import UserCoding._ sequential val cm = ClientManager(Http1Client[IO]().unsafeRunSync, "http://localhost", 9001) val server = TestServer.start() "http4s client support" >> { val (p, s, q, header, fixed, clInH, clFixH, clColl, serMatchH, serSendH, m0, m1, m2, m3, m4, m5, _, _, _) = deriveAll(Api) "paths and segments" >> { p().run[IO](cm).unsafeRunSync() === User("foo", 27) s("jim").run[IO](cm).unsafeRunSync() === User("jim", 27) } "queries" >> { q(42).run[IO](cm).unsafeRunSync() === User("foo", 42) } "headers" >> { header(42).run[IO](cm).unsafeRunSync() === User("foo", 42) fixed().run[IO](cm).unsafeRunSync() === User("joe", 27) clInH("jim").run[IO](cm).unsafeRunSync === User("jim", 27) clFixH().run[IO](cm).unsafeRunSync() === User("joe", 27) clColl(Map("coll" -> "joe", "collect" -> "jim")).run[IO](cm).unsafeRunSync === User("coll: joe,collect: jim", 27) serMatchH().run[IO](cm).unsafeRunSync() === User("joe", 27) serSendH().run[IO](cm).unsafeRunSync() === User("joe", 27) } "methods" >> { m0().run[IO](cm).unsafeRunSync() === User("foo", 27) m1().run[IO](cm).unsafeRunSync() === User("foo", 27) m2(User("jim", 42)).run[IO](cm).unsafeRunSync() === User("jim", 42) m3().run[IO](cm).unsafeRunSync() === User("foo", 27) m4(User("jim", 42)).run[IO](cm).unsafeRunSync() === User("jim", 42) m5(List("because")).run[IO](cm).unsafeRunSync() === User("foo", 27) } step { server.shutdown.unsafeRunSync() } } }
Example 181
Source File: Http4sServerSupportSpec.scala From typedapi with MIT License | 5 votes |
package http.support.tests.server import http.support.tests.{UserCoding, Api} import typedapi.server._ import typedapi.server.http4s._ import cats.effect.IO import org.http4s.server.blaze.BlazeBuilder final class Http4sServerSupportSpec extends ServerSupportSpec[IO] { import UserCoding._ val endpoints = deriveAll[IO](Api).from( path, segment, query, header, fixed, input, clientHdr, coll, matching, send, get, put, putB, post, postB, delete, code200, code400, code500 ) val sm = ServerManager(BlazeBuilder[IO], "localhost", 9000) val server = mount(sm, endpoints).unsafeRunSync() "http4s implements TypedApi's server interface" >> { tests(9000) step { server.shutdown.unsafeRunSync() } } }
Example 182
Source File: TimeService.scala From get-programming-with-scala with MIT License | 5 votes |
package org.example.time import java.time.format.DateTimeFormatter import cats.effect.IO import org.http4s.HttpService import org.http4s.dsl.Http4sDsl class TimeService extends Http4sDsl[IO] { private val printer = new TimePrinter(DateTimeFormatter.RFC_1123_DATE_TIME) val service = HttpService[IO] { case GET -> Root / "datetime" / country => try { Ok(printer.now(country)) } catch { case ex: IllegalStateException => NotFound(ex.getMessage) } } }
Example 183
Source File: EthereumPostgresSpout.scala From Raphtory with Apache License 2.0 | 5 votes |
package com.raphtory.examples.blockchain.spouts import cats.effect.Blocker import cats.effect.IO import com.raphtory.core.components.Spout.SpoutTrait import doobie.implicits._ import doobie.util.ExecutionContexts import doobie.util.transactor.Transactor import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration.Duration import scala.concurrent.duration.MILLISECONDS import scala.concurrent.duration.SECONDS class EthereumPostgresSpout extends SpoutTrait { var startBlock = System.getenv().getOrDefault("STARTING_BLOCK", "46147").trim.toInt //first block to have a transaction by default val batchSize = System.getenv().getOrDefault("BLOCK_BATCH_SIZE", "100").trim.toInt //number of blocks to pull each query val maxblock = System.getenv().getOrDefault("MAX_BLOCK", "8828337").trim.toInt //Maximum block in database to stop querying once this is reached val dbURL = System.getenv().getOrDefault("DB_URL", "jdbc:postgresql:ether").trim //db connection string, default is for local with db called ether val dbUSER = System.getenv().getOrDefault("DB_USER", "postgres").trim //db user defaults to postgres val dbPASSWORD = System.getenv().getOrDefault("DB_PASSWORD", "").trim //default no password // querying done with doobie wrapper for JDBC (https://tpolecat.github.io/doobie/) implicit val cs = IO.contextShift(ExecutionContexts.synchronous) val dbconnector = Transactor.fromDriverManager[IO]( "org.postgresql.Driver", dbURL, dbUSER, dbPASSWORD, Blocker.liftExecutionContext(ExecutionContexts.synchronous) ) override def ProcessSpoutTask(message: Any): Unit = message match { case StartSpout => AllocateSpoutTask(Duration(1, MILLISECONDS), "nextBatch") case "nextBatch" => running() case _ => println("message not recognized!") } protected def running(): Unit = { sql"select from_address, to_address, value,block_timestamp from transactions where block_number >= $startBlock AND block_number < ${startBlock + batchSize} " .query[ (String, String, String, String) ] //get the to,from,value and time for transactions within the set block batch .to[List] // ConnectionIO[List[String]] .transact(dbconnector) // IO[List[String]] .unsafeRunSync // List[String] .foreach(x => sendTuple(x.toString())) //send each transaction to the routers startBlock += batchSize //increment batch for the next query if (startBlock > maxblock) stop() //if we have reached the max block we stop querying the database AllocateSpoutTask(Duration(1, MILLISECONDS), "nextBatch") // line up the next batch } }
Example 184
Source File: StaticLoggerBinder.scala From odin with Apache License 2.0 | 5 votes |
package org.slf4j.impl import cats.effect.{ConcurrentEffect, ContextShift, IO, Timer} import io.odin._ import io.odin.slf4j.{BufferingLogger, OdinLoggerBinder} import scala.concurrent.ExecutionContext class StaticLoggerBinder extends OdinLoggerBinder[IO] { val ec: ExecutionContext = scala.concurrent.ExecutionContext.global implicit val timer: Timer[IO] = IO.timer(ec) implicit val cs: ContextShift[IO] = IO.contextShift(ec) implicit val F: ConcurrentEffect[IO] = IO.ioConcurrentEffect val loggers: PartialFunction[String, Logger[IO]] = { case Level.Trace.toString => new BufferingLogger[IO](Level.Trace) case Level.Debug.toString => new BufferingLogger[IO](Level.Debug) case Level.Info.toString => new BufferingLogger[IO](Level.Info) case Level.Warn.toString => new BufferingLogger[IO](Level.Warn) case Level.Error.toString => new BufferingLogger[IO](Level.Error) case _ => new BufferingLogger[IO](Level.Trace) } } object StaticLoggerBinder extends StaticLoggerBinder { var REQUESTED_API_VERSION: String = "1.7" def getSingleton: StaticLoggerBinder = this }
Example 185
Source File: ClassBasedRouting.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.examples import cats.effect.{ExitCode, IO, IOApp} import io.odin._ import io.odin.config._ object ClassBasedRouting extends IOApp { val logger: Logger[IO] = classRouting[IO]( classOf[Foo[_]] -> consoleLogger[IO]().withMinimalLevel(Level.Warn), classOf[Bar[_]] -> consoleLogger[IO]().withMinimalLevel(Level.Info) ).withNoopFallback def run(args: List[String]): IO[ExitCode] = { (Foo(logger).log *> Bar(logger).log).as(ExitCode.Success) } } case class Foo[F[_]](logger: Logger[F]) { def log: F[Unit] = logger.info("foo") } case class Bar[F[_]](logger: Logger[F]) { def log: F[Unit] = logger.info("bar") }
Example 186
Source File: FilteringStackTrace.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.examples import cats.effect.{ExitCode, IO, IOApp} import io.odin._ import io.odin.formatter.Formatter import io.odin.formatter.options.ThrowableFormat object FilteringStackTrace extends IOApp { val throwableFormat: ThrowableFormat = ThrowableFormat( ThrowableFormat.Depth.Fixed(3), ThrowableFormat.Indent.NoIndent, ThrowableFormat.Filter.Excluding("cats.effect.IOApp", "cats.effect.internals.IOAppPlatform") ) val logger: Logger[IO] = consoleLogger(formatter = Formatter.create(throwableFormat, colorful = true)) def run(args: List[String]): IO[ExitCode] = logger.error("This is an exception", new RuntimeException("here")).as(ExitCode.Success) }
Example 187
Source File: EnclosureBasedRouting.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.examples import cats.effect.{ExitCode, IO, IOApp} import io.odin._ import io.odin.config._ object EnclosureBasedRouting extends IOApp { val logger: Logger[IO] = enclosureRouting( "io.odin.examples.EnclosureBasedRouting.foo" -> consoleLogger[IO]().withMinimalLevel(Level.Warn), "io.odin.examples.EnclosureBasedRouting.bar" -> consoleLogger[IO]().withMinimalLevel(Level.Info), "io.odin.examples" -> consoleLogger[IO]() ).withNoopFallback def zoo: IO[Unit] = logger.debug("Debug") def foo: IO[Unit] = logger.info("Never shown") def bar: IO[Unit] = logger.warn("Warning") def run(args: List[String]): IO[ExitCode] = { (zoo *> foo *> bar).as(ExitCode.Success) } }
Example 188
Source File: EqInstances.scala From odin with Apache License 2.0 | 5 votes |
package io.odin import cats.Eq import cats.effect.IO import io.odin.formatter.Formatter import org.scalacheck.Arbitrary import scala.annotation.tailrec trait EqInstances { @tailrec final def retrySample[T](implicit arb: Arbitrary[T]): T = arb.arbitrary.sample match { case Some(v) => v case _ => retrySample[T] } implicit def loggerEq[F[_]]( implicit arbitraryString: Arbitrary[String], arbitraryCtx: Arbitrary[Map[String, String]], arbitraryThrowable: Arbitrary[Throwable], eqF: Eq[F[Unit]] ): Eq[Logger[F]] = (x: Logger[F], y: Logger[F]) => { val msg = retrySample[String] val ctx = retrySample[Map[String, String]] val throwable = retrySample[Throwable] eqF.eqv(x.trace(msg), y.trace(msg)) && eqF.eqv(x.trace(msg, throwable), y.trace(msg, throwable)) && eqF.eqv(x.trace(msg, ctx), y.trace(msg, ctx)) && eqF.eqv(x.trace(msg, ctx, throwable), y.trace(msg, ctx, throwable)) && eqF.eqv(x.debug(msg), y.debug(msg)) && eqF.eqv(x.debug(msg, throwable), y.debug(msg, throwable)) && eqF.eqv(x.debug(msg, ctx), y.debug(msg, ctx)) && eqF.eqv(x.debug(msg, ctx, throwable), y.debug(msg, ctx, throwable)) && eqF.eqv(x.info(msg), y.info(msg)) && eqF.eqv(x.info(msg, throwable), y.info(msg, throwable)) && eqF.eqv(x.info(msg, ctx), y.info(msg, ctx)) && eqF.eqv(x.info(msg, ctx, throwable), y.info(msg, ctx, throwable)) && eqF.eqv(x.warn(msg), y.warn(msg)) && eqF.eqv(x.warn(msg, throwable), y.warn(msg, throwable)) && eqF.eqv(x.warn(msg, ctx), y.warn(msg, ctx)) && eqF.eqv(x.warn(msg, ctx, throwable), y.warn(msg, ctx, throwable)) && eqF.eqv(x.error(msg), y.error(msg)) && eqF.eqv(x.error(msg, throwable), y.error(msg, throwable)) && eqF.eqv(x.error(msg, ctx), y.error(msg, ctx)) && eqF.eqv(x.error(msg, ctx, throwable), y.error(msg, ctx, throwable)) } implicit def eqIO[A](implicit eqA: Eq[A]): Eq[IO[A]] = Eq.instance { (ioA, ioB) => eqA.eqv(ioA.unsafeRunSync(), ioB.unsafeRunSync()) } implicit val loggerMessageEq: Eq[LoggerMessage] = Eq.instance { (lm1, lm2) => val LoggerMessage(lvl1, msg1, context1, exception1, position1, threadName1, timestamp1) = lm1 val LoggerMessage(lvl2, msg2, context2, exception2, position2, threadName2, timestamp2) = lm2 lvl1 == lvl2 && msg1.value == msg2.value && context1 == context2 && exception1 == exception2 && position1 == position2 && threadName1 == threadName2 && timestamp1 == timestamp2 } implicit def formatterEq(implicit arbLoggerMsg: Arbitrary[LoggerMessage]): Eq[Formatter] = Eq.instance { (fmt1, fmt2) => val msg = retrySample[LoggerMessage] fmt1.format(msg) == fmt2.format(msg) } }
Example 189
Source File: ContextualLoggerSpec.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.loggers import cats.arrow.FunctionK import cats.data.{ReaderT, WriterT} import cats.effect.{Clock, IO, Timer} import cats.instances.list._ import cats.mtl.instances.all._ import io.odin.syntax._ import io.odin.{LoggerMessage, OdinSpec} import scala.concurrent.duration.{FiniteDuration, TimeUnit} class ContextualLoggerSpec extends OdinSpec { type W[A] = WriterT[IO, List[LoggerMessage], A] type F[A] = ReaderT[W, Map[String, String], A] implicit val hasContext: HasContext[Map[String, String]] = (env: Map[String, String]) => env implicit val timer: Timer[IO] = new Timer[IO] { def clock: Clock[IO] = new Clock[IO] { def realTime(unit: TimeUnit): IO[Long] = IO.pure(0) def monotonic(unit: TimeUnit): IO[Long] = IO.pure(0) } def sleep(duration: FiniteDuration): IO[Unit] = ??? } private val logger = new WriterTLogger[IO].mapK(λ[FunctionK[W, F]](ReaderT.liftF(_))).withContext checkAll("ContContextLogger", LoggerTests[F](logger, reader => reader.run(Map()).written.unsafeRunSync()).all) it should "pick up context from F[_]" in { forAll { (loggerMessage: LoggerMessage, ctx: Map[String, String]) => val List(written) = logger.log(loggerMessage).apply(ctx).written.unsafeRunSync() written.context shouldBe loggerMessage.context ++ ctx } } it should "embed context in all messages" in { forAll { (msgs: List[LoggerMessage], ctx: Map[String, String]) => val written = logger.log(msgs).apply(ctx).written.unsafeRunSync() written.map(_.context) shouldBe msgs.map(_.context ++ ctx) } } }
Example 190
Source File: ConstContextLoggerSpec.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.loggers import cats.data.WriterT import cats.effect.{IO, Timer} import cats.instances.list._ import io.odin.syntax._ import io.odin.{LoggerMessage, OdinSpec} class ConstContextLoggerSpec extends OdinSpec { type F[A] = WriterT[IO, List[LoggerMessage], A] implicit val timer: Timer[IO] = zeroTimer checkAll( "ContextualLogger", LoggerTests[F]( new WriterTLogger[IO].withConstContext(Map.empty), _.written.unsafeRunSync() ).all ) it should "add constant context to the record" in { forAll { (loggerMessage: LoggerMessage, ctx: Map[String, String]) => val logger = new WriterTLogger[IO].withConstContext(ctx) val List(written) = logger.log(loggerMessage).written.unsafeRunSync() written.context shouldBe loggerMessage.context ++ ctx } } it should "add constant context to the records" in { forAll { (messages: List[LoggerMessage], ctx: Map[String, String]) => val logger = new WriterTLogger[IO].withConstContext(ctx) val written = logger.log(messages).written.unsafeRunSync() written.map(_.context) shouldBe messages.map(_.context ++ ctx) } } }
Example 191
Source File: FilterLoggerSpec.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.loggers import cats.data.WriterT import cats.effect.{IO, Timer} import io.odin._ import io.odin.syntax._ import cats.instances.list._ import cats.syntax.all._ class FilterLoggerSpec extends OdinSpec { type F[A] = WriterT[IO, List[LoggerMessage], A] implicit val timer: Timer[IO] = zeroTimer checkAll( "FilterLogger", LoggerTests[F](new WriterTLogger[IO].filter(_.exception.isDefined), _.written.unsafeRunSync()).all ) it should "logger.filter(p).log(msg) <-> F.whenA(p)(log(msg))" in { forAll { (msgs: List[LoggerMessage], p: LoggerMessage => Boolean) => { val logger = new WriterTLogger[IO].filter(p) val written = msgs.traverse(logger.log).written.unsafeRunSync() val batchWritten = logger.log(msgs).written.unsafeRunSync() written shouldBe msgs.filter(p) batchWritten shouldBe written } } } }
Example 192
Source File: ConsoleLoggerSpec.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.loggers import java.io.{ByteArrayOutputStream, PrintStream} import cats.effect.{IO, Timer} import cats.syntax.all._ import io.odin.Level._ import io.odin.formatter.Formatter import io.odin.{Level, LoggerMessage, OdinSpec} class ConsoleLoggerSpec extends OdinSpec { implicit val timer: Timer[IO] = IO.timer(scala.concurrent.ExecutionContext.global) it should "route all messages with level <= INFO to stdout" in { forAll { (loggerMessage: LoggerMessage, formatter: Formatter) => whenever(loggerMessage.level <= Info) { val outBaos = new ByteArrayOutputStream() val stdOut = new PrintStream(outBaos) val errBaos = new ByteArrayOutputStream() val stdErr = new PrintStream(errBaos) val consoleLogger = ConsoleLogger[IO](formatter, stdOut, stdErr, Level.Trace) consoleLogger.log(loggerMessage).unsafeRunSync() outBaos.toString() shouldBe (formatter.format(loggerMessage) + System.lineSeparator()) } } } it should "route all messages with level >= WARN to stderr" in { forAll { (loggerMessage: LoggerMessage, formatter: Formatter) => whenever(loggerMessage.level > Info) { val outBaos = new ByteArrayOutputStream() val stdOut = new PrintStream(outBaos) val errBaos = new ByteArrayOutputStream() val stdErr = new PrintStream(errBaos) val consoleLogger = ConsoleLogger[IO](formatter, stdOut, stdErr, Level.Trace) consoleLogger.log(loggerMessage).unsafeRunSync() errBaos.toString() shouldBe (formatter.format(loggerMessage) + System.lineSeparator()) } } } }
Example 193
Source File: LoggerNatTransformSpec.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.loggers import cats.data.{Writer, WriterT} import cats.effect.{Clock, IO, Timer} import cats.{~>, Id} import io.odin.{Level, Logger, LoggerMessage, OdinSpec} import scala.concurrent.duration.{FiniteDuration, TimeUnit} class LoggerNatTransformSpec extends OdinSpec { type F[A] = Writer[List[LoggerMessage], A] type FF[A] = WriterT[IO, List[LoggerMessage], A] it should "transform each method" in { forAll { (msg: String, ctx: Map[String, String], throwable: Throwable, timestamp: Long) => implicit val clk: Timer[Id] = clock(timestamp) val logF = logger.withMinimalLevel(Level.Trace) val logFF = logF.mapK(nat).withMinimalLevel(Level.Trace) check(logF.trace(msg), logFF.trace(msg)) check(logF.trace(msg, throwable), logFF.trace(msg, throwable)) check(logF.trace(msg, ctx), logFF.trace(msg, ctx)) check(logF.trace(msg, ctx, throwable), logFF.trace(msg, ctx, throwable)) check(logF.debug(msg), logFF.debug(msg)) check(logF.debug(msg, throwable), logFF.debug(msg, throwable)) check(logF.debug(msg, ctx), logFF.debug(msg, ctx)) check(logF.debug(msg, ctx, throwable), logFF.debug(msg, ctx, throwable)) check(logF.info(msg), logFF.info(msg)) check(logF.info(msg, throwable), logFF.info(msg, throwable)) check(logF.info(msg, ctx), logFF.info(msg, ctx)) check(logF.info(msg, ctx, throwable), logFF.info(msg, ctx, throwable)) check(logF.warn(msg), logFF.warn(msg)) check(logF.warn(msg, throwable), logFF.warn(msg, throwable)) check(logF.warn(msg, ctx), logFF.warn(msg, ctx)) check(logF.warn(msg, ctx, throwable), logFF.warn(msg, ctx, throwable)) check(logF.error(msg), logFF.error(msg)) check(logF.error(msg, throwable), logFF.error(msg, throwable)) check(logF.error(msg, ctx), logFF.error(msg, ctx)) check(logF.error(msg, ctx, throwable), logFF.error(msg, ctx, throwable)) } } private val nat: F ~> FF = new (F ~> FF) { private val idToIo = new (Id ~> IO) { def apply[A](fa: Id[A]): IO[A] = IO.pure(fa) } def apply[A](fa: F[A]): FF[A] = fa.mapK(idToIo) } private def clock(timestamp: Long): Timer[Id] = new Timer[Id] { def clock: Clock[Id] = new Clock[Id] { def realTime(unit: TimeUnit): Id[Long] = timestamp def monotonic(unit: TimeUnit): Id[Long] = timestamp } def sleep(duration: FiniteDuration): Id[Unit] = ??? } private def logger(implicit timer: Timer[Id]): Logger[F] = new WriterTLogger[Id] private def check(fnF: => F[Unit], fnFF: => FF[Unit]) = { val List(loggerMessageF) = fnF.written val List(loggerMessageFF) = fnFF.written.unsafeRunSync() loggerMessageEq.eqv(loggerMessageF, loggerMessageFF) shouldBe true } }
Example 194
Source File: LoggerMonoidSpec.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.loggers import java.util.UUID import cats.data.WriterT import cats.effect.{Clock, IO, Timer} import cats.instances.list._ import cats.instances.tuple._ import cats.instances.unit._ import cats.instances.uuid._ import cats.kernel.laws.discipline.MonoidTests import cats.syntax.all._ import io.odin.{Level, Logger, LoggerMessage, OdinSpec} import org.scalacheck.{Arbitrary, Gen} import scala.concurrent.duration.{FiniteDuration, TimeUnit} class LoggerMonoidSpec extends OdinSpec { type F[A] = WriterT[IO, List[(UUID, LoggerMessage)], A] checkAll("Logger", MonoidTests[Logger[F]].monoid) it should "(logger1 |+| logger2).log <-> (logger1.log |+| logger2.log)" in { forAll { (uuid1: UUID, uuid2: UUID, msg: LoggerMessage) => val logger1: Logger[F] = NamedLogger(uuid1) val logger2: Logger[F] = NamedLogger(uuid2) val a = (logger1 |+| logger2).log(msg) val b = logger1.log(msg) |+| logger2.log(msg) a.written.unsafeRunSync() shouldBe b.written.unsafeRunSync() } } it should "(logger1 |+| logger2).log(list) <-> (logger1.log |+| logger2.log(list))" in { forAll { (uuid1: UUID, uuid2: UUID, msg: List[LoggerMessage]) => val logger1: Logger[F] = NamedLogger(uuid1) val logger2: Logger[F] = NamedLogger(uuid2) val a = (logger1 |+| logger2).log(msg) val b = logger1.log(msg) |+| logger2.log(msg) a.written.unsafeRunSync() shouldBe b.written.unsafeRunSync() } } it should "set minimal level for underlying loggers" in { forAll { (uuid1: UUID, uuid2: UUID, level: Level, msg: List[LoggerMessage]) => val logger1: Logger[F] = NamedLogger(uuid1) val logger2: Logger[F] = NamedLogger(uuid2) val a = (logger1 |+| logger2).withMinimalLevel(level).log(msg) val b = (logger1.withMinimalLevel(level) |+| logger2.withMinimalLevel(level)).log(msg) a.written.unsafeRunSync() shouldBe b.written.unsafeRunSync() } } case class NamedLogger(loggerId: UUID) extends DefaultLogger[F] { def log(msg: LoggerMessage): F[Unit] = WriterT.tell(List(loggerId -> msg)) } implicit def timer: Timer[IO] = new Timer[IO] { def clock: Clock[IO] = new Clock[IO] { def realTime(unit: TimeUnit): IO[Long] = IO.pure(0) def monotonic(unit: TimeUnit): IO[Long] = IO.pure(0) } def sleep(duration: FiniteDuration): IO[Unit] = ??? } implicit def arbitraryWriterLogger: Arbitrary[Logger[F]] = Arbitrary( Gen.uuid.map(NamedLogger) ) }
Example 195
Source File: ContramapLoggerSpec.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.loggers import cats.data.WriterT import cats.effect.{IO, Timer} import cats.instances.list._ import cats.syntax.all._ import io.odin.{LoggerMessage, OdinSpec} import io.odin.syntax._ class ContramapLoggerSpec extends OdinSpec { type F[A] = WriterT[IO, List[LoggerMessage], A] implicit val timer: Timer[IO] = zeroTimer checkAll("ContramapLogger", LoggerTests[F](new WriterTLogger[IO].contramap(identity), _.written.unsafeRunSync()).all) it should "contramap(identity).log(msg) <-> log(msg)" in { val logger = new WriterTLogger[IO].contramap(identity) forAll { msgs: List[LoggerMessage] => val written = msgs.traverse(logger.log).written.unsafeRunSync() val batchWritten = logger.log(msgs).written.unsafeRunSync() written shouldBe msgs batchWritten shouldBe written } } it should "contramap(f).log(msg) <-> log(f(msg))" in { forAll { (msgs: List[LoggerMessage], fn: LoggerMessage => LoggerMessage) => val logger = new WriterTLogger[IO].contramap(fn) val written = msgs.traverse(logger.log).written.unsafeRunSync() val batchWritten = logger.log(msgs).written.unsafeRunSync() written shouldBe msgs.map(fn) batchWritten shouldBe written } } }
Example 196
Source File: S3CatsIOClientSupoprt.scala From reactive-aws-clients with MIT License | 5 votes |
package com.github.j5ik2o.reactive.aws.s3.cats import java.io.File import java.nio.file.Path import cats.effect.IO import software.amazon.awssdk.core.ResponseBytes import software.amazon.awssdk.core.async.{ AsyncRequestBody, AsyncResponseTransformer } import software.amazon.awssdk.services.s3.model._ trait S3CatsIOClientSupoprt { this: S3CatsIOClient => override type RT[A, B] = AsyncResponseTransformer[A, B] override type RB = AsyncRequestBody override def listBuckets(): IO[ListBucketsResponse] = IO.fromFuture { IO(underlying.listBuckets()) } override def getObjectAsBytes( getObjectRequest: GetObjectRequest ): IO[ResponseBytes[GetObjectResponse]] = IO.fromFuture { IO(underlying.getObjectAsBytes(getObjectRequest)) } override def getObjectToFile(getObjectRequest: GetObjectRequest, file: File): IO[GetObjectResponse] = IO.fromFuture { IO(underlying.getObjectToFile(getObjectRequest, file)) } override def getObjectToPath(getObjectRequest: GetObjectRequest, destinationPath: Path): IO[GetObjectResponse] = IO.fromFuture { IO(underlying.getObjectToPath(getObjectRequest, destinationPath)) } override def getObject[A]( getObjectRequest: GetObjectRequest, responseTransformer: AsyncResponseTransformer[GetObjectResponse, A] ): IO[A] = IO.fromFuture { IO(underlying.getObject(getObjectRequest, responseTransformer)) } override def getObjectTorrentAsBytes( getObjectRequest: GetObjectTorrentRequest ): IO[ResponseBytes[GetObjectTorrentResponse]] = IO.fromFuture { IO(underlying.getObjectTorrentAsBytes(getObjectRequest)) } override def getObjectTorrentToFile( getObjectRequest: GetObjectTorrentRequest, file: File ): IO[GetObjectTorrentResponse] = IO.fromFuture { IO(underlying.getObjectTorrentToFile(getObjectRequest, file)) } override def getObjectTorrentToPath( getObjectTorrentRequest: GetObjectTorrentRequest, destinationPath: Path ): IO[GetObjectTorrentResponse] = IO.fromFuture { IO(underlying.getObjectTorrentToPath(getObjectTorrentRequest, destinationPath)) } override def getObjectTorrent[A]( getObjectTorrentRequest: GetObjectTorrentRequest, responseTransformer: AsyncResponseTransformer[GetObjectTorrentResponse, A] ): IO[A] = IO.fromFuture { IO(underlying.getObjectTorrent(getObjectTorrentRequest, responseTransformer)) } override def putObject(putObjectRequest: PutObjectRequest, requestBody: AsyncRequestBody): IO[PutObjectResponse] = IO.fromFuture { IO(underlying.putObject(putObjectRequest, requestBody)) } override def putObjectFromPath(putObjectRequest: PutObjectRequest, sourcePath: Path): IO[PutObjectResponse] = IO.fromFuture { IO(underlying.putObjectFromPath(putObjectRequest, sourcePath)) } override def putObjectFromFile(putObjectRequest: PutObjectRequest, sourceFile: File): IO[PutObjectResponse] = IO.fromFuture { IO(underlying.putObjectFromFile(putObjectRequest, sourceFile)) } override def uploadPart(uploadPartRequest: UploadPartRequest, requestBody: AsyncRequestBody): IO[UploadPartResponse] = IO.fromFuture { IO(underlying.uploadPart(uploadPartRequest, requestBody)) } override def uploadPartFromPath(uploadPartRequest: UploadPartRequest, sourcePath: Path): IO[UploadPartResponse] = IO.fromFuture { IO(underlying.uploadPartFromPath(uploadPartRequest, sourcePath)) } override def uploadPartFromFile(uploadPartRequest: UploadPartRequest, sourceFile: File): IO[UploadPartResponse] = IO.fromFuture { IO(underlying.uploadPartFromFile(uploadPartRequest, sourceFile)) } }
Example 197
Source File: DynamoDbStreamsCatsIOClient.scala From reactive-aws-clients with MIT License | 5 votes |
// Auto-Generated package com.github.j5ik2o.reactive.aws.dynamodb.streams.cats import cats.effect.{ ContextShift, IO } import com.github.j5ik2o.reactive.aws.dynamodb.streams.{ DynamoDbStreamsAsyncClient, DynamoDbStreamsClient } import software.amazon.awssdk.services.dynamodb.model._ import software.amazon.awssdk.services.dynamodb.streams.paginators.{ DescribeStreamPublisher, ListStreamsPublisher } import scala.concurrent.{ ExecutionContext, Future } object DynamoDbStreamsCatsIOClient { def apply(asyncClient: DynamoDbStreamsAsyncClient)(implicit ec: ExecutionContext): DynamoDbStreamsCatsIOClient = new DynamoDbStreamsCatsIOClient { override val executionContext: ExecutionContext = ec override val underlying: DynamoDbStreamsAsyncClient = asyncClient } } trait DynamoDbStreamsCatsIOClient extends DynamoDbStreamsClient[IO] { val underlying: DynamoDbStreamsAsyncClient def executionContext: ExecutionContext implicit def cs: ContextShift[IO] = IO.contextShift(executionContext) override def describeStream(describeStreamRequest: DescribeStreamRequest): IO[DescribeStreamResponse] = IO.fromFuture { IO(underlying.describeStream(describeStreamRequest)) } def describeStreamPaginator(describeStreamRequest: DescribeStreamRequest): DescribeStreamPublisher = underlying.describeStreamPaginator(describeStreamRequest) override def getRecords(getRecordsRequest: GetRecordsRequest): IO[GetRecordsResponse] = IO.fromFuture { IO(underlying.getRecords(getRecordsRequest)) } override def getShardIterator(getShardIteratorRequest: GetShardIteratorRequest): IO[GetShardIteratorResponse] = IO.fromFuture { IO(underlying.getShardIterator(getShardIteratorRequest)) } override def listStreams(listStreamsRequest: ListStreamsRequest): IO[ListStreamsResponse] = IO.fromFuture { IO(underlying.listStreams(listStreamsRequest)) } override def listStreams(): IO[ListStreamsResponse] = IO.fromFuture { IO(underlying.listStreams()) } def listStreamsPaginator(): ListStreamsPublisher = underlying.listStreamsPaginator() def listStreamsPaginator(listStreamsRequest: ListStreamsRequest): ListStreamsPublisher = underlying.listStreamsPaginator(listStreamsRequest) }
Example 198
Source File: PropPath.scala From shaclex with MIT License | 5 votes |
package es.weso.slang import es.weso.rdf.nodes._ import es.weso.rdf._ import cats.effect.IO trait PropPath extends Product with Serializable { /* private def showSet[A](vs: Set[A]): String = vs.size match { case 0 => s"{}" case 1 => vs.head.toString case _ => s"${vs.map(_.toString).mkString(",")}" } */ def reach(n1: RDFNode, n2: RDFNode, rdf: RDFReader): IO[Boolean] } case class Pred(p: IRI) extends PropPath { override def reach(n1: RDFNode, n2: RDFNode, rdf: RDFReader ): IO[Boolean] = for { ts <- rdf.triplesWithSubjectPredicate(n1,p).compile.toList } yield ts.map(_.obj).contains(n2) } case class Inv(p: IRI) extends PropPath { override def reach(n1: RDFNode, n2: RDFNode, rdf: RDFReader ): IO[Boolean] = for { ts <- rdf.triplesWithSubjectPredicate(n2,p).compile.toList } yield ts.map(_.obj).contains(n1) } case class Sequ(pp1: PropPath, pp2: PropPath) extends PropPath { override def reach(n1: RDFNode, n2: RDFNode, rdf: RDFReader ): IO[Boolean] = IO(false) } case class Alt(pp1: PropPath, pp2: PropPath) extends PropPath { override def reach(n1: RDFNode, n2: RDFNode, rdf: RDFReader ): IO[Boolean] = IO(false) } case class ZeroOrMore(pp: PropPath) extends PropPath { override def reach(n1: RDFNode, n2: RDFNode, rdf: RDFReader ): IO[Boolean] = IO(false) } case class NoPreds(preds: Set[IRI]) extends PropPath { override def reach(n1: RDFNode, n2: RDFNode, rdf: RDFReader ): IO[Boolean] = IO(false) } object PropPath { def oneOrMore(pp: PropPath): PropPath = Sequ(pp, ZeroOrMore(pp)) }
Example 199
Source File: InferredSchema.scala From shaclex with MIT License | 5 votes |
package es.weso.schemaInfer import es.weso.rdf.{PrefixMap, RDFReader} import es.weso.rdf.nodes.IRI import es.weso.shex.{Schema, ShapeExpr} import cats.data._ import cats.implicits._ import cats.effect.IO case class InferredSchema(smap: Map[IRI, InferredShape]) extends AnyVal { def get(label: IRI): Option[InferredShape] = smap.get(label) def updated(label: IRI, shape: InferredShape): InferredSchema = InferredSchema(smap.updated(label,shape)) def values: List[InferredShape] = smap.values.toList type ES[A] = Either[String,A] def toShExSchema(rdf: RDFReader, opts: InferOptions, pm: PrefixMap ): EitherT[IO,String, Schema] = { val rs: List[EitherT[IO,String,ShapeExpr]] = smap.toList.map { case (iri, is) => is.toShapeExpr(Some(iri),opts, rdf) } for { es <- rs.sequence } yield Schema(IRI(""), Some(pm), None, None, None, Some(es),None,List()) } } object InferredSchema { def empty: InferredSchema = InferredSchema(Map()) }
Example 200
Source File: RDF2SGraph.scala From shaclex with MIT License | 5 votes |
package es.weso.rdf.sgraph import cats.data._ import cats.implicits._ import cats.effect.IO import es.weso.rdf.PREFIXES.`rdf:type` import es.weso.rdf.nodes.{IRI, RDFNode} import es.weso.rdf.triples.RDFTriple import es.weso.rdf.{PrefixMap, RDFReader} object RDF2SGraph { type Label = String type HRef = String type S[A] = State[SGraph, A] type Converter[A] = EitherT[S,String,A] def rdfTriple2Edge(t: RDFTriple, pm: PrefixMap): Converter[Edge] = for { n1 <- rdfNode2Node(t.subj, pm) n2 <- rdfNode2Node(t.obj, pm) e <- predicate2href(t.pred, pm) } yield Edge(n1,n2,e._1, e._2) def predicate2href(pred: IRI, pm: PrefixMap): Converter[(Label, HRef)] = pred match { case `rdf:type` => ok(("a", pred.str)) case _ => ok((pm.qualify(pred), pred.str)) } def rdfNode2Node(node: RDFNode, pm: PrefixMap): Converter[Node] = for { g <- getGraph (g1,n) = g.addNode(node,pm) _ <- setGraph(g1) } yield n def getGraph: Converter[SGraph] = EitherT.liftF[S,String,SGraph](StateT.get) def setGraph(g: SGraph): Converter[Unit] = EitherT.liftF[S,String,Unit](StateT.set(g)) def ok[A](x:A): Converter[A] = EitherT.liftF(StateT.pure(x)) def err[A](s: String): Converter[A] = EitherT.fromEither(s.asLeft[A]) def rdf2sgraph(rdf: RDFReader): IO[SGraph] = { val pm = rdf.getPrefixMap() def cmb(u:Unit, t: RDFTriple): Converter[Unit] = for { edge <- rdfTriple2Edge(t, pm) g <- getGraph g1 = g.addEdge(edge) _ <- setGraph(g1) } yield () for { ts <- rdf.rdfTriples.compile.toList } yield { ts.toList.foldM(())(cmb).value.run(SGraph.empty).value._1 } } }