了解Jenkins的人都知道,JMS selector是基于SQL92语法实现的,本文将介绍使用stomp.pyActiveMQ来校验JMS selector的正确性。

Q: 什么是stomp.py?

A: stomp.py是一个基于STOMP(Simple (or Streaming) Text Orientated Messaging Protocol)协议实现的Python的客户端函数库,用来访问诸如ActiveMQ,RabbitMQ之类的消息服务器。

那么,为了使用stomp.py函数库,我们先安装一个ActiveMQ服务。

1.  下载ActiveMQ

$ export TGZBALL=5.15./apache-activemq-5.15.-bin.tar.gz
$ wget https://archive.apache.org/dist/activemq/$TGZBALL

2. 安装ActiveMQ

$ tar zxvf apache-activemq-5.15.-bin.tar.gz
$ sudo mv apache-activemq-5.15. /opt
$ cd /opt
$ sudo ln -s apache-activemq-5.15. activemq

3. 启动ActiveMQ

$ cd /opt/activemq/bin/linux-x86-
$ sudo ./activemq start
Starting ActiveMQ Broker...

注意ActiveMQ默认的监听端口是8161,

$ netstat -an | egrep
tcp6 ::: :::* LISTEN

如果要关闭ActiveMQ,

$ cd /opt/activemq/bin/linux-x86-
$ sudo ./activemq stop
Stopping ActiveMQ Broker...
Stopped ActiveMQ Broker.

一旦ActiveMQ, 我们可以访问其web界面,默认的登录用户名/密码是admin/admin, 例如:

4. 克隆stomp.py的源代码

$ mkdir /var/tmp/sp
$ cd /var/tmp/sp
$ git clone https://github.com/jasonrbriggs/stomp.py.git

5. 准备一个Python脚本foo.py

 #!/usr/bin/python3
import sys
import json
import collections
import time
import stomp g_rcvmsg_cnt = 0 # counter of received messages class MyListener(stomp.ConnectionListener):
def on_error(self, headers, message):
global g_rcvmsg_cnt
g_rcvmsg_cnt = 0 print('Oops!! received an error "%s"' % message) def on_message(self, headers, message):
global g_rcvmsg_cnt
g_rcvmsg_cnt += 1 print('Bingo! received a message, rcv_cnt = %d' % g_rcvmsg_cnt)
print('o message headers :\n%s' % json.dumps(headers, indent=4))
print('o message body : %s\n' % message) def validate():
if g_rcvmsg_cnt > 0:
print(">>> PASS")
return 0
else:
print(">>> FAIL")
return 1 def usage(argv0):
sys.stderr.write("Usage: %s <JMS selector> <message headers>\n" % argv0) def main(argc, argv):
if argc != 3:
usage(argv[0])
return 1 jms_selector = argv[1]
msg_headers = argv[2] d_sub_headers = dict()
d_sub_headers['selector'] = jms_selector
print('>>> SUB HEADERS', d_sub_headers) d_snd_headers = json.loads(msg_headers,
object_pairs_hook=collections.OrderedDict)
print('>>> SND HEADERS', d_snd_headers)
print() conn = stomp.Connection()
conn.set_listener('', MyListener())
conn.start() # Note default user/password of ActiveMQ is admin/admin
user = 'admin'
password = 'admin'
conn.connect(user, password, wait=True) conn.subscribe(destination='/queue/test', id=1, ack='auto',
headers=d_sub_headers) s_body = ' '.join(argv[1:])
conn.send(destination='/queue/test', body=s_body, headers=d_snd_headers) time.sleep(2)
conn.disconnect() return validate() if __name__ == '__main__':
sys.exit(main(len(sys.argv), sys.argv))

在上面的代码中,

    67        conn.subscribe(destination='/queue/test', id=1, ack='auto',
68 headers=d_sub_headers)

L67-68: 根据用户输入的JMS selector进行订阅,

    71        conn.send(destination='/queue/test', body=s_body, headers=d_snd_headers)

L71: 将用户输入的JSON文本作为消息头发送。

6. 使用foo.py测试JMS selector

hdan$ export PYTHONPATH=/var/tmp/sp/stomp.py:$PYTHONPATH
hdan$
hdan$ ./foo.py "Type LIKE 'Tag%'" '{"Type": "tag", "foo": 123}'
>>> SUB HEADERS {'selector': "Type LIKE 'Tag%'"}
>>> SND HEADERS OrderedDict([('Type', 'tag'), ('foo', )]) >>> FAIL
hdan$
hdan$ ./foo.py "Type LIKE 'Tag%'" '{"Type": "Tag", "foo": 123}'
>>> SUB HEADERS {'selector': "Type LIKE 'Tag%'"}
>>> SND HEADERS OrderedDict([('Type', 'Tag'), ('foo', )]) Bingo! received a message, rcv_cnt =
o message headers :
{
"subscription": "",
"content-length": "",
"timestamp": "",
"destination": "/queue/test",
"message-id": "ID:huangdan-40431-1550639739706-3:131:-1:1:1",
"foo": "",
"Type": "Tag",
"expires": "",
"priority": ""
}
o message body : Type LIKE 'Tag%' {"Type": "Tag", "foo": } >>> PASS
hdan$
hdan$ ./foo.py "Type LIKE 'Tag%'" '{"Type": "Tag123", "foo": 123}'
>>> SUB HEADERS {'selector': "Type LIKE 'Tag%'"}
>>> SND HEADERS OrderedDict([('Type', 'Tag123'), ('foo', )]) Bingo! received a message, rcv_cnt =
o message headers :
{
"message-id": "ID:huangdan-40431-1550639739706-3:132:-1:1:1",
"destination": "/queue/test",
"timestamp": "",
"expires": "",
"priority": "",
"subscription": "",
"content-length": "",
"foo": "",
"Type": "Tag123"
}
o message body : Type LIKE 'Tag%' {"Type": "Tag123", "foo": } >>> PASS
hdan$

