Repository: celix
Updated Branches:
  refs/heads/develop 061669071 -> ac4babf33


CELIX-408: Initial commit for adding add_runtime command. Also add some usage 
for running/testing pubsub


Project: http://git-wip-us.apache.org/repos/asf/celix/repo
Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/97df926c
Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/97df926c
Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/97df926c

Branch: refs/heads/develop
Commit: 97df926c2289323379506d47a6095b0182d752b7
Parents: 0616690
Author: Pepijn Noltes <[email protected]>
Authored: Sat Apr 8 21:26:39 2017 +0200
Committer: Pepijn Noltes <[email protected]>
Committed: Mon Apr 10 22:37:29 2017 +0200

----------------------------------------------------------------------
 cmake/CMakeCelix.cmake                          |   1 +
 cmake/cmake_celix/DeployPackaging.cmake         |  22 +-
 cmake/cmake_celix/Runtimes.cmake                | 161 +++++++++++++++
 cmake/cmake_celix/runtime_common.sh.in          | 152 ++++++++++++++
 cmake/cmake_celix/runtime_start.sh.in           |  26 +++
 cmake/cmake_celix/runtime_stop.sh.in            |  19 ++
 documents/cmake_commands/readme.md              |   2 +
 framework/private/src/bundle_context.c          |   2 +-
 launcher/CMakeLists.txt                         |  17 ++
 launcher/private/src/celix_test_runner.cpp      |  73 +++++++
 pubsub/CMakeLists.txt                           |   3 +
 pubsub/deploy/CMakeLists.txt                    |  58 ++++++
 pubsub/mock/CMakeLists.txt                      |   8 +-
 .../private/src/topic_publication.c             |   8 +-
 pubsub/test/CMakeLists.txt                      |  87 ++++++++
 pubsub/test/msg_descriptors/msg.descriptor      |   8 +
 pubsub/test/test/msg.h                          |  27 +++
 pubsub/test/test/sut_activator.c                | 112 +++++++++++
 pubsub/test/test/tst_activator.cpp              | 199 +++++++++++++++++++
 19 files changed, 971 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/cmake/CMakeCelix.cmake
----------------------------------------------------------------------
diff --git a/cmake/CMakeCelix.cmake b/cmake/CMakeCelix.cmake
index 9ca4de7..8c14577 100644
--- a/cmake/CMakeCelix.cmake
+++ b/cmake/CMakeCelix.cmake
@@ -26,6 +26,7 @@ 
include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/Dependencies.cmake)
 include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/BundlePackaging.cmake)
 include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/DeployPackaging.cmake)
 include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/DockerPackaging.cmake)
+include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/Runtimes.cmake)
 include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/ApacheRat.cmake)
 include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/CodeCoverage.cmake)
 include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/BuildOptions.cmake)

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/cmake/cmake_celix/DeployPackaging.cmake
----------------------------------------------------------------------
diff --git a/cmake/cmake_celix/DeployPackaging.cmake 
b/cmake/cmake_celix/DeployPackaging.cmake
index 22e2885..626b7b8 100644
--- a/cmake/cmake_celix/DeployPackaging.cmake
+++ b/cmake/cmake_celix/DeployPackaging.cmake
@@ -28,24 +28,27 @@ function(add_deploy)
     list(REMOVE_AT ARGN 0)
 
     set(OPTIONS COPY)
-    set(ONE_VAL_ARGS GROUP NAME LAUNCHER)
+    set(ONE_VAL_ARGS GROUP NAME LAUNCHER DIR)
     set(MULTI_VAL_ARGS BUNDLES PROPERTIES)
     cmake_parse_arguments(DEPLOY "${OPTIONS}" "${ONE_VAL_ARGS}" 
"${MULTI_VAL_ARGS}" ${ARGN})
 
     ##### Check arguments #####
-    if(NOT DEPLOY_NAME) 
+    if (NOT DEPLOY_NAME)
         set(DEPLOY_NAME "${DEPLOY_TARGET}")
-    endif()
+    endif ()
+    if (NOT DEPLOY_DIR)
+        set(DEPLOY_DIR "${CMAKE_BINARY_DIR}/deploy")
+    endif ()
     ######
 
     ##### Setting defaults #####
-    if(DEPLOY_GROUP) 
-        set(DEPLOY_LOCATION 
"${CMAKE_BINARY_DIR}/deploy/${DEPLOY_GROUP}/${DEPLOY_NAME}")
+    if (DEPLOY_GROUP)
+        set(DEPLOY_LOCATION "${DEPLOY_DIR}/${DEPLOY_GROUP}/${DEPLOY_NAME}")
         set(DEPLOY_PRINT_NAME "${DEPLOY_GROUP}/${DEPLOY_NAME}")
-    else()
-        set(DEPLOY_LOCATION "${CMAKE_BINARY_DIR}/deploy/${DEPLOY_NAME}")
+    else ()
+        set(DEPLOY_LOCATION "${DEPLOY_DIR}/${DEPLOY_NAME}")
         set(DEPLOY_PRINT_NAME "${DEPLOY_NAME}")
-    endif()
+    endif ()
     ######
 
 
