Files
QSfera/Server/services/search/pkg/opensearch/internal/test/os.go
T
Курнат Андрей 2315f25754 Initial QSfera import
2026-06-07 10:20:04 +03:00

257 lines
6.9 KiB
Go

package opensearchtest
import (
"context"
"errors"
"fmt"
"io"
"slices"
"testing"
opensearchgo "github.com/opensearch-project/opensearch-go/v4"
opensearchgoAPI "github.com/opensearch-project/opensearch-go/v4/opensearchapi"
"github.com/stretchr/testify/require"
"github.com/qsfera/server/services/search/pkg/config"
)
type TestClient struct {
c *opensearchgoAPI.Client
Require *testRequireClient
}
func NewDefaultTestClient(t *testing.T, cfg config.EngineOpenSearchClient) *TestClient {
client, err := opensearchgoAPI.NewClient(opensearchgoAPI.Config{
Client: opensearchgo.Config{
Addresses: cfg.Addresses,
Username: cfg.Username,
Password: cfg.Password,
},
})
require.NoError(t, err, "failed to create OpenSearch client")
return NewTestClient(t, client)
}
func NewTestClient(t *testing.T, client *opensearchgoAPI.Client) *TestClient {
tc := &TestClient{c: client}
trc := &testRequireClient{tc: tc, t: t}
tc.Require = trc
return tc
}
func (tc *TestClient) Client() *opensearchgoAPI.Client {
return tc.c
}
func (tc *TestClient) IndicesReset(ctx context.Context, indices []string) error {
indicesToDelete := make([]string, 0, len(indices))
for _, index := range indices {
exist, err := tc.IndicesExists(ctx, []string{index})
if err != nil {
return fmt.Errorf("failed to check if index %s exists: %w", index, err)
}
if !exist {
continue
}
indicesToDelete = append(indicesToDelete, index)
}
if len(indicesToDelete) == 0 {
// If no indices to delete, return nil
return nil
}
return tc.IndicesDelete(ctx, indicesToDelete)
}
func (tc *TestClient) IndicesExists(ctx context.Context, indices []string) (bool, error) {
if err := tc.IndicesRefresh(ctx, indices, []int{404}); err != nil {
return false, err
}
resp, err := tc.c.Indices.Exists(ctx, opensearchgoAPI.IndicesExistsReq{
Indices: indices,
})
switch {
case resp != nil && resp.StatusCode == 404:
return false, nil
case err != nil:
return false, fmt.Errorf("failed to check if indices exist: %w", err)
case resp != nil && resp.IsError():
return false, fmt.Errorf("failed to check if indices exist: %s", resp.String())
default:
return true, nil
}
}
func (tc *TestClient) IndicesRefresh(ctx context.Context, indices []string, allow []int) error {
resp, err := tc.c.Indices.Refresh(ctx, &opensearchgoAPI.IndicesRefreshReq{
Indices: indices,
})
isAllowed := resp != nil
isAllowed = isAllowed && resp.Inspect().Response != nil
isAllowed = isAllowed && slices.Contains(allow, resp.Inspect().Response.StatusCode)
if err != nil && !isAllowed {
return fmt.Errorf("failed to refresh indices %v: %w", indices, err)
}
return nil
}
func (tc *TestClient) IndicesDelete(ctx context.Context, indices []string) error {
if err := tc.IndicesRefresh(ctx, indices, []int{}); err != nil {
return err
}
resp, err := tc.c.Indices.Delete(ctx, opensearchgoAPI.IndicesDeleteReq{
Indices: indices,
})
switch {
case err != nil:
return fmt.Errorf("failed to delete indices: %w", err)
case !resp.Acknowledged:
return errors.New("indices deletion not acknowledged")
default:
return nil
}
}
func (tc *TestClient) IndicesCreate(ctx context.Context, index string, body io.Reader) error {
resp, err := tc.c.Indices.Create(ctx, opensearchgoAPI.IndicesCreateReq{
Index: index,
Body: body,
})
switch {
case err != nil:
return fmt.Errorf("failed to create index %s: %w", index, err)
case !resp.Acknowledged:
return fmt.Errorf("index creation not acknowledged for %s", index)
default:
return nil
}
}
func (tc *TestClient) IndicesCount(ctx context.Context, indices []string, body io.Reader) (int, error) {
if err := tc.IndicesRefresh(ctx, indices, []int{404}); err != nil {
return 0, err
}
resp, err := tc.c.Indices.Count(ctx, &opensearchgoAPI.IndicesCountReq{
Indices: indices,
Body: body,
})
switch {
case err != nil:
return 0, fmt.Errorf("failed to count documents in indices: %w", err)
default:
return resp.Count, nil
}
}
func (tc *TestClient) DocumentCreate(ctx context.Context, index, id string, body io.Reader) error {
if err := tc.IndicesRefresh(ctx, []string{index}, []int{404}); err != nil {
return err
}
_, err := tc.c.Document.Create(ctx, opensearchgoAPI.DocumentCreateReq{
Index: index,
DocumentID: id,
Body: body,
})
switch {
case err != nil:
return fmt.Errorf("failed to create document in index %s: %w", index, err)
default:
return nil
}
}
func (tc *TestClient) Update(ctx context.Context, index, id string, body io.Reader) error {
if err := tc.IndicesRefresh(ctx, []string{index}, []int{404}); err != nil {
return err
}
_, err := tc.c.Update(ctx, opensearchgoAPI.UpdateReq{
Index: index,
DocumentID: id,
Body: body,
})
switch {
case err != nil:
return fmt.Errorf("failed to update document in index %s: %w", index, err)
default:
return nil
}
}
func (tc *TestClient) Search(ctx context.Context, index string, body io.Reader) (opensearchgoAPI.SearchHits, error) {
if err := tc.IndicesRefresh(ctx, []string{index}, []int{404}); err != nil {
return opensearchgoAPI.SearchHits{}, err
}
resp, err := tc.c.Search(ctx, &opensearchgoAPI.SearchReq{
Indices: []string{index},
Body: body,
})
if err != nil {
return opensearchgoAPI.SearchHits{}, fmt.Errorf("failed to search in index %s: %w", index, err)
}
return resp.Hits, nil
}
type testRequireClient struct {
tc *TestClient
t *testing.T
}
func (trc *testRequireClient) IndicesReset(indices []string) {
require.NoError(trc.t, trc.tc.IndicesReset(trc.t.Context(), indices))
}
func (trc *testRequireClient) IndicesRefresh(indices []string, ignore []int) {
require.NoError(trc.t, trc.tc.IndicesRefresh(trc.t.Context(), indices, ignore))
}
func (trc *testRequireClient) IndicesCreate(index string, body io.Reader) {
require.NoError(trc.t, trc.tc.IndicesCreate(trc.t.Context(), index, body))
}
func (trc *testRequireClient) IndicesDelete(indices []string) {
require.NoError(trc.t, trc.tc.IndicesDelete(trc.t.Context(), indices))
}
func (trc *testRequireClient) IndicesCount(indices []string, body io.Reader, expected int) {
count, err := trc.tc.IndicesCount(trc.t.Context(), indices, body)
switch {
case expected <= 0:
require.True(trc.t, count <= 0, "expected indices to have no documents, but got a count of %d", count)
default:
require.Equal(trc.t, expected, count, "expected indices to have %d documents, but got %d", expected, count)
require.NoError(trc.t, err, "expected indices to have documents, but got an error")
}
}
func (trc *testRequireClient) DocumentCreate(index, id string, body io.Reader) {
require.NoError(trc.t, trc.tc.DocumentCreate(trc.t.Context(), index, id, body))
}
func (trc *testRequireClient) Update(index, id string, body io.Reader) {
require.NoError(trc.t, trc.tc.Update(trc.t.Context(), index, id, body))
}
func (trc *testRequireClient) Search(index string, body io.Reader) opensearchgoAPI.SearchHits {
hits, err := trc.tc.Search(trc.t.Context(), index, body)
require.NoError(trc.t, err)
return hits
}