Skip to content

Commit d5182e8

Browse files
authored
bump OpenSearch compatiblity tests to latest releases (opensearch-project#782)
* Update CI compatibility test matrix and enhance Docker infrastructure - Expand compatibility testing from 8 to 30 OpenSearch versions (1.3.20, 2.0.1-2.19.4, 3.0.0-3.4.0, latest) - Add version-aware Docker plugin removal for OpenSearch 3.x dependency chains - Implement proper plugin dependency order handling (flow-framework -> skills -> ml -> anomaly-detection -> security) - Fix flaky connection integration test with proper server readiness polling - Update Go version specification to 1.24.0 for consistency Signed-off-by: Sean Chittenden <sean.chittenden@crowdstrike.com> * Fix OpenSearch 3.1.0+ API compatibility Add missing fields introduced in OpenSearch 3.1.0: - Add phase_results_processors field to NodesInfoSearchPipelines struct for search pipeline phase results processing support - Add time_in_execution and time_in_execution_millis fields to ClusterPendingTasksItem struct for improved task timing information Signed-off-by: Sean Chittenden <sean.chittenden@crowdstrike.com> * Fix OpenSearch 3.2.0+ API compatibility Add missing fields across multiple APIs for OpenSearch 3.2.0+ support: Nodes Stats API: - Add MaxLastIndexRequestTimestamp to indexing stats - Add StartreeQueryTotal, StartreeQueryTimeInMillis, StartreeQueryCurrent for startree query tracking Indices Stats API: - Add same startree query fields and MaxLastIndexRequestTimestamp Cat APIs (nodes, shards, indices): - Add indexing timestamp fields (last_index_request_timestamp) - Add startree query tracking fields Floating Point Precision: - Fix concurrent_avg_slice_count precision loss by changing from float32 to float64 to match OpenSearch's double precision Security Plugin: - Add Settings field to security health API response for plugin configuration like cache TTL settings Signed-off-by: Sean Chittenden <sean.chittenden@crowdstrike.com> * Add OpenSearch 3.3.0+ API compatibility and enhance test infrastructure OpenSearch 3.3.0+ API Compatibility: Add missing fields across multiple APIs for enhanced query failure tracking and system monitoring introduced in OpenSearch 3.3.0+: Nodes Stats API: - Add NeuralSearch breaker for neural search circuit breaker support - Add QueryFailed and StartreeQueryFailed for query failure tracking - Add SystemGeneratedProcessors and SystemGeneratedFactories to search pipeline for system component tracking Indices Stats API: - Add QueryFailed and StartreeQueryFailed search failure tracking fields Cat APIs (nodes, shards, indices): - Add SearchQueryFailed and SearchStartreeQueryFailed fields - Fix JSON field naming inconsistencies in cat indices API where OpenSearch uses mixed formats (pri.search.startree.query_* vs pri.search.startree_query_failed) Cluster State API: - Add IngestionStatus field to ClusterStateMetaDataIndex for tracking index ingestion status in cluster metadata Security Config API: - Add JwksURI field to JWT authentication configuration struct for JSON Web Key Set URI support Field Naming Compatibility Fix: - OpenSearch 3.2.0 introduced inconsistent startree query field naming (pri.startree.* instead of pri.search.startree.*) which was corrected in 3.3.0+. This creates compatibility issues as applications need different field names depending on server version. Solution: Implement dual-field approach with raw API compatibility: - OpenSearch 3.3.0+ fields use corrected naming (pri.search.startree.*) - OpenSearch 3.2.0 fields use original inconsistent naming (pri.startree.*) - Both field sets remain as raw redundant fields for OpenAPI compatibility - Applications choose appropriate field names based on target OpenSearch version Applications should use: - PrimarySearchStartreeQuery* fields when targeting OpenSearch 3.3.0+ - PrimaryStartreeQuery* fields when targeting OpenSearch 3.2.0 Test Infrastructure Enhancements: - Add comprehensive test infrastructure with automatic cluster readiness validation - Implement NewClient(t) with three-phase validation (health + cluster state + nodes info) - Add version-aware client configuration supporting both secure/insecure modes - Create testify-based OpenSearchTestSuite with built-in version detection - Implement robust readiness polling (25 attempts × 5s intervals) to eliminate CI flakiness - Update all integration tests to use enhanced test infrastructure These changes provide enhanced observability for query failures, neural search circuit breaker monitoring, search pipeline system components, index ingestion status tracking, JWT authentication configuration, field naming compatibility, and significantly improved test reliability across all OpenSearch versions. All compatibility code is marked for removal when 3.2.0 support ends. Signed-off-by: Sean Chittenden <sean.chittenden@crowdstrike.com> * Fix OpenSearch 3.4.0+ API compatibility and enhance test infrastructure This commit resolves compatibility issues discovered during integration testing with OpenSearch 3.4.0+, ensuring the Go client works seamlessly with the latest OpenSearch versions. - **Nodes Stats API**: Add warmer fields to merges section with proper _count/_millis suffixes; add status_counter field with doc_status subfields - **Indices Stats API**: Add warmer fields to IndicesStatsMerges struct with proper _count/_millis suffixes - **Cat Thread Pool API**: Add parallelism field for thread pool metrics - **Cat APIs** (indices, shards, nodes): Add comprehensive merges warmer fields matching flattened JSON structure from OpenSearch responses - Fix Cat APIs JSON unmarshaling by changing byte fields from *int to *string to properly handle OpenSearch 3.4.0+ values like "0b" - Remove incorrect ,string JSON tags from string fields - Ensures compatibility with OpenSearch's mixed data type responses - Correctly implement different naming patterns across API families: - Cat APIs: total_invocations, total_time - Stats APIs: total_invocations_count, total_time_millis Signed-off-by: Sean Chittenden <sean.chittenden@crowdstrike.com> * Enable and run the `modernize` linter Signed-off-by: Sean Chittenden <sean.chittenden@crowdstrike.com> --------- Signed-off-by: Sean Chittenden <sean.chittenden@crowdstrike.com>
1 parent 3deff37 commit d5182e8

90 files changed

Lines changed: 1166 additions & 458 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.

.ci/opensearch/Dockerfile.opensearch

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,30 @@ ARG SECURE_INTEGRATION
66
ENV SECURE_INTEGRATION=$SECURE_INTEGRATION
77
ARG OPENSEARCH_INITIAL_ADMIN_PASSWORD
88

9-
# Some opensearch secuirty settings are only present since 2.8.0 and causes older versions to brake if the setting is present
10-
# https://apple.stackexchange.com/a/123408/11374
9+
# Handle plugin dependencies when removing opensearch-security
10+
# OpenSearch 3.x introduced plugin dependencies that prevent direct removal of opensearch-security.
11+
# Plugin dependency evolution:
12+
# 3.0.0: No dependencies - remove opensearch-security directly
13+
# 3.1.0-3.2.0: opensearch-anomaly-detection extends opensearch-security
14+
# 3.3.2: opensearch-skills extends opensearch-ml, which extends opensearch-security
15+
# 3.4.0+: opensearch-flow-framework also extends opensearch-security
16+
# We must remove plugins in dependency order (dependents first, then their dependencies).
17+
ARG OPENSEARCH_VERSION
1118
RUN if [ "$SECURE_INTEGRATION" != "true" ] ; then \
12-
$opensearch_path/bin/opensearch-plugin remove opensearch-security; \
19+
function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }; \
20+
if [ $(version ${OPENSEARCH_VERSION:-0.0.0}) -ge $(version "3.4.0") ] || [ "$OPENSEARCH_VERSION" = "latest" ]; then \
21+
$opensearch_path/bin/opensearch-plugin remove opensearch-flow-framework; \
22+
$opensearch_path/bin/opensearch-plugin remove opensearch-skills; \
23+
$opensearch_path/bin/opensearch-plugin remove opensearch-ml; \
24+
$opensearch_path/bin/opensearch-plugin remove opensearch-anomaly-detection; \
25+
elif [ $(version ${OPENSEARCH_VERSION:-0.0.0}) -ge $(version "3.3.2") ]; then \
26+
$opensearch_path/bin/opensearch-plugin remove opensearch-skills; \
27+
$opensearch_path/bin/opensearch-plugin remove opensearch-ml; \
28+
$opensearch_path/bin/opensearch-plugin remove opensearch-anomaly-detection; \
29+
elif [ $(version ${OPENSEARCH_VERSION:-0.0.0}) -ge $(version "3.1.0") ]; then \
30+
$opensearch_path/bin/opensearch-plugin remove opensearch-anomaly-detection; \
31+
fi; \
32+
$opensearch_path/bin/opensearch-plugin remove opensearch-security; \
1333
else \
1434
$opensearch_path/opensearch-onetime-setup.sh; \
1535
echo "plugins.security.nodes_dn_dynamic_config_enabled: true" | tee -a $opensearch_path/config/opensearch.yml > /dev/null; \
@@ -24,4 +44,4 @@ RUN if [ "$SECURE_INTEGRATION" != "true" ] ; then \
2444
HEALTHCHECK --start-period=20s --interval=30s \
2545
CMD curl -sf --retry 5 --max-time 5 --retry-delay 5 --retry-max-time 30 --retry-all-errors \
2646
$(if $SECURE_INTEGRATION; then echo "--cert config/kirk.pem --key config/kirk-key.pem -k https://"; fi)"localhost:9200" \
27-
|| bash -c 'kill -s 15 -1 && (sleep 10; kill -s 9 -1)'
47+
|| bash -c 'kill -s 15 -1 && (sleep 10; kill -s 9 -1)'

