Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion v2/api/archive-query-service/v2/messages.proto
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ message GetEventsRequest {
yaml: "filters:\n transactionHash: zvqvtjzvgwgpegmalkkjedhbdrnckqcfthpzfqzxbcljttljzidmvaxalxyz\npagination:\n offset: 0\n size: 10"
};
};
map<string, string> filters = 1 [(openapi.v3.property) = {description:"Filters restrict the results by single values. Allowed: transactionHash, tickNumber, eventType"}];
map<string, string> filters = 1 [(openapi.v3.property) = {description:"Filters restrict the results by single values. Allowed: transactionHash, tickNumber, logType"}];
Pagination pagination = 2 [(openapi.v3.property) = {description:"Optional paging information."}];
}

Expand Down
2 changes: 1 addition & 1 deletion v2/api/archive-query-service/v2/query_services.proto
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ service ArchiveQueryService {
// |-----------------|---------|----------|---------------------------------------------------------|
// | transactionHash | string | Hash | Only find events for the specified transaction hash. |
// | tickNumber | string | Numeric | Only find events for the specified tick number. |
// | logType | string | Numeric | Only find events with the specified type (0,1,2,3,8,13).|
// | logType | string | Numeric | Only find events with the specified type (0,1,2,3,8,13). Comma-separated for multiple values.|
rpc GetEvents(GetEventsRequest) returns (GetEventsResponse) {
option (openapi.v3.operation) = {
tags: ["Events (Beta)"]
Expand Down
17 changes: 5 additions & 12 deletions v2/domain/repository/elastic/events.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package elastic

import (
"bytes"
"context"
"encoding/json"
"fmt"
Expand Down Expand Up @@ -109,18 +108,14 @@ func createEventsQuery(filters map[string][]string, from, size uint32) string {
if k == "logType" {
esField = "type"
}
if len(filters[k]) == 1 {
if len(filters[k]) > 1 {
filterStrings = append(filterStrings, fmt.Sprintf(`{"terms":{"%s":["%s"]}}`, esField, strings.Join(filters[k], `","`)))
} else if len(filters[k]) == 1 {
filterStrings = append(filterStrings, fmt.Sprintf(`{"term":{"%s":"%s"}}`, esField, filters[k][0]))
}
}

filterClause := ""
if len(filterStrings) > 0 {
filterClause = strings.Join(filterStrings, ",")
}

var buf bytes.Buffer
buf.WriteString(fmt.Sprintf(`{
return fmt.Sprintf(`{
"query": {
"bool": {
"filter": [%s]
Expand All @@ -130,7 +125,5 @@ func createEventsQuery(filters map[string][]string, from, size uint32) string {
"from": %d,
"size": %d,
"track_total_hits": %d
}`, filterClause, from, size, maxTrackTotalHits))

return buf.String()
}`, strings.Join(filterStrings, ","), from, size, maxTrackTotalHits)
}
2 changes: 1 addition & 1 deletion v2/domain/repository/elastic/events_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func (s *eventsSuite) Test_GetEvents_FilterByTickNumber() {
assert.Empty(s.T(), diff, "event should match. diff: %s", diff)
}

func (s *eventsSuite) Test_GetEvents_FilterByEventType() {
func (s *eventsSuite) Test_GetEvents_FilterByLogType() {
filters := map[string][]string{"logType": {"8"}}
events, hits, err := s.repo.GetEvents(s.ctx, filters, 0, 10)
require.NoError(s.T(), err, "getting events by event type")
Expand Down
24 changes: 22 additions & 2 deletions v2/domain/repository/elastic/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func Test_createEventsQuery_withTickNumber(t *testing.T) {
assert.Equal(t, "42", termFilter["tickNumber"])
}

func Test_createEventsQuery_withEventType(t *testing.T) {
func Test_createEventsQuery_withLogType(t *testing.T) {
filters := map[string][]string{
"logType": {"1"},
}
Expand All @@ -93,7 +93,7 @@ func Test_createEventsQuery_withEventType(t *testing.T) {
filterArr := boolQuery["filter"].([]any)
require.Len(t, filterArr, 1)

// eventType should map to ES field "type"
// logType should map to ES field "type"
termFilter := filterArr[0].(map[string]any)["term"].(map[string]any)
assert.Equal(t, "1", termFilter["type"])
}
Expand All @@ -116,6 +116,26 @@ func Test_createEventsQuery_withMultipleFilters(t *testing.T) {
assert.Len(t, filterArr, 3)
}

func Test_createEventsQuery_withMultipleLogTypes(t *testing.T) {
filters := map[string][]string{
"logType": {"0", "1", "3"},
}
query := createEventsQuery(filters, 0, 10)

var parsed map[string]any
err := json.Unmarshal([]byte(query), &parsed)
require.NoError(t, err)

q := parsed["query"].(map[string]any)
boolQuery := q["bool"].(map[string]any)
filterArr := boolQuery["filter"].([]any)
require.Len(t, filterArr, 1)

termsFilter := filterArr[0].(map[string]any)["terms"].(map[string]any)
typeValues := termsFilter["type"].([]any)
assert.Equal(t, []any{"0", "1", "3"}, typeValues)
}

func Test_createEventsQuery_withPagination(t *testing.T) {
query := createEventsQuery(nil, 20, 50)

Expand Down
2 changes: 1 addition & 1 deletion v2/grpc/service_events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func TestArchiveQueryService_GetEvents_InvalidFilter(t *testing.T) {
assert.Contains(t, st.Message(), "unsupported filter")
}

func TestArchiveQueryService_GetEvents_InvalidEventType(t *testing.T) {
func TestArchiveQueryService_GetEvents_InvalidLogType(t *testing.T) {
evService := &EventsServiceStub{}
service := NewArchiveQueryService(nil, nil, nil, nil, evService, NewPageSizeLimits(1000, 10))

Expand Down
40 changes: 28 additions & 12 deletions v2/grpc/validations_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,33 @@ import (

var allowedEventFilters = [3]string{"transactionHash", "tickNumber", "logType"}

const maxLogType = 13
const maxLogTypeValues = maxLogType + 1 + 1 // 0-maxLogType + type 255

func createEventsFilters(filters map[string]string) (map[string][]string, error) {
res := make(map[string][]string)
for k, v := range filters {
trimmed := strings.TrimSpace(v)
if trimmed == "" {
return nil, fmt.Errorf("filter %s contains an empty value", k)
}
res[k] = []string{trimmed}
if k == "logType" && strings.Contains(trimmed, ",") {
split := strings.Split(trimmed, ",")
if len(split) > maxLogTypeValues {
return nil, fmt.Errorf("filter %s has more than %d values", k, maxLogTypeValues)
}
values := make([]string, 0, len(split))
for _, s := range split {
val := strings.TrimSpace(s)
if val == "" {
return nil, fmt.Errorf("filter %s contains an empty value", k)
}
values = append(values, val)
}
res[k] = values
} else {
res[k] = []string{trimmed}
}
}
return res, nil
}
Expand Down Expand Up @@ -44,18 +63,15 @@ func validateEventsFilters(filters map[string][]string) error {
return fmt.Errorf("invalid [%s] filter: must be a valid number but was [%s]", key, values[0])
}
case "logType":
if len(values) != 1 {
return fmt.Errorf("filter [%s] must have exactly one value", key)
for _, v := range values {
uVal, err := strconv.ParseUint(v, 10, 32)
if err != nil {
return fmt.Errorf("invalid [%s] filter: must be a valid number but was [%s]", key, v)
}
if uVal > maxLogType && uVal != 255 {
return fmt.Errorf("invalid [%s] filter: must be 0-%d or 255 but was [%d]", key, maxLogType, uVal)
}
}

uVal, err := strconv.ParseUint(values[0], 10, 32)
if err != nil {
return fmt.Errorf("invalid [%s] filter: must be a valid number but was [%s]", key, values[0])
}
if uVal > 14 && uVal != 255 {
return fmt.Errorf("invalid [%s] filter: must be 0-13 or 255 but was [%d]", key, uVal)
}

default:
return fmt.Errorf("unsupported filter: [%s]", key)
}
Expand Down
54 changes: 54 additions & 0 deletions v2/grpc/validations_events_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package grpc

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -100,6 +101,59 @@ func TestValidateEventsFilters_CombinedFilters(t *testing.T) {
require.NoError(t, err)
}

func TestCreateEventsFilters_MultipleLogTypes(t *testing.T) {
filters := map[string]string{
"logType": "0,1,3",
}
result, err := createEventsFilters(filters)
require.NoError(t, err)
assert.Equal(t, map[string][]string{
"logType": {"0", "1", "3"},
}, result)
}

func TestCreateEventsFilters_MultipleLogTypesWithSpaces(t *testing.T) {
filters := map[string]string{
"logType": " 0 , 1 , 3 ",
}
result, err := createEventsFilters(filters)
require.NoError(t, err)
assert.Equal(t, map[string][]string{
"logType": {"0", "1", "3"},
}, result)
}

func TestCreateEventsFilters_MultipleLogTypesExceedsMax(t *testing.T) {
filters := map[string]string{
"logType": "0,1,2,3,4,5,6,7,8,9,10,11,12,13,255,0",
}
_, err := createEventsFilters(filters)
require.Error(t, err)
assert.Contains(t, err.Error(), fmt.Sprintf("more than %d values", maxLogTypeValues))
}

func TestCreateEventsFilters_MultipleLogTypesEmptyValue(t *testing.T) {
filters := map[string]string{
"logType": "0,,1",
}
_, err := createEventsFilters(filters)
require.Error(t, err)
assert.Contains(t, err.Error(), "empty value")
}

func TestValidateEventsFilters_MultipleValidLogTypes(t *testing.T) {
filters := map[string][]string{"logType": {"0", "1", "3"}}
err := validateEventsFilters(filters)
require.NoError(t, err)
}

func TestValidateEventsFilters_MultipleLogTypesOneInvalid(t *testing.T) {
filters := map[string][]string{"logType": {"0", "256", "1"}}
err := validateEventsFilters(filters)
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid [logType] filter")
}

func TestValidateEventsFilters_EmptyFilters(t *testing.T) {
err := validateEventsFilters(nil)
require.NoError(t, err)
Expand Down
14 changes: 4 additions & 10 deletions v2/test/grpc_server_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package test

import (
"context"
"testing"
"time"

"github.com/google/go-cmp/cmp"
api "github.com/qubic/archive-query-service/v2/api/archive-query-service/v2"
Expand Down Expand Up @@ -210,7 +208,7 @@ func (s *ServerTestSuite) TestGetEvents_FilterByTickNumber() {
assert.Equal(t, uint32(15001), resp.Events[0].TickNumber)
}

func (s *ServerTestSuite) TestGetEvents_FilterByEventType() {
func (s *ServerTestSuite) TestGetEvents_FilterByLogType() {
t := s.T()
expectedFilters := map[string][]string{"logType": {"8"}}
s.mockEvService.EXPECT().GetEvents(gomock.Any(), expectedFilters, uint32(0), uint32(10)).
Expand Down Expand Up @@ -258,19 +256,15 @@ func (s *ServerTestSuite) TestGetEvents_InvalidFilter() {
assert.Contains(t, st.Message(), "unsupported filter")
}

func (s *ServerTestSuite) TestGetEvents_InvalidEventType() {
func (s *ServerTestSuite) TestGetEvents_InvalidLogType() {
t := s.T()
ctx, cancel := context.WithTimeout(t.Context(), 3*time.Second)
defer cancel()

_, err := s.client.GetEvents(ctx, &api.GetEventsRequest{
Filters: map[string]string{"logType": "invalid"},
_, err := s.client.GetEvents(t.Context(), &api.GetEventsRequest{
Filters: map[string]string{"logType": "256"},
})
require.Error(t, err)
st, ok := status.FromError(err)
require.True(t, ok)
assert.Equal(t, codes.InvalidArgument, st.Code())
assert.Contains(t, st.Message(), "validating filters")
assert.Contains(t, st.Message(), "invalid [logType] filter")
}

Expand Down
6 changes: 3 additions & 3 deletions v2/test/integration/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (s *EventsE2ESuite) TestGRPC_GetEvents_FilterByTickNumber() {
require.Equal(t, uint32(15001), resp.Events[0].TickNumber)
}

func (s *EventsE2ESuite) TestGRPC_GetEvents_FilterByEventType() {
func (s *EventsE2ESuite) TestGRPC_GetEvents_FilterByLogType() {
t := s.T()
resp, err := s.grpcClient.GetEvents(t.Context(), &api.GetEventsRequest{
Filters: map[string]string{"logType": "8"},
Expand Down Expand Up @@ -250,7 +250,7 @@ func (s *EventsE2ESuite) TestGRPC_GetEvents_InvalidFilter() {
require.Equal(t, codes.InvalidArgument, st.Code())
}

func (s *EventsE2ESuite) TestGRPC_GetEvents_InvalidEventType() {
func (s *EventsE2ESuite) TestGRPC_GetEvents_InvalidLogType() {
t := s.T()
_, err := s.grpcClient.GetEvents(t.Context(), &api.GetEventsRequest{
Filters: map[string]string{"logType": "256"},
Expand Down Expand Up @@ -306,7 +306,7 @@ func (s *EventsE2ESuite) TestHTTP_GetEvents_FilterByTransactionHash() {
require.Equal(t, float64(2), hits["total"])
}

func (s *EventsE2ESuite) TestHTTP_GetEvents_FilterByEventType() {
func (s *EventsE2ESuite) TestHTTP_GetEvents_FilterByLogType() {
t := s.T()
result, statusCode := s.postGetEvents(`{"filters":{"logType":"8"}}`)
require.Equal(t, http.StatusOK, statusCode)
Expand Down
Loading