Skip to content

Commit fb4c38c

Browse files
test: E2E test for pgbouncer connections
1 parent bc566cc commit fb4c38c

12 files changed

+333
-45
lines changed

pkg/specs/pgbouncer/deployments.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ const (
3131
// the hash of the Pooler Specification
3232
PgbouncerPoolerSpecHash = specs.MetadataNamespace + "/poolerSpecHash"
3333

34-
pgbouncerNameLabel = specs.MetadataNamespace + "/poolerName"
34+
// PgbouncerNameLabel is the label of the pgbouncer pod used by default
35+
PgbouncerNameLabel = specs.MetadataNamespace + "/poolerName"
3536

3637
// DefaultPgbouncerImage is the name of the pgbouncer image used by default
3738
DefaultPgbouncerImage = "quay.io/enterprisedb/pgbouncer:1.16.0-1"
@@ -50,7 +51,7 @@ func Deployment(pooler *apiv1.Pooler,
5051

5152
podTemplate := podspec.NewFrom(pooler.Spec.Template).
5253
WithAnnotation(PgbouncerConfigVersionAnnotation, configuration.ResourceVersion).
53-
WithLabel(pgbouncerNameLabel, pooler.Name).
54+
WithLabel(PgbouncerNameLabel, pooler.Name).
5455
WithVolume(&corev1.Volume{
5556
Name: "ca",
5657
VolumeSource: corev1.VolumeSource{
@@ -148,7 +149,7 @@ func Deployment(pooler *apiv1.Pooler,
148149
Replicas: &pooler.Spec.Instances,
149150
Selector: &metav1.LabelSelector{
150151
MatchLabels: map[string]string{
151-
pgbouncerNameLabel: pooler.Name,
152+
PgbouncerNameLabel: pooler.Name,
152153
},
153154
},
154155
Template: corev1.PodTemplateSpec{

pkg/specs/pgbouncer/services.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func Service(pooler *apiv1.Pooler) *corev1.Service {
3333
},
3434
},
3535
Selector: map[string]string{
36-
pgbouncerNameLabel: pooler.Name,
36+
PgbouncerNameLabel: pooler.Name,
3737
},
3838
},
3939
}

tests/e2e/asserts_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,3 +492,57 @@ func AssertReplicaModeCluster(
492492
}, 180, 15).Should(BeEquivalentTo("3"))
493493
})
494494
}
495+
496+
func AssertWritesToReplicaFails(
497+
connectingPod *corev1.Pod,
498+
service string,
499+
appDBName string,
500+
appDBUser string,
501+
appDBPass string) {
502+
By(fmt.Sprintf("Verifying %v service doesn't allow writes", service),
503+
func() {
504+
timeout := time.Second * 2
505+
506+
dsn := fmt.Sprintf("host=%v user=%v dbname=%v password=%v sslmode=require",
507+
service, appDBUser, appDBName, appDBPass)
508+
509+
// Expect to be connected to a replica
510+
stdout, _, err := env.ExecCommand(env.Ctx, *connectingPod, "postgres", &timeout,
511+
"psql", dsn, "-tAc", "select pg_is_in_recovery()")
512+
value := strings.Trim(stdout, "\n")
513+
Expect(value, err).To(Equal("t"))
514+
515+
// Expect to be in a read-only transaction
516+
_, _, err = env.ExecCommand(env.Ctx, *connectingPod, "postgres", &timeout,
517+
"psql", dsn, "-tAc", "CREATE TABLE table1(var1 text);")
518+
Expect(err).To(HaveOccurred())
519+
Expect(err.Error()).Should(
520+
ContainSubstring("cannot execute CREATE TABLE in a read-only transaction"))
521+
})
522+
}
523+
524+
func AssertWritesToPrimarySucceeds(
525+
connectingPod *corev1.Pod,
526+
service string,
527+
appDBName string,
528+
appDBUser string,
529+
appDBPass string) {
530+
By(fmt.Sprintf("Verifying %v service correctly manages writes", service),
531+
func() {
532+
timeout := time.Second * 2
533+
534+
dsn := fmt.Sprintf("host=%v user=%v dbname=%v password=%v sslmode=require",
535+
service, appDBUser, appDBName, appDBPass)
536+
537+
// Expect to be connected to a primary
538+
stdout, _, err := env.ExecCommand(env.Ctx, *connectingPod, "postgres", &timeout,
539+
"psql", dsn, "-tAc", "select pg_is_in_recovery()")
540+
value := strings.Trim(stdout, "\n")
541+
Expect(value, err).To(Equal("f"))
542+
543+
// Expect to be able to write
544+
_, _, err = env.ExecCommand(env.Ctx, *connectingPod, "postgres", &timeout,
545+
"psql", dsn, "-tAc", "CREATE TABLE table1(var1 text);")
546+
Expect(err).ToNot(HaveOccurred())
547+
})
548+
}

tests/e2e/connection_test.go

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ package e2e
88

