Skip to content

Commit 214547c

Browse files
committed
Refactor test infrastructure and consolidate test utilities
Modernize the test infrastructure by consolidating test helpers into a shared testutil package and enhancing connection reliability: - Move test utilities from internal/test to opensearchutil/testutil for broader reusability across the project and external packages - Remove obsolete internal/test/config.go in favor of improved helper functions with better error handling and connection management - Add dynamic field filtering for JSON comparison tests to handle version-specific and environment-dependent OpenSearch responses - Enhance connection robustness with improved readiness checks and health monitoring in opensearchtransport layer - Update all integration tests across opensearchapi, plugins, and transport packages to use the new unified test infrastructure - Add comprehensive documentation and examples for the new test utilities This refactor provides a more maintainable foundation for testing across different OpenSearch versions and environments while reducing code duplication and improving test reliability. Signed-off-by: Sean Chittenden <sean.chittenden@crowdstrike.com>
1 parent 6643d35 commit 214547c

85 files changed

Lines changed: 1555 additions & 2592 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
55
## [Unreleased]
66

77
### Added
8-
- Enhanced cluster readiness checking for improved test reliability: `ostest.NewClient()` now includes readiness validation (health + cluster state + nodes info)
8+
- Enhanced cluster readiness checking for improved test reliability: `testutil.NewClient()` now includes readiness validation (health + cluster state + nodes info)
99
- Configuration option `IncludeDedicatedClusterManagers` for controlling cluster manager node routing ([#765](https://github.com/opensearch-project/opensearch-go/issues/765))
1010
- Add connection pool health probes with cluster-aware resurrection timing ([#786](https://github.com/opensearch-project/opensearch-go/pull/786))
1111

@@ -16,6 +16,10 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
1616
- **BREAKING**: Enhanced node discovery to match OpenSearch server behavior ([#765](https://github.com/opensearch-project/opensearch-go/issues/765))
1717
- Dedicated cluster manager nodes are now excluded from client request routing by default (best practice)
1818
- Node selection logic now matches Java client `NodeSelector.SKIP_DEDICATED_CLUSTER_MASTERS` behavior
19+
- **BREAKING**: Migrate `signer/aws` package from AWS SDK v1 to AWS SDK v2 due to AWS SDK v1 reaching end-of-support on July 31, 2025
20+
- Constructor now takes `aws.Config` instead of `session.Options`
21+
- See USER_GUIDE.md for details required to migrate
22+
- Users who need access to the existing `signer/awsv2` API can still use it, however they are encouraged to migrate to `signer/aws`
1923

2024
### Deprecated
2125

@@ -265,7 +269,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
265269

266270
- Updates workflow action versions ([#488](https://github.com/opensearch-project/opensearch-go/pull/488))
267271
- Changes integration tests to work with secure and unsecure OpenSearch ([#488](https://github.com/opensearch-project/opensearch-go/pull/488))
268-
- Moves functions from `opensearch/internal/test` to `internal/test` for more general test uses ([#488](https://github.com/opensearch-project/opensearch-go/pull/488))
272+
- Moves functions from `opensearch/internal/test` to `opensearchutil/testutil` for shared test utilities ([#488](https://github.com/opensearch-project/opensearch-go/pull/488))
269273
- Changes `custom_foldername` field to pointer as it can be `null` ([#488](https://github.com/opensearch-project/opensearch-go/pull/488))
270274
- Changs cat indices Primary and Replica field to pointer as it can be `null` ([#488](https://github.com/opensearch-project/opensearch-go/pull/488))
271275
- Replaces `ioutil` with `io` in examples and integration tests [#495](https://github.com/opensearch-project/opensearch-go/pull/495)

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,8 @@ cluster.scale.3: ## Start full 3-node cluster
227227

228228
cluster.get-cert:
229229
@if [[ -v SECURE_INTEGRATION ]] && [[ $$SECURE_INTEGRATION == "true" ]]; then \
230-
docker cp $$(docker compose --project-directory .ci/opensearch ps --format '{{.Name}}'):/usr/share/opensearch/config/kirk.pem admin.pem && \
231-
docker cp $$(docker compose --project-directory .ci/opensearch ps --format '{{.Name}}'):/usr/share/opensearch/config/kirk-key.pem admin.key; \
230+
docker cp $$(docker compose --project-directory .ci/opensearch ps --format '{{.Name}}' | head -1):/usr/share/opensearch/config/kirk.pem admin.pem && \
231+
docker cp $$(docker compose --project-directory .ci/opensearch ps --format '{{.Name}}' | head -1):/usr/share/opensearch/config/kirk-key.pem admin.key; \
232232
fi
233233

234234

USER_GUIDE.md

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,19 @@ Before starting, we strongly recommend reading the full AWS documentation regard
210210
>
211211
> See [Managed Domains signing-service requests.](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ac.html#managedomains-signing-service-requests)
212212
213-
Depending on the version of AWS SDK used, import the v1 or v2 request signer from `signer/aws` or `signer/awsv2` respectively. Both signers are equivalent in their functionality, they provide AWS Signature Version 4 (SigV4).
213+
Depending on the version of AWS SDK used, import the request signer from `signer/aws` (recommended) or `signer/awsv2`. Both signers use AWS SDK v2 and provide AWS Signature Version 4 (SigV4).
214+
215+
**BREAKING CHANGE**: As of this version, the main `signer/aws` package has been migrated from AWS SDK v1 to AWS SDK v2 due to AWS SDK v1 reaching end-of-support on July 31, 2025.
214216

215217
To read more about SigV4 see [Signature Version 4 signing process](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)
216218

217219
Here are some Go samples that show how to sign each OpenSearch request and automatically search for AWS credentials from the ~/.aws folder or environment variables:
218220

219-
### AWS SDK v1
221+
### AWS SDK v2 (Recommended)
222+
223+
**Migration Note**: If you were previously using `signer/aws` with AWS SDK v1, you need to update your imports and configuration as shown below.
224+
225+
**Credential Caching**: The signer automatically enables credential caching for improved performance, especially when using STS credentials (assume role, web identity, etc.). This reduces API calls to AWS STS and improves signing performance.
220226

221227
```go
222228
package main
@@ -226,7 +232,8 @@ import (
226232
"fmt"
227233
"os"
228234

229-
"github.com/aws/aws-sdk-go/aws/session"
235+
"github.com/aws/aws-sdk-go-v2/aws"
236+
"github.com/aws/aws-sdk-go-v2/config"
230237
requestsigner "github.com/opensearch-project/opensearch-go/v4/signer/aws"
231238

232239
"github.com/opensearch-project/opensearch-go/v4"
@@ -245,16 +252,22 @@ func main() {
245252
const endpoint = "" // e.g. https://opensearch-domain.region.com
246253

247254
func example() error {
248-
// Create an AWS request Signer and load AWS configuration using default config folder or env vars.
249-
// See https://docs.aws.amazon.com/opensearch-service/latest/developerguide/request-signing.html#request-signing-go
250-
signer, err := requestsigner.NewSignerWithService(
251-
session.Options{SharedConfigState: session.SharedConfigEnable},
252-
requestsigner.OpenSearchService, // Use requestsigner.OpenSearchServerless for Amazon OpenSearch Serverless.
253-
)
255+
ctx := context.Background()
256+
257+
// Load AWS configuration
258+
awsCfg, err := config.LoadDefaultConfig(ctx)
254259
if err != nil {
255260
return err
256261
}
257-
// Create an opensearch client and use the request-signer.
262+
263+
// Create an AWS request Signer
264+
signer, err := requestsigner.NewSignerWithService(awsCfg, requestsigner.OpenSearchService)
265+
// Use requestsigner.OpenSearchServerless for Amazon OpenSearch Serverless
266+
if err != nil {
267+
return err
268+
}
269+
270+
// Create an opensearch client and use the request-signer
258271
client, err := opensearchapi.NewClient(
259272
opensearchapi.Config{
260273
Client: opensearch.Config{
@@ -267,20 +280,18 @@ func example() error {
267280
return err
268281
}
269282

270-
ctx := context.Background()
271-
272-
ping, err := client.Ping(ctx, nil)
273-
if err != nil {
274-
return err
275-
}
283+
ping, err := client.Ping(ctx, nil)
284+
if err != nil {
285+
return err
286+
}
276287

277-
fmt.Println(ping)
288+
fmt.Println(ping)
278289

279290
return nil
280291
}
281292
```
282293

283-
### AWS SDK v2
294+
### Alternative: Using signer/awsv2
284295

285296
Use the AWS SDK v2 for Go to authenticate with Amazon OpenSearch service.
286297

error_test.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func TestError(t *testing.T) {
5050
assert.True(t, resp.IsError())
5151
err := opensearch.ParseError(resp)
5252
var testError *opensearch.StructError
53-
require.True(t, errors.As(err, &testError))
53+
require.ErrorAs(t, err, &testError)
5454
assert.Equal(t, http.StatusBadRequest, testError.Status)
5555
assert.Equal(t, "resource_already_exists_exception", testError.Err.Type)
5656
assert.Equal(t, "index [test/HU2mN_RMRXGcS38j3yV-VQ] already exists", testError.Err.Reason)
@@ -92,7 +92,7 @@ func TestError(t *testing.T) {
9292
assert.True(t, resp.IsError())
9393
err := opensearch.ParseError(resp)
9494
var testError *opensearch.StructError
95-
require.True(t, errors.As(err, &testError))
95+
require.ErrorAs(t, err, &testError)
9696
assert.Equal(t, http.StatusBadRequest, testError.Status)
9797
assert.Equal(t, "illegal_argument_exception", testError.Err.Type)
9898
assert.Equal(t, "composable template [posts] template after composition is invalid", testError.Err.Reason)
@@ -117,14 +117,14 @@ func TestError(t *testing.T) {
117117
}`),
118118
)
119119
body, err := io.ReadAll(reader)
120-
require.Nil(t, err)
120+
require.NoError(t, err)
121121

122122
var errStruct *opensearch.StructError
123123
err = json.Unmarshal(body, &errStruct)
124-
assert.NotNil(t, err)
124+
assert.Error(t, err)
125125

126126
var jsonError *json.UnmarshalTypeError
127-
assert.True(t, errors.As(err, &jsonError))
127+
assert.ErrorAs(t, err, &jsonError)
128128
})
129129
t.Run("string", func(t *testing.T) {
130130
reader := io.NopCloser(
@@ -134,14 +134,14 @@ func TestError(t *testing.T) {
134134
}`),
135135
)
136136
body, err := io.ReadAll(reader)
137-
require.Nil(t, err)
137+
require.NoError(t, err)
138138

139139
var errStruct *opensearch.StructError
140140
err = json.Unmarshal(body, &errStruct)
141-
assert.NotNil(t, err)
141+
assert.Error(t, err)
142142

143143
var errStr *opensearch.StringError
144-
require.True(t, errors.As(err, &errStr))
144+
require.ErrorAs(t, err, &errStr)
145145
})
146146
})
147147
})
@@ -159,7 +159,7 @@ func TestError(t *testing.T) {
159159
assert.True(t, resp.IsError())
160160
err := opensearch.ParseError(resp)
161161
var testError *opensearch.StringError
162-
require.True(t, errors.As(err, &testError))
162+
require.ErrorAs(t, err, &testError)
163163
assert.Equal(t, http.StatusMethodNotAllowed, testError.Status)
164164
assert.Contains(t, testError.Err, "Incorrect HTTP method for uri")
165165
_ = fmt.Sprintf("%s", testError)
@@ -175,7 +175,7 @@ func TestError(t *testing.T) {
175175
assert.True(t, resp.IsError())
176176
err := opensearch.ParseError(resp)
177177
var testError *opensearch.StringError
178-
require.True(t, errors.As(err, &testError))
178+
require.ErrorAs(t, err, &testError)
179179
assert.Equal(t, http.StatusNotFound, testError.Status)
180180
assert.Contains(t, testError.Err, "{\"_index\":\"index\",\"_id\":\"2\",\"matched\":false}")
181181
_ = fmt.Sprintf("%s", testError)
@@ -193,7 +193,7 @@ func TestError(t *testing.T) {
193193
assert.True(t, resp.IsError())
194194
err := opensearch.ParseError(resp)
195195
var testError *opensearch.Error
196-
require.True(t, errors.As(err, &testError))
196+
require.ErrorAs(t, err, &testError)
197197
assert.Contains(t, testError.Err, "no handler found for uri [/_plugins/_security/xxx] and method [GET]")
198198
_ = fmt.Sprintf("%s", testError)
199199
})
@@ -214,7 +214,7 @@ func TestError(t *testing.T) {
214214
assert.True(t, resp.IsError())
215215
err := opensearch.ParseError(resp)
216216
var testError *opensearch.ReasonError
217-
require.True(t, errors.As(err, &testError))
217+
require.ErrorAs(t, err, &testError)
218218
assert.Equal(t, "error", testError.Status)
219219
assert.Contains(t, testError.Reason, "Invalid configuration")
220220
_ = fmt.Sprintf("%s", testError)
@@ -230,7 +230,7 @@ func TestError(t *testing.T) {
230230
assert.True(t, resp.IsError())
231231
err := opensearch.ParseError(resp)
232232
var testError *opensearch.MessageError
233-
require.True(t, errors.As(err, &testError))
233+
require.ErrorAs(t, err, &testError)
234234
assert.Equal(t, "BAD_REQUEST", testError.Status)
235235
assert.Contains(t, testError.Message, "Wrong request body")
236236
_ = fmt.Sprintf("%s", testError)
@@ -277,7 +277,7 @@ func TestError(t *testing.T) {
277277
t.Run(tt.Name, func(t *testing.T) {
278278
err := opensearch.ParseError(tt.Resp)
279279
for _, wantedError := range tt.WantedErrors {
280-
assert.True(t, errors.Is(err, wantedError))
280+
assert.ErrorIs(t, err, wantedError)
281281
}
282282
})
283283
}
@@ -289,7 +289,7 @@ func TestError(t *testing.T) {
289289
}
290290
assert.True(t, resp.IsError())
291291
err := opensearch.ParseError(resp)
292-
assert.True(t, errors.Is(err, opensearch.ErrJSONUnmarshalBody))
292+
assert.ErrorIs(t, err, opensearch.ErrJSONUnmarshalBody)
293293
})
294294
t.Run("too many requests", func(t *testing.T) {
295295
resp := &opensearch.Response{
@@ -298,7 +298,7 @@ func TestError(t *testing.T) {
298298
}
299299
assert.True(t, resp.IsError())
300300
err := opensearch.ParseError(resp)
301-
assert.True(t, errors.Is(err, opensearch.ErrJSONUnmarshalBody))
301+
assert.ErrorIs(t, err, opensearch.ErrJSONUnmarshalBody)
302302
})
303303
})
304304
}

go.mod

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ module github.com/opensearch-project/opensearch-go/v4
33
go 1.24.0
44

55
require (
6-
github.com/aws/aws-sdk-go v1.55.8
76
github.com/aws/aws-sdk-go-v2 v1.41.1
87
github.com/aws/aws-sdk-go-v2/config v1.32.7
8+
github.com/aws/aws-sdk-go-v2/credentials v1.19.7
99
github.com/stretchr/testify v1.11.1
1010
github.com/wI2L/jsondiff v0.7.0
11+
golang.org/x/mod v0.32.0
1112
)
1213

1314
require (
14-
github.com/aws/aws-sdk-go-v2/credentials v1.19.7 // indirect
1515
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect
1616
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
1717
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
@@ -24,7 +24,6 @@ require (
2424
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect
2525
github.com/aws/smithy-go v1.24.0 // indirect
2626
github.com/davecgh/go-spew v1.1.1 // indirect
27-
github.com/jmespath/go-jmespath v0.4.0 // indirect
2827
github.com/pmezard/go-difflib v1.0.0 // indirect
2928
github.com/tidwall/gjson v1.18.0 // indirect
3029
github.com/tidwall/match v1.1.1 // indirect

go.sum

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ=
2-
github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk=
31
github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU=
42
github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
53
github.com/aws/aws-sdk-go-v2/config v1.32.7 h1:vxUyWGUwmkQ2g19n7JY/9YL8MfAIl7bTesIUykECXmY=
@@ -28,16 +26,10 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/
2826
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ=
2927
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
3028
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
31-
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3229
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3330
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
34-
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
35-
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
36-
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
37-
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
3831
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
3932
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
40-
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
4133
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
4234
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
4335
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@@ -52,9 +44,9 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
5244
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
5345
github.com/wI2L/jsondiff v0.7.0 h1:1lH1G37GhBPqCfp/lrs91rf/2j3DktX6qYAKZkLuCQQ=
5446
github.com/wI2L/jsondiff v0.7.0/go.mod h1:KAEIojdQq66oJiHhDyQez2x+sRit0vIzC9KeK0yizxM=
47+
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
48+
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
5549
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
5650
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
57-
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
58-
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
5951
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
6052
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/test/config.go

Lines changed: 0 additions & 72 deletions
This file was deleted.

internal/test/doc.go

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)