Connect my Oraclecontainer to an external database (not localhost) for integration tests Java/ Springboot - integration-testing

I want to change my integration tests (use oracle 19c database) by using testcontainers.
So installed docker in local and run the Docker Desktop.
after i used the image gvenzl/oracle-xe:18.4.0-slim and i run it locally.
After in my code (java & spring boot), i have the external database connexion declared in application-integrationTests.properties
app.datasource.url=jdbc:oracle:thin:#//IT-host:1529/DEV_APP
app.datasource.driverClassName=oracle.jdbc.OracleDriver
app.datasource.username=DEMO
app.datasource.password=DEMO
and in my ServerConfigIntegrationTest, i had this code before
public DataSource specificDatasource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
So, i modified this configuration by
#Testcontainers
public class ServerConfigIntegrationTest{
... code
#Container
private final OracleContainer oracleContainer = new OracleContainer("gvenzl/oracle-xe:18.4.0-slim")
.withReuse(true)
.withPassword("DEMO")
.withUsername("DEMO")
.withDatabaseName("DEV_APP")
.withLogConsumer(new Slf4jLogConsumer(LOGGER));
#Bean
#Primary
public DataSource specificDatasource() {
oracleContainer.start();
LOGGER.info("The JDBC URL of the container is: "+ oracleContainer.getJdbcUrl());
dataSource.setDriverClassName(oracleContainer.getDriverClassName());
dataSource.setUrl(oracleContainer.getJdbcUrl());
dataSource.setUsername(oracleContainer.getUsername());
dataSource.setPassword(oracleContainer.getPassword());
return dataSource;
}
when i'm logging the jdbcUrl, i have localhost as server and the bad port.
How can i do to connect my container to the database (with a specific host "IT-host") ? Can you help me ?

When you're using Testcontainers an ephemeral Docker container with the database is created and its lifecycle managed by your tests via Testcontainers.
When you specify this:
#Container
private final OracleContainer oracleContainer = new OracleContainer("gvenzl/oracle-xe:18.4.0-slim")
.withReuse(true)
.withPassword("DEMO")
.withUsername("DEMO")
.withDatabaseName("DEV_APP")
.withLogConsumer(new Slf4jLogConsumer(LOGGER));
Testcontainers JUnit integration will control the lifecycle of the Docker containers with the database. There are more details here you can configure it to create a new DB for every test or test class, etc. There are more options for manual control too.
The container will map the internal ports necessary for DB access to random high ports on your machine, which is why you see localhost & a high port in the jdbcUrl.
The proper way to make you Spring Boot application to use the database in that container is to use DynamicPropertySource: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/DynamicPropertySource.html
Which you'd do like this:
#DynamicPropertySource
static void redisProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", oracleContainer::getJdbcUrl);
registry.add("spring.datasource.username", oracleContainer::getUsername);
registry.add("spring.datasource.password", oracleContainer::getPassword);
}
DynamicPropertySource will configure your Spring Boot app to use the containerized DB for the tests.
You don't need the integration tests configuration or running an existing database at all in that setup.
You cannot use Testcontainers tests against an already existing instance of the database running.

Related

How to create a dotnet gRPC server without using concrete instances

So I am trying to build a .Net Core app that has both REST and gRPC.
Expected results: To have one app running that supports a working REST on one port and gRPC on another.
REST is easy. It's where the app starts. But to configure gRPC's port I saw I needed to create a Server instance:
Server server = new Server
{
Services = { Greeter.BindService(new GreeterImpl()) }
Ports = { new ServerPort("0.0.0.0", 5001, ServerCredentials.Insecure) }
};
server.Start();
That's all fine until we actually put it to use and like any other "Controller" GreeterImpl needs Dependency Injection of services:
private readonly IExampleService _exampleService;
public GreeterImpl (IExampleService exampleService)
{
_exampleService = exampleService;
}
Now the first code snippet will not work since the "new GreeterImpl()" requires an IExampleService.
I searched the web on how to get a ServerServiceDefinition (the thing returned from Greeter.BindService() ) without the use of concrete implementations but found nothing. So, how should this be done or am I on a totally wrong path?
So, I was going at it with the wrong idea. Turns our you can use
app.ApplicationServices.GetService(typeof({YOUR_SERVICE}))
Where "app" is "IApplicationBuilder"
And then just use the resulting service in the ".BindService()".
In the end we don't change the ".BindService()" but pass it a working service to bind.
Important note: You have to register your service first. In my case I used AutoFac to register it

How to deploy and access a guest executable(ASP.NET OWIN self hosted webapi application) in local service fabric cluster

I have created an ASP.NET Owin self hosted webapi application. Below is owin self host code snippet
using Microsoft.Owin.Hosting;
namespace OwinSelfHostSample
{
class Program
{
public static void Main(string[] args)
{
string localhost = "http://localhost:80";
// Start OWIN host
using (WebApp.Start<LocalStartup>(localhost))
{
Console.ReadLine();
}
}
}
}
I can run Owin exe and reach out to my service endpoints like http://localhost:80/keepalive etc
When I try to deploy this as a guest executable to a local service fabric cluster following instructions at here, publish happens successfully but i am not able to hit the endpoint. I always gets 503 service unavailable http response. No related errors in event viewer as well.
My guess would be that your endpoint is not properly configured in service fabric.
Make sure your service is really started by debugging the local cluster
Check your endpoint configuration - did you publish the port in the application manifest?
https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-service-manifest-resources
Look at this documentation. It only mentions APIs in guest executables, but could help you nonetheless
https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-aspnetcore

