Skip to content
Merged
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
6 changes: 3 additions & 3 deletions acceptance/petstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ func (suite *PetStoreSuite) TestSearch_Paging() {
assert.NoError(t, err)
assert.NotNil(t, data)

assert.Equal(t, float64(35), data["total"])
assert.Equal(t, float64(51), data["total"])

items := data["results"].([]any)
assert.Len(t, items, 10)
Expand All @@ -335,13 +335,13 @@ func (suite *PetStoreSuite) TestSearch_Paging() {
assert.NoError(t, err)
assert.NotNil(t, data)

assert.Equal(t, float64(35), data["total"])
assert.Equal(t, float64(51), data["total"])

items := data["results"].([]any)
assert.Len(t, items, 10)
evt := items[0].(map[string]interface{})
assert.Equal(t, "HTTP", evt["type"])
assert.Equal(t, "/pet/{petId}", evt["title"])
assert.Equal(t, "/pet/{petId}/uploadImage", evt["title"])
assert.Equal(t, "Swagger Petstore", evt["domain"])
}),
)
Expand Down
20 changes: 14 additions & 6 deletions js/faker/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ import (
)

func ToJsonSchema(v goja.Value, rt *goja.Runtime) (*jsonSchema.Schema, error) {
s := &jsonSchema.Schema{}
if v == goja.Undefined() {
return nil, nil
}

if s, ok := v.Export().(*jsonSchema.Schema); ok {
return s, nil
}

switch v.ExportType().Kind() {
case reflect.Map:
Expand All @@ -23,22 +29,24 @@ func ToJsonSchema(v goja.Value, rt *goja.Runtime) (*jsonSchema.Schema, error) {
return nil, fmt.Errorf("expect JSON schema but got: %v", util.JsType(v.Export()))
}

s := &jsonSchema.Schema{}
obj := v.ToObject(rt)
for _, k := range obj.Keys() {
switch k {
case "type":
i := obj.Get(k).Export()
if arr, ok := i.([]interface{}); ok {
for _, t := range arr {
switch vv := i.(type) {
case string:
s.Type = []string{vv}
case []any:
for _, t := range vv {
tn, ok := t.(string)
if !ok {
return nil, fmt.Errorf("unexpected type for 'type': %v", util.JsType(t))
}
s.Type = append(s.Type, tn)
}
} else if t, ok := i.(string); ok {
s.Type = []string{t}
} else {
default:
return nil, fmt.Errorf("unexpected type for 'type': %v", util.JsType(i))
}
case "enum":
Expand Down
116 changes: 116 additions & 0 deletions mcp/run_fake_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package mcp_test

import (
"context"
"mokapi/mcp"
"mokapi/providers/asyncapi3"
"mokapi/providers/asyncapi3/asyncapi3test"
"mokapi/runtime"
"mokapi/runtime/runtimetest"
"mokapi/schema/json/generator"
"mokapi/schema/json/schema/schematest"
"testing"

"github.com/stretchr/testify/require"
)

func TestService_Run_Fake(t *testing.T) {
testcases := []struct {
name string
app *runtime.App
test func(t *testing.T, s *mcp.Service)
}{
{
name: "fake string",
app: runtimetest.NewApp(),
test: func(t *testing.T, s *mcp.Service) {
r, err := s.GetRunResponse(
context.Background(),
mcp.RunInput{
Code: `mokapi.fake({ type: 'string' })`,
},
)
require.NoError(t, err)
require.Equal(t, "P8", r.Result)
},
},
{
name: "fake object",
app: runtimetest.NewApp(),
test: func(t *testing.T, s *mcp.Service) {
r, err := s.GetRunResponse(
context.Background(),
mcp.RunInput{
Code: `mokapi.fake({ type: 'object', properties: { foo: { type: 'string' } } })`,
},
)
require.NoError(t, err)
require.Equal(t, map[string]interface{}{"foo": "P8"}, r.Result)
},
},
{
name: "fake from message payload",
app: func() *runtime.App {
msg := asyncapi3test.NewMessage(
asyncapi3test.WithMessageName("msg-name-1"),
asyncapi3test.WithMessageTitle("msg-title-1"),
asyncapi3test.WithMessageSummary("msg-summary-1"),
asyncapi3test.WithMessageDescription("msg-description-1"),
asyncapi3test.WithContentType("application/json"),
asyncapi3test.WithPayload(
schematest.New("object",
schematest.WithProperty("foo", schematest.New("string")),
),
),
)

ch := asyncapi3test.NewChannel(
asyncapi3test.WithChannelTitle("title-1"),
asyncapi3test.WithChannelSummary("channel-1 summary"),
asyncapi3test.WithChannelDescription("description"),
asyncapi3test.UseMessage("foo", &asyncapi3.MessageRef{Value: msg}),
)

return runtimetest.NewKafkaApp(
asyncapi3test.NewConfig(
asyncapi3test.WithInfo("foo", "", ""),
asyncapi3test.AddChannel("channel-1", ch),
asyncapi3test.WithOperation("publish",
asyncapi3test.WithOperationAction("send"),
asyncapi3test.WithOperationTitle("op-title-1"),
asyncapi3test.WithOperationSummary("op-summary-1"),
asyncapi3test.WithOperationDescription("op-description-1"),
asyncapi3test.WithOperationChannel(ch),
),
),
)
}(),
test: func(t *testing.T, s *mcp.Service) {
r, err := s.GetRunResponse(
context.Background(),
mcp.RunInput{
Code: `const topic = mokapi.getApi('foo').getTopic('channel-1')
const operation = topic.operations.find(x => x.action === 'send')
mokapi.fake(operation.messages[0].payload)
`,
},
)
require.NoError(t, err)
require.IsType(t, map[string]any{}, r.Result)
data := r.Result.(map[string]any)
require.Equal(t, map[string]any{
"foo": "P8",
}, data)
},
},
}

for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
generator.Seed(123456)

s := mcp.NewService(tc.app)
tc.test(t, s)
})
}
}
2 changes: 1 addition & 1 deletion mcp/run_kafka_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func TestService_Run_Kafka(t *testing.T) {
},
},
{
name: "get topic operation does not define any message",
name: "get topic operation not define any message",
app: func() *runtime.App {
msg := asyncapi3test.NewMessage(
asyncapi3test.WithMessageName("msg-name-1"),
Expand Down
18 changes: 17 additions & 1 deletion npm/go-mokapi/types/http.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,20 @@ export interface FetchOptions {
* case Mokapi interprets it as milliseconds
* @default "60s"
* @example
* const res = get(url, { timeout: '5m' })
* const res = fetch(url, { timeout: '5m' })
* @example
* // Timeout as milliseconds
* const res = await fetch(url, { timeout: 3000 });
*/
timeout?: number | string;

/**
* If set to true, TLS certificate verification is skipped. This allows connections
* to servers with self-signed or invalid certificates. Default is false.
* @example
* const res = fetch(url, { insecure: true })
*/
insecure?: boolean
}

/**
Expand All @@ -185,6 +193,14 @@ export interface Args {
* const res = get(url, { timeout: '5m' })
*/
timeout?: number | string;

/**
* If set to true, TLS certificate verification is skipped. This allows connections
* to servers with self-signed or invalid certificates. Default is false.
* @example
* const res = get(url, { insecure: true })
*/
insecure?: boolean
}

/**
Expand Down
9 changes: 5 additions & 4 deletions providers/mail/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ func (l *Log) Title() string {

func (l *Log) IndexFields() map[string]any {
m := map[string]any{
"from": l.From,
"to": l.To,
"messageId": l.MessageId,
"subject": l.Subject,
"from": l.From,
"to": l.To,
"messageId": l.MessageId,
"subject": l.Subject,
"metadata.messageId": l.MessageId,
}
return m
}
5 changes: 4 additions & 1 deletion runtime/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func (s *SearchIndex) start(pool *safe.Pool) {
apiField.IncludeInAll = false // Exclude from default search
apiField.Store = true
apiField.Index = true
apiField.IncludeTermVectors = true
docMapping.AddFieldMappingsAt("api", apiField)

// enable term vectors for all fields, allowing phrase queries (like "Swagger Petstore")
Expand All @@ -99,8 +100,10 @@ func (s *SearchIndex) start(pool *safe.Pool) {
"tokenizer": unicode.Name,
"char_filters": []any{asciifolding.Name},
"token_filters": []any{
lowercase.Name,
// Bleve token filters run in sequence
// camelcase must precede lowercase
camelcase.Name,
lowercase.Name,
stemmer,
},
})
Expand Down
2 changes: 1 addition & 1 deletion runtime/runtime_http_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ func (s *HttpStore) addToIndex(cfg *openapi.Config) {
Responses: responses,
}

s.index.Add(id, opData)
s.index.Add(fmt.Sprintf("%s_%d", id, statusCode), opData)
}
} else {
opData := httpOperationSearchIndexData{
Expand Down
59 changes: 59 additions & 0 deletions runtime/runtime_http_search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,65 @@ func TestIndex_Http(t *testing.T) {
r.Results[0])
},
},
{
name: "Search operation with multiple status",
test: func(t *testing.T, app *runtime.App) {
cfg := openapitest.NewConfig("3.0",
openapitest.WithInfo("foo", "1.0", "a description"),
openapitest.WithPath("/pets",
openapitest.WithPathInfo("", "a description"),
openapitest.WithOperation(http.MethodGet,
openapitest.WithOperationInfo("Summary value", "Description value", "", false),
openapitest.WithHeaderParam("foo", true, openapitest.WithParamInfo("parameter description")),
openapitest.WithResponse(http.StatusOK),
openapitest.WithResponse(http.StatusForbidden),
),
),
)
app.Http.Add(toConfig(cfg))

var r search.Result
var err error
waitSearchIndex(t, func() bool {
r, err = app.Search(search.Request{QueryText: "method:get", Limit: 10})
require.NoError(t, err)
return len(r.Results) == 2
})
require.Len(t, r.Results, 2)
require.Contains(t,
r.Results,
search.ResultItem{
Type: "HTTP",
Domain: "foo",
Title: "/pets",
Description: `Summary value Description value`,
Fragments: []string{"<mark>GET</mark>"},
Params: map[string]string{
"type": "http",
"service": "foo",
"path": "/pets",
"method": "GET",
"statusCode": "200",
},
})
require.Contains(t,
r.Results,
search.ResultItem{
Type: "HTTP",
Domain: "foo",
Title: "/pets",
Description: `Summary value Description value`,
Fragments: []string{"<mark>GET</mark>"},
Params: map[string]string{
"type": "http",
"service": "foo",
"path": "/pets",
"method": "GET",
"statusCode": "403",
},
})
},
},
{
name: "Search by api field",
test: func(t *testing.T, app *runtime.App) {
Expand Down
3 changes: 2 additions & 1 deletion runtime/runtime_mail_search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,12 @@ func TestIndex_Mail_Event(t *testing.T) {
require.Len(t, r.Results[0].Fragments, 2)
require.Contains(t, r.Results[0].Fragments, "<mark>Test</mark> <mark>Mail</mark>")
require.Contains(t, r.Results[0].Fragments, "<mark>event</mark>")
require.Len(t, r.Results[0].Params, 4)
require.Len(t, r.Results[0].Params, 5)
require.Equal(t, "event", r.Results[0].Params["type"])
require.Equal(t, "mail", r.Results[0].Params["traits.namespace"])
require.Equal(t, "Test Mail Events", r.Results[0].Params["traits.name"])
require.Contains(t, r.Results[0].Params, "id")
require.Contains(t, r.Results[0].Params, "messageId")
require.NotEmpty(t, r.Results[0].Time)
},
},
Expand Down
2 changes: 1 addition & 1 deletion webui/e2e/mocks/http_handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,7 @@ function getSearchResults() {
type: 'event',
'traits.namespace': 'mail',
'traits.name': 'Mail Testserver',
id: '273cd167-f5a5-4da1-969e-d44213686491'
messageId: '20230223-084925.763-4196@mokapi.io'
}
},
{
Expand Down
Loading
Loading