...

Source file src/github.com/godbus/dbus/v5/export_test.go

Documentation: github.com/godbus/dbus/v5

     1  package dbus
     2  
     3  import (
     4  	"fmt"
     5  	"regexp"
     6  	"strings"
     7  	"testing"
     8  )
     9  
    10  type lowerCaseExport struct{}
    11  
    12  func (export lowerCaseExport) foo() (string, *Error) {
    13  	return "bar", nil
    14  }
    15  
    16  type fooExport struct {
    17  	message Message
    18  }
    19  
    20  func (export *fooExport) Foo(message Message, param string) (string, *Error) {
    21  	export.message = message
    22  	return "foo", nil
    23  }
    24  
    25  type barExport struct{}
    26  
    27  func (export barExport) Foo(param string) (string, *Error) {
    28  	return "bar", nil
    29  }
    30  
    31  type badExport struct{}
    32  
    33  func (export badExport) Foo(param string) string {
    34  	return "bar"
    35  }
    36  
    37  type errorExport struct {
    38  	message Message
    39  }
    40  
    41  func (export *errorExport) Run(message Message, param string) (string, error) {
    42  	export.message = message
    43  	return "pass", nil
    44  }
    45  
    46  type noErrorExport struct {
    47  	message Message
    48  }
    49  
    50  func (export *noErrorExport) Run(message Message, param string) (string) {
    51  	export.message = message
    52  	return "cool"
    53  }
    54  
    55  // Test typical Export usage.
    56  func TestExport(t *testing.T) {
    57  	connection, err := ConnectSessionBus()
    58  	if err != nil {
    59  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
    60  	}
    61  	defer connection.Close()
    62  
    63  	name := connection.Names()[0]
    64  
    65  	connection.Export(server{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
    66  	object := connection.Object(name, "/org/guelfey/DBus/Test")
    67  	subtreeObject := connection.Object(name, "/org/guelfey/DBus/Test/Foo")
    68  
    69  	var response int64
    70  	err = object.Call("org.guelfey.DBus.Test.Double", 0, int64(2)).Store(&response)
    71  	if err != nil {
    72  		t.Errorf("Unexpected error calling Double: %s", err)
    73  	}
    74  
    75  	if response != 4 {
    76  		t.Errorf("Response was %d, expected 4", response)
    77  	}
    78  
    79  	// Verify that calling a subtree of a regular export does not result in a
    80  	// valid method call.
    81  	err = subtreeObject.Call("org.guelfey.DBus.Test.Double", 0, int64(2)).Store(&response)
    82  	if err == nil {
    83  		t.Error("Expected error due to no object being exported on that path")
    84  	}
    85  
    86  	// Now remove export
    87  	connection.Export(nil, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
    88  	err = object.Call("org.guelfey.DBus.Test.Double", 0, int64(2)).Store(&response)
    89  	if err == nil {
    90  		t.Error("Expected an error since the export was removed")
    91  	}
    92  }
    93  
    94  // Test that Exported handlers can use a go error type.
    95  func TestExport_goerror(t *testing.T) {
    96  	connection, err := ConnectSessionBus()
    97  	if err != nil {
    98  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
    99  	}
   100  	defer connection.Close()
   101  
   102  	name := connection.Names()[0]
   103  
   104  	export := &errorExport{}
   105  	connection.ExportAll(export, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   106  	object := connection.Object(name, "/org/guelfey/DBus/Test")
   107  
   108  	var response string
   109  	err = object.Call("org.guelfey.DBus.Test.Run", 0, "qux").Store(&response)
   110  	if err != nil {
   111  		t.Errorf("Unexpected error calling Foo: %s", err)
   112  	}
   113  
   114  	if response != "pass" {
   115  		t.Errorf(`Response was %s, expected "foo"`, response)
   116  	}
   117  
   118  	if export.message.serial == 0 {
   119  		t.Error("Expected a valid message to be given to handler")
   120  	}
   121  }
   122  
   123  // Test that Exported handlers can have no error.
   124  func TestExport_noerror(t *testing.T) {
   125  	connection, err := ConnectSessionBus()
   126  	if err != nil {
   127  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   128  	}
   129  	defer connection.Close()
   130  
   131  	name := connection.Names()[0]
   132  
   133  	export := &noErrorExport{}
   134  	connection.ExportAll(export, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   135  	object := connection.Object(name, "/org/guelfey/DBus/Test")
   136  
   137  	var response string
   138  	err = object.Call("org.guelfey.DBus.Test.Run", 0, "qux").Store(&response)
   139  	if err != nil {
   140  		t.Errorf("Unexpected error calling Foo: %s", err)
   141  	}
   142  
   143  	if response != "cool" {
   144  		t.Errorf(`Response was %s, expected "foo"`, response)
   145  	}
   146  
   147  	if export.message.serial == 0 {
   148  		t.Error("Expected a valid message to be given to handler")
   149  	}
   150  }
   151  
   152  // Test that Exported handlers can obtain raw message.
   153  func TestExport_message(t *testing.T) {
   154  	connection, err := ConnectSessionBus()
   155  	if err != nil {
   156  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   157  	}
   158  	defer connection.Close()
   159  
   160  	name := connection.Names()[0]
   161  
   162  	export := &fooExport{}
   163  	connection.Export(export, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   164  	object := connection.Object(name, "/org/guelfey/DBus/Test")
   165  
   166  	var response string
   167  	err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
   168  	if err != nil {
   169  		t.Errorf("Unexpected error calling Foo: %s", err)
   170  	}
   171  
   172  	if response != "foo" {
   173  		t.Errorf(`Response was %s, expected "foo"`, response)
   174  	}
   175  
   176  	if export.message.serial == 0 {
   177  		t.Error("Expected a valid message to be given to handler")
   178  	}
   179  }
   180  
   181  // Test Export with an invalid path.
   182  func TestExport_invalidPath(t *testing.T) {
   183  	connection, err := ConnectSessionBus()
   184  	if err != nil {
   185  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   186  	}
   187  	defer connection.Close()
   188  
   189  	err = connection.Export(nil, "foo", "bar")
   190  	if err == nil {
   191  		t.Error("Expected an error due to exporting with an invalid path")
   192  	}
   193  }
   194  
   195  // Test Export with an un-exported method. This should not panic, but rather
   196  // result in an invalid method call.
   197  func TestExport_unexportedMethod(t *testing.T) {
   198  	connection, err := ConnectSessionBus()
   199  	if err != nil {
   200  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   201  	}
   202  	defer connection.Close()
   203  
   204  	name := connection.Names()[0]
   205  
   206  	connection.Export(lowerCaseExport{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   207  	object := connection.Object(name, "/org/guelfey/DBus/Test")
   208  
   209  	var response string
   210  	call := object.Call("org.guelfey.DBus.Test.foo", 0)
   211  	err = call.Store(&response)
   212  	if err == nil {
   213  		t.Errorf("Expected an error due to calling unexported method")
   214  	}
   215  }
   216  
   217  // Test Export with a method lacking the correct return signature. This should
   218  // result in an invalid method call.
   219  func TestExport_badSignature(t *testing.T) {
   220  	connection, err := ConnectSessionBus()
   221  	if err != nil {
   222  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   223  	}
   224  	defer connection.Close()
   225  
   226  	name := connection.Names()[0]
   227  
   228  	connection.Export(badExport{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   229  	object := connection.Object(name, "/org/guelfey/DBus/Test")
   230  
   231  	var response string
   232  	call := object.Call("org.guelfey.DBus.Test.Foo", 0)
   233  	err = call.Store(&response)
   234  	if err == nil {
   235  		t.Errorf("Expected an error due to the method lacking the right signature")
   236  	}
   237  }
   238  
   239  // Test typical ExportWithMap usage.
   240  func TestExportWithMap(t *testing.T) {
   241  	connection, err := ConnectSessionBus()
   242  	if err != nil {
   243  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   244  	}
   245  	defer connection.Close()
   246  
   247  	name := connection.Names()[0]
   248  
   249  	mapping := make(map[string]string)
   250  	mapping["Double"] = "double" // Export this method as lower-case
   251  
   252  	connection.ExportWithMap(server{}, mapping, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   253  	object := connection.Object(name, "/org/guelfey/DBus/Test")
   254  
   255  	var response int64
   256  	err = object.Call("org.guelfey.DBus.Test.double", 0, int64(2)).Store(&response)
   257  	if err != nil {
   258  		t.Errorf("Unexpected error calling double: %s", err)
   259  	}
   260  
   261  	if response != 4 {
   262  		t.Errorf("Response was %d, expected 4", response)
   263  	}
   264  }
   265  
   266  // Test that ExportWithMap does not export both method alias and method.
   267  func TestExportWithMap_bypassAlias(t *testing.T) {
   268  	connection, err := ConnectSessionBus()
   269  	if err != nil {
   270  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   271  	}
   272  	defer connection.Close()
   273  
   274  	name := connection.Names()[0]
   275  
   276  	mapping := make(map[string]string)
   277  	mapping["Double"] = "double" // Export this method as lower-case
   278  
   279  	connection.ExportWithMap(server{}, mapping, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   280  	object := connection.Object(name, "/org/guelfey/DBus/Test")
   281  
   282  	var response int64
   283  	// Call upper-case Double (i.e. the real method, not the alias)
   284  	err = object.Call("org.guelfey.DBus.Test.Double", 0, int64(2)).Store(&response)
   285  	if err == nil {
   286  		t.Error("Expected an error due to calling actual method, not alias")
   287  	}
   288  }
   289  
   290  // Test typical ExportSubtree usage.
   291  func TestExportSubtree(t *testing.T) {
   292  	connection, err := ConnectSessionBus()
   293  	if err != nil {
   294  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   295  	}
   296  	defer connection.Close()
   297  
   298  	name := connection.Names()[0]
   299  
   300  	export := &fooExport{}
   301  	connection.ExportSubtree(export, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   302  
   303  	// Call a subpath of the exported path
   304  	object := connection.Object(name, "/org/guelfey/DBus/Test/Foo")
   305  
   306  	var response string
   307  	err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
   308  	if err != nil {
   309  		t.Errorf("Unexpected error calling Foo: %s", err)
   310  	}
   311  
   312  	if response != "foo" {
   313  		t.Errorf(`Response was %s, expected "foo"`, response)
   314  	}
   315  
   316  	if export.message.serial == 0 {
   317  		t.Error("Expected the raw message, got an invalid one")
   318  	}
   319  
   320  	// Now remove export
   321  	connection.Export(nil, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   322  	err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
   323  	if err == nil {
   324  		t.Error("Expected an error since the export was removed")
   325  	}
   326  }
   327  
   328  // Test that using ExportSubtree with exported methods that don't contain a
   329  // Message still work, they just don't get the message.
   330  func TestExportSubtree_noMessage(t *testing.T) {
   331  	connection, err := ConnectSessionBus()
   332  	if err != nil {
   333  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   334  	}
   335  	defer connection.Close()
   336  
   337  	name := connection.Names()[0]
   338  
   339  	connection.ExportSubtree(server{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   340  
   341  	// Call a subpath of the exported path
   342  	object := connection.Object(name, "/org/guelfey/DBus/Test/Foo")
   343  
   344  	var response int64
   345  	err = object.Call("org.guelfey.DBus.Test.Double", 0, int64(2)).Store(&response)
   346  	if err != nil {
   347  		t.Errorf("Unexpected error calling Double: %s", err)
   348  	}
   349  
   350  	if response != 4 {
   351  		t.Errorf("Response was %d, expected 4", response)
   352  	}
   353  
   354  	// Now remove export
   355  	connection.Export(nil, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   356  	err = object.Call("org.guelfey.DBus.Test.Double", 0, int64(2)).Store(&response)
   357  	if err == nil {
   358  		t.Error("Expected an error since the export was removed")
   359  	}
   360  }
   361  
   362  // Test that a regular Export takes precedence over ExportSubtree.
   363  func TestExportSubtree_exportPrecedence(t *testing.T) {
   364  	connection, err := ConnectSessionBus()
   365  	if err != nil {
   366  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   367  	}
   368  	defer connection.Close()
   369  
   370  	name := connection.Names()[0]
   371  
   372  	// Register for the entire subtree of /org/guelfey/DBus/Test
   373  	connection.ExportSubtree(&fooExport{},
   374  		"/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   375  
   376  	// Explicitly register for /org/guelfey/DBus/Test/Foo, a subpath of above
   377  	connection.Export(&barExport{}, "/org/guelfey/DBus/Test/Foo",
   378  		"org.guelfey.DBus.Test")
   379  
   380  	// Call the explicitly exported path
   381  	object := connection.Object(name, "/org/guelfey/DBus/Test/Foo")
   382  
   383  	var response string
   384  	err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
   385  	if err != nil {
   386  		t.Errorf("Unexpected error calling Foo: %s", err)
   387  	}
   388  
   389  	if response != "bar" {
   390  		t.Errorf(`Response was %s, expected "bar"`, response)
   391  	}
   392  
   393  	response = "" // Reset response so errors aren't confusing
   394  
   395  	// Now remove explicit export
   396  	connection.Export(nil, "/org/guelfey/DBus/Test/Foo", "org.guelfey.DBus.Test")
   397  	err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
   398  	if err != nil {
   399  		t.Errorf("Unexpected error calling Foo: %s", err)
   400  	}
   401  
   402  	// Now the subtree export should handle the call
   403  	if response != "foo" {
   404  		t.Errorf(`Response was %s, expected "foo"`, response)
   405  	}
   406  }
   407  
   408  // Test typical ExportSubtreeWithMap usage.
   409  func TestExportSubtreeWithMap(t *testing.T) {
   410  	connection, err := ConnectSessionBus()
   411  	if err != nil {
   412  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   413  	}
   414  	defer connection.Close()
   415  
   416  	name := connection.Names()[0]
   417  
   418  	mapping := make(map[string]string)
   419  	mapping["Foo"] = "foo" // Export this method as lower-case
   420  
   421  	connection.ExportSubtreeWithMap(&fooExport{}, mapping, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   422  
   423  	// Call a subpath of the exported path
   424  	object := connection.Object(name, "/org/guelfey/DBus/Test/Foo")
   425  
   426  	var response string
   427  	// Call the lower-case method
   428  	err = object.Call("org.guelfey.DBus.Test.foo", 0, "qux").Store(&response)
   429  	if err != nil {
   430  		t.Errorf("Unexpected error calling Foo: %s", err)
   431  	}
   432  
   433  	if response != "foo" {
   434  		t.Errorf(`Response was %s, expected "foo"`, response)
   435  	}
   436  
   437  	// Now remove export
   438  	connection.Export(nil, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   439  	err = object.Call("org.guelfey.DBus.Test.foo", 0, "qux").Store(&response)
   440  	if err == nil {
   441  		t.Error("Expected an error since the export was removed")
   442  	}
   443  }
   444  
   445  // Test that ExportSubtreeWithMap does not export both method alias and method.
   446  func TestExportSubtreeWithMap_bypassAlias(t *testing.T) {
   447  	connection, err := ConnectSessionBus()
   448  	if err != nil {
   449  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   450  	}
   451  	defer connection.Close()
   452  
   453  	name := connection.Names()[0]
   454  
   455  	mapping := make(map[string]string)
   456  	mapping["Foo"] = "foo" // Export this method as lower-case
   457  
   458  	connection.ExportSubtreeWithMap(&fooExport{}, mapping, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   459  	object := connection.Object(name, "/org/guelfey/DBus/Test/Foo")
   460  
   461  	var response string
   462  	// Call upper-case Foo (i.e. the real method, not the alias)
   463  	err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
   464  	if err == nil {
   465  		t.Error("Expected an error due to calling actual method, not alias")
   466  	}
   467  }
   468  
   469  func TestExportMethodTable(t *testing.T) {
   470  	connection, err := ConnectSessionBus()
   471  	if err != nil {
   472  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   473  	}
   474  	defer connection.Close()
   475  
   476  	name := connection.Names()[0]
   477  	export := &fooExport{}
   478  	tbl := make(map[string]interface{})
   479  	tbl["Foo"] = func(message Message, param string) (string, *Error) {
   480  		return export.Foo(message, param)
   481  	}
   482  	tbl["Foo2"] = export.Foo
   483  	connection.ExportMethodTable(tbl, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   484  
   485  	object := connection.Object(name, "/org/guelfey/DBus/Test")
   486  
   487  	var response string
   488  	err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
   489  	if err != nil {
   490  		t.Errorf("Unexpected error calling Foo: %s", err)
   491  	}
   492  
   493  	if response != "foo" {
   494  		t.Errorf(`Response was %s, expected "foo"`, response)
   495  	}
   496  
   497  	if export.message.serial == 0 {
   498  		t.Error("Expected the raw message, got an invalid one")
   499  	}
   500  
   501  	err = object.Call("org.guelfey.DBus.Test.Foo2", 0, "qux").Store(&response)
   502  	if err != nil {
   503  		t.Errorf("Unexpected error calling Foo: %s", err)
   504  	}
   505  
   506  	if response != "foo" {
   507  		t.Errorf(`Response was %s, expected "foo"`, response)
   508  	}
   509  
   510  	if export.message.serial == 0 {
   511  		t.Error("Expected the raw message, got an invalid one")
   512  	}
   513  
   514  	// Now remove export
   515  	connection.Export(nil, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   516  	err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
   517  	if err == nil {
   518  		t.Error("Expected an error since the export was removed")
   519  	}
   520  }
   521  
   522  func TestExportSubtreeMethodTable(t *testing.T) {
   523  	connection, err := ConnectSessionBus()
   524  	if err != nil {
   525  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   526  	}
   527  	defer connection.Close()
   528  
   529  	name := connection.Names()[0]
   530  
   531  	export := &fooExport{}
   532  	tbl := make(map[string]interface{})
   533  	tbl["Foo"] = func(message Message, param string) (string, *Error) {
   534  		return export.Foo(message, param)
   535  	}
   536  	tbl["Foo2"] = export.Foo
   537  	connection.ExportSubtreeMethodTable(tbl, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   538  
   539  	// Call a subpath of the exported path
   540  	object := connection.Object(name, "/org/guelfey/DBus/Test/Foo")
   541  
   542  	var response string
   543  	err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
   544  	if err != nil {
   545  		t.Errorf("Unexpected error calling Foo: %s", err)
   546  	}
   547  
   548  	if response != "foo" {
   549  		t.Errorf(`Response was %s, expected "foo"`, response)
   550  	}
   551  
   552  	if export.message.serial == 0 {
   553  		t.Error("Expected the raw message, got an invalid one")
   554  	}
   555  
   556  	err = object.Call("org.guelfey.DBus.Test.Foo2", 0, "qux").Store(&response)
   557  	if err != nil {
   558  		t.Errorf("Unexpected error calling Foo: %s", err)
   559  	}
   560  
   561  	if response != "foo" {
   562  		t.Errorf(`Response was %s, expected "foo"`, response)
   563  	}
   564  
   565  	if export.message.serial == 0 {
   566  		t.Error("Expected the raw message, got an invalid one")
   567  	}
   568  
   569  	// Now remove export
   570  	connection.Export(nil, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   571  	err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
   572  	if err == nil {
   573  		t.Error("Expected an error since the export was removed")
   574  	}
   575  }
   576  
   577  func TestExportMethodTable_NotFunc(t *testing.T) {
   578  	connection, err := ConnectSessionBus()
   579  	if err != nil {
   580  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   581  	}
   582  	defer connection.Close()
   583  
   584  	name := connection.Names()[0]
   585  	export := &fooExport{}
   586  	tbl := make(map[string]interface{})
   587  	tbl["Foo"] = func(message Message, param string) (string, *Error) {
   588  		return export.Foo(message, param)
   589  	}
   590  	tbl["Foo2"] = "foobar"
   591  
   592  	connection.ExportMethodTable(tbl, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   593  	object := connection.Object(name, "/org/guelfey/DBus/Test")
   594  
   595  	var response string
   596  	err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
   597  	if err != nil {
   598  		t.Errorf("Unexpected error calling Foo: %s", err)
   599  	}
   600  
   601  	if response != "foo" {
   602  		t.Errorf(`Response was %s, expected "foo"`, response)
   603  	}
   604  
   605  	if export.message.serial == 0 {
   606  		t.Error("Expected the raw message, got an invalid one")
   607  	}
   608  
   609  	err = object.Call("org.guelfey.DBus.Test.Foo2", 0, "qux").Store(&response)
   610  	if err == nil {
   611  		t.Errorf("Expected an error since the Foo2 was not a function")
   612  	}
   613  }
   614  
   615  func TestExportMethodTable_ReturnNotError(t *testing.T) {
   616  	connection, err := ConnectSessionBus()
   617  	if err != nil {
   618  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   619  	}
   620  	defer connection.Close()
   621  
   622  	name := connection.Names()[0]
   623  	export := &fooExport{}
   624  	tbl := make(map[string]interface{})
   625  	tbl["Foo"] = func(message Message, param string) (string, string) {
   626  		out, _ := export.Foo(message, param)
   627  		return out, out
   628  	}
   629  
   630  	connection.ExportMethodTable(tbl, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
   631  	object := connection.Object(name, "/org/guelfey/DBus/Test")
   632  
   633  	var response string
   634  	err = object.Call("org.guelfey.DBus.Test.Foo", 0, "qux").Store(&response)
   635  	if err == nil {
   636  		t.Errorf("Expected an error since the Foo did not have a final return as *dbus.Error")
   637  	}
   638  }
   639  
   640  // Test that introspection works on sub path of every exported object
   641  func TestExportSubPathIntrospection(t *testing.T) {
   642  	const (
   643  		introIntf    = "org.freedesktop.DBus.Introspectable"
   644  		respTmpl     = `^<node>\s*<node\s+name="%s"\s*/>\s*</node>$`
   645  		pathstr      = "/org/guelfey/DBus/Test"
   646  		foopathstr   = pathstr + "/Foo"
   647  		barpathstr   = pathstr + "/Bar"
   648  		test1intfstr = "org.guelfey.DBus.Test1"
   649  		test2intfstr = "org.guelfey.DBus.Test2"
   650  		intro        = `
   651  			<node>
   652  			<interface name="` + test1intfstr + `">
   653  				<method name="Foo">
   654  					<arg direction="out" type="s"/>
   655  				</method>
   656  			</interface>
   657  			<interface name="` + test2intfstr + `">
   658  				<method name="Foo">
   659  					<arg direction="out" type="s"/>
   660  				</method>
   661  				<method name="Bar">
   662  					<arg direction="out" type="s"/>
   663  				</method>
   664  			</interface>
   665  			<interface name="` + introIntf + `">
   666  				<method name="Introspect">
   667  					<arg name="out" direction="out" type="s"/>
   668  				</method>
   669  			</interface>
   670  			</node>`
   671  	)
   672  	connection, err := ConnectSessionBus()
   673  	if err != nil {
   674  		t.Fatalf("Unexpected error connecting to session bus: %s", err)
   675  	}
   676  	defer connection.Close()
   677  
   678  	name := connection.Names()[0]
   679  
   680  	foo := &fooExport{}
   681  	bar := &barExport{}
   682  	connection.Export(foo, foopathstr, test1intfstr)
   683  	connection.Export(foo, foopathstr, test2intfstr)
   684  	connection.Export(bar, barpathstr, test2intfstr)
   685  	connection.Export(intro, pathstr, introIntf)
   686  
   687  	var response string
   688  	var match bool
   689  	path := strings.Split(pathstr, "/")
   690  	for i := 0; i < len(path)-1; i++ {
   691  		var subpath string
   692  		if i == 0 {
   693  			subpath = "/"
   694  		} else {
   695  			subpath = strings.Join(path[:i+1], "/")
   696  		}
   697  
   698  		object := connection.Object(name, ObjectPath(subpath))
   699  		err = object.Call(introIntf+".Introspect", 0).Store(&response)
   700  		if err != nil {
   701  			t.Errorf("Unexpected error calling Introspect on %s: %s", subpath, err)
   702  		}
   703  
   704  		exp := fmt.Sprintf(respTmpl, path[i+1])
   705  		match, err = regexp.MatchString(exp, response)
   706  		if err != nil {
   707  			t.Fatalf("Error calling MatchString: %s", err)
   708  		}
   709  		if !match {
   710  			t.Errorf("Unexpected introspection response for %s: %s", subpath, response)
   711  		}
   712  	}
   713  
   714  	// Test invalid subpath
   715  	invalSubpath := "/org/guelfey/DBus/Test/Nonexistent"
   716  	object := connection.Object(name, ObjectPath(invalSubpath))
   717  	err = object.Call(introIntf+".Introspect", 0).Store(&response)
   718  	if err != nil {
   719  		t.Errorf("Unexpected error calling Introspect on %s: %s", invalSubpath, err)
   720  	}
   721  	match, err = regexp.MatchString(`^<node>\s*</node>$`, response)
   722  	if err != nil {
   723  		t.Fatalf("Error calling MatchString: %s", err)
   724  	}
   725  	if !match {
   726  		t.Errorf("Unexpected introspection response for %s: %s", invalSubpath, response)
   727  	}
   728  }
   729  

View as plain text