How to provide an HttpClient to ktor server from the outside to facilitate mocking external services? - kotlin

I am trying to provide an HttpClient from the outside to my ktor server so that I can mock external services and write tests, however I get this exception when I run my test:
Please make sure that you use unique name for the plugin and don't install it twice. Conflicting application plugin is already installed with the same key as `Compression`
io.ktor.server.application.DuplicatePluginException: Please make sure that you use unique name for the plugin and don't install it twice. Conflicting application plugin is already installed with the same key as `Compression`
at app//io.ktor.server.application.ApplicationPluginKt.install(ApplicationPlugin.kt:112)
at app//com.example.plugins.HTTPKt.configureHTTP(HTTP.kt:13)
at app//com.example.ApplicationKt.module(Application.kt:14)
at app//com.example.ApplicationTest$expected to work$1$1.invoke(ApplicationTest.kt:39)
at app//com.example.ApplicationTest$expected to work$1$1.invoke(ApplicationTest.kt:38)
and thats a bit unexpected to me because I am not applying the Compression plugin twice as far as I can tell. If I run the server normally and manually call my endpoint with curl then it works as expected. What am I doing wrong?
I added a runnable sample project here with a failing test.
sample project
official ktor-documentation-sample project.

The problem is that you have the application.conf file and by default, the testApplication function tries to load modules which are enumerated there. Since you also explicitly load them in the application {} block the DuplicatePluginException occurs. To solve your problem you can explicitly load an empty configuration instead of the default one:
// ...
application {
module(client)
}
environment {
config = MapApplicationConfig()
}
// ...

Related

Network calls not working in EXE distribution build of Compose for Desktop Application

I have used Ktor JVM Client for doing network calls in Compose for Desktop Application.
Network calls are working fine in Debug build means when I am just running the application it's working fine.
But when I create the EXE distribution file, by executing the packageExe task in Gradle, it's creating an EXE file. I have installed it on my machine. Then I am running the application and I am seeing that network calls are not working. I have checked internet is working properly.
Please provide a solution to fix this issue. Thanks in advance.
Your question doesn't leave any details about the failure type (compile error? runtime exception? Empty data? etc.).
But if I had to speculate based on such limited information, I'd guess it's probably this: https://github.com/JetBrains/compose-jb/issues/429
Specifically, when packaging, you need to specify which JVM modules you want to be packed into your distributable app, and likely you are missing your crypto module. Try something like this:
compose.desktop {
application {
mainClass = "MainKt"
nativeDistributions {
modules("jdk.crypto.ec")
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "untitled"
}
}
}

IntelliJ run vs running a jar, with a Springboot Kotlin, Multi module Gradle project with Social Oauth2

TL;DR: Why does everything run fine when started via IntelliJ, and why is it broken when call java -jar app.jar. And how do I fix this?
Alright, I have some issues with a backend I am trying to dockerize. I have an application created with Spring Boot (1.4.2.RELEASE) following the Spring Oauth (2.0.12.RELEASE) guide on their page. I follow the Gradle version, since I prefer Gradle over Maven. Also I am using Kotlin instead of Java. Everything is fine, I start via IntelliJ my backend with static front end, I can login via Facebook (and Google and Github), I receive a nice Principal witch holds al the information I need, and I can modify Spring Security to authorize and permit endpoints. So far so good.
Now for the bad part, when I run either ./gradlew clean build app:bootrun or ./gradlew clean build app:jar and run the jar via java -jar (like I will do in my Docker container), my backend comes up. My static front end pops up. Now I want to login via Facebook, I end up on the Facebook login page, I enter my credentials, and... nothing!
I end up back on my homepage, not logged in, no log messages that mean anything to me, just silence. The last thing I see in the log is:Getting user info from: https://graph.facebook.com/me
This Url will give me in my browser:
{
"error": {
"message": "An active access token must be used to query information about the current user.",
"type": "OAuthException",
"code": 2500,
"fbtrace_id": "GV/58H5f4fJ"
}
}
When going to this URL via an IntelliJ start, it will give me credential details. Obviously something is going wrong, but I have no clue what. Especially since a run from IntelliJ works fine. There is some difference between how the jar is started, and how IntelliJ's run config works, but I have no clue where to search for what. I could post trace logging, or all my Gradle files, but perhaps thats too much info to put in 1 question. I will defenitly update this question if someone needs some more details :)
The structure outline of this project is as follows:
root:
- api: is going to be opensourced later, contains rest definitions and DTOs.
- core: contains the meat. Also here is included in the gradle file
spring-boot-starter, -web, -security, spring-security-oauth2, and some jackson stuff.
- rest: contains versioned rest service implementations.
- app: contains angular webjars amongst others, the front end, and
my `#SpringBootApplication`, `#EnableOAuth2Client`
and the impl of `WebSecurityConfigurerAdapter`.
Why does everything run fine when started via IntelliJ, and why is it broken using bootRun or the jar artefact. And how do I fix this?
I found it, the problem was not Multi module Graldle, Spring boot, or Oauth2 related. In fact it was due to a src set config of Gradle, where Java was supposed to be in a Java src set folder, and Kotlin in a Java src set folder:
sourceSets {
main.java.srcDirs += 'src/main/java'
main.kotlin.srcDirs += 'src/main/kotlin'
}
As Will Humphreys stated in his comment above, IntelliJ takes all source sets, and runs the app. However, when building the jar via Gradle, these source sets are stricter. I had a Java file in my Kotlin src set, which is no problem for IntelliJ. But the jar created by Gradle takes into account the source sets as defined in the build.gralde file, which are stricter.
I found my missing bean issue with the code below:
#Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
};
}
The Bean I missed was called AuthenticationController, which is a #RestController, and kinda crucial for my authentication code.