@@ -77,6 +80,9 @@ function(add_deploy)
     #setup dependencies based on timestamp
     add_custom_command(OUTPUT "${TIMESTAMP_FILE}"
         COMMAND ${CMAKE_COMMAND} -E touch ${TIMESTAMP_FILE}
+        COMMAND ${CMAKE_COMMAND} -E make_directory 
$<TARGET_PROPERTY:${DEPLOY_TARGET},DEPLOY_LOCATION>
+        COMMAND chmod +x 
$<TARGET_PROPERTY:${DEPLOY_TARGET},DEPLOY_LOCATION>/run.sh
+        COMMAND chmod +x 
$<TARGET_PROPERTY:${DEPLOY_TARGET},DEPLOY_LOCATION>/release.sh
         DEPENDS  "$<TARGET_PROPERTY:${DEPLOY_TARGET},DEPLOY_TARGET_DEPS>" 
${DEPLOY_FILE_TARGETS} 
         WORKING_DIRECTORY "${DEPLOY_LOCATION}"
         COMMENT "Deploying ${DEPLOY_PRINT_NAME}" VERBATIM

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/cmake/cmake_celix/Runtimes.cmake
----------------------------------------------------------------------
diff --git a/cmake/cmake_celix/Runtimes.cmake b/cmake/cmake_celix/Runtimes.cmake
new file mode 100644
index 0000000..14f88eb
--- /dev/null
+++ b/cmake/cmake_celix/Runtimes.cmake
@@ -0,0 +1,161 @@
+add_custom_target(runtimes ALL
+    DEPENDS "$<TARGET_PROPERTY:runtimes,DEPS>"
+)
+set_target_properties(runtimes PROPERTIES "DEPS" "")
+set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES 
"${CMAKE_BINARY_DIR}/runtimes")
+
+function(add_runtime)
+    list(GET ARGN 0 RUNTIME_TARGET_NAME)
+    list(REMOVE_AT ARGN 0)
+
+    set(OPTIONS USE_TERM LOG_TO_FILES)
+    set(ONE_VAL_ARGS WAIT_FOR NAME GROUP)
+    set(MULTI_VAL_ARGS DEPLOYMENTS COMMANDS)
+    cmake_parse_arguments(RUNTIME "${OPTIONS}" "${ONE_VAL_ARGS}" 
"${MULTI_VAL_ARGS}" ${ARGN})
+
+    if (NOT RUNTIME_NAME)
+        set(RUNTIME_NAME ${RUNTIME_TARGET_NAME})
+    endif ()
+    if (NOT RUNTIME_GROUP)
+        set(RUNTIME_LOCATION "${PROJECT_BINARY_DIR}/runtimes/${RUNTIME_NAME}")
+    else ()
+        set(RUNTIME_LOCATION 
"${PROJECT_BINARY_DIR}/runtimes/${RUNTIME_GROUP}/${RUNTIME_NAME}")
+    endif ()
+    set(TIMESTAMP_FILE 
"${CMAKE_CURRENT_BINARY_DIR}/${RUNTIME_TARGET_NAME}-runtime-timestamp")
+
+    set(START_SCRIPT 
"$<TARGET_PROPERTY:${RUNTIME_TARGET_NAME},RUNTIME_LOCATION>/start.sh")
+    set(STOP_SCRIPT 
"$<TARGET_PROPERTY:${RUNTIME_TARGET_NAME},RUNTIME_LOCATION>/stop.sh")
+    set(COMMON_SCRIPT 
"$<TARGET_PROPERTY:${RUNTIME_TARGET_NAME},RUNTIME_LOCATION>/common.sh")
+
+    add_custom_command(OUTPUT "${TIMESTAMP_FILE}"
+        COMMAND ${CMAKE_COMMAND} -E touch ${TIMESTAMP_FILE}
+        COMMAND ${CMAKE_COMMAND} -E make_directory 
$<TARGET_PROPERTY:${RUNTIME_TARGET_NAME},RUNTIME_LOCATION>
+        COMMAND chmod +x 
$<TARGET_PROPERTY:${RUNTIME_TARGET_NAME},RUNTIME_LOCATION>/start.sh
+        COMMAND chmod +x 
$<TARGET_PROPERTY:${RUNTIME_TARGET_NAME},RUNTIME_LOCATION>/stop.sh
+        #TODO DEPENDS  
"$<TARGET_PROPERTY:${DEPLOY_TARGET},DEPLOY_TARGET_DEPS>" ${DEPLOY_FILE_TARGETS}
+        DEPENDS  ${START_SCRIPT} ${STOP_SCRIPT} ${SETUP_SCRIPT}
+        WORKING_DIRECTORY "${RUNTIME_LOCATION}"
+        COMMENT "Creating runtime ${RUNTIME_TARGET_NAME}" VERBATIM
+    )
+    add_custom_target(${RUNTIME_TARGET_NAME}
+        DEPENDS "${TIMESTAMP_FILE}"
+    )
+
+    set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES 
"RUNTIME_DEPLOYMENTS" "") #deployments that should be runned
+    set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_COMMANDS" 
"") #command that should be executed
+    set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_NAME" 
"${RUNTIME_NAME}") #The runtime workdir
+    set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_GROUP" 
"${RUNTIME_GROUP}") #The runtime workdir
+    set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_LOCATION" 
"${RUNTIME_LOCATION}") #The runtime workdir
+    set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_USE_TERM" 
"${RUNTIME_USE_TERM}") #Wether or not the use terminal
+    set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES 
"RUNTIME_LOG_TO_FILES" "${RUNTIME_LOG_TO_FILES}") #log to files or std out/err
+
+    #wait for deployment, e.g. the one that control the lifecycle of the 
runtime.
+    set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES 
"RUNTIME_WAIT_FOR_DEPLOYMENT" "")
+
+    #wait for command, e.g. the one that control the lifecycle of the runtime.
+    set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES 
"RUNTIME_WAIT_FOR_COMMAND" "")
+
+
+    #replaces @RUNTIME_TARGET_NAME@
+    #TODO move to another location
+    configure_file("${CELIX_CMAKE_DIRECTORY}/cmake_celix/runtime_start.sh.in" 
"${CMAKE_CURRENT_BINARY_DIR}/start.sh.${RUNTIME_TARGET_NAME}.in.1" @ONLY)
+    configure_file("${CELIX_CMAKE_DIRECTORY}/cmake_celix/runtime_stop.sh.in" 
"${CMAKE_CURRENT_BINARY_DIR}/stop.sh.${RUNTIME_TARGET_NAME}.in.1" @ONLY)
+    configure_file("${CELIX_CMAKE_DIRECTORY}/cmake_celix/runtime_common.sh.in" 
"${CMAKE_CURRENT_BINARY_DIR}/common.sh.${RUNTIME_TARGET_NAME}.in.1" @ONLY)
+
+
+    #replaces $<TARGET_PROPERTY:<RUNTIME_NAME>,RUNTIME_DEPLOYMENTS>
+    file(GENERATE
+            OUTPUT 
"${CMAKE_CURRENT_BINARY_DIR}/common.sh.${RUNTIME_TARGET_NAME}.in.2"
+            INPUT 
"${CMAKE_CURRENT_BINARY_DIR}/common.sh.${RUNTIME_TARGET_NAME}.in.1"
+    )
+    file(GENERATE
+        OUTPUT "${START_SCRIPT}"
+        INPUT 
"${CMAKE_CURRENT_BINARY_DIR}/start.sh.${RUNTIME_TARGET_NAME}.in.1"
+    )
+    file(GENERATE
+        OUTPUT "${STOP_SCRIPT}"
+        INPUT "${CMAKE_CURRENT_BINARY_DIR}/stop.sh.${RUNTIME_TARGET_NAME}.in.1"
+    )
+
+
+    #replaces list of $<TARGET_PROPERTY:<DEPLOY_NAME>,DEPLOY_LOCATION>, only 
needed for common
+    file(GENERATE
+        OUTPUT "${COMMON_SCRIPT}"
+        INPUT 
"${CMAKE_CURRENT_BINARY_DIR}/common.sh.${RUNTIME_TARGET_NAME}.in.2"
+    )
+
+    get_target_property(DEPS runtimes "DEPS")
+    list(APPEND DEPS "${RUNTIME_TARGET_NAME}")
+    set_target_properties(runtimes PROPERTIES "DEPS" "${DEPS}")
+
+    runtime_deployments(${RUNTIME_TARGET_NAME} ${RUNTIME_DEPLOYMENTS})
+    runtime_commands(${RUNTIME_TARGET_NAME} ${RUNTIME_COMMANDS})
+
+    if (RUNTIME_WAIT_FOR)
+        runtime_deployment_wait_for(${RUNTIME_TARGET_NAME} ${RUNTIME_WAIT_FOR})
+    endif ()
+
+endfunction()
+
+function(runtime_use_term)
+    #0 is runtime TARGET
+    #1 is BOOL (use xterm)
+    list(GET ARGN 0 RUNTIME_NAME)
+    list(GET ARGN 1 USE_TERM)
+    set_target_properties(${RUNTIME_NAME} PROPERTIES "RUNTIME_USE_TERM" 
"${USE_TERM}")
+endfunction()
+
+function(runtime_log_to_files)
+    #0 is runtime TARGET
+    #1 is BOOL (log to files)
+    list(GET ARGN 0 RUNTIME_NAME)
+    list(GET ARGN 1 LOG_TO_FILES)
+    set_target_properties(${RUNTIME_NAME} PROPERTIES "RUNTIME_LOG_TO_FILES" 
"${LOG_TO_FILES}")
+endfunction()
+
+function(runtime_deployments)
+    #0 is runtime TARGET
+    #1..n is deployments
+    list(GET ARGN 0 RUNTIME_NAME)
+    list(REMOVE_AT ARGN 0)
+
+    get_target_property(DEPLOYMENTS ${RUNTIME_NAME} "RUNTIME_DEPLOYMENTS")
+    foreach(DEPLOYMENT IN ITEMS ${ARGN})
+           list(APPEND DEPLOYMENTS 
"$<TARGET_PROPERTY:${DEPLOYMENT},DEPLOY_LOCATION>")
+   endforeach()
+
+   set_target_properties(${RUNTIME_NAME} PROPERTIES "RUNTIME_DEPLOYMENTS" 
"${DEPLOYMENTS}")
+endfunction()
+
+function(runtime_deployment_wait_for)
+    #0 is runtime TARGET
+    #1 is deployment TARGET
+    list(GET ARGN 0 RUNTIME_NAME)
+    list(GET ARGN 1 DEPLOYMENT)
+
+    set_target_properties(${RUNTIME_NAME} PROPERTIES 
"RUNTIME_WAIT_FOR_DEPLOYMENT" 
"$<TARGET_PROPERTY:${DEPLOYMENT},DEPLOY_LOCATION>")
+    set_target_properties(${RUNTIME_NAME} PROPERTIES 
"RUNTIME_WAIT_FOR_COMMAND" "")
+endfunction()
+
+function(runtime_commands)
+    #0 is runtime TARGET
+    #1..n is commands
+    list(GET ARGN 0 RUNTIME_NAME)
+    list(REMOVE_AT ARGN 0)
+
+    get_target_property(COMMANDS ${RUNTIME_NAME} "RUNTIME_COMMANDS")
+    foreach(CMD IN ITEMS ${ARGN})
+        list(APPEND COMMANDS ${CMD})
+    endforeach()
+    set_target_properties(${RUNTIME_NAME} PROPERTIES "RUNTIME_COMMANDS" 
"${COMMANDS}")
+endfunction()
+
+function(runtime_command_wait_for)
+    #0 is deploy TARGET
+    #1 is COMMAND STR
+    list(GET ARGN 0 RUNTIME_NAME)
+    list(GET ARGN 1 COMMAND)
+
+    set_target_properties(${RUNTIME_NAME} PROPERTIES 
"RUNTIME_WAIT_FOR_COMMAND" "${COMMAND}")
+    set_target_properties(${RUNTIME_NAME} PROPERTIES 
"RUNTIME_WAIT_FOR_DEPLOYMENT" "")
+endfunction()
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/cmake/cmake_celix/runtime_common.sh.in
----------------------------------------------------------------------
diff --git a/cmake/cmake_celix/runtime_common.sh.in 
b/cmake/cmake_celix/runtime_common.sh.in
new file mode 100644
index 0000000..e59c6b0
--- /dev/null
+++ b/cmake/cmake_celix/runtime_common.sh.in
@@ -0,0 +1,152 @@
+#!/bin/sh
+
+#Locations
+BUILD_DIR="${BUILD_DIR:-@PROJECT_BINARY_DIR@}"
+RUNTIME_DIR="${RUNTIME_DIR:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_LOCATION>}"
+DEPLOY_DIR="${DEPLOY_DIR:-${BUILD_DIR}/deploy}"
+
+#Name & Group
+RUNTIME_NAME="${RUNTIME_NAME:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_NAME>}"
+RUNTIME_GROUP="${RUNTIME_NAME:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_GROUP>}"
+
+#deployments & commands
+DEPLOYMENTS=${DEPLOYMENTS:-"$<JOIN:$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_DEPLOYMENTS>,
 >"}
+COMMANDS=${COMMANDS:-"$<JOIN:$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_COMMANDS>,
 >"}
+
+#Options
+TERM_CMD="${TERM_CMD:-xterm}"
+TERM_OPTS="${TERM_OPTS:-}"
+USE_TERM="${USE_TERM:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_USE_TERM>}"
+RELEASE_SH="${RELEASE_SH:-}"
+WAIT_FOR_DEPLOYMENT="${WAIT_FOR_DEPLOYMENT:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_WAIT_FOR_DEPLOYMENT>}"
+WAIT_FOR_CMD="${WAIT_FOR_CMD:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_WAIT_FOR_COMMAND>}"
+LOG_TO_FILES="${LOG_TO_FILES:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_LOG_TO_FILES>}"
+KILL_OPTS="${KILL_OPTS:-}"
+
+PIDS=""
+WAIT_FOR_PID=""
+LOG_SUFFIX=$(date +"%s")
+trap stop_all INT
+
+#clear dirs
+function rt_init() {
+    rm -fr ${RUNTIME_DIR}/run #contains pids, etc
+    mkdir ${RUNTIME_DIR}/run
+    if [ ! -e ${RUNTIME_DIR}/logs ] ; then
+        mkdir ${RUNTIME_DIR}/logs
+    fi
+}
+
+##functions
+function rt_stop_all() {
+    for PID in ${PIDS}; do
+        echo "Sending signal to ${PID}"
+        kill ${KILL_OPTS} ${PID}
+    done
+}
+
+function rt_stop() {
+    PIDS=$@
+    echo "Stopping pids ${PIDS}"
+    kill ${KILL_OPTS} ${PIDS}
+}
+
+function rt_run_deployment() {
+    DEPLOYMENT_DIR=$1
+    DEPLOYMENT=$(basename ${DEPLOYMENT_DIR})
+    LOG_FILE="${RUNTIME_DIR}/logs/${DEPLOYMENT}-${LOG_SUFFIX}.log"
+    echo "Running ${DEPLOYMENT}"
+    cd ${DEPLOYMENT_DIR} #assuming absolute dir
+    if [ -d .cache ] ; then
+        echo "Clearing cache"
+        rm -fr .cache #clear cache
+    fi
+    . ./release.sh #run deployment release
+    if [ "${USE_TERM}" = "TRUE" ] ; then
+        if [ "${LOG_TO_FILES}" = "TRUE" ] ; then
+            ${TERM_CMD} ${TERM_OPTS} -e "./${DEPLOYMENT} &> ${LOG_FILE}" &
+        else
+            ${TERM_CMD} ${TERM_OPTS} -e "./${DEPLOYMENT}" &
+        fi
+    else #run in this shell
+        if [ "${LOG_TO_FILES}" = "TRUE" ] ; then
+            ./${DEPLOYMENT} &> ${LOG_FILE} &
+        else
+            ./${DEPLOYMENT} &
+        fi
+    fi
+    PID=$!
+    echo "PID of DEPLOYMENT '${DEPLOYMENT}' is ${PID}"
+    if [ ! -z "${WAIT_FOR_DEPLOYMENT}" -a "${DEPLOYMENT_DIR}" = 
"${WAIT_FOR_DEPLOYMENT}" ] ; then
+        WAIT_FOR_PID=${PID}
+        echo "${PID}" > ${RUNTIME_DIR}/run/wait_for_pid
+    else
+        PIDS="${PID} ${PIDS}"
+        echo "${PIDS}" > ${RUNTIME_DIR}/run/pids
+    fi
+    cd -
+}
+
+function rt_run_cmd() {
+    CMD="$1"
+    LOG_FILE="${RUNTIME_DIR}/logs/${CMD}-${LOG_SUFFIX}.log" #TODO only use 
first word in case of complex command
+    cd ${RUNTIME_DIR}
+    if [ "${USE_TERM}" = "TRUE" ] ; then
+        if [ "${LOG_TO_FILES}" = "TRUE" ] ; then
+            ${TERM_CMD} ${TERM_OPTS} -e "${CMD} &> ${LOG_FILE}" &
+        else
+            ${TERM_CMD} ${TERM_OPTS} -e "${CMD}" &
+        fi
+    else
+        if [ "${LOG_TO_FILES}" = "TRUE" ] ; then
+            ${CMD} &> \"${LOG_FILE}\" &
+        else
+            ${CMD} &
+        fi
+    fi
+    PID=$!
+    echo "PID of COMMAND '${CMD}' is ${PID}"
+    if [ ! -z "${WAIT_FOR_CMD}" -a "${CMD}" = "${MWAIT_FOR_CMD}" ] ; then
+        WAIT_FOR_PID=${PID}
+        echo "${PID}" > ${RUNTIME_DIR}/run/wait_for_pid
+    else
+        PIDS="${PID} ${PIDS}"
+        echo "${PIDS}" > ${RUNTIME_DIR}/run/pids
+    fi
+    cd -
+}
+
+function rt_wait_for() {
+    RESULT=0
+    echo "Waiting for pid ${WAIT_FOR_PID}"
+    if wait ${WAIT_FOR_PID}; then
+        echo "${WAIT_FOR_PID} exited normal"
+    else
+        echo "${WAIT_FOR_PID} exited with error"
+        RESULT=1
+    fi
+
+    echo "Signalling pids:${PIDS}"
+    kill ${PIDS}
+
+    for PID in ${PIDS}; do
+        if wait ${PID}; then
+            echo "${PID} exited normal"
+        else
+            echo "${PID} exited with error"
+        fi
+    done
+
+    echo ${RESULT}
+}
+
+
+if [ -z "${RELEASE_SH}" ] ; then
+    true #pass
+elif [ -e "${RELEASE_SH}" ]; then #absolute release file
+    source ${RELEASE_SH}
+elif [ -e "${RUNTIME_DIR}/${RELEASE_SH}" ] ; then #release file in runtime dir
+    source ${RUNTIME_DIR}/${RELEASE_SH}
+elif [ -e "${BUILD_DIR}/${RELEASE_SH}" ] ; then #release file in build dir
+    source ${BUILD_DIR}/${RELEASE_SH}
+fi
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/cmake/cmake_celix/runtime_start.sh.in
----------------------------------------------------------------------
diff --git a/cmake/cmake_celix/runtime_start.sh.in 
b/cmake/cmake_celix/runtime_start.sh.in
new file mode 100644
index 0000000..e7e94f6
--- /dev/null
+++ b/cmake/cmake_celix/runtime_start.sh.in
@@ -0,0 +1,26 @@
+#!/bin/sh
+source $<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_LOCATION>/common.sh
+
+echo "Starting runtime ${RUNTIME_NAME}"
+
+rt_init
+
+for DEPLOYMENT_DIR in ${DEPLOYMENTS}; do
+    rt_run_deployment ${DEPLOYMENT_DIR}
+done
+
+for CMD in ${COMMANDS}; do
+    rt_run_cmd "${CMD}"
+done
+
+echo "PIDS are ${PIDS}."
+
+if [ ! -z "${WAIT_FOR_PID}" ] ; then
+    rt_wait_for #sets RESULT
+    echo "RESULT is ${RESULT}"
+    exit ${RESULT}
+fi
+
+
+
+

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/cmake/cmake_celix/runtime_stop.sh.in
----------------------------------------------------------------------
diff --git a/cmake/cmake_celix/runtime_stop.sh.in 
b/cmake/cmake_celix/runtime_stop.sh.in
new file mode 100644
index 0000000..fd7338e
--- /dev/null
+++ b/cmake/cmake_celix/runtime_stop.sh.in
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+source $<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_LOCATION>/common.sh
+
+#Options
+USE_SIGNAL=${USE_SIGNAL:-}
+
+#TODO parse option to easily select kill -9
+
+if [ -e ${RUNTIME_DIR}/run/main_pid ] ; then
+    MAIN_PID=$(cat ${RUNTIME_DIR}/run/wait_for_pid)
+    rt_stop ${MAIN_PID}
+fi
+
+if [ -e ${RUNTIME_DIR}/run/pids ] ; then
+    PIDS=$(cat ${RUNTIME_DIR}/run/pids)
+    rt_stop ${PIDS}
+fi
+

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/documents/cmake_commands/readme.md
----------------------------------------------------------------------
diff --git a/documents/cmake_commands/readme.md 
b/documents/cmake_commands/readme.md
index f68eb37..63f8732 100644
--- a/documents/cmake_commands/readme.md
+++ b/documents/cmake_commands/readme.md
@@ -161,6 +161,7 @@ add_deploy(<deploy_target_name>
     [GROUP group_name]
     [NAME deploy_name]
     [LAUNCHER launcher]
+    [DIR dir]
     [BUNDLES <bundle1> <bundle2> ...]
     [PROPERTIES "prop1=val1" "prop2=val2" ...]
 )
@@ -179,6 +180,7 @@ If the bundle target is never added CMake will give an 
error:
 - If GROUP is provided the deployment will be grouped in the provided group 
name. 
 - If NAME is provided that name will be used for the deployment dir. Default 
the deploy target name will be used.
 - If LAUNCHER is provided that path or target will be used as launcher 
executable for the deployment. If no LAUNCHER is not provided the celix 
executable will be used.
+- If DIR is provided, the specified dir is used instead of 
`<cmake_build_dir>/deploy` as deploy dir 
 - If BUNDLES is provided the list of bundles will be added the the generated 
config.properties for startup. Combined with COPY the bundles will also be 
copied to a bundles dir.
 - If PROPERTIES is provided the list of properties will be appended to the 
generated config.properties
 

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/framework/private/src/bundle_context.c
----------------------------------------------------------------------
diff --git a/framework/private/src/bundle_context.c 
b/framework/private/src/bundle_context.c
index 7951f87..face85d 100644
--- a/framework/private/src/bundle_context.c
+++ b/framework/private/src/bundle_context.c
@@ -126,7 +126,7 @@ celix_status_t 
bundleContext_registerService(bundle_context_pt context, const ch
        service_registration_pt registration = NULL;
        celix_status_t status = CELIX_SUCCESS;
 
-       if (context != NULL && *service_registration == NULL) {
+       if (context != NULL) {
            fw_registerService(context->framework, &registration, 
context->bundle, serviceName, svcObj, properties);
            *service_registration = registration;
        } else {

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/launcher/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 920d4c0..8bac20e 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -36,4 +36,21 @@ if (LAUNCHER)
     include_directories("${CURL_INCLUDE_DIRS}")
     
     install(TARGETS celix RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 
COMPONENT framework)
+
+    find_package(CppUTest QUIET)
+    if (CPPUTEST_FOUND)
+        #Test running which start celix and run CppUTest RUN_ALL_TESTS.
+        #Using this test running it is possible to create bundles containing 
CppUTests.
+        add_executable(celix_test_runner
+                private/src/celix_test_runner.cpp
+        )
+        set_target_properties(celix_test_runner PROPERTIES "INSTALL_RPATH" 
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+        target_link_libraries(celix_test_runner
+            celix_framework
+            ${CURL_LIBRARIES}
+            ${CPPUTEST_LIBRARIES}
+            ${CPPUTEST_EXT_LIBRARIES}
+        )
+        install(TARGETS celix_test_runner RUNTIME DESTINATION 
${CMAKE_INSTALL_BINDIR} COMPONENT framework)
+    endif ()
 endif (LAUNCHER) 

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/launcher/private/src/celix_test_runner.cpp
----------------------------------------------------------------------
diff --git a/launcher/private/src/celix_test_runner.cpp 
b/launcher/private/src/celix_test_runner.cpp
new file mode 100644
index 0000000..d1ea2e6
--- /dev/null
+++ b/launcher/private/src/celix_test_runner.cpp
@@ -0,0 +1,73 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you 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.
+ */
+
+
+#include <signal.h>
+
+#include "celix_launcher.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+
+static void shutdown_framework(int signal);
+static void ignore(int signal);
+
+#define DEFAULT_CONFIG_FILE "config.properties"
+
+static framework_pt framework = NULL;
+
+int main(int argc, char *argv[]) {
+    // Perform some minimal command-line option parsing...
+    char *cfg = DEFAULT_CONFIG_FILE;
+
+    // Set signal handler
+    (void) signal(SIGINT, shutdown_framework);
+    (void) signal(SIGUSR1, ignore);
+    (void) signal(SIGUSR2, ignore);
+
+    int rc = celixLauncher_launch(cfg, &framework);
+    if (rc != 0) {
+        printf("Error starting Celix\n");
+    }
+
+    if (rc == 0 && framework != NULL) {
+        rc = RUN_ALL_TESTS(argc, argv);
+
+        celixLauncher_stop(framework);
+        celixLauncher_waitForShutdown(framework);
+        celixLauncher_destroy(framework);
+    }
+
+    if (rc != 0) {
+        printf("*** FAILURE ***\n");
+    } else {
+        printf("*** SUCCESS ***\n");
+    }
+
+    return rc;
+}
+
+static void shutdown_framework(int signal) {
+    if (framework != NULL) {
+        celixLauncher_stop(framework); //NOTE main thread will destroy
+    }
+}
+
+static void ignore(int signal) {
+    //ignoring for signal SIGUSR1, SIGUSR2. Can be used to interrupt sleep, etc
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/pubsub/CMakeLists.txt b/pubsub/CMakeLists.txt
index 44f3bd1..7ad7677 100644
--- a/pubsub/CMakeLists.txt
+++ b/pubsub/CMakeLists.txt
@@ -36,6 +36,9 @@ if (PUBSUB)
        add_subdirectory(deploy)
        add_subdirectory(keygen)
        add_subdirectory(mock)
+       if (ENABLE_TESTING)
+               add_subdirectory(test)
+       endif()
 
        #install api
        install(FILES api/pubsub/publisher.h api/pubsub/subscriber.h 
DESTINATION include/celix/pubsub COMPONENT framework)

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/deploy/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/pubsub/deploy/CMakeLists.txt b/pubsub/deploy/CMakeLists.txt
index b35ae14..52fecc9 100644
--- a/pubsub/deploy/CMakeLists.txt
+++ b/pubsub/deploy/CMakeLists.txt
@@ -15,6 +15,8 @@
 # specific language governing permissions and limitations
 # under the License.
 
+find_program(ETCD_CMD NAMES etcd)
+find_program(XTERM_CMD NAMES xterm)
 
 # UDP Multicast
 add_deploy("pubsub_publisher_udp_mc" 
@@ -54,6 +56,23 @@ add_deploy("pubsub_subscriber2_udp_mc"
        org.apache.celix.pubsub_serializer.PubSubSerializerJson
 )
 
+if (ETCD_CMD AND XTERM_CMD)
+       #Runtime starting a publish and subscriber for udp mc
+       add_runtime(pubsub_rt_upd_mc
+               NAME udp_mc
+               GROUP pubsub
+               DEPLOYMENTS
+                       pubsub_publisher_udp_mc
+                       pubsub_subscriber_udp_mc
+                       pubsub_subscriber2_udp_mc
+               COMMANDS
+                       etcd
+               USE_TERM
+       )
+else ()
+       message(WARNING "Cannot create runtime for pubsub because etcd and/or 
xterm is not installed")
+endif ()
+
 if (BUILD_PUBSUB_PSA_ZMQ)
 
        # Dynamic ZMQ / UDP admin
@@ -168,4 +187,43 @@ if (BUILD_PUBSUB_PSA_ZMQ)
               org.apache.celix.pubsub_serializer.PubSubSerializerJson
        )
 
+       if (ETCD_CMD AND XTERM_CMD)
+               #Runtime starting two bundles using both zmq and upd mc pubsub
+               add_runtime(pubsub_rt_zmq_udpmc_combi
+                       NAME combi
+                       GROUP pubsub
+                       DEPLOYMENTS
+                               pubsub_publisher_zmq
+                               pubsub_subscriber_zmq
+                               pubsub_subscriber_zmq
+                       COMMANDS
+                               etcd
+                       USE_TERM
+               )
+
+               #Runtime starting a publish and 2 subscribers for zmq
+               add_runtime(pubsub_rt_zmq
+                       NAME zmq
+                       GROUP pubsub
+                       DEPLOYMENTS
+                               pubsub_publisher
+                               pubsub_subscriber2_zmq
+                       COMMANDS
+                               etcd
+                       USE_TERM
+               )
+
+               #Runtime starting a multipart (multiple message in one send) 
publish and subscriber for zmq
+               add_runtime(pubsub_rt_multipart_zmq
+                       NAME zmq_multipart
+                       GROUP pubsub
+                       DEPLOYMENTS
+                               pubsub_mp_subscriber_zmq
+                               pubsub_mp_publisher_zmq
+                       COMMANDS
+                               etcd
+                       USE_TERM
+               )
+       endif ()
+
 endif()

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/mock/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/pubsub/mock/CMakeLists.txt b/pubsub/mock/CMakeLists.txt
index 09d7b2a..189ddc2 100644
--- a/pubsub/mock/CMakeLists.txt
+++ b/pubsub/mock/CMakeLists.txt
@@ -23,15 +23,15 @@ if (CPPUTEST_FOUND)
         api
         ${CPPUTEST_INCLUDE_DIR}
     )
-    
+
     add_library(celix_pubsubmock STATIC
         src/publisher_mock.cc
-    )
+            ../test/test/msg.h)
     target_link_libraries(celix_pubsubmock ${CPPUTEST_LIBRARY})
-       
+
     install(TARGETS celix_pubsubmock DESTINATION ${CMAKE_INSTALL_LIBDIR} 
COMPONENT framework)
     install(FILES api/pubsub/publisher_mock.h DESTINATION include/celix/pubsub 
COMPONENT framework)
-    
+
     if (ENABLE_TESTING)
         add_executable(pubsubmock_test
             tst/pubsubmock_test.cc

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c
----------------------------------------------------------------------
diff --git a/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c 
b/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c
index cff5005..aa3faf0 100644
--- a/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c
+++ b/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c
@@ -364,6 +364,8 @@ static int pubsub_topicPublicationSend(void* handle, 
unsigned int msgTypeId, con
     celixThreadMutex_lock(&(bound->parent->tp_lock));
     celixThreadMutex_lock(&(bound->mp_lock));
 
+    //TODO //FIXME -> should use pointer to int as identifier, can be many 
pointers to int ....
+    printf("TODO FIX usage of msg id's in the serializer hashmap. This seems 
wrongly based on pointers to uints!!!!\n");
     pubsub_message_type *msgType = hashMap_get(bound->msgTypes, &msgTypeId);
 
     int major=0, minor=0;
@@ -401,7 +403,11 @@ static int pubsub_topicPublicationSend(void* handle, 
unsigned int msgTypeId, con
                free(serializedOutput);
 
     } else {
-        printf("TP: Message %u not supported.",msgTypeId);
+               if (bound->parent->serializerSvc == NULL) {
+                       printf("TP: Serializer is not set!\n");
+               } else {
+                       printf("TP: Message %u not supported.\n",msgTypeId);
+               }
         status=-1;
     }
 

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/test/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/pubsub/test/CMakeLists.txt b/pubsub/test/CMakeLists.txt
new file mode 100644
index 0000000..7cd0003
--- /dev/null
+++ b/pubsub/test/CMakeLists.txt
@@ -0,0 +1,87 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+
+find_program(ETCD_CMD NAMES etcd)
+
+find_package(CppUTest REQUIRED)
+include_directories(${CPPUTEST_INCLUDE_DIR})
+
+include_directories(
+        ${CMAKE_SOURCE_DIR}/pubsub/api
+        test
+)
+
+add_bundle(pubsub_sut
+    #"Vanilla" bundle which is under test
+    SOURCES
+        test/sut_activator.c
+    VERSION 1.0.0
+)
+bundle_files(pubsub_sut
+    msg_descriptors/msg.descriptor
+    DESTINATION "META-INF/descriptors/messages"
+)
+add_deploy(pubsub_udpmc_sut
+    NAME deploy_sut
+    BUNDLES
+        org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery
+        org.apache.celix.pubsub_topology_manager.PubSubTopologyManager
+        org.apache.celix.pubsub_admin.PubSubAdminUdpMc
+        #org.apache.celix.pubsub_admin.PubSubAdminZmq
+        org.apache.celix.pubsub_serializer.PubSubSerializerJson
+        pubsub_sut
+    DIR ${PROJECT_BINARY_DIR}/runtimes/test/pubsub/udpmc
+)
+
+add_bundle(pubsub_tst
+    #Test bundle containing cpputests and uses celix_test_runner launcher 
instead of the celix launcher
+    SOURCES
+        test/tst_activator.cpp
+    VERSION 1.0.0
+)
+bundle_files(pubsub_tst
+    msg_descriptors/msg.descriptor
+    DESTINATION "META-INF/descriptors/messages"
+)
+add_deploy(pubsub_udpmc_tst
+    NAME deploy_tst
+    BUNDLES
+        org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery
+        org.apache.celix.pubsub_topology_manager.PubSubTopologyManager
+        org.apache.celix.pubsub_admin.PubSubAdminUdpMc
+        #org.apache.celix.pubsub_admin.PubSubAdminZmq
+        org.apache.celix.pubsub_serializer.PubSubSerializerJson
+        pubsub_tst
+    DIR ${PROJECT_BINARY_DIR}/runtimes/test/pubsub/udpmc
+    LAUNCHER celix_test_runner
+)
+
+if (ETCD_CMD)
+    add_runtime(pubsub_rt_test_udpmc
+        NAME udpmc
+        GROUP test/pubsub
+        DEPLOYMENTS
+            pubsub_udpmc_sut
+            pubsub_udpmc_tst
+        COMMANDS
+            etcd
+        WAIT_FOR
+            pubsub_udpmc_tst
+        USE_TERM
+        #LOG_TO_FILES
+    )
+endif ()

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/test/msg_descriptors/msg.descriptor
----------------------------------------------------------------------
diff --git a/pubsub/test/msg_descriptors/msg.descriptor 
b/pubsub/test/msg_descriptors/msg.descriptor
new file mode 100644
index 0000000..808644c
--- /dev/null
+++ b/pubsub/test/msg_descriptors/msg.descriptor
@@ -0,0 +1,8 @@
+:header
+type=message
+name=msg
+version=1.0.0
+:annotations
+:types
+:message
+{n seqnR}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/test/test/msg.h
----------------------------------------------------------------------
diff --git a/pubsub/test/test/msg.h b/pubsub/test/test/msg.h
new file mode 100644
index 0000000..babfd1f
--- /dev/null
+++ b/pubsub/test/test/msg.h
@@ -0,0 +1,27 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you 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.
+ */
+
+#ifndef MSG_H
+#define MSG_H
+
+typedef struct msg {
+    int seqNr;
+} msg_t;
+
+#endif //MSG_H

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/test/test/sut_activator.c
----------------------------------------------------------------------
diff --git a/pubsub/test/test/sut_activator.c b/pubsub/test/test/sut_activator.c
new file mode 100644
index 0000000..3e3b33b
--- /dev/null
+++ b/pubsub/test/test/sut_activator.c
@@ -0,0 +1,112 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bundle_activator.h"
+#include "service_tracker.h"
+
+#include "pubsub/subscriber.h"
+#include "pubsub/publisher.h"
+
+static int sut_receive(void *handle, const char *msgType, unsigned int 
msgTypeId, void *msg, pubsub_multipart_callbacks_t *callbacks, bool *release);
+static int sut_pubAdded(void *handle, service_reference_pt reference, void 
*service);
+static int sut_pubRemoved(void *handle, service_reference_pt reference, void 
*service);
+
+
+struct activator {
+       pubsub_subscriber_t subSvc;
+       service_registration_pt reg;
+
+       service_tracker_pt tracker;
+
+       pthread_mutex_t mutex;
+       pubsub_publisher_t* pubSvc;
+};
+
+celix_status_t bundleActivator_create(bundle_context_pt context, void 
**userData) {
+       struct activator* act = malloc(sizeof(*act));
+       *userData = act;
+       return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_start(void * userData, bundle_context_pt 
context) {
+       struct activator* act = (struct activator*) userData;
+
+       properties_pt props = properties_create();
+       properties_set(props, "pubsub.topic", "ping");
+       act->subSvc.handle = act;
+       act->subSvc.receive = sut_receive;
+       act->reg = NULL;
+       bundleContext_registerService(context, PUBSUB_SUBSCRIBER_SERVICE_NAME, 
&act->subSvc, props, &act->reg);
+
+       const char* filter = 
"(&(objectClass=pubsub.publisher)(pubsub.topic=pong))";
+       service_tracker_customizer_pt customizer = NULL;
+       serviceTrackerCustomizer_create(act, NULL, sut_pubAdded, NULL, 
sut_pubRemoved, &customizer);
+       serviceTracker_createWithFilter(context, filter, customizer, 
&act->tracker);
+       serviceTracker_open(act->tracker);
+
+       return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_stop(void * userData, bundle_context_pt 
__attribute__((unused)) context) {
+       struct activator* act = userData;
+       serviceTracker_close(act->tracker);
+       return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt  
__attribute__((unused)) context) {
+       struct activator* act = userData;
+       serviceTracker_destroy(act->tracker);
+       return CELIX_SUCCESS;
+}
+
+static int sut_receive(void *handle, const char *msgType, unsigned int 
msgTypeId, void *msg, pubsub_multipart_callbacks_t *callbacks, bool *release) {
+       struct activator* act = handle;
+       printf("Received msg %s, sending back\n", msgType);
+       pthread_mutex_lock(&act->mutex);
+       if (act->pubSvc != NULL) {
+               unsigned int sendId = 0;
+               act->pubSvc->localMsgTypeIdForMsgType(act->pubSvc->handle, 
msgType, &sendId);
+               act->pubSvc->send(act->pubSvc->handle, sendId, msg);
+       }
+       pthread_mutex_unlock(&act->mutex);
+       return CELIX_SUCCESS;
+}
+
+static int sut_pubAdded(void *handle, service_reference_pt reference, void 
*service) {
+       struct activator* act = handle;
+       pthread_mutex_lock(&act->mutex);
+       act->pubSvc = service;
+       pthread_mutex_unlock(&act->mutex);
+       return CELIX_SUCCESS;
+
+}
+
+static int sut_pubRemoved(void *handle, service_reference_pt reference, void 
*service) {
+       struct activator* act = handle;
+       pthread_mutex_lock(&act->mutex);
+       if (act->pubSvc == service) {
+               act->pubSvc = NULL;
+       }
+       pthread_mutex_unlock(&act->mutex);
+       return CELIX_SUCCESS;
+}
+

http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/test/test/tst_activator.cpp
----------------------------------------------------------------------
diff --git a/pubsub/test/test/tst_activator.cpp 
b/pubsub/test/test/tst_activator.cpp
new file mode 100644
index 0000000..6d957a0
--- /dev/null
+++ b/pubsub/test/test/tst_activator.cpp
@@ -0,0 +1,199 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bundle_activator.h"
+#include "service_tracker.h"
+
+#include "pubsub/subscriber.h"
+#include "pubsub/publisher.h"
+
+#include "msg.h"
+
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
+
+
+static int tst_receive(void *handle, const char *msgType, unsigned int 
msgTypeId, void *msg, pubsub_multipart_callbacks_t *callbacks, bool *release);
+static int tst_pubAdded(void *handle, service_reference_pt reference, void 
*service);
+static int tst_pubRemoved(void *handle, service_reference_pt reference, void 
*service);
+
+#define MSG_NAME "msg"
+
+struct activator {
+       pubsub_subscriber_t subSvc;
+       service_registration_pt reg = nullptr;
+
+       service_tracker_pt tracker = nullptr;
+
+       pthread_mutex_t mutex; //protects below
+       pubsub_publisher_t* pubSvc = nullptr;
+    unsigned int msgId = 0;
+    unsigned int count = 0;
+
+    bool started = false;
+
+};
+
+static struct activator g_act; //global
+
+celix_status_t bundleActivator_create(__attribute__((unused)) 
bundle_context_pt context, __attribute__((unused)) void **userData) {
+    //memset(&g_act, 0, sizeof(g_act));
+       return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_start(__attribute__((unused)) void * userData, 
bundle_context_pt context) {
+       properties_pt props = properties_create();
+       properties_set(props, "pubsub.topic", "pong");
+       g_act.subSvc.handle = &g_act;
+       g_act.subSvc.receive = tst_receive;
+       bundleContext_registerService(context, PUBSUB_SUBSCRIBER_SERVICE_NAME, 
&g_act.subSvc, props, &g_act.reg);
+
+    const char* filter = 
"(&(objectClass=pubsub.publisher)(pubsub.topic=ping))";
+       service_tracker_customizer_pt customizer = NULL;
+       serviceTrackerCustomizer_create(&g_act, NULL, tst_pubAdded, NULL, 
tst_pubRemoved, &customizer);
+       serviceTracker_createWithFilter(context, filter, customizer, 
&g_act.tracker);
+       serviceTracker_open(g_act.tracker);
+
+    g_act.started = true;
+
+       return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_stop(__attribute__((unused)) void * userData, 
bundle_context_pt __attribute__((unused)) context) {
+       serviceTracker_close(g_act.tracker);
+       return CELIX_SUCCESS;
+}
+
+celix_status_t bundleActivator_destroy(__attribute__((unused)) void * 
userData, bundle_context_pt  __attribute__((unused)) context) {
+       serviceTracker_destroy(g_act.tracker);
+       return CELIX_SUCCESS;
+}
+
+static int tst_receive(void *handle, const char *msgType, unsigned int 
msgTypeId, void *msg, pubsub_multipart_callbacks_t *callbacks, bool *release) {
+       struct activator* act = static_cast<struct activator*>(handle);
+    pthread_mutex_lock(&act->mutex);
+    act->count += 1;
+    pthread_mutex_unlock(&act->mutex);
+       return CELIX_SUCCESS;
+}
+
+static int tst_pubAdded(void *handle, service_reference_pt reference, void 
*service) {
+    struct activator* act = static_cast<struct activator*>(handle);
+    pthread_mutex_lock(&act->mutex);
+       act->pubSvc = static_cast<pubsub_publisher_t*>(service);
+    act->pubSvc->localMsgTypeIdForMsgType(act->pubSvc->handle, MSG_NAME, 
&g_act.msgId);
+       pthread_mutex_unlock(&act->mutex);
+       return CELIX_SUCCESS;
+
+}
+
+static int tst_pubRemoved(void *handle, service_reference_pt reference, void 
*service) {
+    struct activator* act = static_cast<struct activator*>(handle);
+    pthread_mutex_lock(&act->mutex);
+       if (act->pubSvc == service) {
+               act->pubSvc = NULL;
+       }
+       pthread_mutex_unlock(&act->mutex);
+       return CELIX_SUCCESS;
+}
+
+
+TEST_GROUP(PUBSUB_INT_GROUP)
+{
+       void setup() {
+        constexpr int TRIES = 25;
+        constexpr int TIMEOUT = 1000000;
+               CHECK_EQUAL(true, g_act.started);
+
+        //check if publisher is available
+        unsigned int msgId = 0;
+        for (int i = 0; i < TRIES; ++i) {
+            pthread_mutex_lock(&g_act.mutex);
+            msgId = g_act.msgId;
+            pthread_mutex_unlock(&g_act.mutex);
+            if (msgId == 0) {
+                printf("publisher still nullptr / msg Id is still 0, waiting 
for a while\n");
+                usleep(TIMEOUT);
+            } else {
+                break;
+            }
+        }
+        CHECK(msgId != 0);
+
+        //check if message are returned
+        msg_t initMsg;
+        initMsg.seqNr = 0;
+        for (int i = 0; i < TRIES; ++i) {
+            pthread_mutex_lock(&g_act.mutex);
+            g_act.pubSvc->send(g_act.pubSvc->handle, g_act.msgId, &initMsg);
+            pthread_mutex_unlock(&g_act.mutex);
+            usleep(TIMEOUT);
+            pthread_mutex_lock(&g_act.mutex);
+            int count = g_act.count;
+            pthread_mutex_unlock(&g_act.mutex);
+            if (count > 0) {
+                break;
+            } else {
+                printf("No return message received, waiting for a while\n");
+            }
+        }
+       }
+
+       void teardown() {
+               //nop
+       }
+};
+
+TEST(PUBSUB_INT_GROUP, sendRecvTest) {
+    g_act.count = 0;
+    constexpr int COUNT = 50;
+    msg_t msg;
+    for (int i = 0; i < COUNT; ++i) {
+        msg.seqNr = i;
+        pthread_mutex_lock(&g_act.mutex);
+        g_act.pubSvc->send(g_act.pubSvc->handle, g_act.msgId, &msg);
+        pthread_mutex_unlock(&g_act.mutex);
+        usleep(100000);
+    }
+
+    constexpr int TRIES = 25;
+    constexpr int TIMEOUT = 250000;
+    for (int i = 0; i < TRIES; ++i) {
+        pthread_mutex_lock(&g_act.mutex);
+        int count = g_act.count;
+        pthread_mutex_unlock(&g_act.mutex);
+        if (count == COUNT) {
+            break;
+        } else {
+            printf("Current count is %i, should be %i. Waiting a little\n", 
count, COUNT);
+            usleep(TIMEOUT);
+        }
+    }
+
+    pthread_mutex_lock(&g_act.mutex);
+    int count = g_act.count;
+    pthread_mutex_unlock(&g_act.mutex);
+    CHECK_EQUAL(COUNT, count);
+}
\ No newline at end of file

Reply via email to