Skip to content

Commit

Permalink
Pr #224 - somehow I broke it (#271)
Browse files Browse the repository at this point in the history
* Add MariaDB service detection and replace MySQL JDBC prefix
Update MySqlJdbcUrlCreator to add MariaDB schemes, tags and labels
Update MySqlJdbcUrlCreator to override createJdbcUrl from AbstractJdbcUrlCreator
Update MySqlJdbcUrlCreator to add detection of MariaDB service based on CF environment tags, labels and MariaDB uri
Conditionally update the JDBC URL that was either generated or obtained from the CF Service if the current driver class name matches the MariaDB driver and any of the specific MariaDB detection cases
Overload existsByLabelStartsWith method in CfService to allow checking if one of many labels matches the CF service label

* Add test cases for MariaDB database CF Service

* Fix Formatting

* Include mariadb services with label that includes
* not just starts with

---------

Co-authored-by: David Duarte <[email protected]>
  • Loading branch information
anthonydahanne and daviddmd authored Aug 12, 2024
1 parent 424a59d commit 7673f2f
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,48 +23,72 @@
* @author Mark Pollack
*/
public class MySqlJdbcUrlCreator extends AbstractJdbcUrlCreator {

public static final String MYSQL_SCHEME = "mysql";

public static final String MARIADB_SCHEME = "mariadb";
public static final String[] MYSQL_SCHEMES = new String[]{MYSQL_SCHEME, MARIADB_SCHEME};
public static final String MYSQL_TAG = "mysql";

public static final String MARIADB_TAG = "mariadb";
public static final String[] MYSQL_TAGS = new String[]{MYSQL_TAG, MARIADB_TAG};
public static final String MYSQL_LABEL = "mysql";
public static final String MARIADB_LABEL = "mariadb";
public static final String[] MYSQL_LABELS = new String[]{MYSQL_LABEL, MARIADB_LABEL};
public static final String MYSQL_DRIVER_CLASS_NAME = "com.mysql.cj.jdbc.Driver";
public static final String MARIADB_DRIVER_CLASS_NAME = "org.mariadb.jdbc.Driver";

@Override
public boolean isDatabaseService(CfService cfService) {
if (jdbcUrlMatchesScheme(cfService, MYSQL_SCHEME)
|| cfService.existsByTagIgnoreCase(MYSQL_TAG)
|| cfService.existsByLabelStartsWith(MYSQL_LABEL)
|| cfService.existsByUriSchemeStartsWith(MYSQL_SCHEME)
|| cfService.existsByCredentialsContainsUriField(MYSQL_SCHEME)) {
return true;
}
return false;
return jdbcUrlMatchesScheme(cfService, MYSQL_SCHEMES)
|| cfService.existsByTagIgnoreCase(MYSQL_TAGS)
|| cfService.existsByLabelStartsWith(MYSQL_LABELS)
|| cfService.existsByUriSchemeStartsWith(MYSQL_SCHEMES)
|| cfService.existsByCredentialsContainsUriField(MYSQL_SCHEMES);
}

private boolean isMariaDbService(CfService cfService) {
return jdbcUrlMatchesScheme(cfService, MARIADB_SCHEME)
|| cfService.existsByTagIgnoreCase(MARIADB_TAG)
|| cfService.existsByLabelContains(MARIADB_LABEL)
|| cfService.existsByUriSchemeStartsWith(MARIADB_SCHEME)
|| cfService.existsByCredentialsContainsUriField(MARIADB_SCHEME);
}

@Override
public String getDriverClassName() {
String driverClassNameToUse = null;
String driverClassNameToUse;
try {
driverClassNameToUse = "org.mariadb.jdbc.Driver";
driverClassNameToUse = MARIADB_DRIVER_CLASS_NAME;
Class.forName(driverClassNameToUse, false, getClass().getClassLoader());
} catch (ClassNotFoundException e) {
}
catch (ClassNotFoundException e) {
try {
driverClassNameToUse = "com.mysql.cj.jdbc.Driver";
driverClassNameToUse = MYSQL_DRIVER_CLASS_NAME;
Class.forName(driverClassNameToUse, false, getClass().getClassLoader());
} catch (ClassNotFoundException e2) {
}
catch (ClassNotFoundException e2) {
return null;
}
}
return driverClassNameToUse;
}

@Override
public String createJdbcUrl(CfService cfService) {
CfCredentials cfCredentials = cfService.getCredentials();
String jdbcUrl = (String) cfCredentials.getMap().get("jdbcUrl");
if (jdbcUrl == null) {
jdbcUrl = buildJdbcUrlFromUriField(cfCredentials);
}
if (isMariaDbService(cfService) && getDriverClassName().equals(MARIADB_DRIVER_CLASS_NAME)) {
jdbcUrl = jdbcUrl.replaceFirst("^(jdbc:mysql)", "jdbc:mariadb");
}
return jdbcUrl;
}

@Override
public String buildJdbcUrlFromUriField(CfCredentials cfCredentials) {
UriInfo uriInfo = cfCredentials.getUriInfo(MYSQL_SCHEME);
return String.format("%s%s://%s%s/%s%s%s", JDBC_PREFIX, MYSQL_SCHEME,
uriInfo.getHost(), uriInfo.formatPort(), uriInfo.getPath(),
uriInfo.formatUserNameAndPasswordQuery(), uriInfo.formatQuery());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void mysqlServiceCreation() {
assertThat(cfJdbcService.getUsername()).isEqualTo(username);
assertThat(cfJdbcService.getPassword()).isEqualTo(password);
assertThat(cfJdbcService.getDriverClassName())
.isEqualTo("org.mariadb.jdbc.Driver");
.isEqualTo(MySqlJdbcUrlCreator.MARIADB_DRIVER_CLASS_NAME);

assertThatThrownBy(() -> {
cfJdbcEnv.findJdbcServiceByName("mysql.*");
Expand Down Expand Up @@ -160,7 +160,7 @@ public void mysqlServiceCreationWithJdbcUrlOnly() {
assertThat(cfJdbcService.getUsername()).isNull();
assertThat(cfJdbcService.getPassword()).isNull();
assertThat(cfJdbcService.getDriverClassName())
.isEqualTo("org.mariadb.jdbc.Driver");
.isEqualTo(MySqlJdbcUrlCreator.MARIADB_DRIVER_CLASS_NAME);
}

@Test
Expand All @@ -178,6 +178,91 @@ public void mysqlServiceCreationWithJdbcUrlOnlyWithSpecialChars() {
passwordWithSpecialChars)).isEqualTo(jdbcUrlMysql);
}


@Test
public void mariaDbServiceCreation() {
String name1 = "database-1";
String name2 = "database-2";

mockVcapServices(getServicesPayload(
getMariaDbServicePayload("mariadb-1", hostname, port, username, password,
name1),
getMariaDbServicePayload("mariadb-2", hostname, port, username, password,
name2)));

assertJdbcServiceValuesMariaDb(name1, name2);

CfJdbcEnv cfJdbcEnv = new CfJdbcEnv();
CfJdbcService cfJdbcService = cfJdbcEnv.findJdbcServiceByName("mariadb-1");
assertThat(cfJdbcService.getUsername()).isEqualTo(username);
assertThat(cfJdbcService.getPassword()).isEqualTo(password);
assertThat(cfJdbcService.getDriverClassName())
.isEqualTo(MySqlJdbcUrlCreator.MARIADB_DRIVER_CLASS_NAME);
}
@Test
public void mariaDbServiceCreationWithJdbcUrl() {
String name1 = "database-1";
String name2 = "database-2";
mockVcapServices(getServicesPayload(
getMariaDbServicePayloadWithJdbcUrl("mariadb-1", hostname, port, username,
password, name1),
getMariaDbServicePayloadWithJdbcUrl("mariadb-2", hostname, port, username,
password, name2)));

assertJdbcServiceValuesMariaDb(name1, name2);
}

@Test
public void mariaDbServiceCreationWithLabelNoTags() {
String name1 = "database-1";
String name2 = "database-2";
mockVcapServices(getServicesPayload(
getMariaDbServicePayloadWithLabelNoTags("mariadb-1", hostname, port, username,
password, name1),
getMariaDbServicePayloadWithLabelNoTags("mariadb-2", hostname, port, username,
password, name2)));
assertJdbcServiceValuesMariaDb(name1, name2);

}

@Test
public void mariaDbServiceCreationWithUriOnly() {
String name1 = "database-1";
String name2 = "database-2";
mockVcapServices(getServicesPayload(
getMariaDbServicePayloadUri("mariadb-1", hostname, port, username,
password, name1),
getMariaDbServicePayloadUri("mariadb-2", hostname, port, username,
password, name2)));

assertJdbcServiceValuesMariaDb(name1, name2);

CfJdbcEnv cfJdbcEnv = new CfJdbcEnv();
CfJdbcService cfJdbcService = cfJdbcEnv.findJdbcServiceByName("mariadb-1");
assertThat(cfJdbcService.getDriverClassName())
.isEqualTo(MySqlJdbcUrlCreator.MARIADB_DRIVER_CLASS_NAME);
}

@Test
public void mariaDbServiceCreationWithJdbcUrlOnly() {
String name1 = "database-1";
String name2 = "database-2";
mockVcapServices(getServicesPayload(
getMariaDbServicePayloadWithJdbcUrlOnly("mariadb-1", hostname, port, username,
password, name1),
getMariaDbServicePayloadWithJdbcUrlOnly("mariadb-2", hostname, port, username,
password, name2)));

assertJdbcServiceValuesMariaDb(name1, name2);

CfJdbcEnv cfJdbcEnv = new CfJdbcEnv();
CfJdbcService cfJdbcService = cfJdbcEnv.findJdbcServiceByName("mariadb-1");
assertThat(cfJdbcService.getUsername()).isNull();
assertThat(cfJdbcService.getPassword()).isNull();
assertThat(cfJdbcService.getDriverClassName())
.isEqualTo(MySqlJdbcUrlCreator.MARIADB_DRIVER_CLASS_NAME);
}

// Utility methods

private void assertJdbcServiceValues(String name1, String name2) {
Expand Down Expand Up @@ -209,7 +294,40 @@ private void assertJdbcServiceValues(String name1, String name2) {

CfJdbcService cfJdbcService = cfJdbcEnv.findJdbcServiceByName("mysql-1");
assertThat(cfJdbcService.getDriverClassName())
.isEqualTo("org.mariadb.jdbc.Driver");
.isEqualTo(MySqlJdbcUrlCreator.MARIADB_DRIVER_CLASS_NAME);

}

private void assertJdbcServiceValuesMariaDb(String name1, String name2) {
CfJdbcEnv cfJdbcEnv = new CfJdbcEnv();
String jdbcUrlMysql1 = cfJdbcEnv.findJdbcServiceByName("mariadb-1").getJdbcUrl();
String jdbcUrlMysql2 = cfJdbcEnv.findJdbcServiceByName("mariadb-2").getJdbcUrl();

assertThat(getExpectedJdbcUrl(MySqlJdbcUrlCreator.MARIADB_SCHEME, name1))
.isEqualTo(jdbcUrlMysql1);
assertThat(getExpectedJdbcUrl(MySqlJdbcUrlCreator.MARIADB_SCHEME, name2))
.isEqualTo(jdbcUrlMysql2);

CfJdbcService cfJdbcService1 = cfJdbcEnv.findJdbcServiceByName("mariadb-1");
CfJdbcService cfJdbcService2 = cfJdbcEnv.findJdbcServiceByName("mariadb-2");
jdbcUrlMysql1 = cfJdbcService1.getJdbcUrl();
jdbcUrlMysql2 = cfJdbcService2.getJdbcUrl();
assertThat(getExpectedJdbcUrl(MySqlJdbcUrlCreator.MARIADB_SCHEME, name1))
.isEqualTo(jdbcUrlMysql1);
assertThat(getExpectedJdbcUrl(MySqlJdbcUrlCreator.MARIADB_SCHEME, name2))
.isEqualTo(jdbcUrlMysql2);

List<CfJdbcService> cfJdbcServices = cfJdbcEnv.findJdbcServices();
assertThat(cfJdbcServices.size()).isEqualTo(2);

assertThatThrownBy(() -> {
cfJdbcEnv.findJdbcService().getJdbcUrl();
}).isInstanceOf(IllegalArgumentException.class).hasMessage(
"No unique database service found. Found database service names [mariadb-1, mariadb-2]");

CfJdbcService cfJdbcService = cfJdbcEnv.findJdbcServiceByName("mariadb-1");
assertThat(cfJdbcService.getDriverClassName())
.isEqualTo(MySqlJdbcUrlCreator.MARIADB_DRIVER_CLASS_NAME);

}

Expand Down Expand Up @@ -255,6 +373,32 @@ private String getMysqlServicePayloadWithJdbcUrlOnly(String serviceName,
hostname, port, user, password, name);
}

private String getMariaDbServicePayloadWithJdbcUrl(String serviceName, String hostname, int port, String user, String password, String name) {
//Test by MariaDB JDBC url with DB uri
return getTemplatedPayload("test-mariadb-info-jdbc-url.json", serviceName, hostname, port, user, password, name);
}

private String getMariaDbServicePayloadWithLabelNoTags(String serviceName, String hostname, int port, String user, String password, String name) {
//Test by presence of mariadb string in beginning of service label
return getTemplatedPayload("test-mariadb-info-with-label-no-tags.json", serviceName, hostname, port, user, password, name);
}

private String getMariaDbServicePayload(String serviceName, String hostname, int port, String user, String password, String name) {
//Test by MariaDB tag (alongside mysql)
return getTemplatedPayload("test-mariadb-info.json", serviceName, hostname, port, user, password, name);
}

private String getMariaDbServicePayloadUri(String serviceName, String hostname, int port, String user, String password, String name) {
//Test by MariaDB uri
return getTemplatedPayload("test-mariadb-info-uri.json", serviceName, hostname, port, user, password, name);
}

private String getMariaDbServicePayloadWithJdbcUrlOnly(String serviceName, String hostname, int port, String user, String password, String name) {
//Test by MariaDB jdbc url
return getTemplatedPayload("test-mariadb-info-jdbc-url-only.json", serviceName,
hostname, port, user, password, name);
}

@Override
protected String getExpectedJdbcUrl(String databaseType, String name) {
return "jdbc:" + databaseType + "://" + hostname + ":" + port + "/" + name
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "$serviceName",
"credentials": {
"jdbcUrl": "jdbc:mariadb://$hostname:$port/$name?user=$user&password=$password"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "$serviceName",
"credentials": {
"jdbcUrl": "jdbc:mariadb://$hostname:$port/$name?user=$user&password=$password",
"uri": "mariadb://$user:$password@$hostname:$port/$name"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "$serviceName",
"label": "cleardb",
"plan": "free",
"credentials": {
"uri": "mariadb://$user:$password@$hostname:$port/$name"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "$serviceName",
"label": "a9s-mariadb106",
"tags": [],
"plan": "free",
"credentials": {
"uri": "mysql://$user:$password@$hostname:$port/$name"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "$serviceName",
"label": "cleardb",
"tags": [
"mariadb",
"mysql"
],
"plan": "free",
"credentials": {
"uri": "mysql://$user:$password@$hostname:$port/$name"
}
}
28 changes: 28 additions & 0 deletions java-cfenv/src/main/java/io/pivotal/cfenv/core/CfService.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,32 @@ public boolean existsByLabelStartsWith(String label) {
return false;
}

/**
* @param label string to search for in the service label
* @return whether the label includes the provided string
*/
public boolean existsByLabelContains(String label) {
String cfLabel = this.getLabel();
if (cfLabel != null && cfLabel.length() > 0) {
return cfLabel.contains(label);
}
return false;
}

/**
* @param labels Strings to search for as a prefix in the service label
* @return whether any of the provided labels starts with the service label
*/
public boolean existsByLabelStartsWith(String... labels) {
String cfLabel = this.getLabel();
if (labels != null && cfLabel != null && !cfLabel.isEmpty()){
for (String labelToMatch : labels){
if (labelToMatch.startsWith(cfLabel)){
return true;
}
}
}
return false;
}

}

0 comments on commit 7673f2f

Please sign in to comment.