Skip to content
This repository was archived by the owner on Nov 7, 2025. It is now read-only.

Commit f356c43

Browse files
committed
Add integration tests for new "*" configurations
Add test_wildcard_clickhouse.go test which checks the "*": target: [clickhouse] scenario (everything goes to ClickHouse) and test_wildcard_disabled.go test which checks the "*": target: [] scenario (all query/ingest is disabled except for explicitly configured indexes).
1 parent c8ca7c8 commit f356c43

File tree

7 files changed

+330
-6
lines changed

7 files changed

+330
-6
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
frontendConnectors:
2+
- name: elastic-ingest
3+
type: elasticsearch-fe-ingest
4+
config:
5+
listenPort: 8080
6+
- name: elastic-query
7+
type: elasticsearch-fe-query
8+
config:
9+
listenPort: 8080
10+
backendConnectors:
11+
- name: my-minimal-elasticsearch
12+
type: elasticsearch
13+
config:
14+
url: "http://{{ .elasticsearch_host }}:{{ .elasticsearch_port }}"
15+
user: elastic
16+
password: quesmaquesma
17+
- name: my-clickhouse-instance
18+
type: clickhouse-os
19+
config:
20+
url: clickhouse://{{ .clickhouse_host }}:{{ .clickhouse_port }}
21+
ingestStatistics: true
22+
processors:
23+
- name: my-query-processor
24+
type: quesma-v1-processor-query
25+
config:
26+
indexes:
27+
"*":
28+
target: [ my-clickhouse-instance ]
29+
- name: my-ingest-processor
30+
type: quesma-v1-processor-ingest
31+
config:
32+
indexes:
33+
"*":
34+
target: [ my-clickhouse-instance ]
35+
pipelines:
36+
- name: my-elasticsearch-proxy-read
37+
frontendConnectors: [ elastic-query ]
38+
processors: [ my-query-processor ]
39+
backendConnectors: [ my-minimal-elasticsearch, my-clickhouse-instance ]
40+
- name: my-elasticsearch-proxy-write
41+
frontendConnectors: [ elastic-ingest ]
42+
processors: [ my-ingest-processor ]
43+
backendConnectors: [ my-minimal-elasticsearch, my-clickhouse-instance ]
44+
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
frontendConnectors:
2+
- name: elastic-ingest
3+
type: elasticsearch-fe-ingest
4+
config:
5+
listenPort: 8080
6+
- name: elastic-query
7+
type: elasticsearch-fe-query
8+
config:
9+
listenPort: 8080
10+
backendConnectors:
11+
- name: my-minimal-elasticsearch
12+
type: elasticsearch
13+
config:
14+
url: "http://{{ .elasticsearch_host }}:{{ .elasticsearch_port }}"
15+
user: elastic
16+
password: quesmaquesma
17+
- name: my-clickhouse-instance
18+
type: clickhouse-os
19+
config:
20+
url: clickhouse://{{ .clickhouse_host }}:{{ .clickhouse_port }}
21+
ingestStatistics: true
22+
processors:
23+
- name: my-query-processor
24+
type: quesma-v1-processor-query
25+
config:
26+
indexes:
27+
"explicitly_disabled1":
28+
target: [ ]
29+
"explicitly_disabled3":
30+
target: [ ]
31+
"query_enabled":
32+
target: [ my-clickhouse-instance ]
33+
"*":
34+
target: [ ]
35+
- name: my-ingest-processor
36+
type: quesma-v1-processor-ingest
37+
config:
38+
indexes:
39+
"explicitly_disabled2":
40+
target: [ ]
41+
"explicitly_disabled3":
42+
target: [ ]
43+
"ingest_enabled":
44+
target: [ my-clickhouse-instance ]
45+
"*":
46+
target: [ ]
47+
pipelines:
48+
- name: my-elasticsearch-proxy-read
49+
frontendConnectors: [ elastic-query ]
50+
processors: [ my-query-processor ]
51+
backendConnectors: [ my-minimal-elasticsearch, my-clickhouse-instance ]
52+
- name: my-elasticsearch-proxy-write
53+
frontendConnectors: [ elastic-ingest ]
54+
processors: [ my-ingest-processor ]
55+
backendConnectors: [ my-minimal-elasticsearch, my-clickhouse-instance ]
56+

