【仿RabbitMQ的发布订阅式消息队列】 ---- 功能测试联调

Welcome to 9ilk's Code World

(๑•́ ₃ •̀๑) 个人主页: 9ilk

(๑•́ ₃ •̀๑) 文章专栏: 项目


本篇博客主要是对消息队列项目组件的功能的一个测试,主要测试点在于在不同模式下的交换机,客户端是否能正确收到订阅队列的消息,这里我们测试的是广播交换、直接交换和主题交换。

广播交换模式测试

主要测试方案是:

  • 声明一个交换机,且为广播模式
  • 声明两个队列queue1和queue2,设置好binding_key然后和交换机进行绑定。
  • 前面两个操作,为了以防万一,消费者客户端和生产者客户端都做一遍这个工作。
  • 然后订阅客户端就可以订阅queue1,发布客户端发布的消息,订阅客户端应该都能收到

发布客户端:

cpp 复制代码
#include "asyncWorker.hpp"
#include "channel.hpp"
#include"connection.hpp"
#include <google/protobuf/map.h>
#include <memory>
#include <string>

int main()
{
    //1.实例化异步工作线程对现场
    zmq::AsyncWorker::ptr awp = make_shared<zmq::AsyncWorker>();
    //2.实例化连接对象
    zmq::Connection::ptr conn = make_shared<zmq::Connection>("127.0.0.1",8085,awp);
    //3.通过连接创建信道
    zmq::Channel::ptr channel = conn->openChannel();
    //4.通过信道提供的服务完成所需
    //4.1声明一个交换机 exchange1,交换机类型为广播模式
    google::protobuf::Map<string,string> tmp_map;
    channel->declareExchange("exchange1",zmq::ExchangeType::FANOUT,true,false,tmp_map);
    //4.2声明两个队列
    channel->declareQueue("queue1",true,false,false,tmp_map);

    channel->declareQueue("queue2",true,false,false,tmp_map);
    //4.3绑定 queue1-exchange1 且bing_key设置为queue1
    channel->queueBind("exchange1","queue1","queue1");
    channel->queueBind("exchange1","queue2","news.music.#");
    //5. 循环向交换机发布消息
    for(int i = 0 ; i < 10 ; i++)
    {
        //广播
        channel->basicPublish("exchange1",nullptr,"Hello Queue-"+to_string(i));
    }
    //6.关闭信道
    conn->closeChannel(channel);
    return 0;
}

订阅客户端:

cpp 复制代码
#include "asyncWorker.hpp"
#include "channel.hpp"
#include"connection.hpp"
#include <functional>
#include <google/protobuf/map.h>
#include <memory>
#include<thread>
#include <string>
#include<iostream>
#include "../mqcommon/logger.hpp"
using namespace std;

void callBack(zmq::Channel::ptr channel,const string& tag,const zmq::BasicProperties* bp,const string& body)
{
   cout << tag << "消费了消息:" << body << endl;
   //应答
   channel->basicAck(bp->id());
}

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        DBG_LOG("Usage: ./consume_client queue_anme");
        exit(1);
    }
    //1.实例化异步工作线程对现场
    zmq::AsyncWorker::ptr awp = make_shared<zmq::AsyncWorker>();
    //2.实例化连接对象
    zmq::Connection::ptr conn = make_shared<zmq::Connection>("127.0.0.1",8085,awp);
    //3.通过连接创建信道
    zmq::Channel::ptr channel = conn->openChannel();
    //4.通过信道提供的服务完成所需
    //4.1声明一个交换机 exchange1,交换机类型为广播模式
    google::protobuf::Map<string,string> tmp_map;
    channel->declareExchange("exchange1",zmq::ExchangeType::FANOUT,true,false,tmp_map);

    //4.2声明两个队列
    channel->declareQueue("queue1",true,false,false,tmp_map);
    channel->declareQueue("queue2",true,false,false,tmp_map);

    //4.3绑定 queue1-exchange1 且bing_key设置为queue1
    channel->queueBind("exchange1","queue1","queue1");
    channel->queueBind("exchange1","queue2","news.music.#");
    //6.订阅队列消息
    auto functor = std::bind(callBack,channel,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
    channel->basicConsume("consumer1",argv[1],false,functor);
    //7.关闭信道
    while(1)
    {
        std::this_thread::sleep_for(std::chrono::seconds(3));
    }
    conn->closeChannel(channel);
 
    return 0;
}

直接交换模式测试

主要测试方案:

  • 同样声明一个交换机和两个队列,交换机是直接交换模式
  • 直接交换模式下,直接比较routing_key和binding_key是否相同
  • 我们将消息设置为跟queue2的binding_key相同
  • 因此分别启动两个订阅客户端分别订阅queue1、queue2,发布客户端发布消息之后应该是只有订阅了queue2的客户端能收到消息。

发布客户端:

