122 lines
5.1 KiB
Go
122 lines
5.1 KiB
Go
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
package remote
|
|
|
|
import (
|
|
"context"
|
|
"git.stormux.org/storm/cthulhu/internal/atspi"
|
|
"git.stormux.org/storm/cthulhu/internal/wine"
|
|
"github.com/godbus/dbus/v5"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type reviewRecordingHandler struct {
|
|
*recordingHandler
|
|
registry *wine.ReviewRegistry
|
|
}
|
|
|
|
func (h reviewRecordingHandler) RegisterProvider(sender string, path dbus.ObjectPath, version uint32) bool {
|
|
return h.registry.RegisterProvider(sender, path, version)
|
|
}
|
|
func (h reviewRecordingHandler) PresentFocus(sender string, notice wine.ReviewFocusNotice) bool {
|
|
return h.registry.PresentFocus(sender, notice)
|
|
}
|
|
func (h reviewRecordingHandler) BindWineReviewConnection(conn *dbus.Conn) {
|
|
h.registry.BindWineReviewConnection(conn)
|
|
}
|
|
func TestWineReviewAuthorizationAndOptionalHandler(t *testing.T) {
|
|
r := wine.NewReviewRegistry(nil)
|
|
endpoint := newEndpoint(nil, reviewRecordingHandler{&recordingHandler{}, r}, func(dbus.Sender) bool { return false })
|
|
endpoint.startAccepting()
|
|
if accepted, err := endpoint.RegisterWineReviewProvider(":1.2", wine.ReviewObjectPath, 1); accepted || err == nil || err.Name != "org.freedesktop.DBus.Error.AccessDenied" {
|
|
t.Fatal("unauthorized registration accepted")
|
|
}
|
|
optional := newEndpoint(nil, &recordingHandler{}, func(dbus.Sender) bool { return true })
|
|
optional.startAccepting()
|
|
if accepted, err := optional.RegisterWineReviewProvider(":1.2", wine.ReviewObjectPath, 1); accepted || err != nil {
|
|
t.Fatal("older handler compatibility broken")
|
|
}
|
|
}
|
|
|
|
type nativeReviewEndpoint struct {
|
|
conn *dbus.Conn
|
|
calls chan struct{}
|
|
bounds atspi.Rectangle
|
|
}
|
|
|
|
func (f *nativeReviewEndpoint) CaptureWindow(sender dbus.Sender, window, focus string, revision uint64) (map[string]dbus.Variant, *dbus.Error) {
|
|
var owner string
|
|
if err := f.conn.BusObject().Call("org.freedesktop.DBus.GetNameOwner", 0, BusName).Store(&owner); err != nil || owner != string(sender) {
|
|
return nil, dbus.NewError("org.freedesktop.DBus.Error.AccessDenied", nil)
|
|
}
|
|
select {
|
|
case f.calls <- struct{}{}:
|
|
default:
|
|
}
|
|
node := map[string]dbus.Variant{"id": dbus.MakeVariant(window), "parent": dbus.MakeVariant(""), "role": dbus.MakeVariant("window"), "name": dbus.MakeVariant("native fixture"), "protected": dbus.MakeVariant(false), "visible": dbus.MakeVariant(true), "bounds": dbus.MakeVariant(f.bounds), "text_known": dbus.MakeVariant(false), "caret_known": dbus.MakeVariant(false), "caret": dbus.MakeVariant(uint64(0)), "caret_utf16": dbus.MakeVariant(uint64(0)), "ranges": dbus.MakeVariant([]wine.ReviewRange{})}
|
|
return map[string]dbus.Variant{"version": dbus.MakeVariant(uint32(1)), "instance": dbus.MakeVariant("instance"), "window": dbus.MakeVariant(window), "focus": dbus.MakeVariant(focus), "revision": dbus.MakeVariant(revision), "status": dbus.MakeVariant("ok"), "bounds": dbus.MakeVariant(f.bounds), "nodes": dbus.MakeVariant([]map[string]dbus.Variant{node})}, nil
|
|
}
|
|
func TestNativeSessionBusWineReview(t *testing.T) {
|
|
if os.Getenv("CTHULHU_NATIVE_DBUS_TEST") != "1" {
|
|
t.Skip("requires private session bus")
|
|
}
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
registry := wine.NewReviewRegistry(nil)
|
|
if err := registry.Start(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer registry.Stop(context.Background())
|
|
service := New(nil, reviewRecordingHandler{&recordingHandler{}, registry})
|
|
if err := service.Start(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer service.Stop(context.Background())
|
|
provider, err := dbus.ConnectSessionBus()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer provider.Close()
|
|
fixture := &nativeReviewEndpoint{conn: provider, calls: make(chan struct{}, 1), bounds: atspi.Rectangle{X: -10, Y: 20, Width: 400, Height: 300}}
|
|
if err = provider.Export(fixture, wine.ReviewObjectPath, wine.ReviewInterface); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
remote := provider.Object(BusName, ObjectPath)
|
|
var accepted bool
|
|
if err = remote.CallWithContext(ctx, InterfaceName+".RegisterWineReviewProvider", 0, wine.ReviewObjectPath, uint32(1)).Store(&accepted); err != nil || !accepted {
|
|
t.Fatalf("registration: %v %v", accepted, err)
|
|
}
|
|
if err = remote.CallWithContext(ctx, InterfaceName+".PresentWineReviewFocus", 0, "instance", "window", "window", uint64(1), "same title", "window", false, fixture.bounds).Store(&accepted); err != nil || !accepted {
|
|
t.Fatalf("focus: %v %v", accepted, err)
|
|
}
|
|
notices := registry.Focuses()
|
|
if len(notices) != 1 {
|
|
t.Fatalf("focus mailbox: %+v", notices)
|
|
}
|
|
id := notices[0].ID()
|
|
tree, err := registry.Capture(ctx, id)
|
|
if err != nil || tree == nil {
|
|
t.Fatalf("actual owner capture: %v", err)
|
|
}
|
|
wrong, err := dbus.ConnectSessionBus()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer wrong.Close()
|
|
if err = wrong.Object(id.BusName, wine.ReviewObjectPath).CallWithContext(ctx, wine.ReviewInterface+".CaptureWindow", 0, "window", "window", uint64(1)).Err; err == nil {
|
|
t.Fatal("different unique connection accepted")
|
|
}
|
|
provider.Close()
|
|
for registry.Current(id) {
|
|
select {
|
|
case <-registry.Changes():
|
|
case <-ctx.Done():
|
|
t.Fatal("dead provider remained current")
|
|
}
|
|
}
|
|
if len(registry.Focuses()) != 0 {
|
|
t.Fatal("dead focus retained")
|
|
}
|
|
}
|