fix: dead loop introduced by thrift IDL file cycle-referring (#24)

This commit is contained in:
Yi Duan 2023-04-27 16:39:16 +08:00 committed by GitHub
parent 52b70ac401
commit 1f846f24bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 66 additions and 36 deletions

View File

@ -1,5 +1,6 @@
include "base.thrift"
include "deep/deep.ref.thrift"
include "example.thrift"
include "ref.thrift"
namespace go example

View File

@ -1,3 +1,4 @@
include "example.thrift"
namespace go ref

View File

@ -173,23 +173,33 @@ func parseIDLContent(path, content string, includes map[string]string, isAbsIncl
}
_includes[k] = t
}
if err := parseIncludes(tree, _includes, isAbsIncludePath); err != nil {
done := map[string]*parser.Thrift{path: tree}
if err := refIncludes(tree, path, done, _includes, isAbsIncludePath); err != nil {
return nil, err
}
return tree, nil
}
func parseIncludes(tree *parser.Thrift, includes map[string]*parser.Thrift, isAbsIncludePath bool) error {
func refIncludes(tree *parser.Thrift, path string, done map[string]*parser.Thrift, includes map[string]*parser.Thrift, isAbsIncludePath bool) error {
done[path] = tree
for _, i := range tree.Includes {
p := i.Path
if isAbsIncludePath {
p = absPath(tree.Filename, i.Path)
}
// check cycle reference
if t := done[p]; t != nil {
i.Reference = t
continue
}
ref, ok := includes[p]
if !ok {
return fmt.Errorf("miss include path: %s for file: %s", p, tree.Filename)
}
if err := parseIncludes(ref, includes, isAbsIncludePath); err != nil {
if err := refIncludes(ref, p, done, includes, isAbsIncludePath); err != nil {
return err
}
i.Reference = ref

View File

@ -22,7 +22,6 @@ import (
"math"
"testing"
"github.com/cloudwego/dynamicgo/meta"
"github.com/stretchr/testify/require"
)
@ -271,41 +270,15 @@ func TestOptionSetOptionalBitmap(t *testing.T) {
require.Equal(t, true, req.Struct().Requires().IsSet(3))
}
func TestOptionHalfParsing(t *testing.T) {
func TestNewFunctionDescriptorFromContent_absPath(t *testing.T) {
content := `
include "/a/b/main.thrift"
include "/ref.thrift"
namespace go kitex.test.server
struct Base {
1: string DefaultField,
2: optional string OptionalField,
3: required string RequiredField,
}
service InboxService {
Base ExampleMethod(1: Base req)
}
`
p, err := GetDescFromContent(content, "ExampleMethod", &Options{
ParseFunctionMode: meta.ParseResponseOnly,
})
require.NoError(t, err)
require.Nil(t, p.Request())
require.NotNil(t, p.Response())
p, err = GetDescFromContent(content, "ExampleMethod", &Options{
ParseFunctionMode: meta.ParseRequestOnly,
})
require.NoError(t, err)
require.NotNil(t, p.Request())
require.Nil(t, p.Response())
}
func TestNewFunctionDescriptorFromContent(t *testing.T) {
content := `
namespace go kitex.test.server
struct Base {
1: string DefaultField,
1: string DefaultField = ref.ConstString,
2: optional string OptionalField,
3: required string RequiredField,
}
@ -315,16 +288,61 @@ func TestNewFunctionDescriptorFromContent(t *testing.T) {
Base Method2(1: Base req)
}
`
path := "a/b/main.thrift"
ref := `
include "/a/b/main.thrift"
namespace go ref
const string ConstString = "const string"
`
path := "/a/b/main.thrift"
includes := map[string]string{
path: content,
"/ref.thrift": ref,
}
p, err := Options{}.NewDescriptorFromContentWithMethod(context.Background(), path, content, includes, false, "Method1")
require.NoError(t, err)
require.NotNil(t, p.Functions()["Method1"])
require.Nil(t, p.Functions()["Method2"])
}
func TestNewFunctionDescriptorFromContent_relativePath(t *testing.T) {
content := `
include "main.thrift"
include "ref.thrift"
namespace go kitex.test.server
struct Base {
1: string DefaultField = ref.ConstString,
2: optional string OptionalField,
3: required string RequiredField,
}
service InboxService {
Base Method1(1: Base req)
Base Method2(1: Base req)
}
`
ref := `
include "/a/b/main.thrift"
namespace go ref
const string ConstString = "const string"
`
path := "/a/b/main.thrift"
includes := map[string]string{
path: content,
"/a/b/ref.thrift": ref,
}
p, err := Options{}.NewDescriptorFromContentWithMethod(context.Background(), path, content, includes, true, "Method1")
require.NoError(t, err)
require.NotNil(t, p.Functions()["Method1"])
require.Nil(t, p.Functions()["Method2"])
}
func TestNewFunctionDescriptorFromPath(t *testing.T) {
p, err := Options{}.NewDescriptorFromPathWithMethod(context.Background(), "../testdata/idl/example.thrift", nil, "ExampleMethod")
require.NoError(t, err)