Skip to content

Commit eef1b04

Browse files
GODRIVER-3548 Test MONGODB-X509 on cloud-dev (#2166)
Co-authored-by: Copilot <[email protected]>
1 parent 99707bc commit eef1b04

File tree

4 files changed

+236
-50
lines changed

4 files changed

+236
-50
lines changed

Taskfile.yml

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ dotenv: ['.test.env']
1010
tasks:
1111

1212
### Utility tasks. ###
13-
default:
13+
default:
1414
deps: [build, check-license, check-fmt, check-modules, lint, test-short]
1515

1616
add-license: bash etc/check_license.sh -a
@@ -36,15 +36,15 @@ tasks:
3636

3737
build-aws-ecs-test: go test -c ./internal/test/aws -o aws.testbin
3838

39-
cross-compile:
39+
cross-compile:
4040
- GOOS=linux GOARCH=386 go build ./...
4141
- GOOS=linux GOARCH=arm go build ./...
4242
- GOOS=linux GOARCH=arm64 go build ./...
4343
- GOOS=linux GOARCH=amd64 go build ./...
4444
- GOOS=linux GOARCH=ppc64le go build ./...
4545
- GOOS=linux GOARCH=s390x go build ./...
4646

47-
check-fmt:
47+
check-fmt:
4848
deps: [install-lll]
4949
cmds:
5050
- bash etc/check_fmt.sh
@@ -57,9 +57,9 @@ tasks:
5757

5858
api-report: bash etc/api_report.sh
5959

60-
install-libmongocrypt:
60+
install-libmongocrypt:
6161
cmds: [bash etc/install-libmongocrypt.sh]
62-
status:
62+
status:
6363
- test -d install || test -d /cygdrive/c/libmongocrypt/bin
6464

6565
run-docker: bash etc/run_docker.sh
@@ -76,7 +76,7 @@ tasks:
7676
# specific operating systems or architectures. For example, staticcheck will only check for 64-bit
7777
# alignment of atomically accessed variables on 32-bit architectures (see
7878
# https://staticcheck.io/docs/checks#SA1027)
79-
lint:
79+
lint:
8080
cmds:
8181
- GOOS=linux GOARCH=386 etc/golangci-lint.sh
8282
- GOOS=linux GOARCH=arm etc/golangci-lint.sh
@@ -104,8 +104,8 @@ tasks:
104104

105105
test-oidc-remote: bash etc/run-oidc-remote-test.sh
106106

107-
test-atlas-connect:
108-
- go test -v -run ^TestAtlas$ go.mongodb.org/mongo-driver/v2/internal/cmd/testatlas -args "$ATLAS_REPL" "$ATLAS_SHRD" "$ATLAS_FREE" "$ATLAS_TLS11" "$ATLAS_TLS12" "$ATLAS_SERVERLESS" "$ATLAS_SRV_REPL" "$ATLAS_SRV_SHRD" "$ATLAS_SRV_FREE" "$ATLAS_SRV_TLS11" "$ATLAS_SRV_TLS12" "$ATLAS_SRV_SERVERLESS" >> test.suite
107+
test-atlas-connect:
108+
- go test -v -run ^TestAtlas$ go.mongodb.org/mongo-driver/v2/internal/cmd/testatlas -tags atlastest >> test.suite
109109

110110
test-awskms: bash etc/run-awskms-test.sh
111111

@@ -117,9 +117,9 @@ tasks:
117117

118118
### Local FaaS tasks. ###
119119
build-faas-awslambda:
120-
requires:
120+
requires:
121121
vars: [MONGODB_URI]
122-
cmds:
122+
cmds:
123123
- make -c internal/cmd/faas/awslambda
124124

125125
### Evergreen specific tasks. ###
@@ -134,7 +134,7 @@ tasks:
134134
- ATLAS_DATA_LAKE_INTEGRATION_TEST=true go test -v ./internal/integration/unified -run TestUnifiedSpec/atlas-data-lake-testing >> spec_test.suite
135135
- ATLAS_DATA_LAKE_INTEGRATION_TEST=true go test -v ./internal/integration -run TestAtlasDataLake >> spec_test.suite
136136

137-
evg-test-enterprise-auth:
137+
evg-test-enterprise-auth:
138138
- go run -tags gssapi ./internal/cmd/testentauth/main.go
139139

140140
evg-test-oidc-auth:
@@ -188,15 +188,15 @@ tasks:
188188
### Benchmark specific tasks and support. ###
189189
benchmark:
190190
deps: [perf-files]
191-
cmds:
191+
cmds:
192192
- go test ${BUILD_TAGS} -benchmem -bench=. ./benchmark | test benchmark.suite
193193

194-
driver-benchmark:
195-
cmds:
194+
driver-benchmark:
195+
cmds:
196196
- go test ./internal/cmd/benchmark -v --fullRun | tee perf.suite
197197

198198
### Internal tasks. ###
199-
install-lll:
199+
install-lll:
200200
internal: true
201201
cmds:
202202
- go install github.com/walle/lll/...@latest

internal/assert/assertions.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,3 +1073,20 @@ func buildErrorChainString(err error) string {
10731073
}
10741074
return chain
10751075
}
1076+
1077+
// NotEmpty asserts that the specified object is NOT [Empty].
1078+
//
1079+
// if assert.NotEmpty(t, obj) {
1080+
// assert.Equal(t, "two", obj[1])
1081+
// }
1082+
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
1083+
pass := !isEmpty(object)
1084+
if !pass {
1085+
if h, ok := t.(tHelper); ok {
1086+
h.Helper()
1087+
}
1088+
Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
1089+
}
1090+
1091+
return pass
1092+
}

