Repository: GoogleCloudPlatform/pgadapter
Pull request #165 (2022-06-01 05:30:29)

build: rename integration test job
Rename the integration test job so it is easier to reference in the Github configuration.


Patch:
diff --git a/.ci/evaluate-with-psql.sh b/.ci/evaluate-with-psql.sh
index e44e6001..873b542e 100644
--- a/.ci/evaluate-with-psql.sh
+++ b/.ci/evaluate-with-psql.sh
@@ -16,22 +16,22 @@ sed -i "s/---[-]*//g" .ci/e2e-expected/backslash-dn.txt
 sed -i "s/---[-]*//g" .ci/e2e-expected/backslash-dn-param.txt
 
 echo "------Test \"select 1::int8\"------"
-echo "select 1::int8;" | /usr/lib/postgresql/"${PSQL_VERSION}"/bin/psql -h localhost -p 4242 -d "${GOOGLE_CLOUD_DATABASE_WITH_VERSION}" > .ci/e2e-result/select-one.txt
+echo "select 1::int8;" | /usr/lib/postgresql/"${PSQL_VERSION}"/bin/psql -h /tmp -p 4242 -d "${GOOGLE_CLOUD_DATABASE_WITH_VERSION}" > .ci/e2e-result/select-one.txt
 diff -i -w -s .ci/e2e-result/select-one.txt .ci/e2e-expected/select-one.txt
 RETURN_CODE=$((${RETURN_CODE}||$?))
 
 echo "------Test \"select * from <tablename>\"------"
-echo "select * from users;" | /usr/lib/postgresql/"${PSQL_VERSION}"/bin/psql -h localhost -p 4242 -d "${GOOGLE_CLOUD_DATABASE_WITH_VERSION}" > .ci/e2e-result/select-all.txt
+echo "select * from users;" | /usr/lib/postgresql/"${PSQL_VERSION}"/bin/psql -h /tmp -p 4242 -d "${GOOGLE_CLOUD_DATABASE_WITH_VERSION}" > .ci/e2e-result/select-all.txt
 diff -i -w -s .ci/e2e-result/select-all.txt .ci/e2e-expected/select-all.txt
 RETURN_CODE=$((${RETURN_CODE}||$?))
 
 echo "------Test \"\\d\"------"
-echo "\d" | /usr/lib/postgresql/"${PSQL_VERSION}"/bin/psql -h localhost -p 4242 -d "${GOOGLE_CLOUD_DATABASE_WITH_VERSION}" > .ci/e2e-result/backslash-d.txt
+echo "\d" | /usr/lib/postgresql/"${PSQL_VERSION}"/bin/psql -h /tmp -p 4242 -d "${GOOGLE_CLOUD_DATABASE_WITH_VERSION}" > .ci/e2e-result/backslash-d.txt
 diff -i -w -s .ci/e2e-result/backslash-d.txt .ci/e2e-expected/backslash-d.txt
 RETURN_CODE=$((${RETURN_CODE}||$?))
 
 echo "------Test \"\\d <tablename>\"------"
-echo "\d users" | /usr/lib/postgresql/"${PSQL_VERSION}"/bin/psql -h localhost -p 4242 -d "${GOOGLE_CLOUD_DATABASE_WITH_VERSION}" > .ci/e2e-result/backslash-d-param.txt
+echo "\d users" | /usr/lib/postgresql/"${PSQL_VERSION}"/bin/psql -h /tmp -p 4242 -d "${GOOGLE_CLOUD_DATABASE_WITH_VERSION}" > .ci/e2e-result/backslash-d-param.txt
 diff -i -w -s .ci/e2e-result/backslash-d-param.txt .ci/e2e-expected/backslash-d-param.txt
 RETURN_CODE=$((${RETURN_CODE}||$?))
 
diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml
index 47944875..71bc0234 100644
--- a/.github/workflows/integration.yaml
+++ b/.github/workflows/integration.yaml
@@ -18,7 +18,7 @@ jobs:
         if: "${{ env.GCP_PROJECT_ID != '' }}"
         run: echo "::set-output name=defined::true"
 
-  test:
+  integration-test:
     needs: [check-env]
     if: needs.check-env.outputs.has-key == 'true'
     timeout-minutes: 30
diff --git a/README.md b/README.md
index c7932052..0557c1fe 100644
--- a/README.md
+++ b/README.md
@@ -151,7 +151,14 @@ The following options are optional:
 -s <port>
   * The inbound port for the proxy. Defaults to 5432. Choose a different port if you already have
     PostgreSQL running on your local system.
