-
Notifications
You must be signed in to change notification settings - Fork 40.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Auto-configure the Postgres application_name when using Docker Compose #42460
base: main
Are you sure you want to change the base?
Conversation
2ac675e
to
381e85a
Compare
Should I also configure ApplicationName in |
Auto-configure for r2dbc as well. |
0bf5cc3
to
6d627e5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR @nosan. I feel that the testing bits of it are too involved and we should rather attempt to test the logic in simpler tests, if possible. Let us know if you have time to explore that route.
@@ -57,6 +57,38 @@ void runWithBitnamiImageCreatesConnectionDetails(JdbcConnectionDetails connectio | |||
assertConnectionDetails(connectionDetails); | |||
} | |||
|
|||
@DockerComposeTest(composeFile = "postgres-compose-application-name-label.yaml", image = TestImage.POSTGRESQL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those tests shouldn't need to be full integration tests. The only thing that we assert here is that the ConnectionDetails
auto-configured bean has the correct state. I can see that we don't have such tests so far but I wonder if it wouldn't be useful to put something in place so that we don't need all the docker machinery.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1. For this to warrant being a Docker-based test, I think it should somehow check that setting the application_name
has had the desired effect on the Postgres side of things.
I'd then prefer that we only have a single Docker-based test that checks this and that the precedence of the different sources of the application name is unit tested without involving Docker. Right now we're adding a lot to the build time and I don't think the extra test coverage warrants that increase.
@@ -60,6 +61,35 @@ void runWithBitnamiImageCreatesConnectionDetails(R2dbcConnectionDetails connecti | |||
assertConnectionDetails(connectionDetails); | |||
} | |||
|
|||
@DockerComposeTest(composeFile = "postgres-compose-application-name-label.yaml", image = TestImage.POSTGRESQL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto. I can see this also changes the test infrastructure quite a bit and I wonder if that's warranted for this change.
return appendApplicationName(parameters); | ||
} | ||
|
||
private String appendApplicationName(String parameters) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is quite involved. I wonder if there wouldn't be a way to simplify this. And if not, perhaps getParameters
may need to evolve so that such a handling of the raw string is unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will take a look at how it could be done better and easy to read. I have the same feeling that it looks quite messy.
@@ -57,6 +57,38 @@ void runWithBitnamiImageCreatesConnectionDetails(JdbcConnectionDetails connectio | |||
assertConnectionDetails(connectionDetails); | |||
} | |||
|
|||
@DockerComposeTest(composeFile = "postgres-compose-application-name-label.yaml", image = TestImage.POSTGRESQL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1. For this to warrant being a Docker-based test, I think it should somehow check that setting the application_name
has had the desired effect on the Postgres side of things.
I'd then prefer that we only have a single Docker-based test that checks this and that the precedence of the different sources of the application name is unit tested without involving Docker. Right now we're adding a lot to the build time and I don't think the extra test coverage warrants that increase.
Thank you for your feedback @snicoll and @wilkinsona
@DockerComposeTest(composeFile = "postgres-compose.yaml", image = TestImage.POSTGRESQL,
properties = "spring.application.name=my-app")
void runCreatesConnectionDetailsWithAutoConfiguredApplicationName(JdbcConnectionDetails connectionDetails)
throws ClassNotFoundException {
assertThat(connectionDetails.getUsername()).isEqualTo("myuser");
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:postgresql://").endsWith("?ApplicationName=my-app");
assertThat(getApplicationName(connectionDetails)).isEqualTo("my-app");
}
private String getApplicationName(JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {
JdbcTemplate template = getJdbcTemplate(connectionDetails);
return template.queryForObject("select current_setting('application_name')", String.class);
} and @DockerComposeTest(composeFile = "postgres-compose.yaml", image = TestImage.POSTGRESQL,
properties = "spring.application.name=my-app")
void runCreatesConnectionDetailsWithAutoConfiguredApplicationName(R2dbcConnectionDetails connectionDetails) {
assertConnectionDetails(connectionDetails);
assertThat(getApplicationName(connectionDetails)).isEqualTo("my-app");
}
private String getApplicationName(R2dbcConnectionDetails connectionDetails) {
ConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();
return DatabaseClient.create(ConnectionFactories.get(connectionFactoryOptions))
.sql("select current_setting('application_name')")
.map((row, metadata) -> row.get(0))
.first()
.map(Objects::toString)
.block(Duration.ofSeconds(30));
} Does it make sense? |
Also, should I revert my |
35a5ae3
to
54ee498
Compare
PR has been updated.
|
2e0e3a5
to
3a5a70a
Compare
* | ||
* @author Dmytro Nosan | ||
*/ | ||
class PostgresJdbcUrl { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We discussed this today and it feels a bit overly complicated to us. We think the same could be achieved with something similar to the code that disables encryption for SQL Server. One addition that's probably needed here is to encode the application name as its user-provided input and may contain characters that are restricted in a query string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wilkinsona
I initially used this variant
private static String getJdbcUrl(RunningService service, String database, Environment environment) {
String jdbcUrl = jdbcUrlBuilder.build(service, database);
return appendApplicationName(jdbcUrl, environment);
}
private static String appendApplicationName(String jdbcUrl, Environment environment) {
if (hasParameter(jdbcUrl, "ApplicationName")) {
return jdbcUrl;
}
String applicationName = environment.getProperty("spring.application.name");
if (!StringUtils.hasText(applicationName)) {
return jdbcUrl;
}
return appendParameter(jdbcUrl, "ApplicationName", applicationName);
}
private static String appendParameter(String jdbcUrl, String name, String value) {
StringBuilder jdbcUrlBuilder = new StringBuilder(jdbcUrl);
if (!jdbcUrl.contains("?")) {
jdbcUrlBuilder.append('?');
}
else if (!jdbcUrl.endsWith("&")) {
jdbcUrlBuilder.append('&');
}
return jdbcUrlBuilder.append(name)
.append('=')
.append(URLEncoder.encode(value, StandardCharsets.UTF_8))
.toString();
}
private static boolean hasParameter(String jdbcUrl, String parameterName) {
return jdbcUrl.contains("?%s=".formatted(parameterName))
|| jdbcUrl.contains("&%s=".formatted(parameterName));
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
73c945b
to
9ad5cd0
Compare
gh-40772
I added
since 3.4.0
everywhere but maybe it could be merged earlier if everything is ok.Thanks in advance