.github/workflows/test-compatibility.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
matrix:
1111
secured: ["true", "false"]
1212
entry:
13-
- { opensearch_version: 1.3.18 }
13+
- { opensearch_version: 1.3.20 }
1414
- { opensearch_version: 2.0.1 }
1515
- { opensearch_version: 2.1.0 }
1616
- { opensearch_version: 2.2.1 }
@@ -30,8 +30,13 @@ jobs:
3030
- { opensearch_version: 2.16.0 }
3131
- { opensearch_version: 2.17.1 }
3232
- { opensearch_version: 2.18.0 }
33-
- { opensearch_version: 2.19.2 }
33+
- { opensearch_version: 2.19.4 }
3434
- { opensearch_version: 3.0.0 }
35+
- { opensearch_version: 3.1.0 }
36+
- { opensearch_version: 3.2.0 }
37+
- { opensearch_version: 3.3.2 }
38+
- { opensearch_version: 3.4.0 }
39+
- { opensearch_version: latest }
3540
steps:
3641
- uses: actions/checkout@v6
3742

.github/workflows/test-integration.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on: [push, pull_request]
44

55
env:
66
GITHUB_ACTIONS: true
7-
OPENSEARCH_VERSION: 2.19.2
7+
OPENSEARCH_VERSION: 2.19.4
88