Ember.js testing component with service dependency

I'm trying to write tests for my addon, but encountering some weird behaviour.
I have created a service (via ember-cli generate), which is used inside a component.
When an actual application is running everything is working fine.
However, when testing the component I get an error saying that the service is undefined when trying to access any of its properties/methods.
In the test i've put the service in "needs" like so:
needs: ['service:my-service']
"Needing" other components (e.g. child ones used inside) works as expected, services strangely fail.
Are there any additional steps that need to be done?
Running ember-cli 0.1.12.
When you generate a service, it also generates an initializer whose job it is to inject the service into the various places that you need it.
So, when you run acceptance tests your app will have booted and initializers will have been run, therefore the services will be available.
However, when unit testing components you get a clean container (better for testing). You just need to inject what you need:
moduleForComponent('foo-bar', null, {
setup: function(container) {
container.register('service:foo', FooService);
container.injection('component', 'fooService', 'service:foo');
}
});
I managed to get this working by using the new Ember.inject API available in the latest (as of writing) 1.10 release.
Apparently the new inject API is intended to replace needs in the future, it also works great with unit tests.
We just managed to get one working using needs: ['service:myService'] instead of needs: ['service:my-service'].

Yii CAssetManager.basePath is invalid on PHPUnit test

i have a problem to run test. My model use extension Yii mail and then i run test its fail with wrong assert path. Another test runs finaly (model dont use any extensions). Preloading is only log.
I had a similar error and I explicitly set the basePath in config/test.php.
'components'=>array(
...
'assetManager'=>array(
'basePath'=>dirname(__FILE__).'/../../assets',
)
)
Im solved problem
public function setUp(){
Yii::app()->assetManager->basePath = '../../asserts';
}
Im dont know why this error throw only in one model...
PhpUnit runs primary in CLI mode and therefore some of environmental variables are missing. Yii's AssetManager uses one of such variable to determine webroot and since the variable does not exist, it will either throw error or set up invalid assets path on first attempt.
In my opinion, this issue is (indirectly) caused by PHPUnit because it only supports CLI testing mode, which makes some things really more difficult to test than it would be in HTTP request mode. Some guys therefore wrote tools to run unit tests via standard web GUI with whole native HTTP environment (e.g. https://github.com/NSinopoli/VisualPHPUnit). Eventually, you may use HTTP clients like Selenium to run your tests as if clicking over the page (see http://phpunit.de/manual/3.7/en/selenium.html).
Nevertheless, it's a matter of subjective opinion - somebody may argue, that testing in CLI mode has advantages, some guys will hate it. But the fact is, that one has to bear in mind differences between HTTP and CLI mode.

Using Attach API Outside Of JDK

I have a small application that uses the Attach API to modify some third party classes during runtime. Alas, I have run into a large problem: the Attach API only comes with the JDK. The necessary files I can copy from the JDK and add into my project, but the library responsible for this(attach.(dll|so)) I can't. This is because I would have to copy attach.lib from a resource inside jar, and put it in the JRE/lib directory.
An action that would not work if the user isn't root on a Linux machine, therefore losing compatibility to alot of users (as this app is supposed to run on a server, and most servers are Linux, and I can't be sure all are root)
I looked into all the classes responsible for the attach API (VirtualMachine, AttachProvider etc) but found no place where it is loading the library.
Is it possible to do this? I mean, can I use the Attach API outside of a JDK installation? If so, how?
You can do so by modifying java.library.path:
static void addToLibPath(String path) throws NoSuchFieldException,
SecurityException,
IllegalArgumentException,
IllegalAccessException
{
if (System.getProperty("java.library.path") != null) {
// If java.library.path is not empty, we will prepend our path
// Note that path.separator is ; on Windows and : on Unix-like,
// so we can't hard code it.
System.setProperty("java.library.path",
path + System.getProperty("path.separator")
+ System.getProperty("java.library.path"));
} else {
System.setProperty("java.library.path", path);
}
// Important: java.library.path is cached
// We will be using reflection to clear the cache
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);
}
Call addToLibPath("path") will add "path" to java.library.path.
Please note that java.library.path is cached, and reflection is required to clear the cache.
As far as I know, you need to run the application looking to do the "attach" from within a JDK (not a JRE). By doing this, you don't need to worry about providing the Attach API or its dependencies - as they are all provided for and managed by the JDK. That said, you shouldn't have any "root" concerns with doing this - as you can extract and run/use a JDK as any user (it doesn't have to be installed / executed as "root"). That said, you'll just need to ensure that your program doing the attaching and the program being attached to are running as the same OS user as to not run into security restrictions.
Our experience is that there is no reliable way to use the attach API without a full JDK. This was particularly acute on Windows. You might get it to work, but you might want to look into plain old JMX instead.