internal/cmd/testatlas/atlas_test.go

Lines changed: 189 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,60 +4,166 @@
44
// not use this file except in compliance with the License. You may obtain
55
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
66

7+
//go:build atlastest
8+
// +build atlastest
9+
710
package main
811

912
import (
1013
"context"
14+
"crypto/tls"
15+
"encoding/base64"
1116
"errors"
12-
"flag"
1317
"fmt"
18+
"net/url"
1419
"os"
20+
"path/filepath"
1521
"testing"
1622
"time"
1723

1824
"go.mongodb.org/mongo-driver/v2/bson"
25+
"go.mongodb.org/mongo-driver/v2/internal/assert"
1926
"go.mongodb.org/mongo-driver/v2/internal/handshake"
27+
"go.mongodb.org/mongo-driver/v2/internal/require"
2028
"go.mongodb.org/mongo-driver/v2/mongo"
2129
"go.mongodb.org/mongo-driver/v2/mongo/options"
2230
)
2331

24-
func TestMain(m *testing.M) {
25-
flag.Parse()
26-
os.Exit(m.Run())
27-
}
28-
2932
func TestAtlas(t *testing.T) {
30-
uris := flag.Args()
31-
ctx := context.Background()
32-
33-
t.Logf("Running atlas tests for %d uris\n", len(uris))
34-
35-
for idx, uri := range uris {
36-
t.Logf("Running test %d\n", idx)
37-
38-
// Set a low server selection timeout so we fail fast if there are errors.
39-
clientOpts := options.Client().
40-
ApplyURI(uri).
41-
SetServerSelectionTimeout(1 * time.Second)
42-
43-
// Run basic connectivity test.
44-
if err := runTest(ctx, clientOpts); err != nil {
45-
t.Fatalf("error running test with TLS at index %d: %v", idx, err)
46-
}
47-
48-
tlsConfigSkipVerify := clientOpts.TLSConfig
49-
tlsConfigSkipVerify.InsecureSkipVerify = true
50-
51-
// Run the connectivity test with InsecureSkipVerify to ensure SNI is done correctly even if verification is
52-
// disabled.
53-
clientOpts.SetTLSConfig(tlsConfigSkipVerify)
54-
55-
if err := runTest(ctx, clientOpts); err != nil {
56-
t.Fatalf("error running test with tlsInsecure at index %d: %v", idx, err)
57-
}
33+
cases := []struct {
34+
name string
35+
envVar string
36+
certKeyFile string
37+
wantErr string
38+
}{
39+
{
40+
name: "Atlas with TLS",
41+
envVar: "ATLAS_REPL",
42+
certKeyFile: "",
43+
wantErr: "",
44+
},
45+
{
46+
name: "Atlas with TLS and shared cluster",
47+
envVar: "ATLAS_SHRD",
48+
certKeyFile: "",
49+
wantErr: "",
50+
},
51+
{
52+
name: "Atlas with free tier",
53+
envVar: "ATLAS_FREE",
54+
certKeyFile: "",
55+
wantErr: "",
56+
},
57+
{
58+
name: "Atlas with TLS 1.1",
59+
envVar: "ATLAS_TLS11",
60+
certKeyFile: "",
61+
wantErr: "",
62+
},
63+
{
64+
name: "Atlas with TLS 1.2",
65+
envVar: "ATLAS_TLS12",
66+
certKeyFile: "",
67+
wantErr: "",
68+
},
69+
{
70+
name: "Atlas with serverless",
71+
envVar: "ATLAS_SERVERLESS",
72+
certKeyFile: "",
73+
wantErr: "",
74+
},
75+
{
76+
name: "Atlas with srv file on replica set",
77+
envVar: "ATLAS_SRV_REPL",
78+
certKeyFile: "",
79+
wantErr: "",
80+
},
81+
{
82+
name: "Atlas with srv file on shared cluster",
83+
envVar: "ATLAS_SRV_SHRD",
84+
certKeyFile: "",
85+
wantErr: "",
86+
},
87+
{
88+
name: "Atlas with srv file on free tier",
89+
envVar: "ATLAS_SRV_FREE",
90+
certKeyFile: "",
91+
wantErr: "",
92+
},
93+
{
94+
name: "Atlas with srv file on TLS 1.1",
95+
envVar: "ATLAS_SRV_TLS11",
96+
certKeyFile: "",
97+
wantErr: "",
98+
},
99+
{
100+
name: "Atlas with srv file on TLS 1.2",
101+
envVar: "ATLAS_SRV_TLS12",
102+
certKeyFile: "",
103+
wantErr: "",
104+
},
105+
{
106+
name: "Atlas with srv file on serverless",
107+
envVar: "ATLAS_SRV_SERVERLESS",
108+
certKeyFile: "",
109+
wantErr: "",
110+
},
111+
{
112+
name: "Atlas with X509 Dev",
113+
envVar: "ATLAS_X509_DEV",
114+
certKeyFile: createAtlasX509DevCertKeyFile(t),
115+
wantErr: "",
116+
},
117+
{
118+
name: "Atlas with X509 Dev no user",
119+
envVar: "ATLAS_X509_DEV",
120+
certKeyFile: createAtlasX509DevCertKeyFileNoUser(t),
121+
wantErr: "UserNotFound",
122+
},
58123
}
59124

60-
t.Logf("Finished!")
125+
for _, tc := range cases {
126+
t.Run(fmt.Sprintf("%s (%s)", tc.name, tc.envVar), func(t *testing.T) {
127+
uri := os.Getenv(tc.envVar)
128+
require.NotEmpty(t, uri, "Environment variable %s is not set", tc.envVar)
129+
130+
if tc.certKeyFile != "" {
131+
uri = addTLSCertKeyFile(t, tc.certKeyFile, uri)
132+
}
133+
134+
// Set a low server selection timeout so we fail fast if there are errors.
135+
clientOpts := options.Client().
136+
ApplyURI(uri).
137+
SetServerSelectionTimeout(1 * time.Second)
138+
139+
// Run basic connectivity test.
140+
err := runTest(context.Background(), clientOpts)
141+
if tc.wantErr != "" {
142+
assert.ErrorContains(t, err, tc.wantErr, "expected error to contain %q", tc.wantErr)
143+
144+
return
145+
}
146+
require.NoError(t, err, "error running test with TLS")
147+
148+
orig := clientOpts.TLSConfig
149+
if orig == nil {
150+
orig = &tls.Config{}
151+
}
152+
153+
insecure := orig.Clone()
154+
insecure.InsecureSkipVerify = true
155+
156+
// Run the connectivity test with InsecureSkipVerify to ensure SNI is done
157+
// correctly even if verification is disabled.
158+
insecureClientOpts := options.Client().
159+
ApplyURI(uri).
160+
SetServerSelectionTimeout(1 * time.Second).
161+
SetTLSConfig(insecure)
162+
163+
err = runTest(context.Background(), insecureClientOpts)
164+
require.NoError(t, err, "error running test with tlsInsecure")
165+
})
166+
}
61167
}
62168

63169
func runTest(ctx context.Context, clientOpts *options.ClientOptions) error {
@@ -83,3 +189,51 @@ func runTest(ctx context.Context, clientOpts *options.ClientOptions) error {
83189
}
84190
return nil
85191
}
192+
193+
func createAtlasX509DevCertKeyFile(t *testing.T) string {
194+
t.Helper()
195+
196+
b64 := os.Getenv("ATLAS_X509_DEV_CERT_BASE64")
197+
assert.NotEmpty(t, b64, "Environment variable ATLAS_X509_DEV_CERT_BASE64 is not set")
198+
199+
certBytes, err := base64.StdEncoding.DecodeString(b64)
200+
require.NoError(t, err, "failed to decode ATLAS_X509_DEV_CERT_BASE64")
201+
202+
certFilePath := filepath.Join(t.TempDir(), "atlas_x509_dev_cert.pem")
203+
204+
err = os.WriteFile(certFilePath, certBytes, 0600)
205+
require.NoError(t, err, "failed to write ATLAS_X509_DEV_CERT_BASE64 to file")
206+
207+
return certFilePath
208+
}
209+
210+
func createAtlasX509DevCertKeyFileNoUser(t *testing.T) string {
211+
t.Helper()
212+
213+
b64 := os.Getenv("ATLAS_X509_DEV_CERT_NOUSER_BASE64")
214+
assert.NotEmpty(t, b64, "Environment variable ATLAS_X509_DEV_CERT_NOUSER_BASE64 is not set")
215+
216+
keyBytes, err := base64.StdEncoding.DecodeString(b64)
217+
require.NoError(t, err, "failed to decode ATLAS_X509_DEV_CERT_NOUSER_BASE64")
218+
219+
keyFilePath := filepath.Join(t.TempDir(), "atlas_x509_dev_cert_no_user.pem")
220+
221+
err = os.WriteFile(keyFilePath, keyBytes, 0600)
222+
require.NoError(t, err, "failed to write ATLAS_X509_DEV_CERT_NOUSER_BASE64 to file")
223+
224+
return keyFilePath
225+
}
226+
227+
func addTLSCertKeyFile(t *testing.T, certKeyFile, uri string) string {
228+
t.Helper()
229+
230+
u, err := url.Parse(uri)
231+
require.NoError(t, err, "failed to parse uri")
232+
233+
q := u.Query()
234+
q.Set("tlsCertificateKeyFile", filepath.ToSlash(certKeyFile))
235+
236+
u.RawQuery = q.Encode()
237+
238+
return u.String()
239+
}

internal/require/require.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,3 +817,18 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim
817817
}
818818
t.FailNow()
819819
}
820+
821+
// NotEmpty asserts that the specified object is NOT [Empty].
822+
//
823+
// if require.NotEmpty(t, obj) {
824+
// require.Equal(t, "two", obj[1])
825+
// }
826+
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
827+
if h, ok := t.(tHelper); ok {
828+
h.Helper()
829+
}
830+
if assert.NotEmpty(t, object, msgAndArgs...) {
831+
return
832+
}
833+
t.FailNow()
834+
}

0 commit comments

Comments
 (0)