I have a function that has the following type signature:
def post(target: String, partition: String, payload: String): IO[Boolean]
In this function, a call is placed to a third party to post this data to a service through the awssdk. For testing, I don't want these calls actually placed, which has brought me to scalamock, but am not sure how to do this in looking at the documentation.
Within the post function I have leverage my private instance of aws's client for this service after setting credentials. There is a particular method on this instance that is responsible for the call to aws.
How can scalamock be leveraged to mock the awssdk to test the code I have surrounding this and not make the actual call?
Do you have a trait that defines this method? Then you can use Scalamock to get an instance of it and make it respond to post calls with whatever value you want it to.
https://scastie.scala-lang.org/KgJ0kptnRaiteNTWPBzrow
trait MyService {
def post(target: String, partition: String, payload: String): Future[Boolean]
}
val mockedService = mock[MyService]
(mockedService.post _)
.expects("a", "b","c")
.returning(Future.successful(true))
.once()
mockedService.post("a", "b", "c")
I am new to scala, just started with my scala first application.
I have defined my config file under the resources folder, application.conf
projectname{
"application" {
"host":127.0.0.1
"port":8080
}
}
I have wrote one config parser file to parse from config file to case class
case class AppConfig (config: Config) {
val host = config.getString("projectname.application.host")
val port = config.getInt("projectname.application.port")
}
In my grpc server file, i have declared config as
val config = AppConfig(ConfigFactory.load("application.conf"))
I want to use this config variable across application, rather than loading application.conf file everytime.
I want to have one bootstrap function which will parse this config one time, making it available across application
You can do this automatically with PureConfig.
Add Pure Config to you build.sbt with:
libraryDependencies += "com.github.pureconfig" %% "pureconfig" % "0.11.0"
and reload the sbt shell and update your dependencies.
Now, let's say you have the following resource.conf file:
host: example.com
port: 80
user: admin
password: admin_password
You can define a case class called AppConfig:
case class AppConfig(
host: String,
port: Int,
user: String,
password: String
)
And create an instance of it, populated with the application config, using the loadConfig method:
import pureconfig.generic.auto._
val errorsOrConfig: Either[ConfigReaderFailures, AppConfig] = pureconfig.loadConfig[AppConfig]
This returns Either an error or your AppConfig, depending on the values in the config itself.
For example, if the value of port above will be eighty, instead of 80, you will get a detailed error, saying that the second config line (with the port: eighty) contained a string, but the only valid expected type is a number:
ConfigReaderFailures(
ConvertFailure(
reason = WrongType(
foundType = STRING,
expectedTypes = Set(NUMBER)
),
location = Some(
ConfigValueLocation(
new URL("file:~/repos/example-project/target/scala-2.12/classes/application.conf"),
lineNumber = 2
)
),
path = "port"
)
)
You can use loadConfigOrThrow if you want to get AppConfig instead of an Either.
After you load this config once at the start of your application (as close as possible to your main function), you can use dependency injection to pass it along to all the other classes, simply by passing the AppConfig in the constructor.
If you would like to wire up your Logic class (and other services) with the config case class using MacWire, as Krzysztof suggested in one of his options, you can see my answer here.
The plain example (without MacWire), looks like this:
package com.example
import com.example.config.AppConfig
object HelloWorld extends App {
val config: AppConfig = pureconfig.loadConfigOrThrow[AppConfig]
val logic = new Logic(config)
}
class Logic(config: AppConfig) {
// do something with config
}
Where the AppConfig is defined in AppConfig.scala
package com.example.config
case class AppConfig(
host: String,
port: Int,
user: String,
password: String
)
As a bonus, when you use this config variable in your IDE, you will get code completion.
Moreover, your config may be built from the supported types, such as String, Boolean, Int, etc, but also from other case classes that are build from the supported types (this is since a case class represents a value object, that contains data), as well as lists and options of supported types.
This allows you to "class up" a complicated config file and get code completion. For instance, in application.conf:
name: hotels_best_dishes
host: "https://example.com"
port: 80
hotels: [
"Club Hotel Lutraky Greece",
"Four Seasons",
"Ritz",
"Waldorf Astoria"
]
min-duration: 2 days
currency-by-location {
us = usd
england = gbp
il = nis
}
accepted-currency: [usd, gbp, nis]
application-id: 00112233-4455-6677-8899-aabbccddeeff
ssh-directory: /home/whoever/.ssh
developer: {
name: alice,
age: 20
}
Then define a config case class in your code:
import java.net.URL
import java.util.UUID
import scala.concurrent.duration.FiniteDuration
import pureconfig.generic.EnumCoproductHint
import pureconfig.generic.auto._
case class Person(name: String, age: Int)
sealed trait Currency
case object Usd extends Currency
case object Gbp extends Currency
case object Nis extends Currency
object Currency {
implicit val currencyHint: EnumCoproductHint[Currency] = new EnumCoproductHint[Currency]
}
case class Config(
name: String,
host: URL,
port: Int,
hotels: List[String],
minDuration: FiniteDuration,
currencyByLocation: Map[String, Currency],
acceptedCurrency: List[Currency],
applicationId: UUID,
sshDirectory: java.nio.file.Path,
developer: Person
)
And load it with:
val config: Config = pureconfig.loadConfigOrThrow[Config]
There are some possibilities to handle your problem:
Use runtime dependency injection framework like guice. You can use extension for scala.
Use implicits to handle it. You just need to create an object, which will hold your implicit config:
object Implicits {
implicit val config = AppConfig(ConfigFactory.load("application.conf"))
}
And then you can just add implicit config: Config to your arguments list when you need it:
def process(n: Int)(implicit val config: Config) = ??? //as method parameter
case class Processor(n: Int)(implicit val config: AppConfig) //or as class field
And use it like:
import Implicits._
process(5) //config passed implicitly here
Processor(10) //and here
A great advantage of it is you can pass config manually for tests:
process(5)(config)
The downside of this approach is, that having a lot of implicit resolution in your app, will make compilation slow, but it shouldn't be a problem if your app is not humongous.
Make config a field of your classes (it is called constructor injection).
class Foo(config: Config).
Then you can wire-up your dependencies manually, like:
val config: AppConfig = AppConfig()
val foo = Foo(config) //you need to pass config manually to constructors in your object graph
or you can use a framework which can automate it for you, like macwire:
val config = wire[AppConfig]
val foo = wire[Foo]
You can use a pattern called cake-pattern. It works fine for small-sized applications, but the bigger your app is, the clunkier this approach gets.
What is NOT a good approach is using global singleton like this:
object ConfigHolder {
val Config: AppConfig = ???
}
And then use it like:
def process(n: Int) = {
val host = ConfigHolder.Config.host // anti-pattern
}
It is bad because it makes mocking your config for tests very difficult and the whole testing process becomes clunky.
In my opinion, if your app is not very big, you should use implicits.
If you want to learn more on this topic, check this great guide.
You should define the fields as parameters of you case class.
final case class AppConfig(host: String, port: Int)
Then you overload the apply method of your companion object
object AppConfig {
def apply(config: Config): AppConfig = {
val host = config.getString("projectname.application.host")
val port = config.getInt("projectname.application.port")
AppConfig(host, port)
}
}
However the simplest way to process configuration with case classes is to use pureconfig.
I want to use this config variable across application, rather than loading application.conf file everytime.
Just put it in an object, like
object MyConfig {
lazy val config = AppConfig(ConfigFactory.load("application.conf"))
}
I want to have one bootstrap function which will parse this config one time, making it available across application
As soon as you call MyConfig.config it is loaded just once - as object is a Singleton. So no special bootstrap is needed.
The pattern you're trying to achieve is called Dependency Injection. From Martin Fowler's post on this topic
The basic idea of the Dependency Injection is to have a separate object, an assembler, that populates a field in the lister class with an appropriate implementation for the finder interface.
Register this configuration instance in a Dependency Injection tool like Guice.
class AppModule(conf: AppConfiguration) extends AbstractModule {
override def configure(): Unit = {
bind(classOf[AppConfiguration]).toInstance(conf)
}
}
....
// somewhere in the code
import com.google.inject.Inject
class FooClass #Inject() (config: AppConfiguration)
I am trying to create a custom UDT in phantom.
case class CreationTrack(source_ip: String, created_by: String, created_at: UUID)
abstract class Registrations extends CassandraTable[Registrations, CreationTrack] with RootConnector {
object creation_details extends JsonColumn[CreationTrack](this){
override def fromJson(obj: String): CreationTrack = {
JsonParser.parse(obj).extract[CreationTrack]
}
override def toJson(obj: CreationTrack): String = {
compactRender(Extraction.decompose(obj))
}
}
}
Input given:
CreationTrack("192.123.4.5","arun", UUIDs.timeBased())
But i am getting,
Invalid STRING constant{"source_ip":"192.123.4.5","created_by":"arun","created_at":{}}
I believe there is an issue with UUID type casting on json conversion. But i got stucked here. Any help?
Thanks in advance!
PS: I know there is an option called #UDT is available in phantom-pro to resolve this issue. But i dont want to use the pro version here.
This is a solved problem and there is a module available in phantom-pro specifically to address UDT/UDA/UDF support. Details on the website and GitHub documentation, just wanted this question answered in case future Googlers are looking for an answer.
I am facing following task of providing implementation of the trait as a configuration option.
I have following class hierarchy :
trait Storage {
def store()
}
object LocalStorage extends Storage {
def store(){ ... }
}
object RemoteStorage extends Storage {
def store(){ ... }
}
Having a configuration in property file:
storage.class = "com.xxx.LocalStorage"
Having an implementation on the persistence layer:
class CheckPersister{
val storageType = ConfigFactory.load().getString("storage.class")
val storage: Storage = Class.forName(storageType).asInstanceOf[Storage]
...
}
Is there a better way of dealing with this kind of configuration? I am using Typesafe configuration.
Thx
Directly specifying the name of the class in the config file looks like a bad idea. Would something like this be acceptable instead?
storage.location = "local"
class CheckPersister {
val storageType = ConfigFactory.load().getString("storage.class")
val storage: Storage = storageType match {
case "local" => LocalStorage
case "remote" => RemoteStorage
case x => throw new RuntimeException(s"Invalid storage type $x specified")
}
...
}
In this way you can't accidentally instantiate a class you didn't intend.
I'm new to Scala (and functional programming as well) and I'm developing a plugin based application to learn and study.
I've cretead a trait to be the interface of a plugin. So when my app starts, it will load all the classes that implement this trait.
trait Plugin {
def init(config: Properties)
def execute(parameters: Map[String, Array[String]])
}
In my learning of Scala, I've read that if I want to program in functional way, I should avoid using var. Here's my problem:
The init method will be called after the class being loaded. And probably I will want to use the values from the config parameter in the execute method.
How to store this without using a var? Is there a better practice to do what I want here?
Thanks
There is more to programming in a functional way than just avoiding vars. One key concept is also to prefer immutable objects. In that respect your Plugin API is already breaking functional principles as both methods are only executed for their side-effects. With such an API using vars inside the implementation does not make a difference.
For an immutable plugin instance you could split plugin creation:
trait PluginFactory {
def createPlugin (config: Properties): Plugin
}
trait Plugin {
def execute ...
}
Example:
class MyPluginFactory extends MyPlugin {
def createPlugin (config: Properties): Plugin = {
val someValue = ... // extract from config
new MyPlugin(someValue)
}
}
class MyPlugin (someValue: String) extends Plugin {
def execute ... // using someConfig
}
You can use a val! It's basically the same thing, but the value of a val field cannot be modified later on. If you were using a class, you could write:
For example:
class Plugin(val config: Properties) {
def init {
// do init stuff...
}
def execute = // ...
}
Unfortunately, a trait cannot have class parameters. If you want to have a config field in your trait, you wont be able to set its value immediately, so it will have to be a var.