Updated varlink vendored code

Signed-off-by: baude <bbaude@redhat.com>

Closes: #670
Approved by: mheon
This commit is contained in:
baude
2018-04-25 10:54:24 -05:00
committed by Atomic Bot
parent bef93de431
commit 22011b428c
14 changed files with 1127 additions and 1513 deletions

File diff suppressed because it is too large Load Diff

View File

View File

@ -1,13 +0,0 @@
language: go
sudo: false
go:
- '1.9'
- 1.10.x
install:
- go get golang.org/x/tools/cmd/cover
- go get github.com/mattn/goveralls
script:
- '"$HOME/gopath/bin/goveralls" -show -service=travis-ci -repotoken "$COVERALLS_TOKEN"'
env:
global:
- secure: bjxOSgBfB+YooxNTkIDHAD+/X6g56qBWoYpB1JinuS5kmt3vSjfRSuXui71sGuha7jO2FOJja8HcpjOv3UP+qmmej9276o5VWrjS1AwnI95hSQQ4JHm293Z1QeojjRaxmoKrgn7i82Hn4qNdVLQA142s+SIdqOxtN6LDs7i0Yb4IuXoiMQHbd6kAAL95o9IUFPpYAdsXoQ6xnx+TXNiSwPPeh4m5CNKuTtmGTuMGaj8tXxttFKJhZcRzvOpDuh7luc9PSVnQgYmKE/3S9ehzGV8Lk4T8eC7587DY1GdYQKt1egJSE72L+PVnmoalWROaAGHZvYWsSAeNi1UIvcFwGbXBRpq7kz3DVfIULM8V67UAaF3dGYDN3Ae825mDjN5JDfml17AoEjMjI0LlBImZLX2EWIEN225JIREHdpG9seJkaN1ClcpvEIeYuThF2MiivP1EE8/w8S80yoO5nW76Py/th16OuaEiP9LdLsbXimObUPsS9Sr8qquf/PiVqRMMpVW88oOEG5HVn4Ra5B/xVC6nPEF88tE6p9+7RSz4rOWih8QmW+6SX6eo0BI9di4L779f/WfUrddN0JLIvEnRFZZ+pVF/oo+N2INNeIMsZBvG3FVo+Zxzo6SExXnSSpuf1bp140ZdinUMACq6BqK+9gj1C9vNRmqQJaEefrqutws=

View File

@ -1,3 +0,0 @@
all:
go test -v ./...
.PHONY: all

View File

@ -1,85 +0,0 @@
package main
import (
"strings"
"testing"
)
func expect(t *testing.T, expected string, returned string) {
if strings.Compare(returned, expected) != 0 {
t.Fatalf("Expected(%d): `%s`\nGot(%d): `%s`\n",
len(expected), expected,
len(returned), returned)
}
}
func TestIDLParser(t *testing.T) {
pkgname, b, err := generateTemplate(`
# Interface to jump a spacecraft to another point in space. The
# FTL Drive is the propulsion system to achieve faster-than-light
# travel through space. A ship making a properly calculated
# jump can arrive safely in planetary orbit, or alongside other
# ships or spaceborne objects.
interface org.example.ftl
# The current state of the FTL drive and the amount of fuel
# available to jump.
type DriveCondition (
state: (idle, spooling, busy),
booster: bool,
active_engines: [](id: int, state: bool),
tylium_level: int
)
# Speed, trajectory and jump duration is calculated prior to
# activating the FTL drive.
type DriveConfiguration (
speed: int,
trajectory: int,
duration: int
)
# The galactic coordinates use the Sun as the origin. Galactic
# longitude is measured with primary direction from the Sun to
# the center of the galaxy in the galactic plane, while the
# galactic latitude measures the angle of the object above the
# galactic plane.
type Coordinate (
longitude: float,
latitude: float,
distance: int
)
# Monitor the drive. The method will reply with an update whenever
# the drive's state changes
method Monitor() -> (condition: DriveCondition)
# Calculate the drive's jump parameters from the current
# position to the target position in the galaxy
method CalculateConfiguration(
current: Coordinate,
target: Coordinate
) -> (configuration: DriveConfiguration)
# Jump to the calculated point in space
method Jump(configuration: DriveConfiguration) -> ()
# There is not enough tylium to jump with the given parameters
error NotEnoughEnergy ()
# The supplied parameters are outside the supported range
error ParameterOutOfRange (field: string)
# some more coverage
method Foo(interface: string) -> (ret: (go: string, switch: bool, more: (t:bool, f:bool)))
`)
if err != nil {
t.Fatalf("Error parsing %v", err)
}
expect(t, "orgexampleftl", pkgname)
if len(b) <= 0 {
t.Fatal("No generated go source")
}
// FIXME: compare b.String() against expected output
}

View File