99
import (
1010
"fmt"
11-
"strings"
12-
"time"
1311

1412
corev1 "k8s.io/api/core/v1"
1513
"k8s.io/apimachinery/pkg/types"
@@ -27,43 +25,6 @@ var _ = Describe("Connection via services", func() {
2725
const appDBName = "appdb"
2826
const appDBUser = "appuser"
2927

30-
AssertVerifyWrites := func(
31-
connectingPod *corev1.Pod,
32-
service string,
33-
appDBName string,
34-
appDBUser string,
35-
appDBPass string,
36-
isReplica bool) {
37-
By(fmt.Sprintf("Verifying %v service correctly manages writes", service),
38-
func() {
39-
timeout := time.Second * 2
40-
41-
dsn := fmt.Sprintf("host=%v user=%v dbname=%v password=%v sslmode=require",
42-
service, appDBUser, appDBName, appDBPass)
43-
44-
// Expect to be connected to a replica
45-
stdout, _, err := env.ExecCommand(env.Ctx, *connectingPod, "postgres", &timeout,
46-
"psql", dsn, "-tAc", "select pg_is_in_recovery()")
47-
value := strings.Trim(stdout, "\n")
48-
if isReplica {
49-
Expect(value, err).To(Equal("t"))
50-
} else {
51-
Expect(value, err).To(Equal("f"))
52-
}
53-
54-
// Expect to be in a read-only transaction
55-
_, _, err = env.ExecCommand(env.Ctx, *connectingPod, "postgres", &timeout,
56-
"psql", dsn, "-tAc", "CREATE TABLE table1(var1 text);")
57-
if isReplica {
58-
Expect(err).To(HaveOccurred())
59-
Expect(err.Error()).Should(
60-
ContainSubstring("cannot execute CREATE TABLE in a read-only transaction"))
61-
} else {
62-
Expect(err).ToNot(HaveOccurred())
63-
}
64-
})
65-
}
66-
6728
AssertServices := func(namespace string,
6829
clusterName string,
6930
appDBName string,
@@ -93,8 +54,8 @@ var _ = Describe("Connection via services", func() {
9354
AssertConnection(service, appDBUser, appDBName, appPassword, *pod, 10, env)
9455
}
9556

96-
AssertVerifyWrites(pod, roService, appDBName, appDBUser, appPassword, true)
97-
AssertVerifyWrites(pod, rwService, appDBName, appDBUser, appPassword, false)
57+
AssertWritesToReplicaFails(pod, roService, appDBName, appDBUser, appPassword)
58+
AssertWritesToPrimarySucceeds(pod, rwService, appDBName, appDBUser, appPassword)
9859
}
9960

10061
Context("Auto-generated passwords", func() {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cluster-pgbouncer.yaml
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
apiVersion: postgresql.k8s.enterprisedb.io/v1
2+
kind: Cluster
3+
metadata:
4+
name: cluster-pgbouncer
5+
spec:
6+
instances: 3
7+
8+
postgresql:
9+
parameters:
10+
log_checkpoints: "on"
11+
log_lock_waits: "on"
12+
log_min_duration_statement: '1000'
13+
log_statement: 'ddl'
14+
log_temp_files: '1024'
15+
log_autovacuum_min_duration: '1s'
16+
log_replication_commands: 'on'
17+
18+
bootstrap:
19+
initdb:
20+
database: app
21+
owner: app
22+
23+
# Persistent storage configuration
24+
storage:
25+
storageClass: ${E2E_DEFAULT_STORAGE_CLASS}
26+
size: 1Gi
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
apiVersion: postgresql.k8s.enterprisedb.io/v1
2+
kind: Pooler
3+
metadata:
4+
name: pooler-connection-basic-auth-ro
5+
spec:
6+
cluster:
7+
name: cluster-pgbouncer
8+
9+
instances: 1
10+
type: ro
11+
pgbouncer:
12+
poolMode: session
13+
authQuerySecret:
14+
name: cluster-pgbouncer-superuser
15+
authQuery: SELECT usename, passwd FROM pg_shadow WHERE usename=$1
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
apiVersion: postgresql.k8s.enterprisedb.io/v1
2+
kind: Pooler
3+
metadata:
4+
name: pooler-connection-basic-auth-rw
5+
spec:
6+
cluster:
7+
name: cluster-pgbouncer
8+
9+
instances: 1
10+
type: rw
11+
pgbouncer:
12+
poolMode: session
13+
authQuerySecret:
14+
name: cluster-pgbouncer-superuser
15+
authQuery: SELECT usename, passwd FROM pg_shadow WHERE usename=$1
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
apiVersion: postgresql.k8s.enterprisedb.io/v1
2+
kind: Pooler
3+
metadata:
4+
name: pooler-connection-tls-ro
5+
spec:
6+
cluster:
7+
name: cluster-pgbouncer
8+
9+
instances: 1
10+
type: ro
11+
pgbouncer:
12+
poolMode: session
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
apiVersion: postgresql.k8s.enterprisedb.io/v1
2+
kind: Pooler
3+
metadata:
4+
name: pooler-connection-tls-rw
5+
spec:
6+
cluster:
7+
name: cluster-pgbouncer
8+
9+
instances: 1
10+
type: rw
11+
pgbouncer:
12+
poolMode: session

0 commit comments

Comments
 (0)