99
jobs:
1010
test:

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ linters:
4242
- makezero
4343
- mirror
4444
- misspell
45+
- modernize
4546
- musttag
4647
- nakedret
4748
- nestif

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,26 @@ 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)
89

910
### Changed
1011
- Refactor Client struct to use embedded mutex pattern for improved thread safety ([#775](https://github.com/opensearch-project/opensearch-go/pull/775))
1112
- Refactor metrics struct to use atomic counters for lock-free request/failure tracking ([#776](https://github.com/opensearch-project/opensearch-go/pull/776))
13+
- Test against Opensearch 2.19.4, 3.1, 3.3, and 3.4 ([#782](https://github.com/opensearch-project/opensearch-go/pull/782))
1214

1315
### Deprecated
1416

1517
### Removed
1618

1719
### Fixed
20+
- Fix flaky connection integration test by replacing arbitrary sleep times with proper server readiness polling
21+
- Fix OpenSearch 3.1.0+ API compatibility by adding phase_results_processors field to nodes API and time_in_execution fields to cluster pending tasks API
22+
- Fix OpenSearch 3.2.0+ API compatibility by adding max_last_index_request_timestamp and startree query fields across nodes stats, indices stats, and cat APIs, plus settings field to security plugin health API
23+
- Fix OpenSearch 3.3.0+ API compatibility by adding neural_search breaker, query_failed and startree_query_failed search fields, search pipeline system_generated fields across multiple APIs, plus ingestion_status field to cluster state API and jwks_uri field to security config API
24+
- Fix OpenSearch 3.4.0+ API compatibility by adding warmer fields to merges section, parallelism field to thread pool, and status_counter field across multiple APIs
25+
- Fix cat indices API field naming compatibility across OpenSearch versions by using forward-compatible field names (PrimarySearchStartreeQuery*) that match the corrected 3.3.0+ naming, with fallback support for the temporary 3.2.0 field names
26+
- Fix cat APIs data type compatibility by changing byte fields from int to string to properly handle values like "0b"
27+
- Fix floating point precision loss in nodes stats concurrent_avg_slice_count field by changing from float32 to float64
1828

1929
### Security
2030

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/opensearch-project/opensearch-go/v4
22

3-
go 1.24
3+
go 1.24.0
44

55
require (
66
github.com/aws/aws-sdk-go v1.55.8

internal/test/config.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
//
3+
// The OpenSearch Contributors require contributions made to
4+
// this file be licensed under the Apache-2.0 license or a
5+
// compatible open source license.
6+
7+
package ostest
8+
9+
import (
10+
"crypto/tls"
11+
"net/http"
12+
"os"
13+
14+
"github.com/opensearch-project/opensearch-go/v4"
15+
"github.com/opensearch-project/opensearch-go/v4/opensearchapi"
16+
)
17+
18+
// IsSecure returns true when SECURE_INTEGRATION env is set to true
19+
func IsSecure() bool {
20+
return os.Getenv("SECURE_INTEGRATION") == "true"
21+
}
22+
23+
// ClientConfig returns an opensearchapi.Config for both secure and insecure opensearch
24+
func ClientConfig() (*opensearchapi.Config, error) {
25+
if !IsSecure() {
26+
// For insecure integration tests, explicitly use HTTP
27+
return &opensearchapi.Config{
28+
Client: opensearch.Config{
29+
Addresses: []string{"http://localhost:9200"},
30+
},
31+
}, nil
32+
}
33+
34+
password, err := GetPassword()
35+
if err != nil {
36+
return nil, err
37+
}
38+
39+
return &opensearchapi.Config{
40+
Client: opensearch.Config{
41+
Username: "admin",
42+
Password: password,
43+
Addresses: []string{"https://localhost:9200"},
44+
Transport: &http.Transport{
45+
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
46+
},
47+
},
48+
}, nil
49+
}
50+
51+
// GetPassword returns the password suited for the opensearch version
52+
func GetPassword() (string, error) {
53+
var (
54+
major, minor int64
55+
err error
56+
)
57+
password := "admin"
58+
version := os.Getenv("OPENSEARCH_VERSION")
59+
60+
if version != "latest" && version != "" {
61+
major, minor, _, err = opensearch.ParseVersion(version)
62+
if err != nil {
63+
return "", err
64+
}
65+
if version == "latest" || major > 2 || (major == 2 && minor >= 12) {
66+
password = "myStrongPassword123!"
67+
}
68+
} else {
69+
password = "myStrongPassword123!"
70+
}
71+
return password, nil
72+
}

internal/test/doc.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
//
3+
// The OpenSearch Contributors require contributions made to
4+
// this file be licensed under the Apache-2.0 license or a
5+
// compatible open source license.
6+
7+
// Package ostest provides OpenSearch testing utilities and infrastructure.
8+
// Integration-specific functionality is available only when building with integration tags.
9+
package ostest

internal/test/helper.go

Lines changed: 85 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
// The OpenSearch Contributors require contributions made to
44
// this file be licensed under the Apache-2.0 license or a
55
// compatible open source license.
6+
//go:build integration
67

78
package ostest
89

910
import (
1011
"context"
11-
"crypto/tls"
1212
"encoding/json"
1313
"fmt"
1414
"io"
15-
"net/http"
1615
"os"
1716
"testing"
17+
"time"
1818

1919
"github.com/stretchr/testify/assert"
2020
"github.com/stretchr/testify/require"
@@ -25,71 +25,102 @@ import (
2525
)
2626

2727
// NewClient returns an opensearchapi.Client that is adjusted for the wanted test case
28-
func NewClient() (*opensearchapi.Client, error) {
28+
// and ensures the OpenSearch cluster is ready for requests.
29+
func NewClient(t *testing.T) (*opensearchapi.Client, error) {
30+
t.Helper()
2931
config, err := ClientConfig()
3032
if err != nil {
3133
return nil, err
3234
}
33-
if config != nil {
34-
return opensearchapi.NewClient(*config)
35+
36+
client, err := opensearchapi.NewClient(*config)
37+
if err != nil {
38+
return nil, err
3539
}
36-
return opensearchapi.NewDefaultClient()
37-
}
3840

39-
// IsSecure returns true when SECURE_INTEGRATION env is set to true
40-
func IsSecure() bool {
41-
return os.Getenv("SECURE_INTEGRATION") == "true"
41+
// Always wait for cluster readiness
42+
err = waitForClusterReady(t, client)
43+
if err != nil {
44+
return nil, err
45+
}
46+
47+
return client, nil
4248
}
4349

44-
// ClientConfig returns an opensearchapi.Config for secure opensearch
45-
func ClientConfig() (*opensearchapi.Config, error) {
46-
if IsSecure() {
47-
password, err := GetPassword()
48-
if err != nil {
49-
return nil, err
50-
}
50+
// waitForClusterReady waits for the OpenSearch cluster to be fully ready for API calls.
51+
func waitForClusterReady(t *testing.T, client *opensearchapi.Client) error {
52+
t.Helper()
53+
const (
54+
maxAttempts = 25
55+
delayBetweenAttempts = 5 * time.Second
56+
requestTimeout = 2 * time.Second
57+
)
5158

52-
return &opensearchapi.Config{
53-
Client: opensearch.Config{
54-
Username: "admin",
55-
Password: password,
56-
Addresses: []string{"https://localhost:9200"},
57-
Transport: &http.Transport{
58-
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
59-
},
60-
},
61-
}, nil
59+
// Get version for informational logging
60+
major, minor, patch, err := GetVersion(client, t)
61+
if err != nil {
62+
return fmt.Errorf("failed to get OpenSearch version: %w", err)
6263
}
63-
//nolint:nilnil // easier to test with nil rather then doing complex error handling for tests
64-
return nil, nil
65-
}
6664

67-
// GetPassword returns the password suited for the opensearch version
68-
func GetPassword() (string, error) {
69-
var (
70-
major, minor int64
71-
err error
72-
)
73-
password := "admin"
74-
version := os.Getenv("OPENSEARCH_VERSION")
65+
ctx, cancel := context.WithTimeout(t.Context(), requestTimeout)
66+
defer cancel()
7567

76-
if version != "latest" && version != "" {
77-
major, minor, _, err = opensearch.ParseVersion(version)
78-
if err != nil {
79-
return "", err
68+
for attempt := range maxAttempts {
69+
// Basic cluster health check
70+
resp, err := client.Cluster.Health(ctx, nil)
71+
if err != nil || resp == nil {
72+
t.Logf("Waiting %s for cluster readiness (attempt %d/%d)...", delayBetweenAttempts, attempt+1, maxAttempts)
73+
time.Sleep(delayBetweenAttempts)
74+
75+
// Reset context for next attempt
76+
ctx, cancel = context.WithTimeout(t.Context(), requestTimeout)
77+
defer cancel()
78+
continue
8079
}
81-
if version == "latest" || major > 2 || (major == 2 && minor >= 12) {
82-
password = "myStrongPassword123!"
80+
81+
// Extended readiness validation
82+
if err := extendedReadinessCheck(ctx, client); err == nil {
83+
if attempt > 0 {
84+
t.Logf("Cluster ready after %d attempts (version %d.%d.%d)", attempt+1, major, minor, patch)
85+
}
86+
return nil
8387
}
84-
} else {
85-
password = "myStrongPassword123!"
88+
89+
t.Logf("Cluster health OK but readiness validation failed (attempt %d/%d)", attempt+1, maxAttempts)
90+
time.Sleep(delayBetweenAttempts)
91+
92+
// Reset context for next attempt
93+
ctx, cancel = context.WithTimeout(t.Context(), requestTimeout)
94+
defer cancel()
8695
}
87-
return password, nil
96+
97+
return fmt.Errorf("cluster not ready after %d attempts (version %d.%d.%d)", maxAttempts, major, minor, patch)
98+
}
99+
100+
// extendedReadinessCheck performs validation checks to ensure the
101+
// cluster is ready
102+
func extendedReadinessCheck(ctx context.Context, client *opensearchapi.Client) error {
103+
// Try a simple cluster state request - this exercises more Java serialization paths
104+
_, err := client.Cluster.State(ctx, nil)
105+
if err != nil {
106+
return fmt.Errorf("cluster state check failed: %w", err)
107+
}
108+
109+
// Try a simple nodes info request - exercises node-level serialization
110+
_, err = client.Nodes.Info(ctx, nil)
111+
if err != nil {
112+
return fmt.Errorf("nodes info check failed: %w", err)
113+
}
114+
115+
return nil
88116
}
89117

90118
// GetVersion gets cluster info and returns version as int's
91-
func GetVersion(client *opensearchapi.Client) (int64, int64, int64, error) {
92-
resp, err := client.Info(context.Background(), nil)
119+
func GetVersion(client *opensearchapi.Client, t *testing.T) (int64, int64, int64, error) {
120+
if client == nil {
121+
return 0, 0, 0, fmt.Errorf("client cannot be nil")
122+
}
123+
resp, err := client.Info(t.Context(), nil)
93124
if err != nil {
94125
return 0, 0, 0, err
95126
}
@@ -99,22 +130,22 @@ func GetVersion(client *opensearchapi.Client) (int64, int64, int64, error) {
99130
// SkipIfBelowVersion skips a test if the cluster version is below a given version
100131
func SkipIfBelowVersion(t *testing.T, client *opensearchapi.Client, majorVersion, patchVersion int64, testName string) {
101132
t.Helper()
102-
major, patch, _, err := GetVersion(client)
133+
major, patch, _, err := GetVersion(client, t)
103134
assert.Nil(t, err)
104135
if major < majorVersion || (major == majorVersion && patch < patchVersion) {
105-
t.Skipf("Skiping %s as version %d.%d.x does not support this endpoint", testName, major, patch)
136+
t.Skipf("Skipping %s as version %d.%d.x does not support this endpoint", testName, major, patch)
106137
}
107138
}
108139

109-
// SkipIfNotSecure skips a test runs against an unsecure cluster
140+
// SkipIfNotSecure skips a test that runs against an insecure cluster
110141
func SkipIfNotSecure(t *testing.T) {
111142
t.Helper()
112143
if !IsSecure() {
113-
t.Skipf("Skiping %s as it needs a secured cluster", t.Name())
144+
t.Skipf("Skipping %s as it needs a secured cluster", t.Name())
114145
}
115146
}
116147

117-
// CompareRawJSONwithParsedJSON is a helper function to determin the difference between the parsed JSON and the raw JSON
148+
// CompareRawJSONwithParsedJSON is a helper function to determine the difference between the parsed JSON and the raw JSON
118149
// this is helpful to detect missing fields in the go structs
119150
func CompareRawJSONwithParsedJSON(t *testing.T, resp any, rawResp *opensearch.Response) {
120151
t.Helper()

0 commit comments

Comments
 (0)