@ -1,294 +0,0 @@
package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path"
"strings"
"github.com/varlink/go/varlink/idl"
)
var goKeywords = map[string]struct{}{
"break": {},
"case": {},
"chan": {},
"const": {},
"continue": {},
"default": {},
"defer": {},
"else": {},
"fallthrough": {},
"for": {},
"func": {},
"go": {},
"goto": {},
"if": {},
"import": {},
"interface": {},
"map": {},
"package": {},
"range": {},
"return": {},
"select": {},
"struct": {},
"switch": {},
"type": {},
"var": {},
}
func sanitizeGoName(name string) string {
if _, ok := goKeywords[name]; !ok {
return name
}
return name + "_"
}
func writeType(b *bytes.Buffer, t *idl.Type, json bool, ident int) {
switch t.Kind {
case idl.TypeBool:
b.WriteString("bool")
case idl.TypeInt:
b.WriteString("int64")
case idl.TypeFloat:
b.WriteString("float64")
case idl.TypeString, idl.TypeEnum:
b.WriteString("string")
case idl.TypeArray:
b.WriteString("[]")
writeType(b, t.ElementType, json, ident)
case idl.TypeMaybe:
b.WriteString("*")
writeType(b, t.ElementType, json, ident)
case idl.TypeAlias:
b.WriteString(t.Alias)
case idl.TypeStruct:
b.WriteString("struct{\n")
for _, field := range t.Fields {
for i := 0; i < ident+1; i++ {
b.WriteString("\t")
}
b.WriteString(strings.Title(field.Name) + " ")
writeType(b, field.Type, json, ident+1)
if json {
b.WriteString(" `json:\"" + field.Name + "\"`")
}
b.WriteString("\n")
}
for i := 0; i < ident; i++ {
b.WriteString("\t")
}
b.WriteString("}")
}
}
func generateTemplate(description string) (string, []byte, error) {
description = strings.TrimRight(description, "\n")
midl, err := idl.New(description)
if err != nil {
return "", nil, err
}
pkgname := strings.Replace(midl.Name, ".", "", -1)
var b bytes.Buffer
b.WriteString("// Generated with github.com/varlink/go/cmd/varlink-go-interface-generator\n")
b.WriteString("package " + pkgname + "\n\n")
b.WriteString(`import "github.com/varlink/go/varlink"` + "\n\n")
// Type declarations
for _, a := range midl.Aliases {
b.WriteString("type " + a.Name + " ")
writeType(&b, a.Type, true, 0)
b.WriteString("\n\n")
}
// Local interface with all methods
b.WriteString("type " + pkgname + "Interface interface {\n")
for _, m := range midl.Methods {
b.WriteString("\t" + m.Name + "(c VarlinkCall")
for _, field := range m.In.Fields {
b.WriteString(", " + strings.Title(field.Name) + " ")
writeType(&b, field.Type, false, 1)
}
b.WriteString(") error\n")
}
b.WriteString("}\n\n")
// Local object with all methods
b.WriteString("type VarlinkCall struct{ varlink.Call }\n\n")
// Reply methods for all varlink errors
for _, e := range midl.Errors {
b.WriteString("func (c *VarlinkCall) Reply" + e.Name + "(")
for i, field := range e.Type.Fields {
if i > 0 {
b.WriteString(", ")
}
b.WriteString(sanitizeGoName(field.Name) + " ")
writeType(&b, field.Type, false, 1)
}
b.WriteString(") error {\n")
if len(e.Type.Fields) > 0 {
b.WriteString("\tvar out ")
writeType(&b, e.Type, true, 1)
b.WriteString("\n")
for _, field := range e.Type.Fields {
switch field.Type.Kind {
case idl.TypeStruct, idl.TypeArray:
b.WriteString("\tout." + strings.Title(field.Name) + " = ")
writeType(&b, field.Type, true, 1)
b.WriteString("(" + sanitizeGoName(field.Name) + ")\n")
default:
b.WriteString("\tout." + strings.Title(field.Name) + " = " + sanitizeGoName(field.Name) + "\n")
}
}
b.WriteString("\treturn c.ReplyError(\"" + midl.Name + "." + e.Name + "\", &out)\n")
} else {
b.WriteString("\treturn c.ReplyError(\"" + midl.Name + "." + e.Name + "\", nil)\n")
}
b.WriteString("}\n\n")
}
// Reply methods for all varlink methods
for _, m := range midl.Methods {
b.WriteString("func (c *VarlinkCall) Reply" + m.Name + "(")
for i, field := range m.Out.Fields {
if i > 0 {
b.WriteString(", ")
}
b.WriteString(sanitizeGoName(field.Name) + " ")
writeType(&b, field.Type, false, 1)
}
b.WriteString(") error {\n")
if len(m.Out.Fields) > 0 {
b.WriteString("\tvar out ")
writeType(&b, m.Out, true, 1)
b.WriteString("\n")
for _, field := range m.Out.Fields {
switch field.Type.Kind {
case idl.TypeStruct, idl.TypeArray:
b.WriteString("\tout." + strings.Title(field.Name) + " = ")
writeType(&b, field.Type, true, 1)
b.WriteString("(" + sanitizeGoName(field.Name) + ")\n")
default:
b.WriteString("\tout." + strings.Title(field.Name) + " = " + sanitizeGoName(field.Name) + "\n")
}
}
b.WriteString("\treturn c.Reply(&out)\n")
} else {
b.WriteString("\treturn c.Reply(nil)\n")
}
b.WriteString("}\n\n")
}
// Dummy methods for all varlink methods
for _, m := range midl.Methods {
b.WriteString("func (s *VarlinkInterface) " + m.Name + "(c VarlinkCall")
for _, field := range m.In.Fields {
b.WriteString(", " + sanitizeGoName(field.Name) + " ")
writeType(&b, field.Type, false, 1)
}
b.WriteString(") error {\n" +
"\treturn c.ReplyMethodNotImplemented(\"" + m.Name + "\")\n" +
"}\n\n")
}
// Method call dispatcher
b.WriteString("func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) error {\n" +
"\tswitch methodname {\n")
for _, m := range midl.Methods {
b.WriteString("\tcase \"" + m.Name + "\":\n")
if len(m.In.Fields) > 0 {
b.WriteString("\t\tvar in ")
writeType(&b, m.In, true, 2)
b.WriteString("\n")
b.WriteString("\t\terr := call.GetParameters(&in)\n" +
"\t\tif err != nil {\n" +
"\t\t\treturn call.ReplyInvalidParameter(\"parameters\")\n" +
"\t\t}\n")
b.WriteString("\t\treturn s." + pkgname + "Interface." + m.Name + "(VarlinkCall{call}")
if len(m.In.Fields) > 0 {
for _, field := range m.In.Fields {
switch field.Type.Kind {
case idl.TypeStruct, idl.TypeArray:
b.WriteString(", ")
writeType(&b, field.Type, false, 2)
b.WriteString("(in." + strings.Title(field.Name) + ")")
default:
b.WriteString(", in." + strings.Title(field.Name))
}
}
}
b.WriteString(")\n")
} else {
b.WriteString("\t\treturn s." + pkgname + "Interface." + m.Name + "(VarlinkCall{call})\n")
}
b.WriteString("\n")
}
b.WriteString("\tdefault:\n" +
"\t\treturn call.ReplyMethodNotFound(methodname)\n" +
"\t}\n" +
"}\n")
// Varlink interface name
b.WriteString("func (s *VarlinkInterface) VarlinkGetName() string {\n" +
"\treturn `" + midl.Name + "`\n" + "}\n\n")
// Varlink interface description
b.WriteString("func (s *VarlinkInterface) VarlinkGetDescription() string {\n" +
"\treturn `" + midl.Description + "\n`\n}\n\n")
b.WriteString("type VarlinkInterface struct {\n" +
"\t" + pkgname + "Interface\n" +
"}\n\n")
b.WriteString("func VarlinkNew(m " + pkgname + "Interface) *VarlinkInterface {\n" +
"\treturn &VarlinkInterface{m}\n" +
"}\n")
return pkgname, b.Bytes(), nil
}
func generateFile(varlinkFile string) {
file, err := ioutil.ReadFile(varlinkFile)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading file '%s': %s\n", varlinkFile, err)
os.Exit(1)
}
pkgname, b, err := generateTemplate(string(file))
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing file '%s': %s\n", varlinkFile, err)
os.Exit(1)
}
filename := path.Dir(varlinkFile) + "/" + pkgname + ".go"
err = ioutil.WriteFile(filename, b, 0660)
if err != nil {
fmt.Fprintf(os.Stderr, "Error writing file '%s': %s\n", filename, err)
os.Exit(1)
}
}
func main() {
if len(os.Args) != 2 {
fmt.Printf("Usage: %s <file>\n", os.Args[0])
os.Exit(1)
}
generateFile(os.Args[1])
}

