a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
158 lines
4.3 KiB
Go
158 lines
4.3 KiB
Go
package contracts
|
|
|
|
import "testing"
|
|
|
|
func TestThriftExtractor_ServiceFunctions(t *testing.T) {
|
|
ext := &ThriftExtractor{}
|
|
src := []byte(`namespace go shared.calc
|
|
namespace java com.example.calc
|
|
|
|
struct Work {
|
|
1: i32 num1,
|
|
2: i32 num2,
|
|
}
|
|
|
|
service Calculator extends shared.SharedService {
|
|
void ping(),
|
|
|
|
i32 add(1: i32 num1, 2: i32 num2),
|
|
|
|
Work calculate(1: i32 logid, 2: Work w) throws (1: InvalidOperation ouch),
|
|
|
|
oneway void zip()
|
|
}
|
|
`)
|
|
out := ext.Extract("calc.thrift", src, nil, nil)
|
|
if len(out) != 4 {
|
|
t.Fatalf("expected 4 contracts, got %d: %+v", len(out), out)
|
|
}
|
|
|
|
byID := map[string]Contract{}
|
|
for _, c := range out {
|
|
byID[c.ID] = c
|
|
if c.Type != ContractThrift {
|
|
t.Errorf("%s: Type = %q, want thrift", c.ID, c.Type)
|
|
}
|
|
if c.Role != RoleProvider {
|
|
t.Errorf("%s: Role = %q, want provider", c.ID, c.Role)
|
|
}
|
|
}
|
|
|
|
ping, ok := byID["thrift::Calculator::ping"]
|
|
if !ok {
|
|
t.Fatalf("missing thrift::Calculator::ping; got %v", byID)
|
|
}
|
|
if ping.Meta["canonical"] != "shared.calc.Calculator/ping" {
|
|
t.Errorf("ping canonical = %v", ping.Meta["canonical"])
|
|
}
|
|
if ping.Meta["package"] != "shared.calc" {
|
|
t.Errorf("ping package = %v, want the go namespace", ping.Meta["package"])
|
|
}
|
|
if _, hasResp := ping.Meta["response_type"]; hasResp {
|
|
t.Errorf("void function must not carry response_type: %v", ping.Meta["response_type"])
|
|
}
|
|
|
|
add, ok := byID["thrift::Calculator::add"]
|
|
if !ok {
|
|
t.Fatalf("missing thrift::Calculator::add")
|
|
}
|
|
if add.Meta["response_type"] != "i32" {
|
|
t.Errorf("add response_type = %v, want i32", add.Meta["response_type"])
|
|
}
|
|
args, _ := add.Meta["args"].([]string)
|
|
if len(args) != 2 || args[0] != "num1:i32" || args[1] != "num2:i32" {
|
|
t.Errorf("add args = %v, want [num1:i32 num2:i32]", args)
|
|
}
|
|
|
|
calc, ok := byID["thrift::Calculator::calculate"]
|
|
if !ok {
|
|
t.Fatalf("missing thrift::Calculator::calculate")
|
|
}
|
|
if calc.Meta["response_type"] != "Work" {
|
|
t.Errorf("calculate response_type = %v, want Work", calc.Meta["response_type"])
|
|
}
|
|
|
|
zip, ok := byID["thrift::Calculator::zip"]
|
|
if !ok {
|
|
t.Fatalf("missing thrift::Calculator::zip")
|
|
}
|
|
if zip.Meta["oneway"] != true {
|
|
t.Errorf("zip oneway = %v, want true", zip.Meta["oneway"])
|
|
}
|
|
|
|
// Struct fields must not be misread as service functions.
|
|
if _, leaked := byID["thrift::Calculator::num1"]; leaked {
|
|
t.Errorf("struct field leaked into service functions")
|
|
}
|
|
}
|
|
|
|
func TestThriftExtractor_MultipleServicesBounded(t *testing.T) {
|
|
ext := &ThriftExtractor{}
|
|
src := []byte(`namespace py users
|
|
|
|
service UserService {
|
|
User getUser(1: string id)
|
|
}
|
|
|
|
service AdminService {
|
|
void purge(1: string id)
|
|
}
|
|
`)
|
|
out := ext.Extract("users.thrift", src, nil, nil)
|
|
if len(out) != 2 {
|
|
t.Fatalf("expected 2 contracts, got %d: %+v", len(out), out)
|
|
}
|
|
got := map[string]bool{}
|
|
for _, c := range out {
|
|
got[c.ID] = true
|
|
}
|
|
if !got["thrift::UserService::getUser"] || !got["thrift::AdminService::purge"] {
|
|
t.Errorf("missing expected contracts: %v", got)
|
|
}
|
|
if got["thrift::UserService::purge"] {
|
|
t.Errorf("AdminService function leaked into UserService")
|
|
}
|
|
}
|
|
|
|
func TestThriftExtractor_ContainerTypesAndNamespacePreference(t *testing.T) {
|
|
ext := &ThriftExtractor{}
|
|
src := []byte(`namespace java com.example.inventory
|
|
namespace * inventory
|
|
|
|
service Inventory {
|
|
list<Item> listItems(1: map<string, i32> filters),
|
|
map<i32, string> labels()
|
|
}
|
|
`)
|
|
out := ext.Extract("inv.thrift", src, nil, nil)
|
|
if len(out) != 2 {
|
|
t.Fatalf("expected 2 contracts, got %d: %+v", len(out), out)
|
|
}
|
|
byID := map[string]Contract{}
|
|
for _, c := range out {
|
|
byID[c.ID] = c
|
|
}
|
|
li, ok := byID["thrift::Inventory::listItems"]
|
|
if !ok {
|
|
t.Fatalf("missing listItems; got %v", byID)
|
|
}
|
|
// "*" namespace applies to every generator, so it wins over java.
|
|
if li.Meta["package"] != "inventory" {
|
|
t.Errorf("package = %v, want inventory (the * namespace)", li.Meta["package"])
|
|
}
|
|
if li.Meta["response_type"] != "list<Item>" {
|
|
t.Errorf("listItems response_type = %v", li.Meta["response_type"])
|
|
}
|
|
if _, ok := byID["thrift::Inventory::labels"]; !ok {
|
|
t.Errorf("generic return type with no args not extracted")
|
|
}
|
|
}
|
|
|
|
func TestThriftExtractor_NonThriftFileIgnored(t *testing.T) {
|
|
ext := &ThriftExtractor{}
|
|
out := ext.Extract("main.go", []byte("service Foo { void bar() }"), nil, nil)
|
|
if len(out) != 0 {
|
|
t.Fatalf("non-.thrift file must produce no contracts, got %+v", out)
|
|
}
|
|
}
|