Re: Binding Postgres to port 0 for testing

From: Markus Pilman <markus(at)pilman(dot)ch>
To: Michael Paquier <michael(at)paquier(dot)xyz>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: Binding Postgres to port 0 for testing
Date: 2023-03-27 04:49:33
Message-ID: CALavoow6oTvy5fFZ9c5Pcyc6Sga51XdFDEt87pRQLs5RmaFjYw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

Thanks Michael and Erik for the help, I really appreciate it!

Thanks for explaining the context why PostgreSQL doesn't allow binding
against port 0.

I somehow didn't consider looking at the postgres tests, though it makes
sense that they need to solve this problem. If I read the perl code
correctly though it seems that this could, in theory, cause a race? The
script checks first whether the port has been assigned to a test, then
binds a socket to check whether it is used by someone else, closes this
test socker, and then starts a server process. I guess it's unlikely
enough, but isn't there a risk that some other process (that isn't
controlled by this perl script) binds to the found port right after this
test bind but right before postgres calls bind? I guess it should be rare
enough so that it wouldn't cause flaky tests.

I decided to implement the following (this strategy works, though it might
be a bit brittle if PostgreSQL changes the error output format in the
future):
1. Loop, starting from port 5432, incrementing each iteration
2. Start postgres with the given port
3. Parse the output to check whether postgres either writes a line that
ends with "could not create any TCP/IP sockets" (in which case I continue)
or with "database system is ready to accept connections" (in which case I
break).

This is definitely not the most elegant solution, but it should do for now.
At the moment I want to be able to set up everything in one process. In my
experience this makes debugging problems a bit easier but comes at the cost
of a more complex test driver (I recognize that it is a bit weird that the
application layer initializes the runtime environment in this case).

Also, this is a hobby-project and I am more interested in fun learning than
reducing work :) Generally I would agree that reusing existing and testing
code to run this would be better unless there's a really good reason not to
do that.

On Sun, Mar 26, 2023 at 7:27 PM Michael Paquier <michael(at)paquier(dot)xyz> wrote:

> On Sat, Mar 25, 2023 at 11:01:33AM -0600, Markus Pilman wrote:
> > Now the problem is that I need to find a TCP port for each running
> postgres
> > instance. There's multiple ways to do this, but by far the easiest one I
> > know is to bind to port 0. So my plan was to start postgres with "-p 0"
> and
> > then parse stdout to figure out which port it actually uses. But that
> > doesn't seem to work:
>
> Note that you can find some inspiration about that in the code tree
> within src/test/perl/PostgreSQL/Test/Cluster.pm, particularly
> get_free_port(), where we have now accumulated a couple of years of
> experience in designing something that's rather safe, even if it comes
> with its own limits. It is in perl so perhaps you could just reuse it
> rather than reinvent the wheel? Of course, still it should not be
> complicated to translate that in a different language, but there may
> be no need to reinvent the wheel. And seeing your first message with
> the requirements you list, this does what you are looking for:
> - Create an empty cluster.
> - Freely create databases, tablespaces, queries, etc.
> - Wipe out the whole.
>
> The test cases around src/test/recovery/t/ could be a good starting
> point, as well.
> --
> Michael
>

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Michael Paquier 2023-03-27 05:10:30 Re: Binding Postgres to port 0 for testing
Previous Message vignesh C 2023-03-27 03:57:48 Re: Support logical replication of DDLs