View File

@ -1,142 +0,0 @@
package main
import (
"fmt"
"go/ast"
"go/importer"
"go/parser"
"go/token"
"go/types"
"log"
"os"
)
func GoToVarlinkType(t types.Type) string {
switch u := t.(type) {
case *types.Basic:
if u.Info()&types.IsBoolean != 0 {
return "bool"
}
if u.Info()&types.IsInteger != 0 {
return "int"
}
if u.Info()&types.IsFloat != 0 {
return "float"
}
if u.Info()&types.IsString != 0 {
return "string"
}
return fmt.Sprintf("<<<%s>>>", t.String())
case *types.Named:
return u.Obj().Name()
case *types.Map:
return fmt.Sprintf("<<<%s>>>", u.String())
case *types.Interface:
return fmt.Sprintf("<<<%s>>>", u.String())
case *types.Pointer:
return fmt.Sprintf("?%s", GoToVarlinkType(u.Elem()))
case *types.Array:
return fmt.Sprintf("[]%s", GoToVarlinkType(u.Elem()))
case *types.Slice:
return fmt.Sprintf("[]%s", GoToVarlinkType(u.Elem()))
default:
return fmt.Sprintf("<<<%T %s>>>", t, u)
}
return t.String()
}
func PrintDefsUses(name string, fset *token.FileSet, files []*ast.File) error {
conf := types.Config{
Importer: importer.Default(),
FakeImportC: true,
}
info := &types.Info{
Defs: make(map[*ast.Ident]types.Object),
}
_, err := conf.Check(name, fset, files, info)
if err != nil {
return err // type error
}
seen := map[string]interface{}{}
for id, obj := range info.Defs {
if obj == nil {
continue
}
if _, ok := seen[id.Name]; ok {
continue
}
/*
if !obj.Exported() || obj.Pkg().Name() != name {
continue
}
*/
switch f := obj.Type().Underlying().(type) {
case *types.Struct:
if f.NumFields() > 0 {
fmt.Printf("type %s (\n", id.Name)
fmt.Printf("\t%s: %s",
f.Field(0).Name(), GoToVarlinkType(f.Field(0).Type()))
for i := 1; i < f.NumFields(); i++ {
fmt.Printf(",\n\t%s: %s",
f.Field(i).Name(), GoToVarlinkType(f.Field(i).Type()))
}
fmt.Printf("\n)\n\n")
}
}
seen[id.Name] = nil
}
return nil
}
func main() {
path := os.Args[1]
fs := token.NewFileSet()
if stat, err := os.Stat(path); err == nil && stat.IsDir() {
pkgs, err := parser.ParseDir(fs, path, nil, 0)
if err != nil {
fmt.Printf("parsing dir '%s': %s", path, err)
}
for name, pkg := range pkgs {
log.Println("Found package:", name)
fset := make([]*ast.File, len(pkg.Files), len(pkg.Files))
idx := 0
for _, value := range pkg.Files {
fset[idx] = value
idx++
}
if err := PrintDefsUses(name, fs, fset); err != nil {
log.Print(err) // type error
}
}
} else {
fset, err := parser.ParseFile(fs, path, nil, 0)
if err != nil {
fmt.Printf("parsing file '%s': %s", path, err)
}
name := fset.Name.String()
if err := PrintDefsUses(name, fs, []*ast.File{fset}); err != nil {
log.Print(err) // type error
}
}
}

