了解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. PAT甲级 1129. Recommendation System (25)

    1129. Recommendation System (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue ...

  2. JMS 消息队列

    1.jms  broker服务器:Broker:消息队列核心,相当于一个控制中心,负责路由消息.保存订阅和连接.消息确认和控制事务

  3. 从0开始学Python---01

    1.开始 Vim  test.py #!/usr/bin/python print "hello,world!"; chmod +x test.py ./test.py 2.基本知 ...

  4. MySQL--REPALCE INTO操作

    REPLACE INTO语法是MySQL数据库独特的扩展语法,可以提供“不存在即插入,存在即更新”的操作,MySQL官方文档解析其算法为: 1.尝试进行INSER 操作 2.如果INSERT 失败,则 ...

  5. 索引视图DEMO1

    --use tempdb ----------------------在创建视图和所有底层表时,必须打开ANSI_NULLS以及QUOTED_IDENTIFIER选项 --SET ANSI_NULLS ...

  6. 关于Winform下DataGridView中实现checkbox全选反选、同步列表项的处理

    近期接手一个winform 项目,虽然之前有.net 的经验,但是对一些控件的用法还不是很熟悉. 这段时间将会记录一些在工作中遇到的坎坷以及对应的解决办法,写出来与大家分享并希望大神提出更好解决方法来 ...

  7. WPF实现可视化控件打印及打印预览

    打印预览XAML代码: <controls:WindowEx x:Class="SunCreate.Vipf.Client.UI.MapPrintPreview" xmlns ...

  8. jquery banner 轮播配置方法

    1 概述 Banner可以作为网站页面的横幅广告,也可以作为游行活动时用的旗帜,还可以是报纸杂志上的大标题.Banner主要体现中心意旨,形象鲜明表达最主要的情感思想或宣传中心.在以往很多项目中主要体 ...

  9. ionic 2.x 3.x 打包 压缩

    大家都知道Ionic项目ionic serve生成的js css 非常庞大,小有1m多,大有几m,文件如此大load页面的时候需要较长时间的加载,特别在生产环境中,灰常不利于用户体验. 因此我们需要进 ...

  10. Spring Framework 4.3.22.RELEASE Reference文档目录

    <Spring Framework Reference Documentation 4.3.22.RELEASE> https://docs.spring.io/spring/docs/4 ...