Files
cthulhu/internal/remote/wine_review_test.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")
}
}