ci/it/integration_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,13 @@ func TestDualWriteAndCommonTableTestcase(t *testing.T) {
3939
testCase := testcases.NewDualWriteAndCommonTableTestcase()
4040
runIntegrationTest(t, testCase)
4141
}
42+
43+
func TestWildcardDisabledTestcase(t *testing.T) {
44+
testCase := testcases.NewWildcardDisabledTestcase()
45+
runIntegrationTest(t, testCase)
46+
}
47+
48+
func TestWildcardClickhouseTestcase(t *testing.T) {
49+
testCase := testcases.NewWildcardClickhouseTestcase()
50+
runIntegrationTest(t, testCase)
51+
}

ci/it/testcases/test_reading_clickhouse_tables.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package testcases
66
import (
77
"context"
88
"encoding/json"
9+
"fmt"
910
"github.com/stretchr/testify/assert"
1011
"net/http"
1112
"testing"
@@ -36,6 +37,7 @@ func (a *ReadingClickHouseTablesIntegrationTestcase) RunTests(ctx context.Contex
3637
t.Run("test basic request", func(t *testing.T) { a.testBasicRequest(ctx, t) })
3738
t.Run("test random thing", func(t *testing.T) { a.testRandomThing(ctx, t) })
3839
t.Run("test wildcard goes to elastic", func(t *testing.T) { a.testWildcardGoesToElastic(ctx, t) })
40+
t.Run("test ingest is disabled", func(t *testing.T) { a.testIngestIsDisabled(ctx, t) })
3941
return nil
4042
}
4143

@@ -91,5 +93,15 @@ func (a *ReadingClickHouseTablesIntegrationTestcase) testWildcardGoesToElastic(c
9193
assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Elastic-Product"))
9294
}
9395

94-
// At this moment this configuration does not disable ingest (ingest req's will get routed to ES and handled normally)
95-
// Future test idea -> ensure ingest req gets rejected.
96+
func (a *ReadingClickHouseTablesIntegrationTestcase) testIngestIsDisabled(ctx context.Context, t *testing.T) {
97+
// There is no ingest pipeline, so Quesma should reject all ingest requests
98+
for _, tt := range []string{"test_table", "extra_index"} {
99+
t.Run(tt, func(t *testing.T) {
100+
resp, bodyBytes := a.RequestToQuesma(ctx, t, "POST", fmt.Sprintf("/%s/_doc", tt), []byte(`{"name": "Piotr", "age": 11111}`))
101+
assert.Contains(t, string(bodyBytes), "index_closed_exception")
102+
assert.Equal(t, http.StatusOK, resp.StatusCode)
103+
assert.Equal(t, "Clickhouse", resp.Header.Get("X-Quesma-Source"))
104+
assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Elastic-Product"))
105+
})
106+
}
107+
}

ci/it/testcases/test_two_pipelines.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,13 @@ func (a *QueryAndIngestPipelineTestcase) testBasicRequest(ctx context.Context, t
4747

4848
func (a *QueryAndIngestPipelineTestcase) testWildcardGoesToElastic(ctx context.Context, t *testing.T) {
4949
// Given an index in Elasticsearch which falls under `*` in the configuration
50-
var err error
51-
if _, err = a.RequestToElasticsearch(ctx, "PUT", "/unmentioned_index", nil); err != nil {
50+
if _, err := a.RequestToElasticsearch(ctx, "PUT", "/unmentioned_index", nil); err != nil {
5251
t.Fatalf("Failed to create index: %s", err)
5352
}
54-
if _, err = a.RequestToElasticsearch(ctx, "POST", "/unmentioned_index/_doc/1", []byte(`{"name": "Alice"}`)); err != nil {
53+
if _, err := a.RequestToElasticsearch(ctx, "POST", "/unmentioned_index/_doc/1", []byte(`{"name": "Alice"}`)); err != nil {
5554
t.Fatalf("Failed to insert document: %s", err)
5655
}
57-
if _, err = a.RequestToElasticsearch(ctx, "POST", "/unmentioned_index/_refresh", nil); err != nil {
56+
if _, err := a.RequestToElasticsearch(ctx, "POST", "/unmentioned_index/_refresh", nil); err != nil {
5857
t.Fatalf("Failed to refresh index: %s", err)
5958
}
6059
// When Quesma searches for that document
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright Quesma, licensed under the Elastic License 2.0.
2+
// SPDX-License-Identifier: Elastic-2.0
3+
4+
package testcases
5+
6+
import (
7+
"context"
8+
"github.com/stretchr/testify/assert"
9+
"io"
10+
"net/http"
11+
"testing"
12+
)
13+
14+
type WildcardClickhouseTestcase struct {
15+
IntegrationTestcaseBase
16+
}
17+
18+
func NewWildcardClickhouseTestcase() *WildcardClickhouseTestcase {
19+
return &WildcardClickhouseTestcase{
20+
IntegrationTestcaseBase: IntegrationTestcaseBase{
21+
ConfigTemplate: "quesma-wildcard-clickhouse.yml.template",
22+
},
23+
}
24+
}
25+
26+
func (a *WildcardClickhouseTestcase) SetupContainers(ctx context.Context) error {
27+
containers, err := setupAllContainersWithCh(ctx, a.ConfigTemplate)
28+
if err != nil {
29+
return err
30+
}
31+
a.Containers = containers
32+
return nil
33+
}
34+
35+
func (a *WildcardClickhouseTestcase) RunTests(ctx context.Context, t *testing.T) error {
36+
t.Run("test basic request", func(t *testing.T) { a.testBasicRequest(ctx, t) })
37+
t.Run("test ingest+query works", func(t *testing.T) { a.testIngestQueryWorks(ctx, t) })
38+
t.Run("test clickhouse table autodiscovery", func(t *testing.T) { a.testClickHouseTableAutodiscovery(ctx, t) })
39+
return nil
40+
}
41+
42+
func (a *WildcardClickhouseTestcase) testBasicRequest(ctx context.Context, t *testing.T) {
43+
resp, _ := a.RequestToQuesma(ctx, t, "GET", "/", nil)
44+
assert.Equal(t, http.StatusOK, resp.StatusCode)
45+
}
46+
47+
func (a *WildcardClickhouseTestcase) testIngestQueryWorks(ctx context.Context, t *testing.T) {
48+
// First ingest...
49+
resp, bodyBytes := a.RequestToQuesma(ctx, t, "POST", "/test_index/_doc", []byte(`{"name": "Piotr", "age": 22222}`))
50+
assert.Equal(t, http.StatusOK, resp.StatusCode)
51+
assert.Equal(t, "Clickhouse", resp.Header.Get("X-Quesma-Source"))
52+
assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Elastic-Product"))
53+
54+
// ...then query inserted data
55+
resp, bodyBytes = a.RequestToQuesma(ctx, t, "POST", "/test_index/_search", []byte(`{"query": {"match_all": {}}}`))
56+
assert.Contains(t, string(bodyBytes), "Piotr")
57+
assert.Contains(t, string(bodyBytes), "22222")
58+
assert.Equal(t, http.StatusOK, resp.StatusCode)
59+
assert.Equal(t, "Clickhouse", resp.Header.Get("X-Quesma-Source"))
60+
assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Elastic-Product"))
61+
62+
// Also make sure no such index got created in Elasticsearch
63+
resp, err := a.RequestToElasticsearch(ctx, "GET", "/test_index/_refresh", nil)
64+
if err != nil {
65+
t.Fatalf("Failed to make GET request: %s", err)
66+
}
67+
defer resp.Body.Close()
68+
bodyBytes, err = io.ReadAll(resp.Body)
69+
if err != nil {
70+
t.Fatalf("Failed to read response body: %s", err)
71+
}
72+
73+
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
74+
assert.Contains(t, string(bodyBytes), "no such index [test_index]")
75+
}
76+
77+
func (a *WildcardClickhouseTestcase) testClickHouseTableAutodiscovery(ctx context.Context, t *testing.T) {
78+
// Create test table in ClickHouse
79+
createTableQuery := "CREATE TABLE IF NOT EXISTS existing_clickhouse_table (id UInt32, name String) ENGINE = Memory"
80+
if _, err := a.ExecuteClickHouseStatement(ctx, createTableQuery); err != nil {
81+
t.Fatalf("Failed to create table: %s", err)
82+
}
83+
insertRowsQuery := "INSERT INTO existing_clickhouse_table (id, name) VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie')"
84+
if _, err := a.ExecuteClickHouseStatement(ctx, insertRowsQuery); err != nil {
85+
t.Fatalf("Failed to insert rows: %s", err)
86+
}
87+
88+
resp, _ := a.RequestToQuesma(ctx, t, "POST", "/existing_clickhouse_table/_search", []byte(`{"query": {"match_all": {}}}`))
89+
assert.Equal(t, "Clickhouse", resp.Header.Get("X-Quesma-Source"))
90+
91+
// This returns 500 Internal Server Error, but will be tackled in separate PR.
92+
// (The table has not yet been discovered by Quesma )
93+
//
94+
// assert.Equal(t, http.StatusOK, resp.StatusCode)
95+
// assert.Contains(t, string(bodyBytes), "Alice")
96+
// assert.Contains(t, string(bodyBytes), "Bob")
97+
// assert.Contains(t, string(bodyBytes), "Charlie")
98+
// assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Elastic-Product"))
99+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Copyright Quesma, licensed under the Elastic License 2.0.
2+
// SPDX-License-Identifier: Elastic-2.0
3+
4+
package testcases
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"github.com/stretchr/testify/assert"
10+
"net/http"
11+
"testing"
12+
)
13+
14+
type WildcardDisabledTestcase struct {
15+
IntegrationTestcaseBase
16+
}
17+
18+
func NewWildcardDisabledTestcase() *WildcardDisabledTestcase {
19+
return &WildcardDisabledTestcase{
20+
IntegrationTestcaseBase: IntegrationTestcaseBase{
21+
ConfigTemplate: "quesma-wildcard-disabled.yml.template",
22+
},
23+
}
24+
}
25+
26+
func (a *WildcardDisabledTestcase) SetupContainers(ctx context.Context) error {
27+
containers, err := setupAllContainersWithCh(ctx, a.ConfigTemplate)
28+
if err != nil {
29+
return err
30+
}
31+
a.Containers = containers
32+
return nil
33+
}
34+
35+
func (a *WildcardDisabledTestcase) RunTests(ctx context.Context, t *testing.T) error {
36+
t.Run("test basic request", func(t *testing.T) { a.testBasicRequest(ctx, t) })
37+
t.Run("test query is disabled", func(t *testing.T) { a.testQueryIsDisabled(ctx, t) })
38+
t.Run("test ingest is disabled", func(t *testing.T) { a.testIngestIsDisabled(ctx, t) })
39+
t.Run("test explicit index query enabled", func(t *testing.T) { a.testExplicitIndexQueryIsEnabled(ctx, t) })
40+
t.Run("test explicit index ingest enabled", func(t *testing.T) { a.testExplicitIndexIngestIsEnabled(ctx, t) })
41+
return nil
42+
}
43+
44+
func (a *WildcardDisabledTestcase) testBasicRequest(ctx context.Context, t *testing.T) {
45+
resp, _ := a.RequestToQuesma(ctx, t, "GET", "/", nil)
46+
assert.Equal(t, http.StatusOK, resp.StatusCode)
47+
}
48+
49+
func (a *WildcardDisabledTestcase) testQueryIsDisabled(ctx context.Context, t *testing.T) {
50+
if _, err := a.RequestToElasticsearch(ctx, "PUT", "/elastic_index1", nil); err != nil {
51+
t.Fatalf("Failed to create index: %s", err)
52+
}
53+
if _, err := a.RequestToElasticsearch(ctx, "POST", "/elastic_index1/_refresh", nil); err != nil {
54+
t.Fatalf("Failed to refresh index: %s", err)
55+
}
56+
57+
// Quesma should reject all queries
58+
for _, tt := range []string{"test_table", "extra_index", "explicitly_disabled1", "explicitly_disabled2", "explicitly_disabled3", "ingest_enabled", "elastic_index1"} {
59+
t.Run(tt, func(t *testing.T) {
60+
resp, bodyBytes := a.RequestToQuesma(ctx, t, "POST", fmt.Sprintf("/%s/_search", tt), []byte(`{"query": {"match_all": {}}}`))
61+
assert.Contains(t, string(bodyBytes), "index_closed_exception")
62+
assert.Equal(t, http.StatusOK, resp.StatusCode)
63+
assert.Equal(t, "Clickhouse", resp.Header.Get("X-Quesma-Source"))
64+
assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Elastic-Product"))
65+
})
66+
}
67+
}
68+
69+
func (a *WildcardDisabledTestcase) testIngestIsDisabled(ctx context.Context, t *testing.T) {
70+
if _, err := a.RequestToElasticsearch(ctx, "PUT", "/elastic_index2", nil); err != nil {
71+
t.Fatalf("Failed to create index: %s", err)
72+
}
73+
if _, err := a.RequestToElasticsearch(ctx, "POST", "/elastic_index2/_refresh", nil); err != nil {
74+
t.Fatalf("Failed to refresh index: %s", err)
75+
}
76+
77+
// Quesma should reject all ingest requests
78+
for _, tt := range []string{"test_table", "extra_index", "explicitly_disabled1", "explicitly_disabled2", "explicitly_disabled3", "query_enabled", "elastic_index2"} {
79+
t.Run(tt, func(t *testing.T) {
80+
resp, bodyBytes := a.RequestToQuesma(ctx, t, "POST", fmt.Sprintf("/%s/_doc", tt), []byte(`{"name": "Piotr", "age": 22222}`))
81+
assert.Contains(t, string(bodyBytes), "index_closed_exception")
82+
assert.Equal(t, http.StatusOK, resp.StatusCode)
83+
assert.Equal(t, "Clickhouse", resp.Header.Get("X-Quesma-Source"))
84+
assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Elastic-Product"))
85+
})
86+
}
87+
}
88+
89+
func (a *WildcardDisabledTestcase) testExplicitIndexQueryIsEnabled(ctx context.Context, t *testing.T) {
90+
// query_enabled is the only index with query enabled
91+
resp, bodyBytes := a.RequestToQuesma(ctx, t, "POST", "/query_enabled/_search", []byte(`{"query": {"match_all": {}}}`))
92+
assert.NotContains(t, string(bodyBytes), "index_closed_exception")
93+
assert.Equal(t, "Clickhouse", resp.Header.Get("X-Quesma-Source"))
94+
// TODO: the actual request currently fails since there's no such table in ClickHouse
95+
}
96+
97+
func (a *WildcardDisabledTestcase) testExplicitIndexIngestIsEnabled(ctx context.Context, t *testing.T) {
98+
// ingest_enabled is the only index with ingest enabled
99+
resp, bodyBytes := a.RequestToQuesma(ctx, t, "POST", "/ingest_enabled/_doc", []byte(`{"name": "Piotr", "age": 22222}`))
100+
assert.NotContains(t, string(bodyBytes), "index_closed_exception")
101+
assert.Equal(t, http.StatusOK, resp.StatusCode)
102+
assert.Equal(t, "Clickhouse", resp.Header.Get("X-Quesma-Source"))
103+
assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Elastic-Product"))
104+
}

0 commit comments

Comments
 (0)