1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
// Copyright (C) MongoDB, Inc. 2017-present.
//
// 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
package connstring_test
import (
"encoding/json"
"io/ioutil"
"path"
"strings"
"testing"
"github.com/stretchr/testify/require"
testhelpers "go.mongodb.org/mongo-driver/internal/testutil/helpers"
"go.mongodb.org/mongo-driver/x/mongo/driver/connstring"
)
type host struct {
Type string
Host string
Port json.Number
}
type auth struct {
Username string
Password *string
DB string
}
type testCase struct {
Description string
URI string
Valid bool
Warning bool
Hosts []host
Auth *auth
Options map[string]interface{}
}
type testContainer struct {
Tests []testCase
}
const connstringTestsDir = "../../../../data/connection-string/"
const urioptionsTestDir = "../../../../data/uri-options/"
func (h *host) toString() string {
switch h.Type {
case "unix":
return h.Host
case "ip_literal":
if len(h.Port) == 0 {
return "[" + h.Host + "]"
}
return "[" + h.Host + "]" + ":" + string(h.Port)
case "ipv4":
fallthrough
case "hostname":
if len(h.Port) == 0 {
return h.Host
}
return h.Host + ":" + string(h.Port)
}
return ""
}
func hostsToStrings(hosts []host) []string {
out := make([]string, len(hosts))
for i, host := range hosts {
out[i] = host.toString()
}
return out
}
func runTestsInFile(t *testing.T, dirname string, filename string, warningsError bool) {
filepath := path.Join(dirname, filename)
content, err := ioutil.ReadFile(filepath)
require.NoError(t, err)
var container testContainer
require.NoError(t, json.Unmarshal(content, &container))
// Remove ".json" from filename.
filename = filename[:len(filename)-5]
for _, testCase := range container.Tests {
runTest(t, filename, testCase, warningsError)
}
}
var skipDescriptions = map[string]struct{}{
"Valid options specific to single-threaded drivers are parsed correctly": {},
}
var skipKeywords = []string{
"tlsAllowInvalidHostnames",
"tlsAllowInvalidCertificates",
"tlsDisableCertificateRevocationCheck",
"serverSelectionTryOnce",
}
func runTest(t *testing.T, filename string, test testCase, warningsError bool) {
t.Run(test.Description, func(t *testing.T) {
if _, skip := skipDescriptions[test.Description]; skip {
t.Skip()
}
for _, keyword := range skipKeywords {
if strings.Contains(test.Description, keyword) {
t.Skipf("skipping because keyword %s", keyword)
}
}
cs, err := connstring.ParseAndValidate(test.URI)
// Since we don't have warnings in Go, we return warnings as errors.
//
// This is a bit unfortuante, but since we do raise warnings as errors with the newer
// URI options, but don't with some of the older things, we do a switch on the filename
// here. We are trying to not break existing user applications that have unrecognized
// options.
if test.Valid && !(test.Warning && warningsError) {
require.NoError(t, err)
} else {
require.Error(t, err)
return
}
require.Equal(t, test.URI, cs.Original)
if test.Hosts != nil {
require.Equal(t, hostsToStrings(test.Hosts), cs.Hosts)
}
if test.Auth != nil {
require.Equal(t, test.Auth.Username, cs.Username)
if test.Auth.Password == nil {
require.False(t, cs.PasswordSet)
} else {
require.True(t, cs.PasswordSet)
require.Equal(t, *test.Auth.Password, cs.Password)
}
if test.Auth.DB != cs.Database {
require.Equal(t, test.Auth.DB, cs.AuthSource)
} else {
require.Equal(t, test.Auth.DB, cs.Database)
}
}
// Check that all options are present.
testhelpers.VerifyConnStringOptions(t, cs, test.Options)
// Check that non-present options are unset. This will be redundant with the above checks
// for options that are present.
var ok bool
_, ok = test.Options["maxpoolsize"]
require.Equal(t, ok, cs.MaxPoolSizeSet)
})
}
// Test case for all connection string spec tests.
func TestConnStringSpec(t *testing.T) {
for _, file := range testhelpers.FindJSONFilesInDir(t, connstringTestsDir) {
runTestsInFile(t, connstringTestsDir, file, false)
}
}
func TestURIOptionsSpec(t *testing.T) {
for _, file := range testhelpers.FindJSONFilesInDir(t, urioptionsTestDir) {
runTestsInFile(t, urioptionsTestDir, file, true)
}
}
|