View File

@ -1,44 +0,0 @@
%global goipath github.com/varlink/go
Version: 0
%gometa
Name: %{goname}
Release: 1%{?dist}
Summary: Go bindings for varlink
License: ASL 2.0
URL: %{gourl}
Source0: %{gosource}
%description
Native Go bindings for the varlink protocol.
%package devel
Summary: %{summary}
BuildArch: noarch
%description devel
%{summary}
This package contains library source intended for
building other packages which use import path with
%{gobaseipath} prefix.
%prep
%forgesetup
%build
%gobuildroot
%install
gofiles=$(find . %{gofindfilter} -print)
%goinstall $gofiles
%check
%files devel -f devel.file-list
%license LICENSE
%doc README.md
%changelog
* Tue Mar 20 2018 <info@varlink.org> 0-1
- Version 0

View File

@ -27,17 +27,26 @@ type Connection struct {
} }
// Send sends a method call. // Send sends a method call.
func (c *Connection) Send(method string, parameters interface{}, more bool) error { func (c *Connection) Send(method string, parameters interface{}, more bool, oneway bool) error {
type call struct { type call struct {
Method string `json:"method"` Method string `json:"method"`
Parameters interface{} `json:"parameters,omitempty"` Parameters interface{} `json:"parameters,omitempty"`
More bool `json:"more,omitempty"` More bool `json:"more,omitempty"`
OneShot bool `json:"oneshot,omitempty"` Oneway bool `json:"oneway,omitempty"`
} }
if more && oneway {
return &Error{
Name: "org.varlink.InvalidParameter",
Parameters: "oneway",
}
}
m := call{ m := call{
Method: method, Method: method,
Parameters: parameters, Parameters: parameters,
More: more, More: more,
Oneway: oneway,
} }
b, err := json.Marshal(m) b, err := json.Marshal(m)
if err != nil { if err != nil {
@ -54,53 +63,47 @@ func (c *Connection) Send(method string, parameters interface{}, more bool) erro
} }
// Receive receives a method reply. // Receive receives a method reply.
func (c *Connection) Receive(parameters interface{}, continues *bool, oneshot *bool) error { func (c *Connection) Receive(parameters interface{}) (bool, error) {
type reply struct { type reply struct {
Parameters *json.RawMessage `json:"parameters"` Parameters *json.RawMessage `json:"parameters"`
Continues bool `json:"continues"` Continues bool `json:"continues"`
Oneshot bool `json:"oneshot"`
Error string `json:"error"` Error string `json:"error"`
} }
out, err := c.reader.ReadBytes('\x00') out, err := c.reader.ReadBytes('\x00')
if err != nil { if err != nil {
return err return false, err
} }
var m reply var m reply
err = json.Unmarshal(out[:len(out)-1], &m) err = json.Unmarshal(out[:len(out)-1], &m)
if err != nil { if err != nil {
return err return false, err
} }
if m.Error != "" { if m.Error != "" {
return &Error{ return false, &Error{
Name: m.Error, Name: m.Error,
Parameters: m.Parameters, Parameters: m.Parameters,
} }
} }
if continues != nil {
*continues = m.Continues
}
if oneshot != nil {
*oneshot = m.Oneshot
}
if parameters != nil && m.Parameters != nil { if parameters != nil && m.Parameters != nil {
return json.Unmarshal(*m.Parameters, parameters) return m.Continues, json.Unmarshal(*m.Parameters, parameters)
} }
return nil return m.Continues, nil
} }
// Call sends a method call and returns the result of the call. // Call sends a method call and returns the result of the call.
func (c *Connection) Call(method string, parameters interface{}, result interface{}) error { func (c *Connection) Call(method string, parameters interface{}, result interface{}) error {
err := c.Send(method, &parameters, false) err := c.Send(method, &parameters, false, false)
if err != nil { if err != nil {
return err return err
} }
return c.Receive(result, nil, nil) _, err = c.Receive(result)
return err
} }
// GetInterfaceDescription requests the interface description string from the service. // GetInterfaceDescription requests the interface description string from the service.

View File

@ -1,144 +0,0 @@
package varlink_test
// test with no internal access
import (
"github.com/varlink/go/varlink"
"os"
"testing"
"time"
)
type VarlinkInterface struct{}
func (s *VarlinkInterface) VarlinkDispatch(call varlink.Call, methodname string) error {
return call.ReplyMethodNotImplemented(methodname)
}
func (s *VarlinkInterface) VarlinkGetName() string {
return `org.example.test`
}
func (s *VarlinkInterface) VarlinkGetDescription() string {
return "#"
}
type VarlinkInterface2 struct{}
func (s *VarlinkInterface2) VarlinkDispatch(call varlink.Call, methodname string) error {
return call.ReplyMethodNotImplemented(methodname)
}
func (s *VarlinkInterface2) VarlinkGetName() string {
return `org.example.test2`
}
func (s *VarlinkInterface2) VarlinkGetDescription() string {
return "#"
}
func TestRegisterService(t *testing.T) {
newTestInterface := new(VarlinkInterface)
service, err := varlink.NewService(
"Varlink",
"Varlink Test",
"1",
"https://github.com/varlink/go/varlink",
)
if err != nil {
t.Fatalf("NewService(): %v", err)
}
if err := service.RegisterInterface(newTestInterface); err != nil {
t.Fatalf("Couldn't register service: %v", err)
}
if err := service.RegisterInterface(newTestInterface); err == nil {
t.Fatal("Could register service twice")
}
defer func() { service.Shutdown() }()
servererror := make(chan error)
go func() {
servererror <- service.Listen("unix:@varlinkexternal_TestRegisterService", 0)
}()
time.Sleep(time.Second / 5)
n := new(VarlinkInterface2)
if err := service.RegisterInterface(n); err == nil {
t.Fatal("Could register service while running")
}
time.Sleep(time.Second / 5)
service.Shutdown()
if err := <-servererror; err != nil {
t.Fatalf("service.Listen(): %v", err)
}
}
func TestUnix(t *testing.T) {
newTestInterface := new(VarlinkInterface)
service, err := varlink.NewService(
"Varlink",
"Varlink Test",
"1",
"https://github.com/varlink/go/varlink",
)
if err != nil {
t.Fatalf("NewService(): %v", err)
}
if err := service.RegisterInterface(newTestInterface); err != nil {
t.Fatalf("RegisterInterface(): %v", err)
}
servererror := make(chan error)
go func() {
servererror <- service.Listen("unix:varlinkexternal_TestUnix", 0)
}()
time.Sleep(time.Second / 5)
service.Shutdown()
if err := <-servererror; err != nil {
t.Fatalf("service.Listen(): %v", err)
}
}
func TestListenFDSNotInt(t *testing.T) {
newTestInterface := new(VarlinkInterface)
service, err := varlink.NewService(
"Varlink",
"Varlink Test",
"1",
"https://github.com/varlink/go/varlink",
)
if err != nil {
t.Fatalf("NewService(): %v", err)
}
if err := service.RegisterInterface(newTestInterface); err != nil {
t.Fatalf("Couldn't register service: %v", err)
}
os.Setenv("LISTEN_FDS", "foo")
servererror := make(chan error)
go func() {
servererror <- service.Listen("unix:varlinkexternal_TestListenFDSNotInt", 0)
}()
time.Sleep(time.Second / 5)
service.Shutdown()
err = <-servererror
if err != nil {
t.Fatalf("service.Run(): %v", err)
}
}

View File

@ -13,8 +13,10 @@ const (
TypeInt TypeInt
TypeFloat TypeFloat
TypeString TypeString
TypeObject
TypeArray TypeArray
TypeMaybe TypeMaybe
TypeMap
TypeStruct TypeStruct
TypeEnum TypeEnum
TypeAlias TypeAlias
@ -277,9 +279,25 @@ func (p *parser) readType() *Type {
if e == nil { if e == nil {
return nil return nil
} }
if e.Kind == TypeMaybe {
return nil
}
t = &Type{Kind: TypeMaybe, ElementType: e} t = &Type{Kind: TypeMaybe, ElementType: e}
case '[': case '[':
var kind TypeKind
switch p.readKeyword() {
case "string":
kind = TypeMap
case "":
kind = TypeArray
default:
return nil
}
if p.next() != ']' { if p.next() != ']' {
return nil return nil
} }
@ -287,7 +305,7 @@ func (p *parser) readType() *Type {
if e == nil { if e == nil {
return nil return nil
} }
t = &Type{Kind: TypeArray, ElementType: e} t = &Type{Kind: kind, ElementType: e}
default: default:
p.backup() p.backup()
@ -304,6 +322,9 @@ func (p *parser) readType() *Type {
case "string": case "string":
t = &Type{Kind: TypeString} t = &Type{Kind: TypeString}
case "object":
t = &Type{Kind: TypeObject}
} }
} else if name := p.readTypeName(); name != "" { } else if name := p.readTypeName(); name != "" {

View File

@ -1,127 +0,0 @@
package idl
import (
"fmt"
"runtime"
"testing"
)
/*
func expect(t *testing.T, expected string, returned string) {
if strings.Compare(returned, expected) != 0 {
t.Fatalf("Expected(%d): `%s`\nGot(%d): `%s`\n",
len(expected), expected,
len(returned), returned)
}
}
*/
func testParse(t *testing.T, pass bool, description string) {
_, _, line, _ := runtime.Caller(1)
t.Run(fmt.Sprintf("Line-%d", line), func(t *testing.T) {
midl, err := New(description)
if pass {
if err != nil {
t.Fatalf("generateTemplate(`%s`): %v", description, err)
}
if len(midl.Name) <= 0 {
t.Fatalf("generateTemplate(`%s`): returned no pkgname", description)
}
}
if !pass && (err == nil) {
t.Fatalf("generateTemplate(`%s`): did not fail", description)
}
})
}
func TestOneMethod(t *testing.T) {
testParse(t, true, "interface foo.bar\nmethod Foo()->()")
}
func TestOneMethodNoType(t *testing.T) {
testParse(t, false, "interface foo.bar\nmethod Foo()->(b:)")
}
func TestDomainNames(t *testing.T) {
testParse(t, true, "interface org.varlink.service\nmethod F()->()")
testParse(t, true, "interface com.example.0example\nmethod F()->()")
testParse(t, true, "interface com.example.example-dash\nmethod F()->()")
testParse(t, true, "interface xn--lgbbat1ad8j.example.algeria\nmethod F()->()")
testParse(t, false, "interface com.-example.leadinghyphen\nmethod F()->()")
testParse(t, false, "interface com.example-.danglinghyphen-\nmethod F()->()")
testParse(t, false, "interface Com.example.uppercase-toplevel\nmethod F()->()")
testParse(t, false, "interface Co9.example.number-toplevel\nmethod F()->()")
testParse(t, false, "interface 1om.example.number-toplevel\nmethod F()->()")
testParse(t, false, "interface com.Example\nmethod F()->()")
var name string
for i := 0; i < 255; i++ {
name += "a"
}
testParse(t, false, "interface com.example.toolong"+name+"\nmethod F()->()")
testParse(t, false, "interface xn--example.toolong"+name+"\nmethod F()->()")
}
func TestNoMethod(t *testing.T) {
testParse(t, false, `
interface org.varlink.service
type Interface (name: string, types: []Type, methods: []Method)
type Property (key: string, value: string)
`)
}
func TestTypeNoArgs(t *testing.T) {
testParse(t, true, "interface foo.bar\n type I ()\nmethod F()->()")
}
func TestTypeOneArg(t *testing.T) {
testParse(t, true, "interface foo.bar\n type I (b:bool)\nmethod F()->()")
}
func TestTypeOneArray(t *testing.T) {
testParse(t, true, "interface foo.bar\n type I (b:[]bool)\nmethod F()->()")
testParse(t, false, "interface foo.bar\n type I (b:bool[ ])\nmethod F()->()")
testParse(t, false, "interface foo.bar\n type I (b:bool[1])\nmethod F()->()")
testParse(t, false, "interface foo.bar\n type I (b:bool[ 1 ])\nmethod F()->()")
testParse(t, false, "interface foo.bar\n type I (b:bool[ 1 1 ])\nmethod F()->()")
}
func TestFieldnames(t *testing.T) {
testParse(t, false, "interface foo.bar\n type I (Test:[]bool)\nmethod F()->()")
testParse(t, false, "interface foo.bar\n type I (_test:[]bool)\nmethod F()->()")
testParse(t, false, "interface foo.bar\n type I (Äest:[]bool)\nmethod F()->()")
}
func TestNestedStructs(t *testing.T) {
testParse(t, true, "interface foo.bar\n type I ( b: [](foo: bool, bar: bool, baz: int) )\nmethod F()->()")
}
func TestEnum(t *testing.T) {
testParse(t, true, "interface foo.bar\n type I (b:(foo, bar, baz))\nmethod F()->()")
testParse(t, false, "interface foo.bar\n type I (foo, bar, baz : bool)\nmethod F()->()")
}
func TestIncomplete(t *testing.T) {
testParse(t, false, "interfacef foo.bar\nmethod F()->()")
testParse(t, false, "interface foo.bar\nmethod F()->()\ntype I (b: bool")
testParse(t, false, "interface foo.bar\nmethod F()->(")
testParse(t, false, "interface foo.bar\nmethod F(")
testParse(t, false, "interface foo.bar\nmethod ()->()")
testParse(t, false, "interface foo.bar\nmethod F->()\n")
testParse(t, false, "interface foo.bar\nmethod F()->\n")
testParse(t, false, "interface foo.bar\nmethod F()>()\n")
testParse(t, false, "interface foo.bar\nmethod F()->()\ntype (b: bool)")
testParse(t, false, "interface foo.bar\nmethod F()->()\nerror (b: bool)")
testParse(t, false, "interface foo.bar\nmethod F()->()\n dfghdrg")
}
func TestDuplicate(t *testing.T) {
testParse(t, false, `
interface foo.example
type Device()
type Device()
type T()
type T()
method F() -> ()
method F() -> ()
`)
}

View File

@ -152,10 +152,6 @@ func activationListener() net.Listener {
return nil return nil
} }
os.Unsetenv("LISTEN_PID")
os.Unsetenv("LISTEN_FDS")
os.Unsetenv("LISTEN_FDNAMES")
return listener return listener
} }

View File

@ -1,232 +0,0 @@
package varlink
// tests with access to internals
import (
"bufio"
"bytes"
"fmt"
"strings"
"testing"
)
func expect(t *testing.T, expected string, returned string) {
if strings.Compare(returned, expected) != 0 {
t.Fatalf("Expected(%d): `%s`\nGot(%d): `%s`\n",
len(expected), expected,
len(returned), strings.Replace(returned, "\000", "`+\"\\000\"+`", -1))
}
}
func TestService(t *testing.T) {
service, _ := NewService(
"Varlink",
"Varlink Test",
"1",
"https://github.com/varlink/go/varlink",
)
t.Run("ZeroMessage", func(t *testing.T) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
if err := service.handleMessage(w, []byte{0}); err == nil {
t.Fatal("HandleMessage returned non-error")
}
})
t.Run("InvalidJson", func(t *testing.T) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
msg := []byte(`{"method":"foo.GetInterfaceDescription" fdgdfg}`)
if err := service.handleMessage(w, msg); err == nil {
t.Fatal("HandleMessage returned no error on invalid json")
}
})
t.Run("WrongInterface", func(t *testing.T) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
msg := []byte(`{"method":"foo.GetInterfaceDescription"}`)
if err := service.handleMessage(w, msg); err != nil {
t.Fatal("HandleMessage returned error on wrong interface")
}
expect(t, `{"parameters":{"interface":"foo"},"error":"org.varlink.service.InterfaceNotFound"}`+"\000",
b.String())
})
t.Run("InvalidMethod", func(t *testing.T) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
msg := []byte(`{"method":"InvalidMethod"}`)
if err := service.handleMessage(w, msg); err != nil {
t.Fatal("HandleMessage returned error on invalid method")
}
expect(t, `{"parameters":{"parameter":"method"},"error":"org.varlink.service.InvalidParameter"}`+"\000",
b.String())
})
t.Run("WrongMethod", func(t *testing.T) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
msg := []byte(`{"method":"org.varlink.service.WrongMethod"}`)
if err := service.handleMessage(w, msg); err != nil {
t.Fatal("HandleMessage returned error on wrong method")
}
expect(t, `{"parameters":{"method":"WrongMethod"},"error":"org.varlink.service.MethodNotFound"}`+"\000",
b.String())
})
t.Run("GetInterfaceDescriptionNullParameters", func(t *testing.T) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
msg := []byte(`{"method":"org.varlink.service.GetInterfaceDescription","parameters": null}`)
if err := service.handleMessage(w, msg); err != nil {
t.Fatalf("HandleMessage returned error: %v", err)
}
expect(t, `{"parameters":{"parameter":"parameters"},"error":"org.varlink.service.InvalidParameter"}`+"\000",
b.String())
})
t.Run("GetInterfaceDescriptionNoInterface", func(t *testing.T) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
msg := []byte(`{"method":"org.varlink.service.GetInterfaceDescription","parameters":{}}`)
if err := service.handleMessage(w, msg); err != nil {
t.Fatalf("HandleMessage returned error: %v", err)
}
expect(t, `{"parameters":{"parameter":"interface"},"error":"org.varlink.service.InvalidParameter"}`+"\000",
b.String())
})
t.Run("GetInterfaceDescriptionWrongInterface", func(t *testing.T) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
msg := []byte(`{"method":"org.varlink.service.GetInterfaceDescription","parameters":{"interface":"foo"}}`)
if err := service.handleMessage(w, msg); err != nil {
t.Fatalf("HandleMessage returned error: %v", err)
}
expect(t, `{"parameters":{"parameter":"interface"},"error":"org.varlink.service.InvalidParameter"}`+"\000",
b.String())
})
t.Run("GetInterfaceDescription", func(t *testing.T) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
msg := []byte(`{"method":"org.varlink.service.GetInterfaceDescription","parameters":{"interface":"org.varlink.service"}}`)
if err := service.handleMessage(w, msg); err != nil {
t.Fatalf("HandleMessage returned error: %v", err)
}
expect(t, `{"parameters":{"description":"# The Varlink Service Interface is provided by every varlink service. It\n# describes the service and the interfaces it implements.\ninterface org.varlink.service\n\n# Get a list of all the interfaces a service provides and information\n# about the implementation.\nmethod GetInfo() -\u003e (\n vendor: string,\n product: string,\n version: string,\n url: string,\n interfaces: []string\n)\n\n# Get the description of an interface that is implemented by this service.\nmethod GetInterfaceDescription(interface: string) -\u003e (description: string)\n\n# The requested interface was not found.\nerror InterfaceNotFound (interface: string)\n\n# The requested method was not found\nerror MethodNotFound (method: string)\n\n# The interface defines the requested method, but the service does not\n# implement it.\nerror MethodNotImplemented (method: string)\n\n# One of the passed parameters is invalid.\nerror InvalidParameter (parameter: string)"}}`+"\000",
b.String())
})
t.Run("GetInfo", func(t *testing.T) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
msg := []byte(`{"method":"org.varlink.service.GetInfo"}`)
if err := service.handleMessage(w, msg); err != nil {
t.Fatalf("HandleMessage returned error: %v", err)
}
expect(t, `{"parameters":{"vendor":"Varlink","product":"Varlink Test","version":"1","url":"https://github.com/varlink/go/varlink","interfaces":["org.varlink.service"]}}`+"\000",
b.String())
})
}
type VarlinkInterface struct{}
func (s *VarlinkInterface) VarlinkDispatch(call Call, methodname string) error {
switch methodname {
case "Ping":
if !call.WantsMore() {
return fmt.Errorf("More flag not passed")
}
if call.IsOneShot() {
return fmt.Errorf("OneShot flag set")
}
call.Continues = true
if err := call.Reply(nil); err != nil {
return err
}
if err := call.Reply(nil); err != nil {
return err
}
call.Continues = false
if err := call.Reply(nil); err != nil {
return err
}
return nil
case "PingError":
return call.ReplyError("org.example.test.PingError", nil)
}
call.Continues = true
if err := call.Reply(nil); err == nil {
return fmt.Errorf("call.Reply did not fail for Continues/More mismatch")
}
call.Continues = false
if err := call.ReplyError("WrongName", nil); err == nil {
return fmt.Errorf("call.ReplyError accepted invalid error name")
}
if err := call.ReplyError("org.varlink.service.MethodNotImplemented", nil); err == nil {
return fmt.Errorf("call.ReplyError accepted org.varlink.service error")
}
return call.ReplyMethodNotImplemented(methodname)
}
func (s *VarlinkInterface) VarlinkGetName() string {
return `org.example.test`
}
func (s *VarlinkInterface) VarlinkGetDescription() string {
return "#"
}
func TestMoreService(t *testing.T) {
newTestInterface := new(VarlinkInterface)
service, _ := NewService(
"Varlink",
"Varlink Test",
"1",
"https://github.com/varlink/go/varlink",
)
if err := service.RegisterInterface(newTestInterface); err != nil {
t.Fatalf("Couldn't register service: %v", err)
}
t.Run("MethodNotImplemented", func(t *testing.T) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
msg := []byte(`{"method":"org.example.test.Pingf"}`)
if err := service.handleMessage(w, msg); err != nil {
t.Fatalf("HandleMessage returned error: %v", err)
}
expect(t, `{"parameters":{"method":"Pingf"},"error":"org.varlink.service.MethodNotImplemented"}`+"\000",
b.String())
})
t.Run("PingError", func(t *testing.T) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
msg := []byte(`{"method":"org.example.test.PingError", "more" : true}`)
if err := service.handleMessage(w, msg); err != nil {
t.Fatalf("HandleMessage returned error: %v", err)
}
expect(t, `{"error":"org.example.test.PingError"}`+"\000",
b.String())
})
t.Run("MoreTest", func(t *testing.T) {
var b bytes.Buffer
w := bufio.NewWriter(&b)
msg := []byte(`{"method":"org.example.test.Ping", "more" : true}`)
if err := service.handleMessage(w, msg); err != nil {
t.Fatalf("HandleMessage returned error: %v", err)
}
expect(t, `{"continues":true}`+"\000"+`{"continues":true}`+"\000"+`{}`+"\000",
b.String())
})
}