cpp 复制代码
#include "asyncWorker.hpp"
#include "channel.hpp"
#include"connection.hpp"
#include <google/protobuf/map.h>
#include <memory>
#include <string>

int main()
{
    //1.实例化异步工作线程对现场
    zmq::AsyncWorker::ptr awp = make_shared<zmq::AsyncWorker>();
    //2.实例化连接对象
    zmq::Connection::ptr conn = make_shared<zmq::Connection>("127.0.0.1",8085,awp);
    //3.通过连接创建信道
    zmq::Channel::ptr channel = conn->openChannel();
    //4.通过信道提供的服务完成所需
    //4.1声明一个交换机 exchange1,交换机类型为直接模式
    google::protobuf::Map<string,string> tmp_map;
    channel->declareExchange("exchange1",zmq::ExchangeType::DIRECT,true,false,tmp_map);
    //4.2声明两个队列
    channel->declareQueue("queue1",true,false,false,tmp_map);

    channel->declareQueue("queue2",true,false,false,tmp_map);
    //4.3绑定 queue1-exchange1 且bing_key设置为queue1
    channel->queueBind("exchange1","queue1","queue1");
    channel->queueBind("exchange1","queue2","news.music.#");
    //5. 循环向交换机发布消息
    for(int i = 0 ; i < 10 ; i++)
    {
        //直接
        zmq::BasicProperties bp;
        bp.set_id(zmq::uuidHelper::uuid());
        bp.set_delivery_mode(zmq::DeliveryMode::DURABLE);
        bp.set_routing_key("news.music.#");
        channel->basicPublish("exchange1",&bp,"Hello Queue-"+to_string(i));
    }

    //6.关闭信道
    conn->closeChannel(channel);
    return 0;
}

消费客户端:

cpp 复制代码
#include "asyncWorker.hpp"
#include "channel.hpp"
#include"connection.hpp"
#include <functional>
#include <google/protobuf/map.h>
#include <memory>
#include<thread>
#include <string>
#include<iostream>
#include "../mqcommon/logger.hpp"
using namespace std;

void callBack(zmq::Channel::ptr channel,const string& tag,const zmq::BasicProperties* bp,const string& body)
{
   cout << tag << "消费了消息:" << body << endl;
   //应答
   channel->basicAck(bp->id());
}

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        DBG_LOG("Usage: ./consume_client queue_anme");
        exit(1);
    }
    //1.实例化异步工作线程对现场
    zmq::AsyncWorker::ptr awp = make_shared<zmq::AsyncWorker>();
    //2.实例化连接对象
    zmq::Connection::ptr conn = make_shared<zmq::Connection>("127.0.0.1",8085,awp);
    //3.通过连接创建信道
    zmq::Channel::ptr channel = conn->openChannel();
    //4.通过信道提供的服务完成所需
    //4.1声明一个交换机 exchange1,交换机类型为广播模式
    google::protobuf::Map<string,string> tmp_map;
    channel->declareExchange("exchange1",zmq::ExchangeType::FANOUT,true,false,tmp_map);

    //4.2声明两个队列
    channel->declareQueue("queue1",true,false,false,tmp_map);
    channel->declareQueue("queue2",true,false,false,tmp_map);

    //4.3绑定 queue1-exchange1 且bing_key设置为queue1
    channel->queueBind("exchange1","queue1","queue1");
    channel->queueBind("exchange1","queue2","news.music.#");
    //6.订阅队列消息
    auto functor = std::bind(callBack,channel,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
    channel->basicConsume("consumer1",argv[1],false,functor);
    //7.关闭信道
    while(1)
    {
        std::this_thread::sleep_for(std::chrono::seconds(3));
    }
    conn->closeChannel(channel);
 
    return 0;
}

主题交换模式测试

  • 发布三种routing_key消息,分别是news.music.queue、news.music.pop、news.sport
  • 因此订阅queue1的收不到任何消息,订阅queue2的只能收到前两种

发布客户端:

cpp 复制代码
#include "asyncWorker.hpp"
#include "channel.hpp"
#include"connection.hpp"
#include <google/protobuf/map.h>
#include <memory>
#include <string>

