了解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. spark的shuffle机制

    对于大数据计算框架而言,Shuffle阶段的设计优劣是决定性能好坏的关键因素之一.本文将介绍目前Spark的shuffle实现,并将之与MapReduce进行简单对比.本文的介绍顺序是:shuffle ...

  2. codeforces982A

    题意 给你个排列    10001 满足下列条件输出yes  否则输出no 1.不能有两个1相连 2.当点排列不能再加入1 全0判断一下 开头判断一下 结尾判断一下 #include <iost ...

  3. Scala_针对集合的操作

    针对集合的操作 遍历操作 列表的遍历 scala> val list = List(1,2,3,4,5,6) list: List[Int] = List(1, 2, 3, 4, 5, 6) s ...

  4. iOS证书说明和发布

    1.首先通过钥匙串访问——证书助理——从证书颁发机构请求证书——填写证书信息(邮箱,常用名称,存储到磁盘)——存储为(自定义名称.certSigningReuqest,简称CSR文件,只是为了提交到苹 ...

  5. java 异步机制与同步机制的区别

    所谓异步输入输出机制,是指在进行输入输出处理时,不必等到输入输出处理完毕才返回.所以异步的同义语是非阻塞(None Blocking). 网上有很多网友用很通俗的比喻  把同步和异步讲解的很透彻 转过 ...

  6. [C# 面试总结]9个点如何画10条线

    问题描述 9个点画10条直线,要求每条直线上至少3个点,相信这道理题目很多朋友在面试的时候都遇到过的(同时自己在面试的时候也遇到过),所以这里记录下来以备复习. 解决方法1:

  7. Git项目下载部分文件或文件夹

    我们常常要在Github下载一些源码.示例等,但有时候项目库会比较大,而我关心的只是其中很少的一部分内容,由于众所周知的原因,我们下载git库是比较慢的,过大的项目经常会下载失败,所以只下载部分内容就 ...

  8. 在ASP.NET Core中,静态类如何读取配置文件

    这是今天下午一个同事问我的问题,如何在静态类中读取json配置文件.我当时并没有告诉他如何如何去做,办法肯定是有,但是这种编程思维确实得改改了.静态类.静态方法不是面向对象编程的最佳实践..NET C ...

  9. 房屋贷款计算器 Mortgage Calculator

    闲暇时间开发了一款工具 - 房屋贷款计算器 Mortgage Calculator 有需要的可以下载来试试. JACK NJ @ 2017

  10. 背水一战 Windows 10 (54) - 控件(集合类): ItemsControl 的布局控件 - OrientedVirtualizingPanel, VirtualizingStackPanel, WrapGrid

    [源码下载] 背水一战 Windows 10 (54) - 控件(集合类): ItemsControl 的布局控件 - OrientedVirtualizingPanel, VirtualizingS ...