1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
{-# LANGUAGE OverloadedStrings #-}
-- Copyright (C) 2012 John Millikin <john@john-millikin.com>
--
-- 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.
module DBusTests.Integration (test_Integration) where
import Control.Exception (finally)
import System.Directory (removeFile)
import System.Exit
import System.IO (hGetLine)
import System.Process
import Test.Tasty
import Test.Tasty.HUnit
import DBus
import DBus.Socket
import DBus.Client
import DBusTests.Util
test_Integration :: TestTree
test_Integration = testGroup "Integration"
[ test_Socket
, test_Client
]
test_Socket :: TestTree
test_Socket = withDaemon "socket" $ \addr -> do
let hello = (methodCall "/org/freedesktop/DBus" "org.freedesktop.DBus" "Hello")
{ methodCallDestination = Just "org.freedesktop.DBus"
}
sock <- open addr
serial <- send sock hello return
assertBool "invalid serial" $ serialValue serial >= 1
received <- receive sock
let ReceivedMethodReturn _ ret = received
methodReturnSerial ret @?= serial
methodReturnSender ret @?= Just "org.freedesktop.DBus"
close sock
test_Client :: TestTree
test_Client = withDaemon "client" $ \addr -> do
clientA <- connect addr
clientB <- connect addr
export clientA "/"
defaultInterface
{ interfaceName = "com.example.Echo"
, interfaceMethods =
[ Method "Echo" (signature_ [TypeString]) (signature_ []) (
\msg -> if map variantType (methodCallBody msg) == [TypeString]
then return (ReplyReturn (methodCallBody msg))
else
return $ ReplyError
"com.example.Error"
[toVariant ("bad body: " ++ show (methodCallBody msg))])
]
}
-- TODO: get bus address of clientA with a function
let busAddrA = ":1.0"
-- Successful call
let bodyGood = [toVariant ("test" :: String)]
retGood <- call clientB (methodCall "/" "com.example.Echo" "Echo")
{ methodCallDestination = Just busAddrA
, methodCallBody = bodyGood
}
ret <- requireRight retGood
methodReturnBody ret @?= bodyGood
-- Failed call
let bodyBad = [toVariant True]
retBad <- call clientB (methodCall "/" "com.example.Echo" "Echo")
{ methodCallDestination = Just busAddrA
, methodCallBody = bodyBad
}
err <- requireLeft retBad
methodErrorName err @?= "com.example.Error"
methodErrorBody err @?= [toVariant ("bad body: [Variant True]" :: String)]
disconnect clientA
disconnect clientB
configFileContent :: String
configFileContent = "\
\<!DOCTYPE busconfig PUBLIC \"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN\"\
\ \"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd\">\
\<busconfig>\
\ <type>session</type>\
\ <keep_umask/>\
\ <listen>unix:tmpdir=/tmp</listen>\
\ <policy context=\"default\">\
\ <!-- Allow everything to be sent -->\
\ <allow send_destination=\"*\" eavesdrop=\"true\"/>\
\ <!-- Allow everything to be received -->\
\ <allow eavesdrop=\"true\"/>\
\ <!-- Allow anyone to own anything -->\
\ <allow own=\"*\"/>\
\ </policy>\
\</busconfig>"
withDaemon :: String -> (Address -> Assertion) -> TestTree
withDaemon name io = testCase name $ do
(versionExit, _, _) <- readProcessWithExitCode "dbus-daemon" ["--version"] ""
case versionExit of
ExitFailure _ -> assertFailure $ "dbus-daemon failed: " ++ show versionExit
ExitSuccess -> do
configFilePath <- getTempPath
writeFile configFilePath configFileContent
daemon <- createProcess (proc "dbus-daemon" ["--config-file=" ++ configFilePath, "--print-address"])
{ std_out = CreatePipe
, close_fds = True
}
let (_, Just daemonStdout, _, daemonProc) = daemon
finally
(do
addrString <- hGetLine daemonStdout
case parseAddress addrString of
Nothing -> assertFailure $ "dbus-daemon returned invalid address: " ++ show addrString
Just addr -> io addr)
(do
terminateProcess daemonProc
_ <- waitForProcess daemonProc
removeFile configFilePath
return ())
|