int main()
{
    //1.实例化异步工作线程对现场
    zmq::AsyncWorker::ptr awp = make_shared<zmq::AsyncWorker>();
    //2.实例化连接对象
    zmq::Connection::ptr conn = make_shared<zmq::Connection>("127.0.0.1",8085,awp);
    //3.通过连接创建信道
    zmq::Channel::ptr channel = conn->openChannel();
    //4.通过信道提供的服务完成所需
    //4.1声明一个交换机 exchange1,交换机类型为广播模式
    google::protobuf::Map<string,string> tmp_map;
    channel->declareExchange("exchange1",zmq::ExchangeType::FANOUT,true,false,tmp_map);
    //4.2声明两个队列
    channel->declareQueue("queue1",true,false,false,tmp_map);

    channel->declareQueue("queue2",true,false,false,tmp_map);
    //4.3绑定 queue1-exchange1 且bing_key设置为queue1
    channel->queueBind("exchange1","queue1","queue1");
    channel->queueBind("exchange1","queue2","news.music.#");
    //5. 循环向交换机发布消息
    for(int i = 0 ; i < 10 ; i++)
    {
        //直接
        zmq::BasicProperties bp;
        bp.set_id(zmq::uuidHelper::uuid());
        bp.set_delivery_mode(zmq::DeliveryMode::DURABLE);
        bp.set_routing_key("news.music.queue");
        channel->basicPublish("exchange1",&bp,"Hello Queue-"+to_string(i));
    }
    zmq::BasicProperties bp;
    bp.set_id(zmq::uuidHelper::uuid());
    bp.set_delivery_mode(zmq::DeliveryMode::DURABLE);
    bp.set_routing_key("news.music.pop");
    channel->basicPublish("exchange1",&bp,"Hello pop");

    bp.set_id(zmq::uuidHelper::uuid());
    bp.set_delivery_mode(zmq::DeliveryMode::DURABLE);
    bp.set_routing_key("news.sport");
    channel->basicPublish("exchange1",&bp,"Hello sport");
    //6.关闭信道
    conn->closeChannel(channel);
    return 0;
}

消费客户端:

cpp 复制代码
#include "asyncWorker.hpp"
#include "channel.hpp"
#include"connection.hpp"
#include <functional>
#include <google/protobuf/map.h>
#include <memory>
#include<thread>
#include <string>
#include<iostream>
#include "../mqcommon/logger.hpp"
using namespace std;

void callBack(zmq::Channel::ptr channel,const string& tag,const zmq::BasicProperties* bp,const string& body)
{
   cout << tag << "消费了消息:" << body << endl;
   //应答
   channel->basicAck(bp->id());
}

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        DBG_LOG("Usage: ./consume_client queue_anme");
        exit(1);
    }
    //1.实例化异步工作线程对现场
    zmq::AsyncWorker::ptr awp = make_shared<zmq::AsyncWorker>();
    //2.实例化连接对象
    zmq::Connection::ptr conn = make_shared<zmq::Connection>("127.0.0.1",8085,awp);
    //3.通过连接创建信道
    zmq::Channel::ptr channel = conn->openChannel();
    //4.通过信道提供的服务完成所需
    //4.1声明一个交换机 exchange1,交换机类型为广播模式
    google::protobuf::Map<string,string> tmp_map;
    channel->declareExchange("exchange1",zmq::ExchangeType::TOPIC,true,false,tmp_map);

    //4.2声明两个队列
    channel->declareQueue("queue1",true,false,false,tmp_map);
    channel->declareQueue("queue2",true,false,false,tmp_map);

    //4.3绑定 queue1-exchange1 且bing_key设置为queue1
    channel->queueBind("exchange1","queue1","queue1");
    channel->queueBind("exchange1","queue2","news.music.#");
    //6.订阅队列消息
    auto functor = std::bind(callBack,channel,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);
    channel->basicConsume("consumer1",argv[1],false,functor);
    //7.关闭信道
    while(1)
    {
        std::this_thread::sleep_for(std::chrono::seconds(3));
    }
    conn->closeChannel(channel);
 
    return 0;
}
相关推荐
敲敲了个代码2 小时前
从硬编码到 Schema 推断:前端表单开发的工程化转型
前端·javascript·vue.js·学习·面试·职场和发展·前端框架
TG:@yunlaoda360 云老大3 小时前
华为云国际站代理商GeminiDB的企业级高可用具体是如何实现的?
服务器·网络·数据库·华为云
Shanxun Liao3 小时前
Cenots 7.9 配置多台 SSH 互信登陆免密码
linux·运维·ssh
j_xxx404_3 小时前
Linux:第一个程序--进度条|区分回车与换行|行缓冲区|进度条代码两个版本|代码测试与优化
linux·运维·服务器
looking_for__4 小时前
【Linux】Ext系列文件系统
linux
Morwit4 小时前
【力扣hot100】64. 最小路径和
c++·算法·leetcode
我命由我123454 小时前
SVG - SVG 引入(SVG 概述、SVG 基本使用、SVG 使用 CSS、SVG 使用 JavaScript、SVG 实例实操)
开发语言·前端·javascript·css·学习·ecmascript·学习方法
OliverH-yishuihan4 小时前
开发linux项目-在 Windows 上 基于“适用于 Linux 的 Windows 子系统(WSL)”
linux·c++·windows
七禾页丫4 小时前
面试记录12 中级c++开发工程师
c++·面试·职场和发展
zmzb01036 小时前
C++课后习题训练记录Day56
开发语言·c++