What asp.net Core project for MicroService without endpoint

I am looking at taking the Docker plunge with a Microservices Framework. I have seen numerous examples of exposing an endpoint to be called by something to do something (get me the weather at a location, the exchange rate for currency, etc). I have not seen anything that talks about how to replace my current Windows Service type applications or applications that subscribe to queues to do their work.
For Example, lets say I have a windows service that every day at 2:00 AM zips all of the files in a given directory and puts them into a different directory (then publishes a message that it was completed).
Do I build a asp.net core "console app" and add a startup.cs? Do I need a startup.cs or just a startup method in my main?
Like I said, lots of demos of building a tiny web response but little about what else to do if I do not want/need and endpoint.
Startup.cs is quite ASP.NET Core specific, which by itself is a web stack and comes hosted with WebListener or Kestrel behind IIS.
In an console application you wouldn't use a traditional Startup.cs, though you could to have a consistent base, but it would look a bit differently though, because you are in control of creating the IoC container (rather than ASP.NET Core doing it for you in an web application). Normally the Startup.cs is processed by the WebHostBuilder in Program.cs, to allow it to inject it's own stuff before passing the IServiceCollection to the ConfigureServices method.
You're right that you need an console application and there you'd do all the stuff yourself.
public class Program
{
public IConfigurationRoot Configuration { get; private set; }
public IServiceProvider Provider { get; private set; }
public static void Main()
{
var programm = new Programm();
program.Run();
}
private void Run()
{
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
var services = new ServiceCollection();
ConfigureServices(services);
this.Provider = services.BuildServiceProvider();
var host = this.Provider.GetRequiredService<MyHost>();
// blocking operation, the host should be something that keeps the service running
// once it stops, the application stops too as there are no additional
host.Run();
}
private void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IMyService, MyService>();
services.AddSingleton<MyHost>();
...
}
}
What you want to use as host, is up to you. It could be i.e. an Azure Web Task/Host:
using(var jobHost = new JobHost(new JobHostConfiguration(Configuration.GetConnectionString("AzureWebJobsDashboard"))))
{
jobHost.RunAndBlock();
}
which would get started and keep the application running and receiving Azure messages and events registered within it. Or you use some of the other background tasks frameworks like Hangfire.
In ASP.NET Core all of this is handled by the framework, but ASP.NET Core is made for web stuff and hence, depends on an endpoint. Most of the stuff inside Configure method of Startup class used in ASP.NET Core application is about registering middlewares, which work on the HttpContext. You don't have these in a microservice w/o an endpoint. No endpoint, no HttpContext, no need for middlewares.
Of course you also don't have an IApplicationBuilder in an console application, just an IServiceProvider to resolve the services you registered earlier.

How to use angular2's http with other port than application host port?

I have a ASP.NET solution with both a web project that hosts my angular2 app and a web api project.
Both projects are setup as startup projects and are running on different ports (45365 for the web project and 20234 for the web api project).
Let´s say I have a web api controller that exposes /api/values which is currently accessible via http://localhost:20234/api/values
How can I access this in my angular2 web app? If I try
this.http.get("api/values")
it tries to access http://localhost:45365/api/values which is not desired. However, I want it to call http://localhost:20234/api/values without specifying the whole url including domain to make my service work even when the app is published to a public server with an other domain than localhost.
How do I tell http.get()to use 20234 as port number?
constructor(private location:Location, private locationStrategy:LocationStrategy) {}
someMethod() {
var base = this.locationStrategy.getBaseHref();
// replace port
this.location.prepareExternalUrl(base + 'xxx');
}
You can implement this in a service that forwards to Http so you don't need to repeat it.
(not tested)

Startup.cs is not firing

I am trying to test my MVC project. For the sake of simplicity, in the Startup class I have:
public static IConfiguration Configuration { get; set; }
public Startup(IHostingEnvironment env)
{
// Setup configuration sources.
var configuration = new Configuration()
.AddJsonFile("config.json");
Configuration = configuration;
}
And I am using this configuration globally, like this:
private static string connectionString = Startup.Configuration["Database:ConnectionString"];
It works, it can find this in the file.
My problem:
When I am running tests, the Startup class seems to not be firing. Because of that whenever I access Startup.Configuration, this field is null.
What can I do to fire it so that the config.json file is read? Or how else could I solve this issue?
The Startup method is typically called when you start up your web server whether it be on IIS Express, Web Listener, Kestrel etc. If you're trying to run tests you need to start a server or test server which will then invoke your Startup method.
Microsoft.AspNet.TestHost is a great utility to use to create test based servers. In particular the TestServer I'm speaking of lives here: https://github.com/aspnet/Hosting/blob/dev/src/Microsoft.AspNet.TestHost/TestServer.cs
Here's how we use it in MVC:
https://github.com/aspnet/Mvc/blob/dev/test/Microsoft.AspNet.Mvc.FunctionalTests/TestHelper.cs
and an actual test creating a server
https://github.com/aspnet/Mvc/blob/cc4ee1068de55a0948c35f5a87f6c05907cb8461/test/Microsoft.AspNet.Mvc.FunctionalTests/DefaultValuesTest.cs#L42
Hope this helps!

Resources