diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 58e986dd4b..186370aae3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,6 +15,35 @@ on: - release-* jobs: + test: + name: "Unit tests" + runs-on: ubuntu-latest + timeout-minutes: 30 + continue-on-error: false + env: + JDK_VER: 17 + steps: + - uses: actions/checkout@v5 + - name: Set up OpenJDK ${{ env.JDK_VER }} + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: ${{ env.JDK_VER }} + - name: Run tests + run: ./mvnw clean install -B -q + - name: Codecov + uses: codecov/codecov-action@v5.5.0 + - name: Upload test report for sdk + uses: actions/upload-artifact@v4 + with: + name: test-dapr-java-sdk-jdk${{ env.JDK_VER }} + path: sdk/target/jacoco-report/ + - name: Upload test report for sdk-actors + uses: actions/upload-artifact@v4 + with: + name: report-dapr-java-sdk-actors-jdk${{ env.JDK_VER }} + path: sdk-actors/target/jacoco-report/ + build: name: "Build jdk:${{ matrix.java }} sb:${{ matrix.spring-boot-display-version }} exp:${{ matrix.experimental }}" runs-on: ubuntu-latest @@ -114,27 +143,11 @@ jobs: /home/runner/.local/bin/toxiproxy-server --version - name: Clean up and install sdk run: ./mvnw clean install -B -q -DskipTests - - name: Unit tests - run: ./mvnw test # making it temporarily verbose. - env: - DOCKER_HOST: ${{steps.setup_docker.outputs.sock}} - - name: Codecov - uses: codecov/codecov-action@v5.5.0 - name: Integration tests using spring boot version ${{ matrix.spring-boot-version }} id: integration_tests run: PRODUCT_SPRING_BOOT_VERSION=${{ matrix.spring-boot-version }} ./mvnw -B -Pintegration-tests verify env: DOCKER_HOST: ${{steps.setup_docker.outputs.sock}} - - name: Upload test report for sdk - uses: actions/upload-artifact@v4 - with: - name: report-dapr-java-sdk-jdk${{ matrix.java }}-sb${{ matrix.spring-boot-version }} - path: sdk/target/jacoco-report/ - - name: Upload test report for sdk-actors - uses: actions/upload-artifact@v4 - with: - name: report-dapr-java-sdk-actors-jdk${{ matrix.java }}-sb${{ matrix.spring-boot-version }} - path: sdk-actors/target/jacoco-report/ - name: Upload failsafe test report for sdk-tests on failure if: ${{ failure() && steps.integration_tests.conclusion == 'failure' }} uses: actions/upload-artifact@v4 @@ -150,7 +163,7 @@ jobs: publish: runs-on: ubuntu-latest - needs: build + needs: [ build, test ] timeout-minutes: 30 env: JDK_VER: 17 diff --git a/sdk/pom.xml b/sdk/pom.xml index 57154623c8..af01cfa88b 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -132,18 +132,6 @@ assertj-core ${assertj.version} - - org.bouncycastle - bcprov-jdk15on - 1.70 - test - - - org.bouncycastle - bcpkix-jdk15on - 1.70 - test - io.grpc grpc-netty-shaded diff --git a/sdk/src/test/java/io/dapr/utils/NetworkUtilsTest.java b/sdk/src/test/java/io/dapr/utils/NetworkUtilsTest.java index 3823bef3bd..a8bd189e30 100644 --- a/sdk/src/test/java/io/dapr/utils/NetworkUtilsTest.java +++ b/sdk/src/test/java/io/dapr/utils/NetworkUtilsTest.java @@ -27,20 +27,9 @@ import org.junit.jupiter.api.condition.OS; import java.io.File; -import java.nio.file.Files; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.cert.X509Certificate; -import java.util.Date; +import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.ArrayList; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.X509v3CertificateBuilder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; public class NetworkUtilsTest { private final int defaultGrpcPort = 50001; @@ -48,47 +37,6 @@ public class NetworkUtilsTest { private ManagedChannel channel; private static final List channels = new ArrayList<>(); - // Helper method to generate a self-signed certificate for testing - private static KeyPair generateKeyPair() throws Exception { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); - keyPairGenerator.initialize(2048); - return keyPairGenerator.generateKeyPair(); - } - - private static X509Certificate generateCertificate(KeyPair keyPair) throws Exception { - X500Name issuer = new X500Name("CN=Test Certificate"); - X500Name subject = new X500Name("CN=Test Certificate"); - Date notBefore = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000); - Date notAfter = new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000L); - SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()); - X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder( - issuer, - java.math.BigInteger.valueOf(System.currentTimeMillis()), - notBefore, - notAfter, - subject, - publicKeyInfo - ); - - ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate()); - X509Certificate cert = new JcaX509CertificateConverter().getCertificate(certBuilder.build(signer)); - return cert; - } - - private static void writeCertificateToFile(X509Certificate cert, File file) throws Exception { - String certPem = "-----BEGIN CERTIFICATE-----\n" + - java.util.Base64.getEncoder().encodeToString(cert.getEncoded()) + - "\n-----END CERTIFICATE-----"; - Files.write(file.toPath(), certPem.getBytes()); - } - - private static void writePrivateKeyToFile(KeyPair keyPair, File file) throws Exception { - String keyPem = "-----BEGIN PRIVATE KEY-----\n" + - java.util.Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()) + - "\n-----END PRIVATE KEY-----"; - Files.write(file.toPath(), keyPem.getBytes()); - } - @AfterEach public void tearDown() { if (channel != null && !channel.isShutdown()) { @@ -157,56 +105,35 @@ public void testBuildGrpcManagedChannel_httpsEndpointWithPort() { @Test public void testBuildGrpcManagedChannelWithTls() throws Exception { - // Generate test certificate and key - KeyPair keyPair = generateKeyPair(); - X509Certificate cert = generateCertificate(keyPair); - - File certFile = File.createTempFile("test-cert", ".pem"); - File keyFile = File.createTempFile("test-key", ".pem"); - try { - writeCertificateToFile(cert, certFile); - writePrivateKeyToFile(keyPair, keyFile); + File certFile = new File(this.getClass().getResource("/certs/test-cert.pem").getFile()); + File keyFile = new File(this.getClass().getResource("/certs/test-cert.key").getFile()); - var properties = new Properties(Map.of( + var properties = new Properties(Map.of( Properties.GRPC_TLS_CERT_PATH.getName(), certFile.getAbsolutePath(), Properties.GRPC_TLS_KEY_PATH.getName(), keyFile.getAbsolutePath() )); - channel = NetworkUtils.buildGrpcManagedChannel(properties); - channels.add(channel); - String expectedAuthority = String.format("%s:%s", defaultSidecarIP, defaultGrpcPort); - Assertions.assertEquals(expectedAuthority, channel.authority()); - } finally { - certFile.delete(); - keyFile.delete(); - } + channel = NetworkUtils.buildGrpcManagedChannel(properties); + channels.add(channel); + String expectedAuthority = String.format("%s:%s", defaultSidecarIP, defaultGrpcPort); + Assertions.assertEquals(expectedAuthority, channel.authority()); + } @Test public void testBuildGrpcManagedChannelWithTlsAndEndpoint() throws Exception { - // Generate test certificate and key - KeyPair keyPair = generateKeyPair(); - X509Certificate cert = generateCertificate(keyPair); - - File certFile = File.createTempFile("test-cert", ".pem"); - File keyFile = File.createTempFile("test-key", ".pem"); - try { - writeCertificateToFile(cert, certFile); - writePrivateKeyToFile(keyPair, keyFile); + File certFile = new File(this.getClass().getResource("/certs/test-cert.pem").getFile()); + File keyFile = new File(this.getClass().getResource("/certs/test-cert.key").getFile()); - var properties = new Properties(Map.of( - Properties.GRPC_TLS_CERT_PATH.getName(), certFile.getAbsolutePath(), - Properties.GRPC_TLS_KEY_PATH.getName(), keyFile.getAbsolutePath(), - Properties.GRPC_ENDPOINT.getName(), "https://example.com:443" - )); + var properties = new Properties(Map.of( + Properties.GRPC_TLS_CERT_PATH.getName(), certFile.getAbsolutePath(), + Properties.GRPC_TLS_KEY_PATH.getName(), keyFile.getAbsolutePath(), + Properties.GRPC_ENDPOINT.getName(), "https://example.com:443" + )); - channel = NetworkUtils.buildGrpcManagedChannel(properties); - channels.add(channel); - Assertions.assertEquals("example.com:443", channel.authority()); - } finally { - certFile.delete(); - keyFile.delete(); - } + channel = NetworkUtils.buildGrpcManagedChannel(properties); + channels.add(channel); + Assertions.assertEquals("example.com:443", channel.authority()); } @Test @@ -229,49 +156,32 @@ public void testBuildGrpcManagedChannelWithTlsAndUnixSocket() throws Exception { System.getProperty("os.name").toLowerCase().contains("mac")); // Generate test certificate and key - KeyPair keyPair = generateKeyPair(); - X509Certificate cert = generateCertificate(keyPair); - - File certFile = File.createTempFile("test-cert", ".pem"); - File keyFile = File.createTempFile("test-key", ".pem"); - try { - writeCertificateToFile(cert, certFile); - writePrivateKeyToFile(keyPair, keyFile); + File certFile = new File(this.getClass().getResource("/certs/test-cert.pem").getFile()); + File keyFile = new File(this.getClass().getResource("/certs/test-cert.key").getFile()); - var properties = new Properties(Map.of( - Properties.GRPC_TLS_CERT_PATH.getName(), certFile.getAbsolutePath(), - Properties.GRPC_TLS_KEY_PATH.getName(), keyFile.getAbsolutePath(), - Properties.GRPC_ENDPOINT.getName(), "unix:/tmp/test.sock" - )); + var properties = new Properties(Map.of( + Properties.GRPC_TLS_CERT_PATH.getName(), certFile.getAbsolutePath(), + Properties.GRPC_TLS_KEY_PATH.getName(), keyFile.getAbsolutePath(), + Properties.GRPC_ENDPOINT.getName(), "unix:/tmp/test.sock" + )); - // For Unix sockets, we expect an exception if the platform doesn't support it - try { - channel = NetworkUtils.buildGrpcManagedChannel(properties); - channels.add(channel); - // If we get here, Unix sockets are supported - Assertions.assertNotNull(channel.authority(), "Channel authority should not be null"); - } catch (Exception e) { - // If we get here, Unix sockets are not supported - Assertions.assertTrue(e.getMessage().contains("DomainSocketAddress")); - } - } finally { - certFile.delete(); - keyFile.delete(); + // For Unix sockets, we expect an exception if the platform doesn't support it + try { + channel = NetworkUtils.buildGrpcManagedChannel(properties); + channels.add(channel); + // If we get here, Unix sockets are supported + Assertions.assertNotNull(channel.authority(), "Channel authority should not be null"); + } catch (Exception e) { + // If we get here, Unix sockets are not supported + Assertions.assertTrue(e.getMessage().contains("DomainSocketAddress")); } + } @Test public void testBuildGrpcManagedChannelWithTlsAndDnsAuthority() throws Exception { - // Generate test certificate and key - KeyPair keyPair = generateKeyPair(); - X509Certificate cert = generateCertificate(keyPair); - - File certFile = File.createTempFile("test-cert", ".pem"); - File keyFile = File.createTempFile("test-key", ".pem"); - try { - writeCertificateToFile(cert, certFile); - writePrivateKeyToFile(keyPair, keyFile); - + File certFile = new File(this.getClass().getResource("/certs/test-cert.pem").getFile()); + File keyFile = new File(this.getClass().getResource("/certs/test-cert.key").getFile()); var properties = new Properties(Map.of( Properties.GRPC_TLS_CERT_PATH.getName(), certFile.getAbsolutePath(), Properties.GRPC_TLS_KEY_PATH.getName(), keyFile.getAbsolutePath(), @@ -281,44 +191,26 @@ public void testBuildGrpcManagedChannelWithTlsAndDnsAuthority() throws Exception channel = NetworkUtils.buildGrpcManagedChannel(properties); channels.add(channel); Assertions.assertEquals("example.com:443", channel.authority()); - } finally { - certFile.delete(); - keyFile.delete(); - } + } @Test public void testBuildGrpcManagedChannelWithTlsAndCaCert() throws Exception { - // Generate test CA certificate - KeyPair caKeyPair = generateKeyPair(); - X509Certificate caCert = generateCertificate(caKeyPair); - - File caCertFile = File.createTempFile("test-ca-cert", ".pem"); - try { - writeCertificateToFile(caCert, caCertFile); + File caCertFile = new File(this.getClass().getResource("/certs/test-ca-cert.pem").getFile()); - var properties = new Properties(Map.of( - Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath() - )); + var properties = new Properties(Map.of( + Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath() + )); - channel = NetworkUtils.buildGrpcManagedChannel(properties); - channels.add(channel); - String expectedAuthority = String.format("%s:%s", defaultSidecarIP, defaultGrpcPort); - Assertions.assertEquals(expectedAuthority, channel.authority()); - } finally { - caCertFile.delete(); - } + channel = NetworkUtils.buildGrpcManagedChannel(properties); + channels.add(channel); + String expectedAuthority = String.format("%s:%s", defaultSidecarIP, defaultGrpcPort); + Assertions.assertEquals(expectedAuthority, channel.authority()); } @Test public void testBuildGrpcManagedChannelWithTlsAndCaCertAndEndpoint() throws Exception { - // Generate test CA certificate - KeyPair caKeyPair = generateKeyPair(); - X509Certificate caCert = generateCertificate(caKeyPair); - - File caCertFile = File.createTempFile("test-ca-cert", ".pem"); - try { - writeCertificateToFile(caCert, caCertFile); + File caCertFile = new File(this.getClass().getResource("/certs/test-ca-cert.pem").getFile()); var properties = new Properties(Map.of( Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(), @@ -328,9 +220,7 @@ public void testBuildGrpcManagedChannelWithTlsAndCaCertAndEndpoint() throws Exce channel = NetworkUtils.buildGrpcManagedChannel(properties); channels.add(channel); Assertions.assertEquals("example.com:443", channel.authority()); - } finally { - caCertFile.delete(); - } + } @Test @@ -346,37 +236,22 @@ public void testBuildGrpcManagedChannelWithInvalidCaCert() { @Test public void testBuildGrpcManagedChannelWithMtlsAndCaCert() throws Exception { - // Generate test certificates - KeyPair caKeyPair = generateKeyPair(); - X509Certificate caCert = generateCertificate(caKeyPair); - KeyPair clientKeyPair = generateKeyPair(); - X509Certificate clientCert = generateCertificate(clientKeyPair); - - File caCertFile = File.createTempFile("test-ca-cert", ".pem"); - File clientCertFile = File.createTempFile("test-client-cert", ".pem"); - File clientKeyFile = File.createTempFile("test-client-key", ".pem"); - try { - writeCertificateToFile(caCert, caCertFile); - writeCertificateToFile(clientCert, clientCertFile); - writePrivateKeyToFile(clientKeyPair, clientKeyFile); + File caCertFile = new File(this.getClass().getResource("/certs/test-ca-cert.pem").getFile()); + File clientCertFile = new File(this.getClass().getResource("/certs/test-cert.pem").getFile()); + File clientKeyFile = new File(this.getClass().getResource("/certs/test-cert.key").getFile()); - // Test mTLS with both client certs and CA cert - var properties = new Properties(Map.of( - Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(), - Properties.GRPC_TLS_CERT_PATH.getName(), clientCertFile.getAbsolutePath(), - Properties.GRPC_TLS_KEY_PATH.getName(), clientKeyFile.getAbsolutePath() - )); + // Test mTLS with both client certs and CA cert + var properties = new Properties(Map.of( + Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(), + Properties.GRPC_TLS_CERT_PATH.getName(), clientCertFile.getAbsolutePath(), + Properties.GRPC_TLS_KEY_PATH.getName(), clientKeyFile.getAbsolutePath() + )); - channel = NetworkUtils.buildGrpcManagedChannel(properties); - channels.add(channel); - String expectedAuthority = String.format("%s:%s", defaultSidecarIP, defaultGrpcPort); - Assertions.assertEquals(expectedAuthority, channel.authority()); - Assertions.assertFalse(channel.isTerminated(), "Channel should be active"); - } finally { - caCertFile.delete(); - clientCertFile.delete(); - clientKeyFile.delete(); - } + channel = NetworkUtils.buildGrpcManagedChannel(properties); + channels.add(channel); + String expectedAuthority = String.format("%s:%s", defaultSidecarIP, defaultGrpcPort); + Assertions.assertEquals(expectedAuthority, channel.authority()); + Assertions.assertFalse(channel.isTerminated(), "Channel should be active"); } @Test @@ -463,57 +338,40 @@ private static void testGrpcEndpointParsingErrorScenario(String grpcEndpointEnvV @Test public void testBuildGrpcManagedChannelWithCaCertAndUnixSocket() throws Exception { // Skip test if Unix domain sockets are not supported - Assumptions.assumeTrue(System.getProperty("os.name").toLowerCase().contains("linux") || - System.getProperty("os.name").toLowerCase().contains("mac")); + Assumptions.assumeTrue(System.getProperty("os.name").toLowerCase().contains("linux") || + System.getProperty("os.name").toLowerCase().contains("mac")); - // Generate test CA certificate - KeyPair caKeyPair = generateKeyPair(); - X509Certificate caCert = generateCertificate(caKeyPair); - - File caCertFile = File.createTempFile("test-ca-cert", ".pem"); - try { - writeCertificateToFile(caCert, caCertFile); + File caCertFile = new File(this.getClass().getResource("/certs/test-ca-cert.pem").getFile()); - var properties = new Properties(Map.of( - Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(), - Properties.GRPC_ENDPOINT.getName(), "unix:/tmp/test.sock" - )); + var properties = new Properties(Map.of( + Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(), + Properties.GRPC_ENDPOINT.getName(), "unix:/tmp/test.sock" + )); - // For Unix sockets, we expect an exception if the platform doesn't support it - try { - channel = NetworkUtils.buildGrpcManagedChannel(properties); - channels.add(channel); - Assertions.assertNotNull(channel.authority(), "Channel authority should not be null"); - } catch (Exception e) { - // If we get here, Unix sockets are not supported - Assertions.assertTrue(e.getMessage().contains("DomainSocketAddress")); - } - } finally { - caCertFile.delete(); + // For Unix sockets, we expect an exception if the platform doesn't support it + try { + channel = NetworkUtils.buildGrpcManagedChannel(properties); + channels.add(channel); + Assertions.assertNotNull(channel.authority(), "Channel authority should not be null"); + } catch (Exception e) { + // If we get here, Unix sockets are not supported + Assertions.assertTrue(e.getMessage().contains("DomainSocketAddress")); } + } @Test public void testBuildGrpcManagedChannelWithCaCertAndDnsAuthority() throws Exception { - // Generate test CA certificate - KeyPair caKeyPair = generateKeyPair(); - X509Certificate caCert = generateCertificate(caKeyPair); - - File caCertFile = File.createTempFile("test-ca-cert", ".pem"); - try { - writeCertificateToFile(caCert, caCertFile); + File caCertFile = new File(this.getClass().getResource("/certs/test-ca-cert.pem").getFile()); - var properties = new Properties(Map.of( - Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(), - Properties.GRPC_ENDPOINT.getName(), "dns://authority:53/example.com:443" - )); + var properties = new Properties(Map.of( + Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(), + Properties.GRPC_ENDPOINT.getName(), "dns://authority:53/example.com:443" + )); - channel = NetworkUtils.buildGrpcManagedChannel(properties); - channels.add(channel); - Assertions.assertEquals("example.com:443", channel.authority()); - } finally { - caCertFile.delete(); - } + channel = NetworkUtils.buildGrpcManagedChannel(properties); + channels.add(channel); + Assertions.assertEquals("example.com:443", channel.authority()); } @Test @@ -536,43 +394,28 @@ public void testBuildGrpcManagedChannelWithInsecureTls() throws Exception { @Test public void testBuildGrpcManagedChannelWithInsecureTlsAndMtls() throws Exception { - // Generate test certificates - KeyPair caKeyPair = generateKeyPair(); - X509Certificate caCert = generateCertificate(caKeyPair); - KeyPair clientKeyPair = generateKeyPair(); - X509Certificate clientCert = generateCertificate(clientKeyPair); - - File caCertFile = File.createTempFile("test-ca-cert", ".pem"); - File clientCertFile = File.createTempFile("test-client-cert", ".pem"); - File clientKeyFile = File.createTempFile("test-client-key", ".pem"); - try { - writeCertificateToFile(caCert, caCertFile); - writeCertificateToFile(clientCert, clientCertFile); - writePrivateKeyToFile(clientKeyPair, clientKeyFile); + File caCertFile = new File(this.getClass().getResource("/certs/test-ca-cert.pem").getFile()); + File clientCertFile = new File(this.getClass().getResource("/certs/test-cert.pem").getFile()); + File clientKeyFile = new File(this.getClass().getResource("/certs/test-cert.key").getFile()); - // Test that insecure TLS still works with mTLS settings - // The client certs should be ignored since we're using InsecureTrustManagerFactory - var properties = new Properties(Map.of( - Properties.GRPC_TLS_INSECURE.getName(), "true", - Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(), - Properties.GRPC_TLS_CERT_PATH.getName(), clientCertFile.getAbsolutePath(), - Properties.GRPC_TLS_KEY_PATH.getName(), clientKeyFile.getAbsolutePath(), - Properties.GRPC_ENDPOINT.getName(), "dns:///example.com:443?tls=true" - )); + // Test that insecure TLS still works with mTLS settings + // The client certs should be ignored since we're using InsecureTrustManagerFactory + var properties = new Properties(Map.of( + Properties.GRPC_TLS_INSECURE.getName(), "true", + Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(), + Properties.GRPC_TLS_CERT_PATH.getName(), clientCertFile.getAbsolutePath(), + Properties.GRPC_TLS_KEY_PATH.getName(), clientKeyFile.getAbsolutePath(), + Properties.GRPC_ENDPOINT.getName(), "dns:///example.com:443?tls=true" + )); - channel = NetworkUtils.buildGrpcManagedChannel(properties); - channels.add(channel); - - // Verify the channel is created with the correct authority - Assertions.assertEquals("example.com:443", channel.authority()); - - // Verify the channel is active and using TLS (not plaintext) - Assertions.assertFalse(channel.isTerminated(), "Channel should be active"); - } finally { - caCertFile.delete(); - clientCertFile.delete(); - clientKeyFile.delete(); - } + channel = NetworkUtils.buildGrpcManagedChannel(properties); + channels.add(channel); + + // Verify the channel is created with the correct authority + Assertions.assertEquals("example.com:443", channel.authority()); + + // Verify the channel is active and using TLS (not plaintext) + Assertions.assertFalse(channel.isTerminated(), "Channel should be active"); } @Test diff --git a/sdk/src/test/resources/certs/test-ca-cert.key b/sdk/src/test/resources/certs/test-ca-cert.key new file mode 100644 index 0000000000..eac281d7aa --- /dev/null +++ b/sdk/src/test/resources/certs/test-ca-cert.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +fg8QEv831uJb0uItcjDy5Yr0TEYMqg== +-----END PRIVATE KEY----- diff --git a/sdk/src/test/resources/certs/test-ca-cert.pem b/sdk/src/test/resources/certs/test-ca-cert.pem new file mode 100644 index 0000000000..087998d230 --- /dev/null +++ b/sdk/src/test/resources/certs/test-ca-cert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFUzCCAzugAwIBAgIUFHmlZNi1305lvonC4ePOulB207UwDQYJKoZIhvcNAQEL +BQAwOTENMAsGA1UECgwEREFQUjENMAsGA1UECwwEREFQUjEZMBcGA1UEAwwQVEVT +VCBDRVJUSUZJQ0FURTAeFw0yNTA4MjgxNTI4MTlaFw0yNzA4MjgxNTI4MTlaMDkx +DTALBgNVBAoMBERBUFIxDTALBgNVBAsMBERBUFIxGTAXBgNVBAMMEFRFU1QgQ0VS +VElGSUNBVEUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDbzg+ow2pe ++tWKSISVIF6kFi9VYReq0sJ8gJ+mQRkBK7Hs8G0WD9KS+Ebg15CTEulNbyp3sqPa +28tD1bq69ST8aMjUxD8NyWyYd7NQSd7pWHuR+NMDsh908W+JDyTxGgonXFaU5s8m ++FAS25nC8dzEgolxrQlVraXld1ZxMVW/OnOdl4dlSsXpGR4Zwv2S4BrppQvGhGTK +aURuOI1mot0IZVnV4acg5iK+2wPvDD2UJp6fMR6PplKrgb8dV2SqEEEVPwsXY0nb +idRb3yJ6VRtibkbu7u987BpEEaNeSmsC0BOIeHj90Jc+ilDQEgVRkMvP9zSPh6yY +4kOuMevof2J86FTRZWo7b9u1BG/2WoLeOPk00kAzN2jmk4hnytknWz1G0dxVZSJr +OcLHv9tWKk4TI3l54DrKw+n3pQA2Qs22P97n6d151mi3Yr45YtypmQhn4f4tsLxT +16mp2Vs/D4vU1M4jldpi9vDin+R4wIgDxXThUUd3c6NqrhyRiLteRaZVVsWeudi/ +jZt7H676S5lVdLTsU1jmOxef1mTzJxNAhw7VClq8YXeq8Z65Mj84fARxEh+WgN31 +5+JlIE6gPdYz7A+h5pupDVXJdhOViafQMBsAkUWautz4n47F5X+oB53rKEvRjjgV +sSVNB3oLBWCoXPxfpANQjNXky9QRb2Ib1wIDAQABo1MwUTAdBgNVHQ4EFgQUnBy0 +t/3jxb0LK0SWaKjOlRlebmowHwYDVR0jBBgwFoAUnBy0t/3jxb0LK0SWaKjOlRle +bmowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAh/5qDtYaiTWN +3cX0H/ucdsT1fzVCiWmniRBrvGgLOJ4VfBpcGAeyt3nTOCGBpLIHi6M47mv6+DA8 +GVA+k4FgAbFRWgSR5zDsOOC0/jTTEMpcrz13DgpCeh/Jj0MdNe3nzkC+eAT2bp07 +ZYLrO++N+IEpDEuDz3YlqIpgKpEREoGKWXrXcCEdsAUbIjOSWBfLBTuF8x11IVi7 +V4y3UUVTg6aA8ILmtWStoBuVroOH/HY/8RuQztUejjtd3PIEzPRgITekpWEDxI1D +Ycc7ZgdxEYmzXTvRAmLkIAoSPR5U61i09SSHmCs9hoWUGQGxSsxBFloTH6IoJFls +VDeWw3Shzu1PSPP5NedGgdRC8GKjOVDAgXzYPSoTYab5mGHTbL3HtRELthCmQSaC +SrNwKjd1MmhJ6yrjxKruE9mpSHUu50IDIP+PyMokWMRf504eGvPJstvD6+I4sUS3 +/Owu0eGM3incgG/ulAWpRDCXRq49JpAoq7evbyBQyzDfrCSN0U6sgjBVlJuoEuXD +t1cNmvPxf0730HxQYrq1nYahdt5Mi9+Pv8ublylKuGeYiWqiSeSE6wRRTktL7Xmf +BotM8yvJBhpY00GAPSxXQ2Kl+OielJq9QSCOgtQkMCMzKMsfbO+YA+WvMICe+GNJ +sfrgLw0imYT1npKJbNtg/vRxTZFj9hc= +-----END CERTIFICATE----- diff --git a/sdk/src/test/resources/certs/test-cert.key b/sdk/src/test/resources/certs/test-cert.key new file mode 100644 index 0000000000..87b958ab6d --- /dev/null +++ b/sdk/src/test/resources/certs/test-cert.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCX9WC+9qfCu7Lh +LTkm1XpYnIFowqlIAARHxWv08xbOIm/4bUtruuy0nOEVzzYiu8fdRP2LsBp9iKuR +JzBw6QOeASeepCorOFnU24bG3oAdjPHp7Bj76tM1GW5H8izOlln22My4asaOP4kx +C+LQt7aolF1Ca7A9J3TNEBxSaowUpCCDtwNnBTPoFa28vhFjga32BnNEZCTPWCrn +97WfDKj4trb+lQIt77jSBpPmwBJIqsOaM02uIlnF8MElX2TEUfMFGWAzDBmllB80 +cZHybC2Ic2nrYKuuHtpZrtMM6atGstxiHDt002p6yxUUEbcXE1SvB6ZGuBDw9frp +F7J5xnRQ7PAaKl17hXinnOPG/b3xtvOrx2rewWHHUxfCDzzaDcr1+31zfoW83wcw +fcuuS8E9iO4mIIYKoB+3C0430IMlqv61BVlHB9FajSEXhg8KIRDB8dZZGX4Y95te +RGv4s69Wr0gFFrPG5XJ0m4gS7mpkJeYwTrvtgb2Rm+D7vjxKR4xW8zSRnj4W644Y +SpBI9n/fCw3wmWAvs+2wt1m6JcvXyOFJPY96BQWE3eIGV052OCc69rXUhEV/vFRV +Nn4UJMCGptpJZiTM+/jvC94YEY2GzMu0jfuBYrnzeeasRnnVh6gfFKXui3xKGApm +Moqfd/2DogdmMXilZQ4SHinS6Bj0yQIDAQABAoICAAhIdiiSoLG1si93W+5+Tnf2 +t/sc4/CqcjvzSp+EgfwPK9P6fn+geyHxNze4HsxP42TFS54fUE0CySSqt9zqZqm9 +3bSrtXy7n/HsBscKU9NzM7CQ5Qpo/MWf3ZS1t7Q0b9z2aQUDFPr7WErAdMb0bKl4 +b4jyU8im65qjQ9fzj4UvLnKKOaOWSK5gQs3PUnqpE/Fy3TpKIdOHi8yEgnWT/BXq +km5YHaahXY1dPGykkEU+bFZtxiXgIM1FrVGQh0Py75tEjIDb1P4N5Tw3lewFR4ob +jcIod9M67U4G1eGV+cxrGCY6QbzBgBlcvokPL3q7hq8vweQy86wezGQuSCqTzb08 +pif1g3gkZmPJWArVl40gBv1Hz5PeFL1zlUSHjYz8NOuVOHWIqb1tXWrY+XH58QsC +0QCLc+vxUXxBfyEipcyGAqjp5Vv5zBbBWC1kmXOF1tPkXePOyEQuCHTPHiyuyeA3 +AhaiXd7RyQdEeqST9US9MQOpOqaqtE0wvbdWJGwAl4cslHozSLSALbN8TUmlgm5A +UN66BDUF7H3TYbbPeBC86nivtLeEToZDOprjiLrbNgbsXNG+WnYWtV+l0SIy09fY +fTOeyH1YDe/KzBSqsOhRNilDIIAX7TZuuyySyOQZAG62XTgKbem9ivs1cxpGMp4D +I+ZGmpeQunDHxMT3fMi9AoIBAQDSg3kDlj5e26I69WfhFn1sUI+eZo5BW/WLtvf9 +302vwmOqjy6XY/g9MMu6NsVkdNjpNAJrVkPr8QOWT8lyChaRRxPhPSbltfrZurJh +4zP2qXGogNUGLo1stXnIGhcWTE0anDf0x9zM6K6IM964BxFLFjFDE2o4Jxr3ge/R +zwZPcPm8zF8bLIzgbTsKGRigPyp38byXLWgWZ7SEtRAO60AwxyNieZYB4hU/5vx/ +WltkC9qdvOMX2QDAA51mSiXLvENX7MfnDjCPqJtWEYHoClPDpSgY2xua15bGCUdt +H1bYRawMfmcAajhplKYb5cL+4Gc4p2UF/UcY+mpflHebfkk7AoIBAQC4yvDQur8h +gtnhBhQuClHyrQyHQyk634/HbA5ZvPach4YNR2kC/R5YZS0yrzB3SiCOJScLE2TF +zfC0jeByYC4Yjr1oXDNNslNkRCjXhzJZiC2KWNLhEgm90/DLUPbIFMhOHDdyMcV6 +OWOlvZERKKFjFU3I0rqoFo36FeXt1GBk4B3U8rAIagJfPrMdS73V+PcSNKki1Ug3 +Ds45UR3n2ibS2Y+wCR5wWR4hogaoFjxSn1HwggZJ5FrIwd7U2kfthVltkl43TJZR +Fgd1BqWubY6QMumGjrF5DuLbi7/Qk9UwSkWi/yejGsB61eoZZIE53jNielioIp1u +pCkmmNbZiHnLAoIBACUfZCa6xvLpXllxT0lFMwb3yevQAAQMmGdz85WEXGnDKNo5 +96hgy7TWtwZ2hCar6FhvgIG3K7EexlgqZ8bBeqtR0nKk2wglKEBfCPf0HgTAareh +SG+Xo/7onboox6t59xrbM47p88j6u1RveTYQoP8RwcwnT1Lpqnq9IjJohJ9bt96Q +V7EuEQW+nWuxc0NHAFE4gt5R9ooE7bN9ToCjAaXYaCgEcuyQFtk2/Y3jvDwPTxUD +6zQYY2Z4/Le+GZ4s699EdRgMy4l53TK3UaY+s/jLVh/T+7E5lXAE0OCwZxsqZiWp +4LYVBS+xM/21bcaOggVel5UPzgrclgeW4eS8x2MCggEACJSLt/Vj2Id93F/u4fBi +u7TjRwiMSoqE34qZ4/rNLJlyVP2C17uvBAW2oorV4kQT3OXGuVHuNO0KBygrSsRC +f6tpCgZ1716fVqF/j/pcESIskybqq76tqx3DKX2Z59JnNpFC1c+PzswJX3G84aIU +VEhx8ygtuI5Li1gm8/MPgr+RQwj9uXZKo+eCY5LXvq6vsi21yMNEdiH+21Rz4gcU +FGg7rr3NpwPMTV17l6RoqqFxKYywBBBRUs8FrLZx7oppi5fnPgQVWrB+KiXj3YSC +wRlMFI5dmTRivjTv9BxZIsPgFeBpE76zP0DdfM5Y3bn+gs0RfsUUsEV5D6y7FSCs +HwKCAQEAz2K9KVwA/hocmUlAkH1jnT3lBtparZa5Be/KfLgqpmRp3ujgPbH1L+vL +vPUaAHJ0VScKwe0vY+FFFo+WDdAHnVEdcrolwoQ2oFV9/7wdtk1LS8VEFFdObrff +8wx20yy00yfLTcwrG3g3K9RCCD9/JdkhFahBNX+Vn+pBmgABGiu1gESKiNA/lUar +7Ki/eU2fUwgyHKXsYRhSrcw6aatHE/yJVUgyExjcdYyy0wPkSiwB0hEfyDv/yIOm +Hdce5kkMFRNcsp2E0nP3zpt0+lhbhGVal+8gkH2q0YucqZsIaF0Ha2jpUbIsE81A +mfPgTPwyRZiGKrz43GpgD0Zg/eytPw== +-----END PRIVATE KEY----- diff --git a/sdk/src/test/resources/certs/test-cert.pem b/sdk/src/test/resources/certs/test-cert.pem new file mode 100644 index 0000000000..00a8155f78 --- /dev/null +++ b/sdk/src/test/resources/certs/test-cert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFUzCCAzugAwIBAgIUbPytgC1pfbqeBSbdOok03mPcoU8wDQYJKoZIhvcNAQEL +BQAwOTENMAsGA1UECgwEREFQUjENMAsGA1UECwwEREFQUjEZMBcGA1UEAwwQVGVz +dCBDZXJ0aWZpY2F0ZTAeFw0yNTA4MjgxNTIzMzJaFw0yNzA4MjgxNTIzMzJaMDkx +DTALBgNVBAoMBERBUFIxDTALBgNVBAsMBERBUFIxGTAXBgNVBAMMEFRlc3QgQ2Vy +dGlmaWNhdGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCX9WC+9qfC +u7LhLTkm1XpYnIFowqlIAARHxWv08xbOIm/4bUtruuy0nOEVzzYiu8fdRP2LsBp9 +iKuRJzBw6QOeASeepCorOFnU24bG3oAdjPHp7Bj76tM1GW5H8izOlln22My4asaO +P4kxC+LQt7aolF1Ca7A9J3TNEBxSaowUpCCDtwNnBTPoFa28vhFjga32BnNEZCTP +WCrn97WfDKj4trb+lQIt77jSBpPmwBJIqsOaM02uIlnF8MElX2TEUfMFGWAzDBml +lB80cZHybC2Ic2nrYKuuHtpZrtMM6atGstxiHDt002p6yxUUEbcXE1SvB6ZGuBDw +9frpF7J5xnRQ7PAaKl17hXinnOPG/b3xtvOrx2rewWHHUxfCDzzaDcr1+31zfoW8 +3wcwfcuuS8E9iO4mIIYKoB+3C0430IMlqv61BVlHB9FajSEXhg8KIRDB8dZZGX4Y +95teRGv4s69Wr0gFFrPG5XJ0m4gS7mpkJeYwTrvtgb2Rm+D7vjxKR4xW8zSRnj4W +644YSpBI9n/fCw3wmWAvs+2wt1m6JcvXyOFJPY96BQWE3eIGV052OCc69rXUhEV/ +vFRVNn4UJMCGptpJZiTM+/jvC94YEY2GzMu0jfuBYrnzeeasRnnVh6gfFKXui3xK +GApmMoqfd/2DogdmMXilZQ4SHinS6Bj0yQIDAQABo1MwUTAdBgNVHQ4EFgQUuj4S +u+I/pBSJFGVoCK4y+QvGm/QwHwYDVR0jBBgwFoAUuj4Su+I/pBSJFGVoCK4y+QvG +m/QwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAR18zFnyf22+h +bLT8ab0fD6pLQUW0/yr0PpsNNrsnNbTMr+tgOQDZgi/jpnG8eQmyA5aVjBxgxBNq +BhXFMixVputyafbb+fCIGvwWAMGtKL3Jf2yYfn6IhMftMB2e3xp4hUNBfRC92fVT +McypKFf/bWPxk7ZDeZGwNK0CViB2XNDCPWvR+RxQI4stilpN47/fAQdpnAmcDVi6 +wVljILTaPhgpWj0Q3c6ccdgFE8ETRQK46dDW6C2KstIjqOxP4Go5HQw5bGTQVRPw +bX2v7kadLfFDJJDwmCRUNzQJfWM+8qROy8YgexFe5rBUkOOFCz2Wd2I0LjiN8SrP +aY3iEoZQO/bIUPJsi3qtLgb9HDZ6iXeB1SHEXnn/l0b1zpb2kumdhiNif2s1NXsw +LQV7xai3xrdT96fnWElqD39gHunLO2hCE4ra7YJ3yZnXyi21EdErhpCaD1aPo96d +0m/2rbIfafrBZFdcu4hvS56qtnVajOfXaN5bCKyRsByA8Ebv2XlWWWCRDii5ft/W +RYrRDZhC6t9dZNv1ObhDLzx/2FNq82lxhi4VCwlAy6Qdc8kY7uh92IWUUQoLonQB +QI0QuROI9W9Vc/DUJFvts/qCKWtD0XdoTVlZc/1B2WFbiwZ5U04x5inFBtudvyEL +ZEyQNL0MVlOgpxK3igY4xKM8r+m4bi4= +-----END CERTIFICATE-----