-   
+
+-dir <socket-file-directory>
+  * This proxy's domain socket directory. Defaults to '/tmp'.
+    Note: Some distributions of PostgreSQL and psql use '/var/run/postgresql' as the
+    default directory for Unix domain socket file names. When connecting to PGAdapter
+    using psql from one of these distributions, you either need to use 'psql -h /tmp'
+    or change the default Unix domain socket directory used by PGAdapter to '/var/run/postgresql'.
+
 -a
   * Use authentication when connecting. Currently authentication is not strictly
     implemented in the proxy layer, as it is expected to be run locally, and
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/ProxyServer.java b/src/main/java/com/google/cloud/spanner/pgadapter/ProxyServer.java
index 496f9939..1a00f5cc 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/ProxyServer.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/ProxyServer.java
@@ -202,7 +202,8 @@ public class ProxyServer extends AbstractApiService {
    * @throws IOException if ServerSocket cannot start.
    */
   void runTcpServer(CountDownLatch startupLatch, CountDownLatch stoppedLatch) throws IOException {
-    ServerSocket tcpSocket = new ServerSocket(this.options.getProxyPort());
+    ServerSocket tcpSocket =
+        new ServerSocket(this.options.getProxyPort(), this.options.getMaxBacklog());
     this.serverSockets.add(tcpSocket);
     this.localPort = tcpSocket.getLocalPort();
     tcpStartedLatch.countDown();
@@ -211,16 +212,30 @@ public class ProxyServer extends AbstractApiService {
 
   void runDomainSocketServer(CountDownLatch startupLatch, CountDownLatch stoppedLatch)
       throws IOException, InterruptedException {
-    // Wait until the TCP server has started, so we can get the port number it is using.
-    if (!tcpStartedLatch.await(30L, TimeUnit.SECONDS)) {
+    // Wait until the TCP server has started if it is using a dynamic port, so we can get the port
+    // number it is using.
+    if (options.getProxyPort() == 0 && !tcpStartedLatch.await(30L, TimeUnit.SECONDS)) {
       throw SpannerExceptionFactory.newSpannerException(
           ErrorCode.DEADLINE_EXCEEDED, "Timeout while waiting for TCP server to start");
     }
     File tempDir = new File(this.options.getSocketFile(getLocalPort()));
-    AFUNIXServerSocket domainSocket = AFUNIXServerSocket.newInstance();
-    domainSocket.bind(AFUNIXSocketAddress.of(tempDir));
-    this.serverSockets.add(domainSocket);
-    runServer(domainSocket, startupLatch, stoppedLatch);
+    try {
+      if (tempDir.getParentFile() != null && !tempDir.getParentFile().exists()) {
+        tempDir.mkdirs();
+      }
+      AFUNIXServerSocket domainSocket = AFUNIXServerSocket.newInstance();
+      domainSocket.bind(AFUNIXSocketAddress.of(tempDir), this.options.getMaxBacklog());
+      this.serverSockets.add(domainSocket);
+      runServer(domainSocket, startupLatch, stoppedLatch);
+    } catch (SocketException socketException) {
+      logger.log(
+          Level.SEVERE,
+          String.format(
+              "Failed to bind to Unix domain socket. Please verify that the user running PGAdapter has write permission for file %s",
+              tempDir),
+          socketException);
+      startupLatch.countDown();
+    }
   }
 
   void runServer(
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadata.java b/src/main/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadata.java
index 211fc45f..3dddf719 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadata.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadata.java
@@ -19,6 +19,7 @@ import com.google.cloud.spanner.SpannerExceptionFactory;
 import com.google.cloud.spanner.pgadapter.Server;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
+import java.io.File;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
@@ -61,7 +62,8 @@ public class OptionsMetadata {
   private static final String DEFAULT_USER_AGENT = "pg-adapter";
 
   private static final String OPTION_SERVER_PORT = "s";
-  private static final String OPTION_SOCKET_FILE = "f";
+  private static final String OPTION_SOCKET_DIR = "dir";
+  private static final String OPTION_MAX_BACKLOG = "max_backlog";
   private static final String OPTION_PROJECT_ID = "p";
   private static final String OPTION_INSTANCE_ID = "i";
   private static final String OPTION_DATABASE_NAME = "d";
@@ -78,7 +80,9 @@ public class OptionsMetadata {
   private static final String OPTION_HELP = "h";
   private static final String DEFAULT_PORT = "5432";
   private static final int MIN_PORT = 0, MAX_PORT = 65535;
-  private static final String DEFAULT_SOCKET_FILE = "/tmp/.s.PGSQL.%d";
+  private static final String DEFAULT_SOCKET_DIR = "/tmp";
+  private static final String SOCKET_FILE_NAME = ".s.PGSQL.%d";
+  private static final int DEFAULT_MAX_BACKLOG = 1000;
   /*Note: this is a private preview feature, not meant for GA version. */
   private static final String OPTION_SPANNER_ENDPOINT = "e";
   private static final String OPTION_JDBC_PROPERTIES = "r";
@@ -91,6 +95,7 @@ public class OptionsMetadata {
   private final String defaultConnectionUrl;
   private final int proxyPort;
   private final String socketFile;
+  private final int maxBacklog;
   private final TextFormat textFormat;
   private final boolean binaryFormat;
   private final boolean authenticate;
@@ -119,6 +124,7 @@ public class OptionsMetadata {
     }
     this.proxyPort = buildProxyPort(commandLine);
     this.socketFile = buildSocketFile(commandLine);
+    this.maxBacklog = buildMaxBacklog(commandLine);
     this.textFormat = TextFormat.POSTGRESQL;
     this.binaryFormat = commandLine.hasOption(OPTION_BINARY_FORMAT);
     this.authenticate = commandLine.hasOption(OPTION_AUTHENTICATE);
@@ -171,7 +177,8 @@ public class OptionsMetadata {
     this.commandMetadataParser = new CommandMetadataParser();
     this.defaultConnectionUrl = defaultConnectionUrl;
     this.proxyPort = proxyPort;
-    this.socketFile = isWindows() ? "" : DEFAULT_SOCKET_FILE;
+    this.socketFile = isWindows() ? "" : DEFAULT_SOCKET_DIR + File.separatorChar + SOCKET_FILE_NAME;
+    this.maxBacklog = DEFAULT_MAX_BACKLOG;
     this.textFormat = textFormat;
     this.binaryFormat = forceBinary;
     this.authenticate = authenticate;
@@ -230,9 +237,27 @@ public class OptionsMetadata {
 
   private String buildSocketFile(CommandLine commandLine) {
     // Unix domain sockets are disabled by default on Windows.
-    return commandLine
-        .getOptionValue(OPTION_SOCKET_FILE, isWindows() ? "" : DEFAULT_SOCKET_FILE)
-        .trim();
+    String directory =
+        commandLine.getOptionValue(OPTION_SOCKET_DIR, isWindows() ? "" : DEFAULT_SOCKET_DIR).trim();
+    if (!Strings.isNullOrEmpty(directory)) {
+      if (directory.charAt(directory.length() - 1) != File.separatorChar) {
+        directory += File.separatorChar;
+      }
+      return directory + SOCKET_FILE_NAME;
+    }
+    return "";
+  }
+
+  private int buildMaxBacklog(CommandLine commandLine) {
+    int backlog =
+        Integer.parseInt(
+            commandLine
+                .getOptionValue(OPTION_MAX_BACKLOG, String.valueOf(DEFAULT_MAX_BACKLOG))
+                .trim());
+    if (backlog <= 0) {
+      throw new IllegalArgumentException("Max backlog must be greater than 0");
+    }
+    return backlog;
   }
 
   /**
@@ -348,14 +373,20 @@ public class OptionsMetadata {
     options.addOption(
         OPTION_SERVER_PORT, "server-port", true, "This proxy's port number (Default 5432).");
     options.addOption(
-        OPTION_SOCKET_FILE,
-        "server-socket-file",
+        null,
+        OPTION_SOCKET_DIR,
         true,
         String.format(
-            "This proxy's domain socket file (Default %s). "
+            "This proxy's domain socket directory (Default %s). "
                 + "Domain sockets are disabled by default on Windows. Set this property to a non-empty value on Windows to enable domain sockets. "
                 + "Set this property to the empty string on other operating systems to disable domain sockets.",
-            String.format(DEFAULT_SOCKET_FILE, 5432)));
+            DEFAULT_SOCKET_DIR));
+    options.addOption(
+        null,
+        OPTION_MAX_BACKLOG,
+        true,
+        String.format(
+            "Maximum queue length of incoming connections. Defaults to %d.", DEFAULT_MAX_BACKLOG));
     options.addRequiredOption(
         OPTION_PROJECT_ID,
         "project",
@@ -551,6 +582,10 @@ public class OptionsMetadata {
     return String.format(this.socketFile, localPort);
   }
 
+  public int getMaxBacklog() {
+    return this.maxBacklog;
+  }
+
   public TextFormat getTextFormat() {
     return this.textFormat;
   }
@@ -581,7 +616,7 @@ public class OptionsMetadata {
 
   /** Returns true if the OS is Windows. */
   public boolean isWindows() {
-    return osName.toLowerCase().contains("win");
+    return osName.toLowerCase().startsWith("windows");
   }
 
   /**
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/BindMessage.java b/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/BindMessage.java
index 402a2f07..2c07e78e 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/BindMessage.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/BindMessage.java
@@ -29,7 +29,6 @@ import java.util.List;
  */
 @InternalApi
 public class BindMessage extends ControlMessage {
-
   protected static final char IDENTIFIER = 'B';
 
   private String portalName;
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/ExecuteMessage.java b/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/ExecuteMessage.java
index 833dfedb..bdcbb304 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/ExecuteMessage.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/ExecuteMessage.java
@@ -23,7 +23,6 @@ import java.text.MessageFormat;
 /** Executes a portal. */
 @InternalApi
 public class ExecuteMessage extends ControlMessage {
-
   protected static final char IDENTIFIER = 'E';
 
   private String name;
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/ParseMessage.java b/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/ParseMessage.java
index 0f770e6b..fb94c1f3 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/ParseMessage.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/wireprotocol/ParseMessage.java
@@ -23,7 +23,6 @@ import com.google.cloud.spanner.pgadapter.ConnectionHandler;
 import com.google.cloud.spanner.pgadapter.statements.IntermediatePreparedStatement;
 import com.google.cloud.spanner.pgadapter.wireoutput.ParseCompleteResponse;
 import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
 import java.text.MessageFormat;
 
 /** Creates a prepared statement. */
@@ -41,7 +40,6 @@ public class ParseMessage extends ControlMessage {
     super(connection);
     this.name = this.readString();
     ParsedStatement parsedStatement = PARSER.parse(Statement.of(this.readString()));
-    ImmutableList.Builder<Integer> builder = ImmutableList.builder();
     short numberOfParameters = this.inputStream.readShort();
     this.parameterDataTypes = new int[numberOfParameters];
     for (int i = 0; i < numberOfParameters; i++) {


Test patch:
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/AbstractMockServerTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/AbstractMockServerTest.java
index 76363ed5..587d46c8 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/AbstractMockServerTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/AbstractMockServerTest.java
@@ -368,13 +368,15 @@ public abstract class AbstractMockServerTest {
 
   @AfterClass
   public static void stopMockSpannerAndPgAdapterServers() throws Exception {
-    try {
-      pgServer.stopServer();
-    } catch (IllegalStateException exception) {
-      logger.warning(
-          String.format(
-              "Ignoring %s as this can happen if the server is sent multiple invalid messages",
-              exception.getMessage()));
+    if (pgServer != null) {
+      try {
+        pgServer.stopServer();
+      } catch (IllegalStateException exception) {
+        logger.warning(
+            String.format(
+                "Ignoring %s as this can happen if the server is sent multiple invalid messages",
+                exception.getMessage()));
+      }
     }
     try {
       SpannerPool.closeSpannerPool();
@@ -393,8 +395,10 @@ public abstract class AbstractMockServerTest {
         throw exception;
       }
     }
-    spannerServer.shutdown();
-    spannerServer.awaitTermination(10L, TimeUnit.SECONDS);
+    if (spannerServer != null) {
+      spannerServer.shutdown();
+      spannerServer.awaitTermination(10L, TimeUnit.SECONDS);
+    }
   }
 
   /**
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/DomainSocketsTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/DomainSocketsTest.java
new file mode 100644
index 00000000..5538462e
--- /dev/null
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/DomainSocketsTest.java
@@ -0,0 +1,129 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.cloud.spanner.pgadapter;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+
+import com.google.common.collect.ImmutableList;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collections;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class DomainSocketsTest extends AbstractMockServerTest {
+
+  @BeforeClass
+  public static void startMockSpannerAndPgAdapterServers() throws Exception {
+    // Hide the implementation in the base class to prevent PGAdapter to be started for the test
+    // class.
+    assumeFalse(
+        "Domain sockets are disabled by default on Windows",
+        System.getProperty("os.name", "").toLowerCase().startsWith("windows"));
+    // Make sure the PG JDBC driver is loaded.
+    Class.forName("org.postgresql.Driver");
+  }
+
+  @Before
+  @Override
+  public void clearRequests() {}
+
+  private String createUrl(String socketFile) {
+    return String.format(
+        "jdbc:postgresql://localhost/?"
+            + "socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory$FactoryArg"
+            + "&socketFactoryArg="
+            + socketFile
+            + "&preferQueryMode=simple",
+        pgServer.getLocalPort());
+  }
+
+  @Test
+  public void testDefaultDomainSocketFile() throws Exception {
+    doStartMockSpannerAndPgAdapterServers(null, Collections.emptyList());
+
+    String sql = "SELECT 1";
+
+    try (Connection connection = DriverManager.getConnection(createUrl("/tmp/.s.PGSQL.%d"))) {
+      try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) {
+        assertTrue(resultSet.next());
+        assertEquals(1L, resultSet.getLong(1));
+        assertFalse(resultSet.next());
+      }
+    }
+
+    stopMockSpannerAndPgAdapterServers();
+  }
+
+  @Test
+  public void testCustomDomainSocketFile() throws Exception {
+    doStartMockSpannerAndPgAdapterServers(null, ImmutableList.of("-dir", "./"));
+
+    String sql = "SELECT 1";
+
+    try (Connection connection = DriverManager.getConnection(createUrl("./.s.PGSQL.%d"))) {
+      try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) {
+        assertTrue(resultSet.next());
+        assertEquals(1L, resultSet.getLong(1));
+        assertFalse(resultSet.next());
+      }
+    }
+
+    stopMockSpannerAndPgAdapterServers();
+  }
+
+  @Test
+  public void testConnectionFailsForIncorrectDomainSocketFile() throws Exception {
+    doStartMockSpannerAndPgAdapterServers(null, ImmutableList.of("-dir", "./sockets"));
+
+    assertThrows(SQLException.class, () -> DriverManager.getConnection(createUrl("./.s.PGSQL.%d")));
+
+    stopMockSpannerAndPgAdapterServers();
+  }
+
+  @Test
+  public void testPGAdapterStartFailsWithInvalidSocketFile() throws Exception {
+    doStartMockSpannerAndPgAdapterServers(null, ImmutableList.of("-dir", "/"));
+
+    // Verify that we cannot connect to the invalid (not permitted) domain socket.
+    assertThrows(SQLException.class, () -> DriverManager.getConnection(createUrl("/.s.PGSQL.%d")));
+
+    // Verify that the TCP socket does work.
+    String sql = "SELECT 1";
+    try (Connection connection =
+        DriverManager.getConnection(
+            String.format(
+                "jdbc:postgresql://localhost:%d/my-db?preferQueryMode=simple",
+                pgServer.getLocalPort()))) {
+      try (ResultSet resultSet = connection.createStatement().executeQuery(sql)) {
+        assertTrue(resultSet.next());
+        assertEquals(1L, resultSet.getLong(1));
+        assertFalse(resultSet.next());
+      }
+    }
+
+    stopMockSpannerAndPgAdapterServers();
+  }
+}
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadataTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadataTest.java
index ba3d9eb2..4b6a8328 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadataTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadataTest.java
@@ -18,6 +18,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import java.io.File;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -33,7 +34,7 @@ public class OptionsMetadataTest {
         assertEquals("", options.getSocketFile(5432));
         assertFalse(options.isDomainSocketEnabled());
       } else {
-        assertEquals("/tmp/.s.PGSQL.5432", options.getSocketFile(5432));
+        assertEquals("/tmp" + File.separator + ".s.PGSQL.5432", options.getSocketFile(5432));
         assertTrue(options.isDomainSocketEnabled());
       }
     }
@@ -43,9 +44,23 @@ public class OptionsMetadataTest {
   public void testCustomDomainSocketFile() {
     for (String os : new String[] {"ubuntu", "windows"}) {
       OptionsMetadata options =
-          new OptionsMetadata(os, new String[] {"-p p", "-i i", "-f /tmp/.my-socket.%d"});
-      assertEquals("/tmp/.my-socket.5432", options.getSocketFile(5432));
+          new OptionsMetadata(os, new String[] {"-p p", "-i i", "-c \"\"", "-dir /pgadapter"});
+      assertEquals(
+          "/pgadapter" + File.separatorChar + ".s.PGSQL.5432", options.getSocketFile(5432));
       assertTrue(options.isDomainSocketEnabled());
     }
   }
+
+  @Test
+  public void testDefaultMaxBacklog() {
+    OptionsMetadata options = new OptionsMetadata(new String[] {"-p p", "-i i"});
+    assertEquals(1000, options.getMaxBacklog());
+  }
+
+  @Test
+  public void testCustomMaxBacklog() {
+    OptionsMetadata options =
+        new OptionsMetadata(new String[] {"-p p", "-i i", "-max_backlog 100"});
+    assertEquals(100, options.getMaxBacklog());
+  }
 }