snippetsqlModerate
How can I fake inet_client_addr() for unit tests in PostgreSQL?
Viewed 0 times
postgresqlcaninet_client_addrtestsforhowunitfake
Problem
I have a simple stored procedure whose return value depends on the value of
The only solution I've come up with so far is to create a wrapper function around
Then use that in my function:
Then in my unit test, I can re-define
Is there any way to accomplish the same without the wrapper function
inet_client_addr(). How can I override inet_client_addr() for the purpose of unit tests when testing my stored procedure?The only solution I've come up with so far is to create a wrapper function around
inet_client_addr():CREATE FUNCTION my_inet_client_addr() RETURNS INET AS $
SELECT inet_client_addr();
$ LANGUAGE sql;Then use that in my function:
CREATE local_connection() RETURNS BOOLEAN AS $
SELECT my_inet_client_addr() = '127.0.0.1';
$ LANGUAGE sql;Then in my unit test, I can re-define
my_inet_client_addr():BEGIN;
SELECT PLAN(2);
REPLACE FUNCTION my_inet_client_addr() RETURNS INET AS $
SELECT '127.0.0.1'::INET;
$ LANGUAGE sql;
is(local_connection(),TRUE,'Connection from 127.0.0.1 is local');
REPLACE FUNCTION my_inet_client_addr() RETURNS INET AS $
SELECT '192.168.1.1'::INET;
$ LANGUAGE sql;
is(local_connection(),FALSE,'Connection from 192.168.1.1. is not local');
ROLLBACK;Is there any way to accomplish the same without the wrapper function
my_inet_client_addr()?Solution
inet_client_addr() is a system information function.It is located in the schema
pg_catalog like other built-in functions (except for additional modules).pg_catalog is automatically part of the search_path. Per documentation:In addition to
public and user-created schemas, each database containsa
pg_catalog schema, which contains the system tables and all thebuilt-in data types, functions, and operators.
pg_catalog is alwayseffectively part of the search path. If it is not named explicitly in
the path then it is implicitly searched before searching the path's
schemas. This ensures that built-in names will always be findable.
However, you can explicitly place
pg_catalog at the end of your searchpath if you prefer to have user-defined names override built-in names.
Bold emphasis mine.
So we create a dedicated schema and place it before
pg_catalog in the search_path:CREATE SCHEMA override;
CREATE OR REPLACE FUNCTION override.inet_client_addr()
RETURNS inet LANGUAGE sql IMMUTABLE PARALLEL SAFE AS
$func$
SELECT '127.0.0.1'::inet
$func$;
SET search_path = override, pg_catalog, public;Then your call finds your custom override-function first:
SELECT inet_client_addr();db<>fiddle here
Make sure, unprivileged users cannot create objects in the
override schema, or they can play all kinds of tricks on you. That's not the case by default. Per documentation:No privileges are granted to PUBLIC by default on tables, columns, schemas or tablespaces.
Bold emphasis mine.
Care is needed if the same user should be allowed to create objects in the database.
Per documentation:
The first schema named in the search path is called the current
schema. Aside from being the first schema searched, it is also the
schema in which new tables will be created if the
CREATE TABLE commanddoes not specify a schema name.
Always specify a schema name for
CREATE commands, and disallow creating object to all by default to rule out mistakes.Code Snippets
CREATE SCHEMA override;
CREATE OR REPLACE FUNCTION override.inet_client_addr()
RETURNS inet LANGUAGE sql IMMUTABLE PARALLEL SAFE AS
$func$
SELECT '127.0.0.1'::inet
$func$;
SET search_path = override, pg_catalog, public;SELECT inet_client_addr();Context
StackExchange Database Administrators Q#69988, answer score: 12
Revisions (0)
No revisions yet.