From bea558b61f7c51e495c1863b0f9b07085b585714 Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Thu, 19 Nov 2015 23:33:42 +0100 Subject: [PATCH] godeps: update go-systemd to v4 and godbus/dbus to v3 Signed-off-by: Antonio Murdaca --- Godeps/Godeps.json | 12 +- .../src/github.com/coreos/go-systemd/LICENSE | 191 +++++++++ .../github.com/coreos/go-systemd/dbus/dbus.go | 42 +- .../coreos/go-systemd/dbus/dbus_test.go | 77 ---- .../coreos/go-systemd/dbus/methods_test.go | 345 ---------------- .../coreos/go-systemd/dbus/set_test.go | 53 --- .../go-systemd/dbus/subscription_set_test.go | 82 ---- .../go-systemd/dbus/subscription_test.go | 105 ----- .../src/github.com/godbus/dbus/LICENSE | 2 +- .../github.com/godbus/dbus/README.markdown | 3 + .../src/github.com/godbus/dbus/call.go | 111 ------ .../src/github.com/godbus/dbus/conn.go | 48 ++- .../src/github.com/godbus/dbus/conn_test.go | 199 ---------- .../src/github.com/godbus/dbus/encoder.go | 41 +- .../github.com/godbus/dbus/examples_test.go | 50 --- .../src/github.com/godbus/dbus/export.go | 203 +++++++--- .../github.com/godbus/dbus/introspect/call.go | 2 +- .../godbus/dbus/introspect/introspectable.go | 3 +- .../src/github.com/godbus/dbus/object.go | 126 ++++++ .../src/github.com/godbus/dbus/proto_test.go | 369 ------------------ .../src/github.com/godbus/dbus/sig_test.go | 70 ---- .../godbus/dbus/transport_unix_test.go | 49 --- .../github.com/godbus/dbus/variant_test.go | 78 ---- 23 files changed, 586 insertions(+), 1675 deletions(-) create mode 100644 Godeps/_workspace/src/github.com/coreos/go-systemd/LICENSE delete mode 100644 Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/dbus_test.go delete mode 100644 Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/methods_test.go delete mode 100644 Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/set_test.go delete mode 100644 Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_set_test.go delete mode 100644 Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_test.go delete mode 100644 Godeps/_workspace/src/github.com/godbus/dbus/conn_test.go delete mode 100644 Godeps/_workspace/src/github.com/godbus/dbus/examples_test.go create mode 100644 Godeps/_workspace/src/github.com/godbus/dbus/object.go delete mode 100644 Godeps/_workspace/src/github.com/godbus/dbus/proto_test.go delete mode 100644 Godeps/_workspace/src/github.com/godbus/dbus/sig_test.go delete mode 100644 Godeps/_workspace/src/github.com/godbus/dbus/transport_unix_test.go delete mode 100644 Godeps/_workspace/src/github.com/godbus/dbus/variant_test.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 780a8122..533ac03c 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -14,13 +14,13 @@ }, { "ImportPath": "github.com/coreos/go-systemd/dbus", - "Comment": "v3", - "Rev": "be94bc700879ae8217780e9d141789a2defa302b" + "Comment": "v4", + "Rev": "b4a58d95188dd092ae20072bac14cece0e67c388" }, { "ImportPath": "github.com/coreos/go-systemd/util", - "Comment": "v3", - "Rev": "be94bc700879ae8217780e9d141789a2defa302b" + "Comment": "v4", + "Rev": "b4a58d95188dd092ae20072bac14cece0e67c388" }, { "ImportPath": "github.com/docker/docker/pkg/mount", @@ -44,8 +44,8 @@ }, { "ImportPath": "github.com/godbus/dbus", - "Comment": "v2", - "Rev": "88765d85c0fdadcd98a54e30694fa4e4f5b51133" + "Comment": "v3", + "Rev": "c7fdd8b5cd55e87b4e1f4e372cdb1db61dd6c66f" }, { "ImportPath": "github.com/golang/protobuf/proto", diff --git a/Godeps/_workspace/src/github.com/coreos/go-systemd/LICENSE b/Godeps/_workspace/src/github.com/coreos/go-systemd/LICENSE new file mode 100644 index 00000000..37ec93a1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/coreos/go-systemd/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/dbus.go b/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/dbus.go index 625a32b8..5dd748e6 100644 --- a/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/dbus.go +++ b/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/dbus.go @@ -64,11 +64,11 @@ func PathBusEscape(path string) string { type Conn struct { // sysconn/sysobj are only used to call dbus methods sysconn *dbus.Conn - sysobj *dbus.Object + sysobj dbus.BusObject // sigconn/sigobj are only used to receive dbus signals sigconn *dbus.Conn - sigobj *dbus.Object + sigobj dbus.BusObject jobListener struct { jobs map[dbus.ObjectPath]chan<- string @@ -86,14 +86,30 @@ type Conn struct { // New establishes a connection to the system bus and authenticates. // Callers should call Close() when done with the connection. func New() (*Conn, error) { - return newConnection(dbus.SystemBusPrivate) + return newConnection(func() (*dbus.Conn, error) { + return dbusAuthHelloConnection(dbus.SystemBusPrivate) + }) } // NewUserConnection establishes a connection to the session bus and // authenticates. This can be used to connect to systemd user instances. // Callers should call Close() when done with the connection. func NewUserConnection() (*Conn, error) { - return newConnection(dbus.SessionBusPrivate) + return newConnection(func() (*dbus.Conn, error) { + return dbusAuthHelloConnection(dbus.SessionBusPrivate) + }) +} + +// NewSystemdConnection establishes a private, direct connection to systemd. +// This can be used for communicating with systemd without a dbus daemon. +// Callers should call Close() when done with the connection. +func NewSystemdConnection() (*Conn, error) { + return newConnection(func() (*dbus.Conn, error) { + // We skip Hello when talking directly to systemd. + return dbusAuthConnection(func() (*dbus.Conn, error) { + return dbus.Dial("unix:path=/run/systemd/private") + }) + }) } // Close closes an established connection @@ -103,12 +119,12 @@ func (c *Conn) Close() { } func newConnection(createBus func() (*dbus.Conn, error)) (*Conn, error) { - sysconn, err := dbusConnection(createBus) + sysconn, err := createBus() if err != nil { return nil, err } - sigconn, err := dbusConnection(createBus) + sigconn, err := createBus() if err != nil { sysconn.Close() return nil, err @@ -132,7 +148,7 @@ func newConnection(createBus func() (*dbus.Conn, error)) (*Conn, error) { return c, nil } -func dbusConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { +func dbusAuthConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { conn, err := createBus() if err != nil { return nil, err @@ -149,8 +165,16 @@ func dbusConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { return nil, err } - err = conn.Hello() + return conn, nil +} + +func dbusAuthHelloConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { + conn, err := dbusAuthConnection(createBus) if err != nil { + return nil, err + } + + if err = conn.Hello(); err != nil { conn.Close() return nil, err } @@ -158,6 +182,6 @@ func dbusConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { return conn, nil } -func systemdObject(conn *dbus.Conn) *dbus.Object { +func systemdObject(conn *dbus.Conn) dbus.BusObject { return conn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1")) } diff --git a/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/dbus_test.go b/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/dbus_test.go deleted file mode 100644 index 3ea131e2..00000000 --- a/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/dbus_test.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -import ( - "testing" -) - -func TestNeedsEscape(t *testing.T) { - // Anything not 0-9a-zA-Z should always be escaped - for want, vals := range map[bool][]byte{ - false: []byte{'a', 'b', 'z', 'A', 'Q', '1', '4', '9'}, - true: []byte{'#', '%', '$', '!', '.', '_', '-', '%', '\\'}, - } { - for i := 1; i < 10; i++ { - for _, b := range vals { - got := needsEscape(i, b) - if got != want { - t.Errorf("needsEscape(%d, %c) returned %t, want %t", i, b, got, want) - } - } - } - } - - // 0-9 in position 0 should be escaped - for want, vals := range map[bool][]byte{ - false: []byte{'A', 'a', 'e', 'x', 'Q', 'Z'}, - true: []byte{'0', '4', '5', '9'}, - } { - for _, b := range vals { - got := needsEscape(0, b) - if got != want { - t.Errorf("needsEscape(0, %c) returned %t, want %t", b, got, want) - } - } - } - -} - -func TestPathBusEscape(t *testing.T) { - for in, want := range map[string]string{ - "": "_", - "foo.service": "foo_2eservice", - "foobar": "foobar", - "woof@woof.service": "woof_40woof_2eservice", - "0123456": "_30123456", - "account_db.service": "account_5fdb_2eservice", - "got-dashes": "got_2ddashes", - } { - got := PathBusEscape(in) - if got != want { - t.Errorf("bad result for PathBusEscape(%s): got %q, want %q", in, got, want) - } - } - -} - -// TestNew ensures that New() works without errors. -func TestNew(t *testing.T) { - _, err := New() - - if err != nil { - t.Fatal(err) - } -} diff --git a/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/methods_test.go b/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/methods_test.go deleted file mode 100644 index c9f9ccde..00000000 --- a/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/methods_test.go +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -import ( - "fmt" - "math/rand" - "os" - "path/filepath" - "reflect" - "testing" - - "github.com/godbus/dbus" -) - -func setupConn(t *testing.T) *Conn { - conn, err := New() - if err != nil { - t.Fatal(err) - } - - return conn -} - -func findFixture(target string, t *testing.T) string { - abs, err := filepath.Abs("../fixtures/" + target) - if err != nil { - t.Fatal(err) - } - return abs -} - -func setupUnit(target string, conn *Conn, t *testing.T) { - // Blindly stop the unit in case it is running - conn.StopUnit(target, "replace", nil) - - // Blindly remove the symlink in case it exists - targetRun := filepath.Join("/run/systemd/system/", target) - os.Remove(targetRun) -} - -func linkUnit(target string, conn *Conn, t *testing.T) { - abs := findFixture(target, t) - fixture := []string{abs} - - changes, err := conn.LinkUnitFiles(fixture, true, true) - if err != nil { - t.Fatal(err) - } - - if len(changes) < 1 { - t.Fatalf("Expected one change, got %v", changes) - } - - runPath := filepath.Join("/run/systemd/system/", target) - if changes[0].Filename != runPath { - t.Fatal("Unexpected target filename") - } -} - -// Ensure that basic unit starting and stopping works. -func TestStartStopUnit(t *testing.T) { - target := "start-stop.service" - conn := setupConn(t) - - setupUnit(target, conn, t) - linkUnit(target, conn, t) - - // 2. Start the unit - reschan := make(chan string) - _, err := conn.StartUnit(target, "replace", reschan) - if err != nil { - t.Fatal(err) - } - - job := <-reschan - if job != "done" { - t.Fatal("Job is not done:", job) - } - - units, err := conn.ListUnits() - - var unit *UnitStatus - for _, u := range units { - if u.Name == target { - unit = &u - } - } - - if unit == nil { - t.Fatalf("Test unit not found in list") - } - - if unit.ActiveState != "active" { - t.Fatalf("Test unit not active") - } - - // 3. Stop the unit - _, err = conn.StopUnit(target, "replace", reschan) - if err != nil { - t.Fatal(err) - } - - // wait for StopUnit job to complete - <-reschan - - units, err = conn.ListUnits() - - unit = nil - for _, u := range units { - if u.Name == target { - unit = &u - } - } - - if unit != nil { - t.Fatalf("Test unit found in list, should be stopped") - } -} - -// Enables a unit and then immediately tears it down -func TestEnableDisableUnit(t *testing.T) { - target := "enable-disable.service" - conn := setupConn(t) - - setupUnit(target, conn, t) - abs := findFixture(target, t) - runPath := filepath.Join("/run/systemd/system/", target) - - // 1. Enable the unit - install, changes, err := conn.EnableUnitFiles([]string{abs}, true, true) - if err != nil { - t.Fatal(err) - } - - if install != false { - t.Fatal("Install was true") - } - - if len(changes) < 1 { - t.Fatalf("Expected one change, got %v", changes) - } - - if changes[0].Filename != runPath { - t.Fatal("Unexpected target filename") - } - - // 2. Disable the unit - dChanges, err := conn.DisableUnitFiles([]string{abs}, true) - if err != nil { - t.Fatal(err) - } - - if len(dChanges) != 1 { - t.Fatalf("Changes should include the path, %v", dChanges) - } - if dChanges[0].Filename != runPath { - t.Fatalf("Change should include correct filename, %+v", dChanges[0]) - } - if dChanges[0].Destination != "" { - t.Fatalf("Change destination should be empty, %+v", dChanges[0]) - } -} - -// TestGetUnitProperties reads the `-.mount` which should exist on all systemd -// systems and ensures that one of its properties is valid. -func TestGetUnitProperties(t *testing.T) { - conn := setupConn(t) - - unit := "-.mount" - - info, err := conn.GetUnitProperties(unit) - if err != nil { - t.Fatal(err) - } - - names := info["Wants"].([]string) - - if len(names) < 1 { - t.Fatal("/ is unwanted") - } - - if names[0] != "system.slice" { - t.Fatal("unexpected wants for /") - } - - prop, err := conn.GetUnitProperty(unit, "Wants") - if err != nil { - t.Fatal(err) - } - - if prop.Name != "Wants" { - t.Fatal("unexpected property name") - } - - val := prop.Value.Value().([]string) - if !reflect.DeepEqual(val, names) { - t.Fatal("unexpected property value") - } -} - -// TestGetUnitPropertiesRejectsInvalidName attempts to get the properties for a -// unit with an invalid name. This test should be run with --test.timeout set, -// as a fail will manifest as GetUnitProperties hanging indefinitely. -func TestGetUnitPropertiesRejectsInvalidName(t *testing.T) { - conn := setupConn(t) - - unit := "//invalid#$^/" - - _, err := conn.GetUnitProperties(unit) - if err == nil { - t.Fatal("Expected an error, got nil") - } - - _, err = conn.GetUnitProperty(unit, "Wants") - if err == nil { - t.Fatal("Expected an error, got nil") - } -} - -// TestSetUnitProperties changes a cgroup setting on the `tmp.mount` -// which should exist on all systemd systems and ensures that the -// property was set. -func TestSetUnitProperties(t *testing.T) { - conn := setupConn(t) - - unit := "tmp.mount" - - if err := conn.SetUnitProperties(unit, true, Property{"CPUShares", dbus.MakeVariant(uint64(1023))}); err != nil { - t.Fatal(err) - } - - info, err := conn.GetUnitTypeProperties(unit, "Mount") - if err != nil { - t.Fatal(err) - } - - value := info["CPUShares"].(uint64) - if value != 1023 { - t.Fatal("CPUShares of unit is not 1023:", value) - } -} - -// Ensure that basic transient unit starting and stopping works. -func TestStartStopTransientUnit(t *testing.T) { - conn := setupConn(t) - - props := []Property{ - PropExecStart([]string{"/bin/sleep", "400"}, false), - } - target := fmt.Sprintf("testing-transient-%d.service", rand.Int()) - - // Start the unit - reschan := make(chan string) - _, err := conn.StartTransientUnit(target, "replace", props, reschan) - if err != nil { - t.Fatal(err) - } - - job := <-reschan - if job != "done" { - t.Fatal("Job is not done:", job) - } - - units, err := conn.ListUnits() - - var unit *UnitStatus - for _, u := range units { - if u.Name == target { - unit = &u - } - } - - if unit == nil { - t.Fatalf("Test unit not found in list") - } - - if unit.ActiveState != "active" { - t.Fatalf("Test unit not active") - } - - // 3. Stop the unit - _, err = conn.StopUnit(target, "replace", reschan) - if err != nil { - t.Fatal(err) - } - - // wait for StopUnit job to complete - <-reschan - - units, err = conn.ListUnits() - - unit = nil - for _, u := range units { - if u.Name == target { - unit = &u - } - } - - if unit != nil { - t.Fatalf("Test unit found in list, should be stopped") - } -} - -func TestConnJobListener(t *testing.T) { - target := "start-stop.service" - conn := setupConn(t) - - setupUnit(target, conn, t) - linkUnit(target, conn, t) - - jobSize := len(conn.jobListener.jobs) - - reschan := make(chan string) - _, err := conn.StartUnit(target, "replace", reschan) - if err != nil { - t.Fatal(err) - } - - <-reschan - - _, err = conn.StopUnit(target, "replace", reschan) - if err != nil { - t.Fatal(err) - } - - <-reschan - - currentJobSize := len(conn.jobListener.jobs) - if jobSize != currentJobSize { - t.Fatal("JobListener jobs leaked") - } -} diff --git a/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/set_test.go b/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/set_test.go deleted file mode 100644 index 2f04096f..00000000 --- a/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/set_test.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -import ( - "testing" -) - -// TestBasicSetActions asserts that Add & Remove behavior is correct -func TestBasicSetActions(t *testing.T) { - s := newSet() - - if s.Contains("foo") { - t.Fatal("set should not contain 'foo'") - } - - s.Add("foo") - - if !s.Contains("foo") { - t.Fatal("set should contain 'foo'") - } - - v := s.Values() - if len(v) != 1 { - t.Fatal("set.Values did not report correct number of values") - } - if v[0] != "foo" { - t.Fatal("set.Values did not report value") - } - - s.Remove("foo") - - if s.Contains("foo") { - t.Fatal("set should not contain 'foo'") - } - - v = s.Values() - if len(v) != 0 { - t.Fatal("set.Values did not report correct number of values") - } -} diff --git a/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_set_test.go b/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_set_test.go deleted file mode 100644 index 53f75dfb..00000000 --- a/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_set_test.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -import ( - "testing" - "time" -) - -// TestSubscribeUnit exercises the basics of subscription of a particular unit. -func TestSubscriptionSetUnit(t *testing.T) { - target := "subscribe-events-set.service" - - conn, err := New() - - if err != nil { - t.Fatal(err) - } - - err = conn.Subscribe() - if err != nil { - t.Fatal(err) - } - - subSet := conn.NewSubscriptionSet() - evChan, errChan := subSet.Subscribe() - - subSet.Add(target) - setupUnit(target, conn, t) - linkUnit(target, conn, t) - - reschan := make(chan string) - _, err = conn.StartUnit(target, "replace", reschan) - if err != nil { - t.Fatal(err) - } - - job := <-reschan - if job != "done" { - t.Fatal("Couldn't start", target) - } - - timeout := make(chan bool, 1) - go func() { - time.Sleep(3 * time.Second) - close(timeout) - }() - - for { - select { - case changes := <-evChan: - tCh, ok := changes[target] - - if !ok { - t.Fatal("Unexpected event:", changes) - } - - if tCh.ActiveState == "active" && tCh.Name == target { - goto success - } - case err = <-errChan: - t.Fatal(err) - case <-timeout: - t.Fatal("Reached timeout") - } - } - -success: - return -} diff --git a/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_test.go b/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_test.go deleted file mode 100644 index e50fc6f9..00000000 --- a/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_test.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -import ( - "testing" - "time" -) - -// TestSubscribe exercises the basics of subscription -func TestSubscribe(t *testing.T) { - conn, err := New() - - if err != nil { - t.Fatal(err) - } - - err = conn.Subscribe() - if err != nil { - t.Fatal(err) - } - - err = conn.Unsubscribe() - if err != nil { - t.Fatal(err) - } -} - -// TestSubscribeUnit exercises the basics of subscription of a particular unit. -func TestSubscribeUnit(t *testing.T) { - target := "subscribe-events.service" - - conn, err := New() - - if err != nil { - t.Fatal(err) - } - - err = conn.Subscribe() - if err != nil { - t.Fatal(err) - } - - err = conn.Unsubscribe() - if err != nil { - t.Fatal(err) - } - - evChan, errChan := conn.SubscribeUnits(time.Second) - - setupUnit(target, conn, t) - linkUnit(target, conn, t) - - reschan := make(chan string) - _, err = conn.StartUnit(target, "replace", reschan) - if err != nil { - t.Fatal(err) - } - - job := <-reschan - if job != "done" { - t.Fatal("Couldn't start", target) - } - - timeout := make(chan bool, 1) - go func() { - time.Sleep(3 * time.Second) - close(timeout) - }() - - for { - select { - case changes := <-evChan: - tCh, ok := changes[target] - - // Just continue until we see our event. - if !ok { - continue - } - - if tCh.ActiveState == "active" && tCh.Name == target { - goto success - } - case err = <-errChan: - t.Fatal(err) - case <-timeout: - t.Fatal("Reached timeout") - } - } - -success: - return -} diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/LICENSE b/Godeps/_workspace/src/github.com/godbus/dbus/LICENSE index 06b252bc..670d88fc 100644 --- a/Godeps/_workspace/src/github.com/godbus/dbus/LICENSE +++ b/Godeps/_workspace/src/github.com/godbus/dbus/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013, Georg Reinke () +Copyright (c) 2013, Georg Reinke (), Google All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/README.markdown b/Godeps/_workspace/src/github.com/godbus/dbus/README.markdown index 3ab21166..0a6e7e5b 100644 --- a/Godeps/_workspace/src/github.com/godbus/dbus/README.markdown +++ b/Godeps/_workspace/src/github.com/godbus/dbus/README.markdown @@ -27,6 +27,9 @@ The complete package documentation and some simple examples are available at [_examples](https://github.com/godbus/dbus/tree/master/_examples) directory gives a short overview over the basic usage. +#### Projects using godbus +- [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library. + Please note that the API is considered unstable for now and may change without further notice. diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/call.go b/Godeps/_workspace/src/github.com/godbus/dbus/call.go index 1d2fbc7e..ba6e73f6 100644 --- a/Godeps/_workspace/src/github.com/godbus/dbus/call.go +++ b/Godeps/_workspace/src/github.com/godbus/dbus/call.go @@ -2,7 +2,6 @@ package dbus import ( "errors" - "strings" ) // Call represents a pending or completed method call. @@ -35,113 +34,3 @@ func (c *Call) Store(retvalues ...interface{}) error { return Store(c.Body, retvalues...) } - -// Object represents a remote object on which methods can be invoked. -type Object struct { - conn *Conn - dest string - path ObjectPath -} - -// Call calls a method with (*Object).Go and waits for its reply. -func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call { - return <-o.Go(method, flags, make(chan *Call, 1), args...).Done -} - -// GetProperty calls org.freedesktop.DBus.Properties.GetProperty on the given -// object. The property name must be given in interface.member notation. -func (o *Object) GetProperty(p string) (Variant, error) { - idx := strings.LastIndex(p, ".") - if idx == -1 || idx+1 == len(p) { - return Variant{}, errors.New("dbus: invalid property " + p) - } - - iface := p[:idx] - prop := p[idx+1:] - - result := Variant{} - err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result) - - if err != nil { - return Variant{}, err - } - - return result, nil -} - -// Go calls a method with the given arguments asynchronously. It returns a -// Call structure representing this method call. The passed channel will -// return the same value once the call is done. If ch is nil, a new channel -// will be allocated. Otherwise, ch has to be buffered or Go will panic. -// -// If the flags include FlagNoReplyExpected, ch is ignored and a Call structure -// is returned of which only the Err member is valid. -// -// If the method parameter contains a dot ('.'), the part before the last dot -// specifies the interface on which the method is called. -func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call { - iface := "" - i := strings.LastIndex(method, ".") - if i != -1 { - iface = method[:i] - } - method = method[i+1:] - msg := new(Message) - msg.Type = TypeMethodCall - msg.serial = o.conn.getSerial() - msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected) - msg.Headers = make(map[HeaderField]Variant) - msg.Headers[FieldPath] = MakeVariant(o.path) - msg.Headers[FieldDestination] = MakeVariant(o.dest) - msg.Headers[FieldMember] = MakeVariant(method) - if iface != "" { - msg.Headers[FieldInterface] = MakeVariant(iface) - } - msg.Body = args - if len(args) > 0 { - msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...)) - } - if msg.Flags&FlagNoReplyExpected == 0 { - if ch == nil { - ch = make(chan *Call, 10) - } else if cap(ch) == 0 { - panic("dbus: unbuffered channel passed to (*Object).Go") - } - call := &Call{ - Destination: o.dest, - Path: o.path, - Method: method, - Args: args, - Done: ch, - } - o.conn.callsLck.Lock() - o.conn.calls[msg.serial] = call - o.conn.callsLck.Unlock() - o.conn.outLck.RLock() - if o.conn.closed { - call.Err = ErrClosed - call.Done <- call - } else { - o.conn.out <- msg - } - o.conn.outLck.RUnlock() - return call - } - o.conn.outLck.RLock() - defer o.conn.outLck.RUnlock() - if o.conn.closed { - return &Call{Err: ErrClosed} - } - o.conn.out <- msg - return &Call{Err: nil} -} - -// Destination returns the destination that calls on o are sent to. -func (o *Object) Destination() string { - return o.dest -} - -// Path returns the path that calls on o are sent to. -func (o *Object) Path() ObjectPath { - return o.path -} diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/conn.go b/Godeps/_workspace/src/github.com/godbus/dbus/conn.go index 18027a09..a4f53940 100644 --- a/Godeps/_workspace/src/github.com/godbus/dbus/conn.go +++ b/Godeps/_workspace/src/github.com/godbus/dbus/conn.go @@ -32,7 +32,7 @@ var ErrClosed = errors.New("dbus: connection closed by user") type Conn struct { transport - busObj *Object + busObj BusObject unixFD bool uuid string @@ -46,7 +46,7 @@ type Conn struct { calls map[uint32]*Call callsLck sync.RWMutex - handlers map[ObjectPath]map[string]interface{} + handlers map[ObjectPath]map[string]exportWithMapping handlersLck sync.RWMutex out chan *Message @@ -157,7 +157,7 @@ func newConn(tr transport) (*Conn, error) { conn.transport = tr conn.calls = make(map[uint32]*Call) conn.out = make(chan *Message, 10) - conn.handlers = make(map[ObjectPath]map[string]interface{}) + conn.handlers = make(map[ObjectPath]map[string]exportWithMapping) conn.nextSerial = 1 conn.serialUsed = map[uint32]bool{0: true} conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") @@ -166,7 +166,7 @@ func newConn(tr transport) (*Conn, error) { // BusObject returns the object owned by the bus daemon which handles // administrative requests. -func (conn *Conn) BusObject() *Object { +func (conn *Conn) BusObject() BusObject { return conn.busObj } @@ -303,18 +303,33 @@ func (conn *Conn) inWorker() { // as per http://dbus.freedesktop.org/doc/dbus-specification.html , // sender is optional for signals. sender, _ := msg.Headers[FieldSender].value.(string) - if iface == "org.freedesktop.DBus" && member == "NameLost" && - sender == "org.freedesktop.DBus" { - - name, _ := msg.Body[0].(string) - conn.namesLck.Lock() - for i, v := range conn.names { - if v == name { - copy(conn.names[i:], conn.names[i+1:]) - conn.names = conn.names[:len(conn.names)-1] + if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" { + if member == "NameLost" { + // If we lost the name on the bus, remove it from our + // tracking list. + name, ok := msg.Body[0].(string) + if !ok { + panic("Unable to read the lost name") } + conn.namesLck.Lock() + for i, v := range conn.names { + if v == name { + conn.names = append(conn.names[:i], + conn.names[i+1:]...) + } + } + conn.namesLck.Unlock() + } else if member == "NameAcquired" { + // If we acquired the name on the bus, add it to our + // tracking list. + name, ok := msg.Body[0].(string) + if !ok { + panic("Unable to read the acquired name") + } + conn.namesLck.Lock() + conn.names = append(conn.names, name) + conn.namesLck.Unlock() } - conn.namesLck.Unlock() } signal := &Signal{ Sender: sender, @@ -360,7 +375,7 @@ func (conn *Conn) Names() []string { } // Object returns the object identified by the given destination name and path. -func (conn *Conn) Object(dest string, path ObjectPath) *Object { +func (conn *Conn) Object(dest string, path ObjectPath) BusObject { return &Object{conn, dest, path} } @@ -554,7 +569,7 @@ type transport interface { } var ( - transports map[string]func(string) (transport, error) = make(map[string]func(string) (transport, error)) + transports = make(map[string]func(string) (transport, error)) ) func getTransport(address string) (transport, error) { @@ -571,6 +586,7 @@ func getTransport(address string) (transport, error) { f := transports[v[:i]] if f == nil { err = errors.New("dbus: invalid bus address (invalid or unsupported transport)") + continue } t, err = f(v[i+1:]) if err == nil { diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/conn_test.go b/Godeps/_workspace/src/github.com/godbus/dbus/conn_test.go deleted file mode 100644 index a2b14e8c..00000000 --- a/Godeps/_workspace/src/github.com/godbus/dbus/conn_test.go +++ /dev/null @@ -1,199 +0,0 @@ -package dbus - -import "testing" - -func TestSessionBus(t *testing.T) { - _, err := SessionBus() - if err != nil { - t.Error(err) - } -} - -func TestSystemBus(t *testing.T) { - _, err := SystemBus() - if err != nil { - t.Error(err) - } -} - -func TestSend(t *testing.T) { - bus, err := SessionBus() - if err != nil { - t.Error(err) - } - ch := make(chan *Call, 1) - msg := &Message{ - Type: TypeMethodCall, - Flags: 0, - Headers: map[HeaderField]Variant{ - FieldDestination: MakeVariant(bus.Names()[0]), - FieldPath: MakeVariant(ObjectPath("/org/freedesktop/DBus")), - FieldInterface: MakeVariant("org.freedesktop.DBus.Peer"), - FieldMember: MakeVariant("Ping"), - }, - } - call := bus.Send(msg, ch) - <-ch - if call.Err != nil { - t.Error(call.Err) - } -} - -type server struct{} - -func (server) Double(i int64) (int64, *Error) { - return 2 * i, nil -} - -func BenchmarkCall(b *testing.B) { - b.StopTimer() - var s string - bus, err := SessionBus() - if err != nil { - b.Fatal(err) - } - name := bus.Names()[0] - obj := bus.BusObject() - b.StartTimer() - for i := 0; i < b.N; i++ { - err := obj.Call("org.freedesktop.DBus.GetNameOwner", 0, name).Store(&s) - if err != nil { - b.Fatal(err) - } - if s != name { - b.Errorf("got %s, wanted %s", s, name) - } - } -} - -func BenchmarkCallAsync(b *testing.B) { - b.StopTimer() - bus, err := SessionBus() - if err != nil { - b.Fatal(err) - } - name := bus.Names()[0] - obj := bus.BusObject() - c := make(chan *Call, 50) - done := make(chan struct{}) - go func() { - for i := 0; i < b.N; i++ { - v := <-c - if v.Err != nil { - b.Error(v.Err) - } - s := v.Body[0].(string) - if s != name { - b.Errorf("got %s, wanted %s", s, name) - } - } - close(done) - }() - b.StartTimer() - for i := 0; i < b.N; i++ { - obj.Go("org.freedesktop.DBus.GetNameOwner", 0, c, name) - } - <-done -} - -func BenchmarkServe(b *testing.B) { - b.StopTimer() - srv, err := SessionBus() - if err != nil { - b.Fatal(err) - } - cli, err := SessionBusPrivate() - if err != nil { - b.Fatal(err) - } - if err = cli.Auth(nil); err != nil { - b.Fatal(err) - } - if err = cli.Hello(); err != nil { - b.Fatal(err) - } - benchmarkServe(b, srv, cli) -} - -func BenchmarkServeAsync(b *testing.B) { - b.StopTimer() - srv, err := SessionBus() - if err != nil { - b.Fatal(err) - } - cli, err := SessionBusPrivate() - if err != nil { - b.Fatal(err) - } - if err = cli.Auth(nil); err != nil { - b.Fatal(err) - } - if err = cli.Hello(); err != nil { - b.Fatal(err) - } - benchmarkServeAsync(b, srv, cli) -} - -func BenchmarkServeSameConn(b *testing.B) { - b.StopTimer() - bus, err := SessionBus() - if err != nil { - b.Fatal(err) - } - - benchmarkServe(b, bus, bus) -} - -func BenchmarkServeSameConnAsync(b *testing.B) { - b.StopTimer() - bus, err := SessionBus() - if err != nil { - b.Fatal(err) - } - - benchmarkServeAsync(b, bus, bus) -} - -func benchmarkServe(b *testing.B, srv, cli *Conn) { - var r int64 - var err error - dest := srv.Names()[0] - srv.Export(server{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test") - obj := cli.Object(dest, "/org/guelfey/DBus/Test") - b.StartTimer() - for i := 0; i < b.N; i++ { - err = obj.Call("org.guelfey.DBus.Test.Double", 0, int64(i)).Store(&r) - if err != nil { - b.Fatal(err) - } - if r != 2*int64(i) { - b.Errorf("got %d, wanted %d", r, 2*int64(i)) - } - } -} - -func benchmarkServeAsync(b *testing.B, srv, cli *Conn) { - dest := srv.Names()[0] - srv.Export(server{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test") - obj := cli.Object(dest, "/org/guelfey/DBus/Test") - c := make(chan *Call, 50) - done := make(chan struct{}) - go func() { - for i := 0; i < b.N; i++ { - v := <-c - if v.Err != nil { - b.Fatal(v.Err) - } - i, r := v.Args[0].(int64), v.Body[0].(int64) - if 2*i != r { - b.Errorf("got %d, wanted %d", r, 2*i) - } - } - close(done) - }() - b.StartTimer() - for i := 0; i < b.N; i++ { - obj.Go("org.guelfey.DBus.Test.Double", 0, c, int64(i)) - } - <-done -} diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/encoder.go b/Godeps/_workspace/src/github.com/godbus/dbus/encoder.go index f9d2f057..9f0a9e89 100644 --- a/Godeps/_workspace/src/github.com/godbus/dbus/encoder.go +++ b/Godeps/_workspace/src/github.com/godbus/dbus/encoder.go @@ -16,24 +16,43 @@ type encoder struct { // NewEncoder returns a new encoder that writes to out in the given byte order. func newEncoder(out io.Writer, order binary.ByteOrder) *encoder { + return newEncoderAtOffset(out, 0, order) +} + +// newEncoderAtOffset returns a new encoder that writes to out in the given +// byte order. Specify the offset to initialize pos for proper alignment +// computation. +func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder) *encoder { enc := new(encoder) enc.out = out enc.order = order + enc.pos = offset return enc } // Aligns the next output to be on a multiple of n. Panics on write errors. func (enc *encoder) align(n int) { - if enc.pos%n != 0 { - newpos := (enc.pos + n - 1) & ^(n - 1) - empty := make([]byte, newpos-enc.pos) + pad := enc.padding(0, n) + if pad > 0 { + empty := make([]byte, pad) if _, err := enc.out.Write(empty); err != nil { panic(err) } - enc.pos = newpos + enc.pos += pad } } +// pad returns the number of bytes of padding, based on current position and additional offset. +// and alignment. +func (enc *encoder) padding(offset, algn int) int { + abs := enc.pos + offset + if abs%algn != 0 { + newabs := (abs + algn - 1) & ^(algn - 1) + return newabs - abs + } + return 0 +} + // Calls binary.Write(enc.out, enc.order, v) and panics on write errors. func (enc *encoder) binwrite(v interface{}) { if err := binary.Write(enc.out, enc.order, v); err != nil { @@ -108,8 +127,13 @@ func (enc *encoder) encode(v reflect.Value, depth int) { if depth >= 64 { panic(FormatError("input exceeds container depth limit")) } + // Lookahead offset: 4 bytes for uint32 length (with alignment), + // plus alignment for elements. + n := enc.padding(0, 4) + 4 + offset := enc.pos + n + enc.padding(n, alignment(v.Type().Elem())) + var buf bytes.Buffer - bufenc := newEncoder(&buf, enc.order) + bufenc := newEncoderAtOffset(&buf, offset, enc.order) for i := 0; i < v.Len(); i++ { bufenc.encode(v.Index(i), depth+1) @@ -159,8 +183,13 @@ func (enc *encoder) encode(v reflect.Value, depth int) { panic(InvalidTypeError{v.Type()}) } keys := v.MapKeys() + // Lookahead offset: 4 bytes for uint32 length (with alignment), + // plus 8-byte alignment + n := enc.padding(0, 4) + 4 + offset := enc.pos + n + enc.padding(n, 8) + var buf bytes.Buffer - bufenc := newEncoder(&buf, enc.order) + bufenc := newEncoderAtOffset(&buf, offset, enc.order) for _, k := range keys { bufenc.align(8) bufenc.encode(k, depth+2) diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/examples_test.go b/Godeps/_workspace/src/github.com/godbus/dbus/examples_test.go deleted file mode 100644 index 0218ac55..00000000 --- a/Godeps/_workspace/src/github.com/godbus/dbus/examples_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package dbus - -import "fmt" - -func ExampleConn_Emit() { - conn, err := SessionBus() - if err != nil { - panic(err) - } - - conn.Emit("/foo/bar", "foo.bar.Baz", uint32(0xDAEDBEEF)) -} - -func ExampleObject_Call() { - var list []string - - conn, err := SessionBus() - if err != nil { - panic(err) - } - - err = conn.BusObject().Call("org.freedesktop.DBus.ListNames", 0).Store(&list) - if err != nil { - panic(err) - } - for _, v := range list { - fmt.Println(v) - } -} - -func ExampleObject_Go() { - conn, err := SessionBus() - if err != nil { - panic(err) - } - - ch := make(chan *Call, 10) - conn.BusObject().Go("org.freedesktop.DBus.ListActivatableNames", 0, ch) - select { - case call := <-ch: - if call.Err != nil { - panic(err) - } - list := call.Body[0].([]string) - for _, v := range list { - fmt.Println(v) - } - // put some other cases here - } -} diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/export.go b/Godeps/_workspace/src/github.com/godbus/dbus/export.go index 1dd15915..c6440a74 100644 --- a/Godeps/_workspace/src/github.com/godbus/dbus/export.go +++ b/Godeps/_workspace/src/github.com/godbus/dbus/export.go @@ -2,9 +2,9 @@ package dbus import ( "errors" + "fmt" "reflect" "strings" - "unicode" ) var ( @@ -22,16 +22,52 @@ var ( } ) +// exportWithMapping represents an exported struct along with a method name +// mapping to allow for exporting lower-case methods, etc. +type exportWithMapping struct { + export interface{} + + // Method name mapping; key -> struct method, value -> dbus method. + mapping map[string]string + + // Whether or not this export is for the entire subtree + includeSubtree bool +} + // Sender is a type which can be used in exported methods to receive the message // sender. type Sender string -func exportedMethod(v interface{}, name string) reflect.Value { - if v == nil { +func exportedMethod(export exportWithMapping, name string) reflect.Value { + if export.export == nil { return reflect.Value{} } - m := reflect.ValueOf(v).MethodByName(name) - if !m.IsValid() { + + // If a mapping was included in the export, check the map to see if we + // should be looking for a different method in the export. + if export.mapping != nil { + for key, value := range export.mapping { + if value == name { + name = key + break + } + + // Catch the case where a method is aliased but the client is calling + // the original, e.g. the "Foo" method was exported mapped to + // "foo," and dbus client called the original "Foo." + if key == name { + return reflect.Value{} + } + } + } + + value := reflect.ValueOf(export.export) + m := value.MethodByName(name) + + // Catch the case of attempting to call an unexported method + method, ok := value.Type().MethodByName(name) + + if !m.IsValid() || !ok || method.PkgPath != "" { return reflect.Value{} } t := m.Type() @@ -43,6 +79,42 @@ func exportedMethod(v interface{}, name string) reflect.Value { return m } +// searchHandlers will look through all registered handlers looking for one +// to handle the given path. If a verbatim one isn't found, it will check for +// a subtree registration for the path as well. +func (conn *Conn) searchHandlers(path ObjectPath) (map[string]exportWithMapping, bool) { + conn.handlersLck.RLock() + defer conn.handlersLck.RUnlock() + + handlers, ok := conn.handlers[path] + if ok { + return handlers, ok + } + + // If handlers weren't found for this exact path, look for a matching subtree + // registration + handlers = make(map[string]exportWithMapping) + path = path[:strings.LastIndex(string(path), "/")] + for len(path) > 0 { + var subtreeHandlers map[string]exportWithMapping + subtreeHandlers, ok = conn.handlers[path] + if ok { + for iface, handler := range subtreeHandlers { + // Only include this handler if it registered for the subtree + if handler.includeSubtree { + handlers[iface] = handler + } + } + + break + } + + path = path[:strings.LastIndex(string(path), "/")] + } + + return handlers, ok +} + // handleCall handles the given method call (i.e. looks if it's one of the // pre-implemented ones and searches for a corresponding handler if not). func (conn *Conn) handleCall(msg *Message) { @@ -62,40 +134,35 @@ func (conn *Conn) handleCall(msg *Message) { } return } - if len(name) == 0 || unicode.IsLower([]rune(name)[0]) { + if len(name) == 0 { conn.sendError(errmsgUnknownMethod, sender, serial) } + + // Find the exported handler (if any) for this path + handlers, ok := conn.searchHandlers(path) + if !ok { + conn.sendError(errmsgNoObject, sender, serial) + return + } + var m reflect.Value if hasIface { - conn.handlersLck.RLock() - obj, ok := conn.handlers[path] - if !ok { - conn.sendError(errmsgNoObject, sender, serial) - conn.handlersLck.RUnlock() - return - } - iface := obj[ifaceName] - conn.handlersLck.RUnlock() + iface := handlers[ifaceName] m = exportedMethod(iface, name) } else { - conn.handlersLck.RLock() - if _, ok := conn.handlers[path]; !ok { - conn.sendError(errmsgNoObject, sender, serial) - conn.handlersLck.RUnlock() - return - } - for _, v := range conn.handlers[path] { + for _, v := range handlers { m = exportedMethod(v, name) if m.IsValid() { break } } - conn.handlersLck.RUnlock() } + if !m.IsValid() { conn.sendError(errmsgUnknownMethod, sender, serial) return } + t := m.Type() vs := msg.Body pointers := make([]interface{}, t.NumIn()) @@ -106,27 +173,36 @@ func (conn *Conn) handleCall(msg *Message) { pointers[i] = val.Interface() if tp == reflect.TypeOf((*Sender)(nil)).Elem() { val.Elem().SetString(sender) + } else if tp == reflect.TypeOf((*Message)(nil)).Elem() { + val.Elem().Set(reflect.ValueOf(*msg)) } else { decode = append(decode, pointers[i]) } } + if len(decode) != len(vs) { conn.sendError(errmsgInvalidArg, sender, serial) return } + if err := Store(vs, decode...); err != nil { conn.sendError(errmsgInvalidArg, sender, serial) return } + + // Extract parameters params := make([]reflect.Value, len(pointers)) for i := 0; i < len(pointers); i++ { params[i] = reflect.ValueOf(pointers[i]).Elem() } + + // Call method ret := m.Call(params) if em := ret[t.NumOut()-1].Interface().(*Error); em != nil { conn.sendError(*em, sender, serial) return } + if msg.Flags&FlagNoReplyExpected == 0 { reply := new(Message) reply.Type = TypeMethodReply @@ -203,6 +279,10 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro // contribute to the dbus signature of the method (i.e. the method is exposed // as if the parameters of type Sender were not there). // +// Similarly, any parameters with the type Message are set to the raw message +// received on the bus. Again, parameters of this type do not contribute to the +// dbus signature of the method. +// // Every method call is executed in a new goroutine, so the method may be called // in multiple goroutines at once. // @@ -214,10 +294,51 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro // // Export returns an error if path is not a valid path name. func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error { + return conn.ExportWithMap(v, nil, path, iface) +} + +// ExportWithMap works exactly like Export but provides the ability to remap +// method names (e.g. export a lower-case method). +// +// The keys in the map are the real method names (exported on the struct), and +// the values are the method names to be exported on DBus. +func (conn *Conn) ExportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error { + return conn.exportWithMap(v, mapping, path, iface, false) +} + +// ExportSubtree works exactly like Export but registers the given value for +// an entire subtree rather under the root path provided. +// +// In order to make this useful, one parameter in each of the value's exported +// methods should be a Message, in which case it will contain the raw message +// (allowing one to get access to the path that caused the method to be called). +// +// Note that more specific export paths take precedence over less specific. For +// example, a method call using the ObjectPath /foo/bar/baz will call a method +// exported on /foo/bar before a method exported on /foo. +func (conn *Conn) ExportSubtree(v interface{}, path ObjectPath, iface string) error { + return conn.ExportSubtreeWithMap(v, nil, path, iface) +} + +// ExportSubtreeWithMap works exactly like ExportSubtree but provides the +// ability to remap method names (e.g. export a lower-case method). +// +// The keys in the map are the real method names (exported on the struct), and +// the values are the method names to be exported on DBus. +func (conn *Conn) ExportSubtreeWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error { + return conn.exportWithMap(v, mapping, path, iface, true) +} + +// exportWithMap is the worker function for all exports/registrations. +func (conn *Conn) exportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string, includeSubtree bool) error { if !path.IsValid() { - return errors.New("dbus: invalid path name") + return fmt.Errorf(`dbus: Invalid path name: "%s"`, path) } + conn.handlersLck.Lock() + defer conn.handlersLck.Unlock() + + // Remove a previous export if the interface is nil if v == nil { if _, ok := conn.handlers[path]; ok { delete(conn.handlers[path], iface) @@ -225,51 +346,39 @@ func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error { delete(conn.handlers, path) } } + return nil } + + // If this is the first handler for this path, make a new map to hold all + // handlers for this path. if _, ok := conn.handlers[path]; !ok { - conn.handlers[path] = make(map[string]interface{}) + conn.handlers[path] = make(map[string]exportWithMapping) } - conn.handlers[path][iface] = v - conn.handlersLck.Unlock() + + // Finally, save this handler + conn.handlers[path][iface] = exportWithMapping{export: v, mapping: mapping, includeSubtree: includeSubtree} + return nil } -// ReleaseName calls org.freedesktop.DBus.ReleaseName. You should use only this -// method to release a name (see below). +// ReleaseName calls org.freedesktop.DBus.ReleaseName and awaits a response. func (conn *Conn) ReleaseName(name string) (ReleaseNameReply, error) { var r uint32 err := conn.busObj.Call("org.freedesktop.DBus.ReleaseName", 0, name).Store(&r) if err != nil { return 0, err } - if r == uint32(ReleaseNameReplyReleased) { - conn.namesLck.Lock() - for i, v := range conn.names { - if v == name { - copy(conn.names[i:], conn.names[i+1:]) - conn.names = conn.names[:len(conn.names)-1] - } - } - conn.namesLck.Unlock() - } return ReleaseNameReply(r), nil } -// RequestName calls org.freedesktop.DBus.RequestName. You should use only this -// method to request a name because package dbus needs to keep track of all -// names that the connection has. +// RequestName calls org.freedesktop.DBus.RequestName and awaits a response. func (conn *Conn) RequestName(name string, flags RequestNameFlags) (RequestNameReply, error) { var r uint32 err := conn.busObj.Call("org.freedesktop.DBus.RequestName", 0, name, flags).Store(&r) if err != nil { return 0, err } - if r == uint32(RequestNameReplyPrimaryOwner) { - conn.namesLck.Lock() - conn.names = append(conn.names, name) - conn.namesLck.Unlock() - } return RequestNameReply(r), nil } diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/introspect/call.go b/Godeps/_workspace/src/github.com/godbus/dbus/introspect/call.go index 4aca2ea6..790a23ec 100644 --- a/Godeps/_workspace/src/github.com/godbus/dbus/introspect/call.go +++ b/Godeps/_workspace/src/github.com/godbus/dbus/introspect/call.go @@ -8,7 +8,7 @@ import ( // Call calls org.freedesktop.Introspectable.Introspect on a remote object // and returns the introspection data. -func Call(o *dbus.Object) (*Node, error) { +func Call(o dbus.BusObject) (*Node, error) { var xmldata string var node Node diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/introspect/introspectable.go b/Godeps/_workspace/src/github.com/godbus/dbus/introspect/introspectable.go index 38982e77..2f16690b 100644 --- a/Godeps/_workspace/src/github.com/godbus/dbus/introspect/introspectable.go +++ b/Godeps/_workspace/src/github.com/godbus/dbus/introspect/introspectable.go @@ -59,7 +59,8 @@ func Methods(v interface{}) []Method { m.Name = t.Method(i).Name m.Args = make([]Arg, 0, mt.NumIn()+mt.NumOut()-2) for j := 1; j < mt.NumIn(); j++ { - if mt.In(j) != reflect.TypeOf((*dbus.Sender)(nil)).Elem() { + if mt.In(j) != reflect.TypeOf((*dbus.Sender)(nil)).Elem() && + mt.In(j) != reflect.TypeOf((*dbus.Message)(nil)).Elem() { arg := Arg{"", dbus.SignatureOfType(mt.In(j)).String(), "in"} m.Args = append(m.Args, arg) } diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/object.go b/Godeps/_workspace/src/github.com/godbus/dbus/object.go new file mode 100644 index 00000000..7ef45da4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/godbus/dbus/object.go @@ -0,0 +1,126 @@ +package dbus + +import ( + "errors" + "strings" +) + +// BusObject is the interface of a remote object on which methods can be +// invoked. +type BusObject interface { + Call(method string, flags Flags, args ...interface{}) *Call + Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call + GetProperty(p string) (Variant, error) + Destination() string + Path() ObjectPath +} + +// Object represents a remote object on which methods can be invoked. +type Object struct { + conn *Conn + dest string + path ObjectPath +} + +// Call calls a method with (*Object).Go and waits for its reply. +func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call { + return <-o.Go(method, flags, make(chan *Call, 1), args...).Done +} + +// Go calls a method with the given arguments asynchronously. It returns a +// Call structure representing this method call. The passed channel will +// return the same value once the call is done. If ch is nil, a new channel +// will be allocated. Otherwise, ch has to be buffered or Go will panic. +// +// If the flags include FlagNoReplyExpected, ch is ignored and a Call structure +// is returned of which only the Err member is valid. +// +// If the method parameter contains a dot ('.'), the part before the last dot +// specifies the interface on which the method is called. +func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call { + iface := "" + i := strings.LastIndex(method, ".") + if i != -1 { + iface = method[:i] + } + method = method[i+1:] + msg := new(Message) + msg.Type = TypeMethodCall + msg.serial = o.conn.getSerial() + msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected) + msg.Headers = make(map[HeaderField]Variant) + msg.Headers[FieldPath] = MakeVariant(o.path) + msg.Headers[FieldDestination] = MakeVariant(o.dest) + msg.Headers[FieldMember] = MakeVariant(method) + if iface != "" { + msg.Headers[FieldInterface] = MakeVariant(iface) + } + msg.Body = args + if len(args) > 0 { + msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...)) + } + if msg.Flags&FlagNoReplyExpected == 0 { + if ch == nil { + ch = make(chan *Call, 10) + } else if cap(ch) == 0 { + panic("dbus: unbuffered channel passed to (*Object).Go") + } + call := &Call{ + Destination: o.dest, + Path: o.path, + Method: method, + Args: args, + Done: ch, + } + o.conn.callsLck.Lock() + o.conn.calls[msg.serial] = call + o.conn.callsLck.Unlock() + o.conn.outLck.RLock() + if o.conn.closed { + call.Err = ErrClosed + call.Done <- call + } else { + o.conn.out <- msg + } + o.conn.outLck.RUnlock() + return call + } + o.conn.outLck.RLock() + defer o.conn.outLck.RUnlock() + if o.conn.closed { + return &Call{Err: ErrClosed} + } + o.conn.out <- msg + return &Call{Err: nil} +} + +// GetProperty calls org.freedesktop.DBus.Properties.GetProperty on the given +// object. The property name must be given in interface.member notation. +func (o *Object) GetProperty(p string) (Variant, error) { + idx := strings.LastIndex(p, ".") + if idx == -1 || idx+1 == len(p) { + return Variant{}, errors.New("dbus: invalid property " + p) + } + + iface := p[:idx] + prop := p[idx+1:] + + result := Variant{} + err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result) + + if err != nil { + return Variant{}, err + } + + return result, nil +} + +// Destination returns the destination that calls on o are sent to. +func (o *Object) Destination() string { + return o.dest +} + +// Path returns the path that calls on o are sent to. +func (o *Object) Path() ObjectPath { + return o.path +} diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/proto_test.go b/Godeps/_workspace/src/github.com/godbus/dbus/proto_test.go deleted file mode 100644 index 608a770d..00000000 --- a/Godeps/_workspace/src/github.com/godbus/dbus/proto_test.go +++ /dev/null @@ -1,369 +0,0 @@ -package dbus - -import ( - "bytes" - "encoding/binary" - "io/ioutil" - "math" - "reflect" - "testing" -) - -var protoTests = []struct { - vs []interface{} - bigEndian []byte - littleEndian []byte -}{ - { - []interface{}{int32(0)}, - []byte{0, 0, 0, 0}, - []byte{0, 0, 0, 0}, - }, - { - []interface{}{true, false}, - []byte{0, 0, 0, 1, 0, 0, 0, 0}, - []byte{1, 0, 0, 0, 0, 0, 0, 0}, - }, - { - []interface{}{byte(0), uint16(12), int16(32), uint32(43)}, - []byte{0, 0, 0, 12, 0, 32, 0, 0, 0, 0, 0, 43}, - []byte{0, 0, 12, 0, 32, 0, 0, 0, 43, 0, 0, 0}, - }, - { - []interface{}{int64(-1), uint64(1<<64 - 1)}, - bytes.Repeat([]byte{255}, 16), - bytes.Repeat([]byte{255}, 16), - }, - { - []interface{}{math.Inf(+1)}, - []byte{0x7f, 0xf0, 0, 0, 0, 0, 0, 0}, - []byte{0, 0, 0, 0, 0, 0, 0xf0, 0x7f}, - }, - { - []interface{}{"foo"}, - []byte{0, 0, 0, 3, 'f', 'o', 'o', 0}, - []byte{3, 0, 0, 0, 'f', 'o', 'o', 0}, - }, - { - []interface{}{Signature{"ai"}}, - []byte{2, 'a', 'i', 0}, - []byte{2, 'a', 'i', 0}, - }, - { - []interface{}{[]int16{42, 256}}, - []byte{0, 0, 0, 4, 0, 42, 1, 0}, - []byte{4, 0, 0, 0, 42, 0, 0, 1}, - }, - { - []interface{}{MakeVariant("foo")}, - []byte{1, 's', 0, 0, 0, 0, 0, 3, 'f', 'o', 'o', 0}, - []byte{1, 's', 0, 0, 3, 0, 0, 0, 'f', 'o', 'o', 0}, - }, - { - []interface{}{MakeVariant(MakeVariant(Signature{"v"}))}, - []byte{1, 'v', 0, 1, 'g', 0, 1, 'v', 0}, - []byte{1, 'v', 0, 1, 'g', 0, 1, 'v', 0}, - }, - { - []interface{}{map[int32]bool{42: true}}, - []byte{0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 1}, - []byte{8, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 1, 0, 0, 0}, - }, - { - []interface{}{map[string]Variant{}, byte(42)}, - []byte{0, 0, 0, 0, 0, 0, 0, 0, 42}, - []byte{0, 0, 0, 0, 0, 0, 0, 0, 42}, - }, - { - []interface{}{[]uint64{}, byte(42)}, - []byte{0, 0, 0, 0, 0, 0, 0, 0, 42}, - []byte{0, 0, 0, 0, 0, 0, 0, 0, 42}, - }, -} - -func TestProto(t *testing.T) { - for i, v := range protoTests { - buf := new(bytes.Buffer) - bigEnc := newEncoder(buf, binary.BigEndian) - bigEnc.Encode(v.vs...) - marshalled := buf.Bytes() - if bytes.Compare(marshalled, v.bigEndian) != 0 { - t.Errorf("test %d (marshal be): got '%v', but expected '%v'\n", i+1, marshalled, - v.bigEndian) - } - buf.Reset() - litEnc := newEncoder(buf, binary.LittleEndian) - litEnc.Encode(v.vs...) - marshalled = buf.Bytes() - if bytes.Compare(marshalled, v.littleEndian) != 0 { - t.Errorf("test %d (marshal le): got '%v', but expected '%v'\n", i+1, marshalled, - v.littleEndian) - } - unmarshalled := reflect.MakeSlice(reflect.TypeOf(v.vs), - 0, 0) - for i := range v.vs { - unmarshalled = reflect.Append(unmarshalled, - reflect.New(reflect.TypeOf(v.vs[i]))) - } - bigDec := newDecoder(bytes.NewReader(v.bigEndian), binary.BigEndian) - vs, err := bigDec.Decode(SignatureOf(v.vs...)) - if err != nil { - t.Errorf("test %d (unmarshal be): %s\n", i+1, err) - continue - } - if !reflect.DeepEqual(vs, v.vs) { - t.Errorf("test %d (unmarshal be): got %#v, but expected %#v\n", i+1, vs, v.vs) - } - litDec := newDecoder(bytes.NewReader(v.littleEndian), binary.LittleEndian) - vs, err = litDec.Decode(SignatureOf(v.vs...)) - if err != nil { - t.Errorf("test %d (unmarshal le): %s\n", i+1, err) - continue - } - if !reflect.DeepEqual(vs, v.vs) { - t.Errorf("test %d (unmarshal le): got %#v, but expected %#v\n", i+1, vs, v.vs) - } - - } -} - -func TestProtoMap(t *testing.T) { - m := map[string]uint8{ - "foo": 23, - "bar": 2, - } - var n map[string]uint8 - buf := new(bytes.Buffer) - enc := newEncoder(buf, binary.LittleEndian) - enc.Encode(m) - dec := newDecoder(buf, binary.LittleEndian) - vs, err := dec.Decode(Signature{"a{sy}"}) - if err != nil { - t.Fatal(err) - } - if err = Store(vs, &n); err != nil { - t.Fatal(err) - } - if len(n) != 2 || n["foo"] != 23 || n["bar"] != 2 { - t.Error("got", n) - } -} - -func TestProtoVariantStruct(t *testing.T) { - var variant Variant - v := MakeVariant(struct { - A int32 - B int16 - }{1, 2}) - buf := new(bytes.Buffer) - enc := newEncoder(buf, binary.LittleEndian) - enc.Encode(v) - dec := newDecoder(buf, binary.LittleEndian) - vs, err := dec.Decode(Signature{"v"}) - if err != nil { - t.Fatal(err) - } - if err = Store(vs, &variant); err != nil { - t.Fatal(err) - } - sl := variant.Value().([]interface{}) - v1, v2 := sl[0].(int32), sl[1].(int16) - if v1 != int32(1) { - t.Error("got", v1, "as first int") - } - if v2 != int16(2) { - t.Error("got", v2, "as second int") - } -} - -func TestProtoStructTag(t *testing.T) { - type Bar struct { - A int32 - B chan interface{} `dbus:"-"` - C int32 - } - var bar1, bar2 Bar - bar1.A = 234 - bar2.C = 345 - buf := new(bytes.Buffer) - enc := newEncoder(buf, binary.LittleEndian) - enc.Encode(bar1) - dec := newDecoder(buf, binary.LittleEndian) - vs, err := dec.Decode(Signature{"(ii)"}) - if err != nil { - t.Fatal(err) - } - if err = Store(vs, &bar2); err != nil { - t.Fatal(err) - } - if bar1 != bar2 { - t.Error("struct tag test: got", bar2) - } -} - -func TestProtoStoreStruct(t *testing.T) { - var foo struct { - A int32 - B string - c chan interface{} - D interface{} `dbus:"-"` - } - src := []interface{}{[]interface{}{int32(42), "foo"}} - err := Store(src, &foo) - if err != nil { - t.Fatal(err) - } -} - -func TestProtoStoreNestedStruct(t *testing.T) { - var foo struct { - A int32 - B struct { - C string - D float64 - } - } - src := []interface{}{ - []interface{}{ - int32(42), - []interface{}{ - "foo", - 3.14, - }, - }, - } - err := Store(src, &foo) - if err != nil { - t.Fatal(err) - } -} - -func TestMessage(t *testing.T) { - buf := new(bytes.Buffer) - message := new(Message) - message.Type = TypeMethodCall - message.serial = 32 - message.Headers = map[HeaderField]Variant{ - FieldPath: MakeVariant(ObjectPath("/org/foo/bar")), - FieldMember: MakeVariant("baz"), - } - message.Body = make([]interface{}, 0) - err := message.EncodeTo(buf, binary.LittleEndian) - if err != nil { - t.Error(err) - } - _, err = DecodeMessage(buf) - if err != nil { - t.Error(err) - } -} - -func TestProtoStructInterfaces(t *testing.T) { - b := []byte{42} - vs, err := newDecoder(bytes.NewReader(b), binary.LittleEndian).Decode(Signature{"(y)"}) - if err != nil { - t.Fatal(err) - } - if vs[0].([]interface{})[0].(byte) != 42 { - t.Errorf("wrongs results (got %v)", vs) - } -} - -// ordinary org.freedesktop.DBus.Hello call -var smallMessage = &Message{ - Type: TypeMethodCall, - serial: 1, - Headers: map[HeaderField]Variant{ - FieldDestination: MakeVariant("org.freedesktop.DBus"), - FieldPath: MakeVariant(ObjectPath("/org/freedesktop/DBus")), - FieldInterface: MakeVariant("org.freedesktop.DBus"), - FieldMember: MakeVariant("Hello"), - }, -} - -// org.freedesktop.Notifications.Notify -var bigMessage = &Message{ - Type: TypeMethodCall, - serial: 2, - Headers: map[HeaderField]Variant{ - FieldDestination: MakeVariant("org.freedesktop.Notifications"), - FieldPath: MakeVariant(ObjectPath("/org/freedesktop/Notifications")), - FieldInterface: MakeVariant("org.freedesktop.Notifications"), - FieldMember: MakeVariant("Notify"), - FieldSignature: MakeVariant(Signature{"susssasa{sv}i"}), - }, - Body: []interface{}{ - "app_name", - uint32(0), - "dialog-information", - "Notification", - "This is the body of a notification", - []string{"ok", "Ok"}, - map[string]Variant{ - "sound-name": MakeVariant("dialog-information"), - }, - int32(-1), - }, -} - -func BenchmarkDecodeMessageSmall(b *testing.B) { - var err error - var rd *bytes.Reader - - b.StopTimer() - buf := new(bytes.Buffer) - err = smallMessage.EncodeTo(buf, binary.LittleEndian) - if err != nil { - b.Fatal(err) - } - decoded := buf.Bytes() - b.StartTimer() - for i := 0; i < b.N; i++ { - rd = bytes.NewReader(decoded) - _, err = DecodeMessage(rd) - if err != nil { - b.Fatal(err) - } - } -} - -func BenchmarkDecodeMessageBig(b *testing.B) { - var err error - var rd *bytes.Reader - - b.StopTimer() - buf := new(bytes.Buffer) - err = bigMessage.EncodeTo(buf, binary.LittleEndian) - if err != nil { - b.Fatal(err) - } - decoded := buf.Bytes() - b.StartTimer() - for i := 0; i < b.N; i++ { - rd = bytes.NewReader(decoded) - _, err = DecodeMessage(rd) - if err != nil { - b.Fatal(err) - } - } -} - -func BenchmarkEncodeMessageSmall(b *testing.B) { - var err error - for i := 0; i < b.N; i++ { - err = smallMessage.EncodeTo(ioutil.Discard, binary.LittleEndian) - if err != nil { - b.Fatal(err) - } - } -} - -func BenchmarkEncodeMessageBig(b *testing.B) { - var err error - for i := 0; i < b.N; i++ { - err = bigMessage.EncodeTo(ioutil.Discard, binary.LittleEndian) - if err != nil { - b.Fatal(err) - } - } -} diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/sig_test.go b/Godeps/_workspace/src/github.com/godbus/dbus/sig_test.go deleted file mode 100644 index da37bc96..00000000 --- a/Godeps/_workspace/src/github.com/godbus/dbus/sig_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package dbus - -import ( - "testing" -) - -var sigTests = []struct { - vs []interface{} - sig Signature -}{ - { - []interface{}{new(int32)}, - Signature{"i"}, - }, - { - []interface{}{new(string)}, - Signature{"s"}, - }, - { - []interface{}{new(Signature)}, - Signature{"g"}, - }, - { - []interface{}{new([]int16)}, - Signature{"an"}, - }, - { - []interface{}{new(int16), new(uint32)}, - Signature{"nu"}, - }, - { - []interface{}{new(map[byte]Variant)}, - Signature{"a{yv}"}, - }, - { - []interface{}{new(Variant), new([]map[int32]string)}, - Signature{"vaa{is}"}, - }, -} - -func TestSig(t *testing.T) { - for i, v := range sigTests { - sig := SignatureOf(v.vs...) - if sig != v.sig { - t.Errorf("test %d: got %q, expected %q", i+1, sig.str, v.sig.str) - } - } -} - -var getSigTest = []interface{}{ - []struct { - b byte - i int32 - t uint64 - s string - }{}, - map[string]Variant{}, -} - -func BenchmarkGetSignatureSimple(b *testing.B) { - for i := 0; i < b.N; i++ { - SignatureOf("", int32(0)) - } -} - -func BenchmarkGetSignatureLong(b *testing.B) { - for i := 0; i < b.N; i++ { - SignatureOf(getSigTest...) - } -} diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/transport_unix_test.go b/Godeps/_workspace/src/github.com/godbus/dbus/transport_unix_test.go deleted file mode 100644 index 302233fc..00000000 --- a/Godeps/_workspace/src/github.com/godbus/dbus/transport_unix_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package dbus - -import ( - "os" - "testing" -) - -const testString = `This is a test! -This text should be read from the file that is created by this test.` - -type unixFDTest struct{} - -func (t unixFDTest) Test(fd UnixFD) (string, *Error) { - var b [4096]byte - file := os.NewFile(uintptr(fd), "testfile") - defer file.Close() - n, err := file.Read(b[:]) - if err != nil { - return "", &Error{"com.github.guelfey.test.Error", nil} - } - return string(b[:n]), nil -} - -func TestUnixFDs(t *testing.T) { - conn, err := SessionBus() - if err != nil { - t.Fatal(err) - } - r, w, err := os.Pipe() - if err != nil { - t.Fatal(err) - } - defer w.Close() - if _, err := w.Write([]byte(testString)); err != nil { - t.Fatal(err) - } - name := conn.Names()[0] - test := unixFDTest{} - conn.Export(test, "/com/github/guelfey/test", "com.github.guelfey.test") - var s string - obj := conn.Object(name, "/com/github/guelfey/test") - err = obj.Call("com.github.guelfey.test.Test", 0, UnixFD(r.Fd())).Store(&s) - if err != nil { - t.Fatal(err) - } - if s != testString { - t.Fatal("got", s, "wanted", testString) - } -} diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/variant_test.go b/Godeps/_workspace/src/github.com/godbus/dbus/variant_test.go deleted file mode 100644 index da917c8e..00000000 --- a/Godeps/_workspace/src/github.com/godbus/dbus/variant_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package dbus - -import "reflect" -import "testing" - -var variantFormatTests = []struct { - v interface{} - s string -}{ - {int32(1), `1`}, - {"foo", `"foo"`}, - {ObjectPath("/org/foo"), `@o "/org/foo"`}, - {Signature{"i"}, `@g "i"`}, - {[]byte{}, `@ay []`}, - {[]int32{1, 2}, `[1, 2]`}, - {[]int64{1, 2}, `@ax [1, 2]`}, - {[][]int32{{3, 4}, {5, 6}}, `[[3, 4], [5, 6]]`}, - {[]Variant{MakeVariant(int32(1)), MakeVariant(1.0)}, `[<1>, <@d 1>]`}, - {map[string]int32{"one": 1, "two": 2}, `{"one": 1, "two": 2}`}, - {map[int32]ObjectPath{1: "/org/foo"}, `@a{io} {1: "/org/foo"}`}, - {map[string]Variant{}, `@a{sv} {}`}, -} - -func TestFormatVariant(t *testing.T) { - for i, v := range variantFormatTests { - if s := MakeVariant(v.v).String(); s != v.s { - t.Errorf("test %d: got %q, wanted %q", i+1, s, v.s) - } - } -} - -var variantParseTests = []struct { - s string - v interface{} -}{ - {"1", int32(1)}, - {"true", true}, - {"false", false}, - {"1.0", float64(1.0)}, - {"0x10", int32(16)}, - {"1e1", float64(10)}, - {`"foo"`, "foo"}, - {`"\a\b\f\n\r\t"`, "\x07\x08\x0c\n\r\t"}, - {`"\u00e4\U0001f603"`, "\u00e4\U0001f603"}, - {"[1]", []int32{1}}, - {"[1, 2, 3]", []int32{1, 2, 3}}, - {"@ai []", []int32{}}, - {"[1, 5.0]", []float64{1, 5.0}}, - {"[[1, 2], [3, 4.0]]", [][]float64{{1, 2}, {3, 4}}}, - {`[@o "/org/foo", "/org/bar"]`, []ObjectPath{"/org/foo", "/org/bar"}}, - {"<1>", MakeVariant(int32(1))}, - {"[<1>, <2.0>]", []Variant{MakeVariant(int32(1)), MakeVariant(2.0)}}, - {`[[], [""]]`, [][]string{{}, {""}}}, - {`@a{ss} {}`, map[string]string{}}, - {`{"foo": 1}`, map[string]int32{"foo": 1}}, - {`[{}, {"foo": "bar"}]`, []map[string]string{{}, {"foo": "bar"}}}, - {`{"a": <1>, "b": <"foo">}`, - map[string]Variant{"a": MakeVariant(int32(1)), "b": MakeVariant("foo")}}, - {`b''`, []byte{0}}, - {`b"abc"`, []byte{'a', 'b', 'c', 0}}, - {`b"\x01\0002\a\b\f\n\r\t"`, []byte{1, 2, 0x7, 0x8, 0xc, '\n', '\r', '\t', 0}}, - {`[[0], b""]`, [][]byte{{0}, {0}}}, - {"int16 0", int16(0)}, - {"byte 0", byte(0)}, -} - -func TestParseVariant(t *testing.T) { - for i, v := range variantParseTests { - nv, err := ParseVariant(v.s, Signature{}) - if err != nil { - t.Errorf("test %d: parsing failed: %s", i+1, err) - continue - } - if !reflect.DeepEqual(nv.value, v.v) { - t.Errorf("test %d: got %q, wanted %q", i+1, nv, v.v) - } - } -}