Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F11722863
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
29 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/rabbitmq-tcl.c b/src/rabbitmq-tcl.c
index 9d8d828..2bc6525 100644
--- a/src/rabbitmq-tcl.c
+++ b/src/rabbitmq-tcl.c
@@ -1,648 +1,664 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* ___ __ \_____ ___ /____ /____(_)_ /___ |/ /_ __ \
* __ /_/ / __ `/_ __ \_ __ \_ /_ __/_ /|_/ /_ / / /
* _ _, _// /_/ /_ /_/ / /_/ / / / /_ _ / / / / /_/ /
* /_/ |_| \__,_/ /_.___//_.___//_/ \__/ /_/ /_/ \___\_\
* _____________________
* RabbitMQ C AMQP client library TCL wrapper ___ __/_ ____/__ /
* TCL module to connect to AMQP brokers. __ / _ / __ /
* _ / / /___ _ /___
* (c) 2015, Nasqueron, some rights reserved. /_/ \____/ /_____/
* Released under BSD-2-Clause license.
*
* Provides a TCL rabbitmq.so module to get a 'mq' TCL command.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <stdlib.h>
#include <string.h>
#include <tcl.h>
#include <amqp_tcp_socket.h>
#include <amqp.h>
#include <amqp_framing.h>
#include "config.h"
#include "version.h"
#include "rabbitmq-tcl.h"
/* -------------------------------------------------------------
Broker connections
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
* Represents a connection with the broker, and stores properties.
*/
struct broker_connection {
int connected; /* 0 if disconnected, 1 if connected */
amqp_connection_state_t connection;
} brokerConnections[MQ_COMMANDS_AMOUNT];
/**
* Represents the client data information for a command.
*/
struct command_context {
int commandNumber;
};
/* -------------------------------------------------------------
Helper functions
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
* Gets product version string
*
* @return The product name and version
*/
char *get_version_string() {
char *versionString = malloc(256 * sizeof(char));
sprintf(versionString, "%s %s", RABBITMQ_TCL_PRODUCT_NAME,
RABBITMQ_TCL_PRODUCT_VERSION);
return versionString;
}
/**
* Determines if the specified connection slot is currently connected
*
* @param connectionNumber the number of the connection to check
* @return 1 if connected, 0 if disconnected
*/
int is_mq_connected(int connectionNumber) {
return brokerConnections[connectionNumber].connected;
}
/**
* Determines if the connection will probably be non blocking
*
* @return 1 if the operation should be non blocking ; 0 on block
*/
int amqp_will_be_non_blocking_operation(amqp_connection_state_t connection) {
// See
// http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2012-February/018188.html
return amqp_frames_enqueued(connection) || amqp_data_in_buffer(connection);
// TODO: at the stage, we can try a third solution: run amqp_get_sockfd()
// to get the socket descriptor, then call select() or poll().
// If the socket can be read, we can return true.
}
/**
* Prints an error message as command result and notify TCL an error occured.
*
* @param[out] tclInterpreter The interpreter in which to set result
* @param[in] error The error message
* @return TCL_ERROR
*/
int tcl_error(Tcl_Interp *tclInterpreter, char *error) {
Tcl_SetResult(tclInterpreter, error, TCL_STATIC);
return TCL_ERROR;
}
/**
* Gets a broker error
*
* @param[in] connection The AMQP connection
* @param[out] rcpReply The AMQP RPC reply
* @return 1 if an error occured, 0 if not
*/
int amqp_get_error(amqp_connection_state_t connection,
amqp_rpc_reply_t *rpcReply) {
amqp_rpc_reply_t reply = amqp_get_rpc_reply(connection);
rpcReply = &reply;
return reply.reply_type != AMQP_RESPONSE_NORMAL;
}
/**
* Determines the AMQP error from the server RPC reply, prints an error message
* based on this error and the specified context, then notify TCL an error
*occured.
*
* @param[out] tclInterpreter The interpreter in which to set result
* @param[in] errorContext The context of the error message, typically what were
*done at the moment of the error
* @param[in] rcpReply The AMQP RPC reply
* @return TCL_ERROR
*/
int tcl_amqp_error(Tcl_Interp *tclInterpreter, const char *errorContext,
amqp_rpc_reply_t rpcReply, int connectionNumber) {
char *error;
if (rpcReply.reply_type == AMQP_RESPONSE_NORMAL) {
// Not an error
return TCL_OK;
}
error = malloc(1024 * sizeof(char));
if (rpcReply.reply_type == AMQP_RESPONSE_NONE) {
sprintf(error, "%s a broker error occurred, but with an unexpected RPC "
"reply type. Please report this bug as issue.",
errorContext);
} else if (rpcReply.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION) {
sprintf(error, "%s %s", errorContext,
amqp_error_string2(rpcReply.library_error));
} else if (rpcReply.reply_type == AMQP_RESPONSE_SERVER_EXCEPTION) {
if (rpcReply.reply.id == AMQP_CONNECTION_CLOSE_METHOD) {
amqp_connection_close_t *m =
(amqp_connection_close_t *)rpcReply.reply.decoded;
sprintf(error,
"%s a server connection error %d occurred, message: %.*s",
errorContext, m->reply_code, (int)m->reply_text.len,
(char *)m->reply_text.bytes);
// Marks the connection as disconnected
brokerConnections[connectionNumber].connected = 0;
} else if (rpcReply.reply.id == AMQP_CHANNEL_CLOSE_METHOD) {
amqp_channel_close_t *m =
(amqp_channel_close_t *)rpcReply.reply.decoded;
sprintf(error, "%s a server channel error %d occurred: %.*s",
errorContext, m->reply_code, (int)m->reply_text.len,
(char *)m->reply_text.bytes);
// Marks the connection as disconnected
brokerConnections[connectionNumber].connected = 0;
} else {
sprintf(error,
"%s an unknown server error occurred, method id 0x%08X",
errorContext, rpcReply.reply.id);
}
}
return tcl_error(tclInterpreter, error);
}
/* -------------------------------------------------------------
TCL commands
mq
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
* mq command
*
* @param[in] connectionNumber The connection offset (0 for mq, 1 for mq1, …)
* @param[out] tclInterpreter The interpreter calling this function
* @param[in] argc The amount of command arguments
* @param[in] argv The command arguments
* @return TCL_OK, TCL_ERROR, TCL_RETURN, TCL_BREAK or TCL_CONTINUE
*/
static int mq_command(ClientData clientData, Tcl_Interp *tclInterpreter,
int argc, Tcl_Obj *const argv[]) {
int connectionNumber;
char *command;
struct command_context *context;
if (argc <= 1) {
return mq_usage(tclInterpreter);
}
context = clientData;
connectionNumber = context->commandNumber;
command = Tcl_GetString(argv[1]);
if (strcmp(command, "connect") == 0) {
return mq_connect(connectionNumber, tclInterpreter, argc - 2, argv + 2);
+ } else if (strcmp(command, "connected") == 0) {
+ return mq_connected(connectionNumber, tclInterpreter);
} else if (strcmp(command, "disconnect") == 0) {
return mq_disconnect(connectionNumber, tclInterpreter);
} else if (strcmp(command, "get") == 0) {
return mq_get(connectionNumber, tclInterpreter, argc - 2, argv + 2);
} else if (strcmp(command, "publish") == 0) {
return mq_publish(connectionNumber, tclInterpreter, argc - 2, argv + 2);
} else if (strcmp(command, "version") == 0) {
return mq_version(tclInterpreter);
} else {
return mq_usage(tclInterpreter);
}
}
/**
* mq [not existing command] usage output
*
* @param[out] tclInterpreter The interpreter to send command result to
*/
int mq_usage(Tcl_Interp *tclInterpreter) {
return tcl_error(
tclInterpreter,
- "Usage: mq <connect|disconnect|get|publish|version>");
+ "Usage: mq <connect|connected|disconnect|get|publish|version>");
}
/**
* mq version
*
* @param[out] tclInterpreter The interpreter calling this function
* @return TCL_OK
*/
int mq_version(Tcl_Interp *tclInterpreter) {
Tcl_SetResult(tclInterpreter, get_version_string(), TCL_STATIC);
return TCL_OK;
}
/**
* mq connect
*
* @param[in] connectionNumber The connection offset (0 for mq, 1 for mq1, …)
* @param[out] tclInterpreter The interpreter calling this function
* @param[in] argc The amount of command arguments
* @param[in] argv The command arguments
* @return TCL_OK on success, TCL_ERROR if already connected or can't connect
*/
int mq_connect(int connectionNumber, Tcl_Interp *tclInterpreter, int argc,
Tcl_Obj *const argv[]) {
char *host, *hostPortExpression, *user, *pass, *vhost;
int port, status;
amqp_connection_state_t conn;
amqp_socket_t *socket;
amqp_rpc_reply_t result;
// We don't allow to reconnect without first used mq disconnect
if (is_mq_connected(connectionNumber)) {
return tcl_error(tclInterpreter, "Already connected.");
}
// Connection parameters
if (argc > 0 && argv[0]) {
hostPortExpression = Tcl_GetString(argv[0]);
host = get_host(hostPortExpression, BROKER_HOST);
port = get_port(hostPortExpression, BROKER_PORT);
} else {
host = BROKER_HOST;
port = BROKER_PORT;
}
if (argc > 1 && argv[1]) {
user = Tcl_GetString(argv[1]);
} else {
user = BROKER_USER;
}
if (argc > 2 && argv[2]) {
pass = Tcl_GetString(argv[2]);
} else {
pass = BROKER_PASS;
}
if (argc > 3 && argv[3]) {
vhost = Tcl_GetString(argv[3]);
} else {
vhost = BROKER_VHOST;
}
// Opens a TCP connection to the broker
conn = amqp_new_connection();
socket = amqp_tcp_socket_new(conn);
if (!socket) {
return tcl_error(tclInterpreter, "Can't create TCP socket.");
}
status = amqp_socket_open(socket, host, port);
if (status) {
return tcl_error(tclInterpreter, "Can't connect to the broker.");
}
// Logins to the broker
// No heartbeat, unlimited channels, 128K (131072) frame size
result = amqp_login(conn, vhost, 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, user,
pass);
if (result.reply_type != AMQP_RESPONSE_NORMAL) {
return tcl_error(tclInterpreter, "Can't login to the broker.");
}
// Opens a first channel
amqp_channel_open(conn, 1);
if (amqp_get_error(conn, &result)) {
return tcl_amqp_error(tclInterpreter, "Can't open a channel:", result,
connectionNumber);
}
// We're connected. All is good.
brokerConnections[connectionNumber].connection = conn;
brokerConnections[connectionNumber].connected = 1;
return TCL_OK;
}
/**
* mq disconnect
*
* @param[in] connectionNumber The connection offset (0 for mq, 1 for mq1, …)
* @param[out] tclInterpreter The interpreter calling this function
* @return TCL_OK on success, TCL_ERROR if not connected
*/
int mq_disconnect(int connectionNumber, Tcl_Interp *tclInterpreter) {
amqp_rpc_reply_t result;
if (!is_mq_connected(connectionNumber)) {
return tcl_error(tclInterpreter, "Not connected.");
}
// We mark early as disconnected, to allow to recycle the slot
// event if an error occurs during disconnect.
brokerConnections[connectionNumber].connected = 0;
amqp_connection_state_t conn =
brokerConnections[connectionNumber].connection;
result = amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS);
if (result.reply_type != AMQP_RESPONSE_NORMAL) {
return tcl_amqp_error(tclInterpreter,
"An error occured closing channel:", result,
connectionNumber);
}
result = amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
if (result.reply_type != AMQP_RESPONSE_NORMAL) {
return tcl_amqp_error(tclInterpreter,
"An error occured closing connection:", result,
connectionNumber);
}
amqp_destroy_connection(conn);
return TCL_OK;
}
+/**
+ * mq connected
+ *
+ * @param[in] connectionNumber The connection offset (0 for mq, 1 for mq1, …)
+ * @param[out] tclInterpreter The interpreter calling this function
+ * @return TCL_OK
+ */
+int mq_connected(int connectionNumber, Tcl_Interp *tclInterpreter) {
+ char *reply = malloc(2 * sizeof(char));
+ sprintf(reply, "%d", is_mq_connected(connectionNumber));
+ Tcl_SetResult(tclInterpreter, reply, TCL_STATIC);
+ return TCL_OK;
+}
+
/**
* mq get <queue> [-noack]
*/
int mq_get(int connectionNumber, Tcl_Interp *tclInterpreter, int argc,
Tcl_Obj *const argv[]) {
char *queue;
char *argument;
char *error;
char *messageBody;
amqp_boolean_t noAck = 0;
amqp_connection_state_t conn;
amqp_rpc_reply_t result;
amqp_message_t message;
// Parses arguments
if (argc == 0) {
return tcl_error(tclInterpreter, "Required queue missing.");
}
queue = Tcl_GetString(argv[0]);
if (argc > 1) {
argument = Tcl_GetString(argv[1]);
if (strcmp(argument, "-noack") == 0) {
noAck = 1;
} else {
error = malloc(1024 * sizeof(char));
sprintf(error, "Unknown argument: %s", argument);
return tcl_error(tclInterpreter, error);
}
}
if (argc > 2) {
return tcl_error(tclInterpreter, "Too many arguments.");
}
// Ensures we're connected
if (!is_mq_connected(connectionNumber)) {
return tcl_error(tclInterpreter, "Not connected.");
}
conn = brokerConnections[connectionNumber].connection;
// Gets message from specified queue (basic.get operation)
result = amqp_basic_get(conn, 1, amqp_cstring_bytes(queue), noAck);
if (amqp_get_error(conn, &result)) {
return tcl_amqp_error(tclInterpreter, "Can't get message from queue:",
result, connectionNumber);
}
if (!amqp_will_be_non_blocking_operation(conn)) {
// We can't assert the operation will be non blocking
return TCL_OK;
}
result = amqp_read_message(conn, 1, &message, 0);
if (amqp_get_error(conn, &result)) {
return tcl_amqp_error(tclInterpreter, "Can't read message:", result,
connectionNumber);
}
if (&message && &(message.body)) {
messageBody = malloc(message.body.len + 1024);
sprintf(messageBody, "%.*s", (int)message.body.len,
(char *)message.body.bytes);
// Cleans up
amqp_destroy_message(&message);
amqp_maybe_release_buffers(conn);
}
// TCL return
Tcl_SetResult(tclInterpreter, messageBody, TCL_STATIC);
return TCL_OK;
}
/**
*
* mq publish <target> [-key <routing key>] [-mandatory] [-immediate] <message>
*
* The target could be: <exchange>, -exchange <exchange> or -queue <queue>
*
* @param[in] connectionNumber The connection offset (0 for mq, 1 for mq1, …)
* @param[out] tclInterpreter The interpreter calling this function
* @param[in] argc The amount of command arguments
* @param[in] argv The command arguments
* @return TCL_OK on success, TCL_ERROR if already connected or can't connect
*/
int mq_publish(int connectionNumber, Tcl_Interp *tclInterpreter, int argc,
Tcl_Obj *const argv[]) {
int i;
amqp_connection_state_t conn;
amqp_rpc_reply_t result;
char *argument, *exchange, *routingKey, *content;
int contentParsed = 0;
int targetParsed = 0;
int routingKeyParsed = 0;
int mustRouteToQueue = 0; // -mandatory
int mustImmediatelyDeliverToConsumer = 0; // -immediate
// Parses arguments
for (i = 0; i < argc; i++) {
argument = Tcl_GetString(argv[i]);
if (strcmp(argument, "-key") == 0) {
if (argc < i + 2) {
return tcl_error(tclInterpreter,
"Required routing key argument missing.");
}
routingKey = Tcl_GetString(argv[++i]);
routingKeyParsed = 1;
} else if (strcmp(argument, "-mandatory") == 0) {
mustRouteToQueue = 1;
} else if (strcmp(argument, "-immediate") == 0) {
mustImmediatelyDeliverToConsumer = 1;
} else if (strcmp(argument, "-exchange") == 0) {
if (argc < i + 2) {
return tcl_error(tclInterpreter,
"Required exchange argument missing.");
}
exchange = Tcl_GetString(argv[++i]);
targetParsed = 1;
} else if (strcmp(argument, "-queue") == 0) {
if (argc < i + 2) {
return tcl_error(tclInterpreter,
"Required queue argument missing.");
}
exchange = BROKER_DEFAULT_EXCHANGE;
routingKey = Tcl_GetString(argv[++i]);
targetParsed = 1;
routingKeyParsed = 1;
} else if (i == 0) {
exchange = Tcl_GetString(argv[0]);
targetParsed = 1;
} else {
content = Tcl_GetString(argv[i]);
contentParsed = 1;
}
}
if (!routingKeyParsed) {
routingKey = BROKER_DEFAULT_ROUTING_KEY;
}
// Throws error when we haven't enough information (what and where)
if (!targetParsed) {
return tcl_error(tclInterpreter, "Required message target missing.");
}
if (!contentParsed) {
return tcl_error(tclInterpreter,
"Required message content argument missing.");
}
// Ensures we're connected
if (!is_mq_connected(connectionNumber)) {
return tcl_error(tclInterpreter, "Not connected.");
}
// Sends the message and checks the result
conn = brokerConnections[connectionNumber].connection;
amqp_basic_publish(conn, 1, amqp_cstring_bytes(exchange),
amqp_cstring_bytes(routingKey), mustRouteToQueue,
mustImmediatelyDeliverToConsumer, NULL,
amqp_cstring_bytes(content));
if (amqp_get_error(conn, &result)) {
return tcl_amqp_error(tclInterpreter, "Can't publish message:", result,
connectionNumber);
}
#ifdef DEBUG
char *debugMessage = malloc(1024 * sizeof(char) + sizeof(content));
sprintf(
debugMessage,
"Message published to exchange '%s', routing key '%s'. Content: '%s'.",
exchange, routingKey, content);
Tcl_SetResult(tclInterpreter, debugMessage, TCL_STATIC);
#endif
return TCL_OK;
}
/* -------------------------------------------------------------
TCL initialisation code
Creation of the mq and mq2-10 commands.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifdef WINDOWS
extern __declspec(dllexport) int Rabbitmq_Init(Tcl_Interp *tclInterpreter);
#else
extern int Rabbitmq_Init(Tcl_Interp *tclInterpreter);
#endif
/**
* Determines TCL environment is correct and initiliazes stubs if needed
*
* @param[out] tclInterpreter The current TCL interpreter
* @return 1 on success; otherwise, 0
*/
int tcl_init(Tcl_Interp *tclInterpreter) {
// This extension requires TCL 8.0+
if (Tcl_PkgRequire(tclInterpreter, "Tcl", TCL_VERSION, 0) == NULL) {
if (TCL_VERSION[0] == '7') {
if (Tcl_PkgRequire(tclInterpreter, "Tcl", "8.0", 0) == NULL) {
return 0;
}
}
}
#if USE_TCL_STUBS
// Initializes stubs (requires TCL 8.1+)
if (Tcl_InitStubs(tclInterpreter, "8.1", 0) == NULL) {
return 0;
}
#endif
return 1;
}
/**
* Gets command context
*
* @param commandNumber The command number (3 for mq3)
* @return the command context
*/
ClientData get_mq_command_context(int commandNumber) {
struct command_context *context = malloc(sizeof(int));
context->commandNumber = commandNumber;
return context;
}
/**
* Creates TCL commands
*
* @param[out] tclInterpreter The current TCL interpreter
*/
void tcl_create_commands(Tcl_Interp *tclInterpreter) {
int i;
char commandName[10];
// Creates mq and mq1-mq10 commands
for (i = 0; i <= MQ_COMMANDS_AMOUNT; i++) {
if (i == 0) {
strcpy(commandName, "mq");
} else {
sprintf(commandName, "mq%d", i);
}
Tcl_CreateObjCommand(tclInterpreter, commandName, mq_command,
get_mq_command_context(i),
(Tcl_CmdDeleteProc *)NULL);
brokerConnections[i].connected = 0;
}
}
/**
* Provides TCL package
*
* @param[out] tclInterpreter The current TCL interpreter
*/
int tcl_provide_package(Tcl_Interp *tclInterpreter) {
int result;
result = Tcl_PkgProvide(tclInterpreter, RABBITMQ_TCL_PACKAGE_NAME,
RABBITMQ_TCL_PACKAGE_VERSION);
return (result != TCL_ERROR);
}
/**
* Initializes the library and provide mq commands
*
* @param[out] tclInterpreter The current TCL interpreter to provide commands to
* @return TCL_OK on success; otherwise, TCL_ERROR
*/
int Rabbitmq_Init(Tcl_Interp *tclInterpreter) {
if (!tcl_init(tclInterpreter)) {
return TCL_ERROR;
}
tcl_create_commands(tclInterpreter);
if (!tcl_provide_package(tclInterpreter)) {
return TCL_ERROR;
}
return TCL_OK;
}
diff --git a/src/rabbitmq-tcl.h b/src/rabbitmq-tcl.h
index 1016c37..27c189b 100644
--- a/src/rabbitmq-tcl.h
+++ b/src/rabbitmq-tcl.h
@@ -1,59 +1,60 @@
/* -------------------------------------------------------------
RabbitMQ TCL - Header
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
___ __ \_____ ___ /____ /____(_)_ /___ |/ /_ __ \
__ /_/ / __ `/_ __ \_ __ \_ /_ __/_ /|_/ /_ / / /
_ _, _// /_/ /_ /_/ / /_/ / / / /_ _ / / / / /_/ /
/_/ |_| \__,_/ /_.___//_.___//_/ \__/ /_/ /_/ \___\_\
_____________________
RabbitMQ C AMQP client library TCL wrapper ___ __/_ ____/__ /
TCL module to connect to AMQP brokers. __ / _ / __ /
_ / / /___ _ /___
(c) 2015, Nasqueron, some rights reserved. /_/ \____/ /_____/
Released under BSD-2-Clause license.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Software: RabbitMQ TCL
Author: Sébastien Santoro aka Dereckson
Filename: rabbitmq-tcl.h
Created: 2015-12-08
Licence: BSD-2-Clause
------------------------------------------------------------- */
#include <amqp.h>
#include <tcl.h>
/* -------------------------------------------------------------
Functions from utils/
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "utils/netutils.h"
/* -------------------------------------------------------------
Functions explicit declaration (by alphabetical order)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int amqp_will_be_non_blocking_operation(amqp_connection_state_t connection);
ClientData get_mq_command_context(int commandNumber);
char *get_version_string();
static int mq_command(ClientData clientData, Tcl_Interp *tclInterpreter,
int argc, Tcl_Obj *const argv[]);
int mq_connect(int connectionNumber, Tcl_Interp *tclInterpreter, int argc,
Tcl_Obj *const argv[]);
+int mq_connected(int connectionNumber, Tcl_Interp *tclInterpreter);
int mq_disconnect(int connectionNumber, Tcl_Interp *tclInterpreter);
int mq_get(int connectionNumber, Tcl_Interp *tclInterpreter, int argc,
Tcl_Obj *const argv[]);
int mq_publish(int connectionNumber, Tcl_Interp *tclInterpreter, int argc,
Tcl_Obj *const argv[]);
int mq_usage(Tcl_Interp *tclInterpreter);
int mq_version(Tcl_Interp *tclInterpreter);
int Rabbitmq_Init(Tcl_Interp *tclInterpreter);
void tcl_create_commands(Tcl_Interp *tclInterpreter);
int tcl_error(Tcl_Interp *tclInterpreter, char *error);
int tcl_init(Tcl_Interp *tclInterpreter);
int tcl_provide_package(Tcl_Interp *tclInterpreter);
diff --git a/tests/Makefile b/tests/Makefile
index 9cae80b..758220d 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,73 +1,76 @@
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# #
# ___ __ \_____ ___ /____ /____(_)_ /___ |/ /_ __ \ #
# __ /_/ / __ `/_ __ \_ __ \_ /_ __/_ /|_/ /_ / / / #
# _ _, _// /_/ /_ /_/ / /_/ / / / /_ _ / / / / /_/ / #
# /_/ |_| \__,_/ /_.___//_.___//_/ \__/ /_/ /_/ \___\_\ #
# _____________________ #
# RabbitMQ C AMQP client library TCL wrapper ___ __/_ ____/__ / #
# TCL module to connect to AMQP brokers. __ / _ / __ / #
# _ / / /___ _ /___ #
# (c) 2015, Nasqueron, some rights reserved. /_/ \____/ /_____/ #
# Released under BSD-2-Clause license. #
# #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Useful targets:
# ---------------
# Compile and run tests ........ make runtest
# Clean, compile and run ....... make retest
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# #
# Codebase and build configuration #
# #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# 3rd party versions
TCLVERSION=8.6
# Headers to include
TCL_INCLUDE=/usr/include/tcl${TCLVERSION}
INCLUDES=-I$(TCL_INCLUDE)
# Libraries to use
LIBS=-lcmocka -ltcl -lrabbitmq
# Commands to use
CC=clang ${INCLUDES} ${LIBS}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# #
# Targets, build process utility steps #
# #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Main targets
all: runtest
runtest: test
+ @echo [ Part I - C tests ]
./test
+ @echo [ Part II - TCL tests ]
+ tclsh${TCLVERSION} tests.tcl
clean:
rm -f test
# Secondary convenience targets
tests: test
retest: clean runtest
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# #
# Compile and link process #
# #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
test:
${CC} test.c -o test
diff --git a/tests/tests.tcl b/tests/tests.tcl
new file mode 100644
index 0000000..d2439a9
--- /dev/null
+++ b/tests/tests.tcl
@@ -0,0 +1,32 @@
+# -------------------------------------------------------------
+# RabbitMQ TCL - Unit testing
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#
+# ___ __ \_____ ___ /____ /____(_)_ /___ |/ /_ __ \
+# __ /_/ / __ `/_ __ \_ __ \_ /_ __/_ /|_/ /_ / / /
+# _ _, _// /_/ /_ /_/ / /_/ / / / /_ _ / / / / /_/ /
+# /_/ |_| \__,_/ /_.___//_.___//_/ \__/ /_/ /_/ \___\_\
+# _____________________
+# RabbitMQ C AMQP client library TCL wrapper ___ __/_ ____/__ /
+# TCL module to connect to AMQP brokers. __ / _ / __ /
+# _ / / /___ _ /___
+# (c) 2015, Nasqueron, some rights reserved. /_/ \____/ /_____/
+# Released under BSD-2-Clause license.
+#
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Software: RabbitMQ TCL
+# Author: Sébastien Santoro aka Dereckson
+# Filename: tests.tcl
+# Created: 2015-12-12
+# Licence: BSD-2-Clause
+# -------------------------------------------------------------
+
+load ../build/rabbitmq.so
+
+package require rabbitmq
+package require tcltest
+namespace import ::tcltest::*
+
+test mq-connected {When the interpreter starts, we shouldn't be marked as connected to the broker.} {
+ mq connected
+} 0
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Sep 18, 06:11 (16 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2990093
Default Alt Text
(29 KB)
Attached To
Mode
rRABBITMQTCL RabbitMQ TCL extension
Attached
Detach File
Event Timeline
Log In to Comment