附录: SQL92的LIKE操作符 (来源戳这里

A like string consists of a set of characters where the percent (%),
underscore (_) and escape character, such as backslash (\) are
treated differently. * The percent (%) matches any number of characters including
zero characters
* The underscore (_) matches only one character e.g.
+-------------+---------------------------------------+
| Like string | Meaning |
+-------------+---------------------------------------+
| Topic% | All strings starting with Topic |
| %/abc/% | Any string containing /abc/ |
| Name_ | Any string starting with Name and |
| | having exactly one more character |
| Name\_2 | Only the string Name_2 |
+-------------+---------------------------------------+

参考资料:

[Python学习笔记-006] 使用stomp.py校验JMS selector的正确性的更多相关文章

  1. Python学习笔记006

    算术运算符 加+ 减- 乘* 除/ 整除//,地板除 取余% 指数** ()区分 优先级 比较运算符 赋值 = 等于 == 不等于 != 大于等于 >= 小于等于 <=

  2. Python学习笔记:装饰器

    Python 装饰器的基本概念和应用 代码编写要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即: 封闭:已 ...

  3. VS2013中Python学习笔记[Django Web的第一个网页]

    前言 前面我简单介绍了Python的Hello World.看到有人问我搞搞Python的Web,一时兴起,就来试试看. 第一篇 VS2013中Python学习笔记[环境搭建] 简单介绍Python环 ...

  4. python学习笔记之module && package

    个人总结: import module,module就是文件名,导入那个python文件 import package,package就是一个文件夹,导入的文件夹下有一个__init__.py的文件, ...

  5. python学习笔记(六)文件夹遍历,异常处理

    python学习笔记(六) 文件夹遍历 1.递归遍历 import os allfile = [] def dirList(path): filelist = os.listdir(path) for ...

  6. python学习笔记--Django入门四 管理站点--二

    接上一节  python学习笔记--Django入门四 管理站点 设置字段可选 编辑Book模块在email字段上加上blank=True,指定email字段为可选,代码如下: class Autho ...

  7. python学习笔记--Django入门0 安装dangjo

    经过这几天的折腾,经历了Django的各种报错,翻译的内容虽然不错,但是与实际的版本有差别,会出现各种奇葩的错误.现在终于找到了解决方法:查看英文原版内容:http://djangobook.com/ ...

  8. Python学习笔记(十三)

    Python学习笔记(十三): 模块 包 if name == main 软件目录结构规范 作业-ATM+购物商城程序 1. 模块 1. 模块导入方法 import 语句 import module1 ...

  9. Python学习笔记(十一)

    Python学习笔记(十一): 生成器,迭代器回顾 模块 作业-计算器 1. 生成器,迭代器回顾 1. 列表生成式:[x for x in range(10)] 2. 生成器 (generator o ...

随机推荐

  1. Java理论学时第三节。课后作业。

    如果一个类中既有初始化块,又有构造方法,同时还设定了字段的初始值,谁说了算? 运行结果. 根据我的总结,它们三个的优先级是:构造方法 > 字段初始值 > 初始化块. 当多个类之间有继承关系 ...

  2. (DFS)展开字符串 -- hdu -- 1274

    http://acm.hdu.edu.cn/showproblem.php?pid=1274 展开字符串 Time Limit: 2000/1000 MS (Java/Others)    Memor ...

  3. java中三种注释

    //单行注释 /* 多行注释 */ /** * 文档注释 * version 2018.10.25 * authou GMY */

  4. 必修3第三章概率mindmaps

    % !Mode:: "TeX:UTF-8" \documentclass{article} \usepackage[screen]{geometry} \usepackage[no ...

  5. [javascript]Three parts of javascript code snippet

    <script> (function(){ /* if (navigator.userAgent.toLowerCase().indexOf("iphone") == ...

  6. eclipse 离线安装插件报cannot perform operation.Computing alternate solutions...解决办法

    当不能连接外网,离线安装SVN插件时,可能会发现以下问题:eclipse长时间停留在下图所示状态,提示“cannot perform operation.Computing alternate sol ...

  7. Convolutional Restricted Boltzmann Machines

    参考论文:1.Stacks of Convolutional Restricted Boltzmann Machines for Shift-Invariant Feature Learning   ...

  8. 【转】jQuery.validate 用法

    名称                              返回类型                描述 validate(options)          返回:Validator       ...

  9. CentOS BIND9安装及配置

    1.安装 #yum install bind   2.备份 named.conf #cp /etc/named.conf /etc/named.conf.bak   3.编辑 named.conf ( ...

  10. node.js second day

    create global link 使用全局模式安装的包不能直接通过require使用,但是nmp提供了一个 nmp link ,这个可以打破限制 $ nmp link [express] ./no ...