From 2e49b27d25c38cad24a22026bb0cbb5606c98315 Mon Sep 17 00:00:00 2001 From: Tanmay Vartak Date: Thu, 7 May 2026 19:17:49 +0000 Subject: [PATCH] feat: add TLS support to TCP proxy listener --- .../google/cloud/spanner/adapter/Adapter.java | 85 +++++++++- .../cloud/spanner/adapter/AdapterOptions.java | 25 +++ .../cloud/spanner/adapter/Launcher.java | 3 +- .../cloud/spanner/adapter/LauncherConfig.java | 38 ++++- .../adapter/configs/ConfigConstants.java | 2 + .../adapter/configs/GlobalClientConfigs.java | 153 ++++++++++++------ .../cloud/spanner/adapter/AdapterTest.java | 27 ++++ .../adapter/LauncherConfigParserTest.java | 12 +- .../cloud/spanner/adapter/LauncherTest.java | 6 +- 9 files changed, 292 insertions(+), 59 deletions(-) diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Adapter.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Adapter.java index a4b29dea..3ff912ea 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Adapter.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Adapter.java @@ -94,6 +94,11 @@ void start() { } try { + if (Strings.isNullOrEmpty(options.getProxyTLSCertPath()) + != Strings.isNullOrEmpty(options.getProxyTLSKeyPath())) { + throw new IllegalArgumentException( + "Both proxyTLSCertPath and proxyTLSKeyPath must be specified for TLS support"); + } Credentials credentials = options.getCredentials(); if (options.usePlainText() || !Strings.isNullOrEmpty(options.getExperimentalHostEndpoint())) { credentials = null; @@ -180,10 +185,21 @@ void start() { new AdapterClientWrapper(adapterClient, attachmentsCache, sessionManager); // Start listening on the specified host and port. - serverSocket = - new ServerSocket( - options.getTcpPort(), DEFAULT_CONNECTION_BACKLOG, options.getInetAddress()); - LOG.info("Local TCP server started on {}:{}", options.getInetAddress(), options.getTcpPort()); + if (options.useProxyTLS()) { + try { + serverSocket = createSSLServerSocket(); + LOG.info( + "Local TLS server started on {}:{}", options.getInetAddress(), options.getTcpPort()); + } catch (Exception e) { + throw new RuntimeException("Failed to create TLS server socket", e); + } + } else { + serverSocket = + new ServerSocket( + options.getTcpPort(), DEFAULT_CONNECTION_BACKLOG, options.getInetAddress()); + LOG.info( + "Local TCP server started on {}:{}", options.getInetAddress(), options.getTcpPort()); + } if (executor == null) { executor = Executors.newCachedThreadPool(); @@ -195,6 +211,8 @@ void start() { started = true; LOG.info("Adapter started for database '{}'.", options.getDatabaseUri()); + } catch (IllegalArgumentException e) { + throw e; } catch (IOException | RuntimeException e) { throw new AdapterStartException(e); } @@ -267,4 +285,63 @@ public AdapterStartException(Throwable cause) { super("Failed to start the adapter.", cause); } } + + private ServerSocket createSSLServerSocket() throws Exception { + javax.net.ssl.SSLContext sslContext = + createSSLContext(options.getProxyTLSCertPath(), options.getProxyTLSKeyPath()); + return sslContext + .getServerSocketFactory() + .createServerSocket( + options.getTcpPort(), DEFAULT_CONNECTION_BACKLOG, options.getInetAddress()); + } + + private javax.net.ssl.SSLContext createSSLContext(String certPath, String keyPath) + throws Exception { + // 1. Read the FULL certificate chain + java.security.cert.CertificateFactory cf = + java.security.cert.CertificateFactory.getInstance("X.509"); + java.util.Collection certs; + try (java.io.FileInputStream certIs = new java.io.FileInputStream(certPath)) { + // generateCertificates reads all certs in a bundled PEM file + certs = cf.generateCertificates(certIs); + } + java.security.cert.Certificate[] certChain = + certs.toArray(new java.security.cert.Certificate[0]); + + // 2. Parse the Private Key (Requires unencrypted PKCS#8 format) + String keyStr = + new String(java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(keyPath))) + .replace("-----BEGIN PRIVATE KEY-----", "") + .replace("-----END PRIVATE KEY-----", "") + .replaceAll("\\s", ""); + byte[] keyBytes = java.util.Base64.getDecoder().decode(keyStr); + java.security.spec.PKCS8EncodedKeySpec spec = + new java.security.spec.PKCS8EncodedKeySpec(keyBytes); + + // 3. Generate the key, falling back to EC if RSA fails + java.security.PrivateKey key; + try { + key = java.security.KeyFactory.getInstance("RSA").generatePrivate(spec); + } catch (java.security.spec.InvalidKeySpecException e) { + key = java.security.KeyFactory.getInstance("EC").generatePrivate(spec); + } + + // 4. Build the KeyStore + java.security.KeyStore ks = + java.security.KeyStore.getInstance(java.security.KeyStore.getDefaultType()); + ks.load(null, null); // Initialize empty keystore + ks.setKeyEntry("key", key, new char[0], certChain); + + // 5. Initialize the SSLContext + javax.net.ssl.KeyManagerFactory kmf = + javax.net.ssl.KeyManagerFactory.getInstance( + javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(ks, new char[0]); + + javax.net.ssl.SSLContext sslContext = javax.net.ssl.SSLContext.getInstance("TLS"); + // Passing null for TrustManagers uses the default Java trust store + sslContext.init(kmf.getKeyManagers(), null, null); + + return sslContext; + } } diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/AdapterOptions.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/AdapterOptions.java index 4a91308f..2c30ee1e 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/AdapterOptions.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/AdapterOptions.java @@ -45,6 +45,8 @@ static class Builder { private String experimentalHostEndpoint = null; private String clientCertPath = null; private String clientKeyPath = null; + private String proxyTLSCertPath = null; + private String proxyTLSKeyPath = null; /** The Cloud Spanner endpoint. */ Builder spannerEndpoint(String spannerEndpoint) { @@ -132,6 +134,13 @@ Builder useClientCert(String clientCertPath, String clientKeyPath) { return this; } + /** (Optional) Use TLS connection for the proxy listener. */ + Builder useProxyTLS(String proxyTLSCertPath, String proxyTLSKeyPath) { + this.proxyTLSCertPath = proxyTLSCertPath; + this.proxyTLSKeyPath = proxyTLSKeyPath; + return this; + } + private void validateHostConflict( String spannerEndpointToCheck, String experimentalHostEndpointToCheck) { if (!Strings.isNullOrEmpty(spannerEndpointToCheck) @@ -161,6 +170,8 @@ AdapterOptions build() { private String experimentalHostEndpoint; private String clientCertPath; private String clientKeyPath; + private String proxyTLSCertPath; + private String proxyTLSKeyPath; private AdapterOptions(Builder builder) { this.spannerEndpoint = builder.spannerEndpoint; @@ -177,6 +188,8 @@ private AdapterOptions(Builder builder) { this.experimentalHostEndpoint = builder.experimentalHostEndpoint; this.clientCertPath = builder.clientCertPath; this.clientKeyPath = builder.clientKeyPath; + this.proxyTLSCertPath = builder.proxyTLSCertPath; + this.proxyTLSKeyPath = builder.proxyTLSKeyPath; } static Builder newBuilder() { @@ -242,4 +255,16 @@ String getClientCertPath() { String getClientKeyPath() { return clientKeyPath; } + + boolean useProxyTLS() { + return !Strings.isNullOrEmpty(proxyTLSCertPath) && !Strings.isNullOrEmpty(proxyTLSKeyPath); + } + + String getProxyTLSCertPath() { + return proxyTLSCertPath; + } + + String getProxyTLSKeyPath() { + return proxyTLSKeyPath; + } } diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Launcher.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Launcher.java index 866a6e07..081f033c 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Launcher.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/Launcher.java @@ -230,7 +230,8 @@ private AdapterOptions buildAdapterOptions( .metricsRecorder(metricsRecorder) .usePlainText(config.usePlainText()) .setExperimentalHostEndpoint(config.getExperimentalHostEndpoint()) - .useClientCert(config.getClientCertPath(), config.getClientKeyPath()); + .useClientCert(config.getClientCertPath(), config.getClientKeyPath()) + .useProxyTLS(config.getProxyTLSCertPath(), config.getProxyTLSKeyPath()); if (config.getMaxCommitDelayMillis() != null) { opBuilder.maxCommitDelay(Duration.ofMillis(config.getMaxCommitDelayMillis())); } diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/LauncherConfig.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/LauncherConfig.java index 128bb332..2af48d06 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/LauncherConfig.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/LauncherConfig.java @@ -63,6 +63,8 @@ static LauncherConfig fromUserConfigs(UserConfigs userConfigs) throws UnknownHos final String experimentalHostEndpoint; final String clientCertPath; final String clientKeyPath; + final String proxyTLSCertPath; + final String proxyTLSKeyPath; HealthCheckConfig healthCheckConfig = null; if (userConfigs.getGlobalClientConfigs() != null) { @@ -84,6 +86,8 @@ static LauncherConfig fromUserConfigs(UserConfigs userConfigs) throws UnknownHos experimentalHostEndpoint = userConfigs.getGlobalClientConfigs().getExperimentalHostEndpoint(); clientCertPath = userConfigs.getGlobalClientConfigs().getClientCertPath(); clientKeyPath = userConfigs.getGlobalClientConfigs().getClientKeyPath(); + proxyTLSCertPath = userConfigs.getGlobalClientConfigs().getProxyTLSCertPath(); + proxyTLSKeyPath = userConfigs.getGlobalClientConfigs().getProxyTLSKeyPath(); } else { globalSpannerEndpoint = ConfigConstants.DEFAULT_SPANNER_ENDPOINT; globalEnableBuiltInMetrics = false; @@ -91,6 +95,8 @@ static LauncherConfig fromUserConfigs(UserConfigs userConfigs) throws UnknownHos experimentalHostEndpoint = null; clientCertPath = null; clientKeyPath = null; + proxyTLSCertPath = null; + proxyTLSKeyPath = null; } List listenerConfigs = new ArrayList<>(); @@ -104,7 +110,9 @@ static LauncherConfig fromUserConfigs(UserConfigs userConfigs) throws UnknownHos usePlainText, experimentalHostEndpoint, clientCertPath, - clientKeyPath)); + clientKeyPath, + proxyTLSCertPath, + proxyTLSKeyPath)); } return new LauncherConfig(listenerConfigs, healthCheckConfig); @@ -150,6 +158,8 @@ final class ListenerConfig { private final String experimentalHostEndpoint; private String clientCertPath; private String clientKeyPath; + private final String proxyTLSCertPath; + private final String proxyTLSKeyPath; private ListenerConfig(Builder builder) { this.databaseUri = builder.databaseUri; @@ -163,6 +173,8 @@ private ListenerConfig(Builder builder) { this.experimentalHostEndpoint = builder.experimentalHostEndpoint; this.clientCertPath = builder.clientCertPath; this.clientKeyPath = builder.clientKeyPath; + this.proxyTLSCertPath = builder.proxyTLSCertPath; + this.proxyTLSKeyPath = builder.proxyTLSKeyPath; } public String getDatabaseUri() { @@ -210,6 +222,14 @@ public String getClientKeyPath() { return clientKeyPath; } + public String getProxyTLSCertPath() { + return proxyTLSCertPath; + } + + public String getProxyTLSKeyPath() { + return proxyTLSKeyPath; + } + static ListenerConfig fromListenerConfigs( ListenerConfigs listener, String globalSpannerEndpoint, @@ -217,7 +237,9 @@ static ListenerConfig fromListenerConfigs( boolean usePlainText, String experimentalHostEndpoint, String clientCertPath, - String clientKeyPath) + String clientKeyPath, + String proxyTLSCertPath, + String proxyTLSKeyPath) throws UnknownHostException { String host = listener.getHost() != null ? listener.getHost() : ConfigConstants.DEFAULT_HOST; int port = listener.getPort() != null ? listener.getPort() : ConfigConstants.DEFAULT_PORT; @@ -238,6 +260,7 @@ static ListenerConfig fromListenerConfigs( .setExperimentalHostEndpoint(experimentalHostEndpoint) .usePlainText(usePlainText) .useClientCert(clientCertPath, clientKeyPath) + .useProxyTLS(proxyTLSCertPath, proxyTLSKeyPath) .build(); } @@ -269,6 +292,8 @@ static ListenerConfig fromProperties(Map properties) throws Unkn properties.get(ConfigConstants.EXPERIMENTAL_HOST_ENDPOINT_PROP_KEY); String clientCertPath = properties.get(ConfigConstants.CLIENT_CERT_PATH_PROP_KEY); String clientKeyPath = properties.get(ConfigConstants.CLIENT_KEY_PATH_PROP_KEY); + String proxyTLSCertPath = properties.get(ConfigConstants.PROXY_TLS_CERT_PATH_PROP_KEY); + String proxyTLSKeyPath = properties.get(ConfigConstants.PROXY_TLS_KEY_PATH_PROP_KEY); String databaseUri = properties.get(ConfigConstants.DATABASE_URI_PROP_KEY); if (!Strings.isNullOrEmpty(experimentalHostEndpoint)) { if (!DatabaseName.isParsableFrom(databaseUri)) { @@ -288,6 +313,7 @@ static ListenerConfig fromProperties(Map properties) throws Unkn .usePlainText(usePlainText) .setExperimentalHostEndpoint(experimentalHostEndpoint) .useClientCert(clientCertPath, clientKeyPath) + .useProxyTLS(proxyTLSCertPath, proxyTLSKeyPath) .build(); } @@ -307,6 +333,8 @@ static class Builder { private String experimentalHostEndpoint; private String clientCertPath; private String clientKeyPath; + private String proxyTLSCertPath; + private String proxyTLSKeyPath; private void validateHostConflict( String spannerEndpointToCheck, String experimentalHostEndpointToCheck) { @@ -371,6 +399,12 @@ public Builder useClientCert(String clientCertPath, String clientKeyPath) { return this; } + public Builder useProxyTLS(String proxyTLSCertPath, String proxyTLSKeyPath) { + this.proxyTLSCertPath = proxyTLSCertPath; + this.proxyTLSKeyPath = proxyTLSKeyPath; + return this; + } + public ListenerConfig build() { return new ListenerConfig(this); } diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/ConfigConstants.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/ConfigConstants.java index 596f3e63..e0e5acba 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/ConfigConstants.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/ConfigConstants.java @@ -39,4 +39,6 @@ private ConfigConstants() {} public static final String EXPERIMENTAL_HOST_ENDPOINT_PROP_KEY = "experimentalHostEndpoint"; public static final String CLIENT_CERT_PATH_PROP_KEY = "clientCertPath"; public static final String CLIENT_KEY_PATH_PROP_KEY = "clientKeyPath"; + public static final String PROXY_TLS_CERT_PATH_PROP_KEY = "proxyTLSCertPath"; + public static final String PROXY_TLS_KEY_PATH_PROP_KEY = "proxyTLSKeyPath"; } diff --git a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/GlobalClientConfigs.java b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/GlobalClientConfigs.java index 0fe2a30e..4dae538d 100644 --- a/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/GlobalClientConfigs.java +++ b/google-cloud-spanner-cassandra/src/main/java/com/google/cloud/spanner/adapter/configs/GlobalClientConfigs.java @@ -16,7 +16,6 @@ package com.google.cloud.spanner.adapter.configs; -import com.google.common.base.Strings; import java.util.Map; /** Represents the global client configurations loaded from a YAML file. */ @@ -28,27 +27,28 @@ public class GlobalClientConfigs { private final String experimentalHostEndpoint; private final String clientCertPath; private final String clientKeyPath; - - public GlobalClientConfigs( - String spannerEndpoint, - Boolean enableBuiltInMetrics, - String healthCheckEndpoint, - Boolean usePlainText, - String experimentalHostEndpoint, - String clientCertPath, - String clientKeyPath) { - this.spannerEndpoint = spannerEndpoint; - this.enableBuiltInMetrics = enableBuiltInMetrics; - this.healthCheckEndpoint = healthCheckEndpoint; - this.usePlainText = usePlainText; - this.experimentalHostEndpoint = experimentalHostEndpoint; - this.clientCertPath = clientCertPath; - this.clientKeyPath = clientKeyPath; + private final String proxyTLSCertPath; + private final String proxyTLSKeyPath; + + private GlobalClientConfigs(Builder builder) { + this.spannerEndpoint = builder.spannerEndpoint; + this.enableBuiltInMetrics = builder.enableBuiltInMetrics; + this.healthCheckEndpoint = builder.healthCheckEndpoint; + this.usePlainText = builder.usePlainText; + this.experimentalHostEndpoint = builder.experimentalHostEndpoint; + this.clientCertPath = builder.clientCertPath; + this.clientKeyPath = builder.clientKeyPath; + this.proxyTLSCertPath = builder.proxyTLSCertPath; + this.proxyTLSKeyPath = builder.proxyTLSKeyPath; } public GlobalClientConfigs( String spannerEndpoint, Boolean enableBuiltInMetrics, String healthCheckEndpoint) { - this(spannerEndpoint, enableBuiltInMetrics, healthCheckEndpoint, null, null, null, null); + this( + new Builder() + .spannerEndpoint(spannerEndpoint) + .enableBuiltInMetrics(enableBuiltInMetrics) + .healthCheckEndpoint(healthCheckEndpoint)); } public GlobalClientConfigs( @@ -57,23 +57,72 @@ public GlobalClientConfigs( String healthCheckEndpoint, Boolean usePlainText) { this( - spannerEndpoint, enableBuiltInMetrics, healthCheckEndpoint, usePlainText, null, null, null); + new Builder() + .spannerEndpoint(spannerEndpoint) + .enableBuiltInMetrics(enableBuiltInMetrics) + .healthCheckEndpoint(healthCheckEndpoint) + .usePlainText(usePlainText)); } - public GlobalClientConfigs( - String spannerEndpoint, - Boolean enableBuiltInMetrics, - String healthCheckEndpoint, - Boolean usePlainText, - String experimentalHostEndpoint) { - this( - spannerEndpoint, - enableBuiltInMetrics, - healthCheckEndpoint, - usePlainText, - experimentalHostEndpoint, - null, - null); + public static class Builder { + private String spannerEndpoint; + private Boolean enableBuiltInMetrics; + private String healthCheckEndpoint; + private Boolean usePlainText; + private String experimentalHostEndpoint; + private String clientCertPath; + private String clientKeyPath; + private String proxyTLSCertPath; + private String proxyTLSKeyPath; + + public Builder spannerEndpoint(String spannerEndpoint) { + this.spannerEndpoint = spannerEndpoint; + return this; + } + + public Builder enableBuiltInMetrics(Boolean enableBuiltInMetrics) { + this.enableBuiltInMetrics = enableBuiltInMetrics; + return this; + } + + public Builder healthCheckEndpoint(String healthCheckEndpoint) { + this.healthCheckEndpoint = healthCheckEndpoint; + return this; + } + + public Builder usePlainText(Boolean usePlainText) { + this.usePlainText = usePlainText; + return this; + } + + public Builder experimentalHostEndpoint(String experimentalHostEndpoint) { + this.experimentalHostEndpoint = experimentalHostEndpoint; + return this; + } + + public Builder clientCertPath(String clientCertPath) { + this.clientCertPath = clientCertPath; + return this; + } + + public Builder clientKeyPath(String clientKeyPath) { + this.clientKeyPath = clientKeyPath; + return this; + } + + public Builder proxyTLSCertPath(String proxyTLSCertPath) { + this.proxyTLSCertPath = proxyTLSCertPath; + return this; + } + + public Builder proxyTLSKeyPath(String proxyTLSKeyPath) { + this.proxyTLSKeyPath = proxyTLSKeyPath; + return this; + } + + public GlobalClientConfigs build() { + return new GlobalClientConfigs(this); + } } public static GlobalClientConfigs fromMap(Map yamlMap) { @@ -84,22 +133,20 @@ public static GlobalClientConfigs fromMap(Map yamlMap) { String experimentalHostEndpoint = (String) yamlMap.get("experimentalHostEndpoint"); String clientCertPath = (String) yamlMap.get("clientCertPath"); String clientKeyPath = (String) yamlMap.get("clientKeyPath"); - if (Strings.isNullOrEmpty(clientCertPath) || Strings.isNullOrEmpty(clientKeyPath)) { - return new GlobalClientConfigs( - spannerEndpoint, - enableBuiltInMetrics, - healthCheckEndpoint, - usePlainText, - experimentalHostEndpoint); - } - return new GlobalClientConfigs( - spannerEndpoint, - enableBuiltInMetrics, - healthCheckEndpoint, - usePlainText, - experimentalHostEndpoint, - clientCertPath, - clientKeyPath); + String proxyTLSCertPath = (String) yamlMap.get("proxyTLSCertPath"); + String proxyTLSKeyPath = (String) yamlMap.get("proxyTLSKeyPath"); + + return new GlobalClientConfigs.Builder() + .spannerEndpoint(spannerEndpoint) + .enableBuiltInMetrics(enableBuiltInMetrics) + .healthCheckEndpoint(healthCheckEndpoint) + .usePlainText(usePlainText) + .experimentalHostEndpoint(experimentalHostEndpoint) + .clientCertPath(clientCertPath) + .clientKeyPath(clientKeyPath) + .proxyTLSCertPath(proxyTLSCertPath) + .proxyTLSKeyPath(proxyTLSKeyPath) + .build(); } public String getSpannerEndpoint() { @@ -129,4 +176,12 @@ public String getClientCertPath() { public String getClientKeyPath() { return clientKeyPath; } + + public String getProxyTLSCertPath() { + return proxyTLSCertPath; + } + + public String getProxyTLSKeyPath() { + return proxyTLSKeyPath; + } } diff --git a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/AdapterTest.java b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/AdapterTest.java index 14e909eb..0a9e2390 100644 --- a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/AdapterTest.java +++ b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/AdapterTest.java @@ -104,4 +104,31 @@ public void stopWithoutStart() { // Adapter is in the not-started state. assertThrows(IllegalStateException.class, adapter::stop); } + + @Test + public void startWithInvalidTLSConfig() { + // Only cert specified + AdapterOptions options1 = + new AdapterOptions.Builder() + .spannerEndpoint(TEST_HOST) + .tcpPort(TEST_PORT) + .databaseUri(TEST_DATABASE_URI) + .inetAddress(inetAddress) + .useProxyTLS("cert.pem", null) + .build(); + Adapter adapter1 = new Adapter(options1); + assertThrows(IllegalArgumentException.class, adapter1::start); + + // Only key specified + AdapterOptions options2 = + new AdapterOptions.Builder() + .spannerEndpoint(TEST_HOST) + .tcpPort(TEST_PORT) + .databaseUri(TEST_DATABASE_URI) + .inetAddress(inetAddress) + .useProxyTLS(null, "key.pem") + .build(); + Adapter adapter2 = new Adapter(options2); + assertThrows(IllegalArgumentException.class, adapter2::start); + } } diff --git a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherConfigParserTest.java b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherConfigParserTest.java index 90564907..bf0d0854 100644 --- a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherConfigParserTest.java +++ b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherConfigParserTest.java @@ -50,7 +50,11 @@ public class LauncherConfigParserTest { public void testParse_withValidConfigFile() throws Exception { UserConfigs userConfigs = new UserConfigs( - new GlobalClientConfigs("spanner.googleapis.com:443", true, "127.0.0.1:8080"), + new GlobalClientConfigs.Builder() + .spannerEndpoint("spanner.googleapis.com:443") + .enableBuiltInMetrics(true) + .healthCheckEndpoint("127.0.0.1:8080") + .build(), Arrays.asList( new ListenerConfigs( "listener_1", @@ -230,7 +234,11 @@ public void testParse_withInvalidConfigFile_throwsIOException() { public void testParse_withUnknownHost_throwsIOException() throws IOException { UserConfigs userConfigs = new UserConfigs( - new GlobalClientConfigs("spanner.googleapis.com:443", true, "unknown-host:8080"), + new GlobalClientConfigs.Builder() + .spannerEndpoint("spanner.googleapis.com:443") + .enableBuiltInMetrics(true) + .healthCheckEndpoint("unknown-host:8080") + .build(), Collections.singletonList( new ListenerConfigs( "listener_1", diff --git a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherTest.java b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherTest.java index 6988c4ac..a76c3f31 100644 --- a/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherTest.java +++ b/google-cloud-spanner-cassandra/src/test/java/com/google/cloud/spanner/adapter/LauncherTest.java @@ -83,7 +83,11 @@ public void tearDown() { public void testRun_withMultipleListeners_startsMultipleAdapters() throws Exception { UserConfigs userConfigs = new UserConfigs( - new GlobalClientConfigs("spanner.googleapis.com:443", true, "127.0.0.1:8080"), + new GlobalClientConfigs.Builder() + .spannerEndpoint("spanner.googleapis.com:443") + .enableBuiltInMetrics(true) + .healthCheckEndpoint("127.0.0.1:8080") + .build(), Arrays.asList( new ListenerConfigs( "listener_1",