本专栏内容为:项目专栏

💓博主csdn个人主页:小小unicorn
⏩专栏分类:微服务即时通讯系统
🚚代码仓库:小小unicorn的代码仓库🚚
🌹🌹🌹关注我带你学习编程知识

功能设计

用户管理子服务,主要用于管理用户的数据,以及关于用户信息的各项操作,因此在上述项目功能中,用户子服务需要提供以下接口:

  1. 用户注册:用户输入用户名(昵称),以及密码进行用户名的注册
  2. 用户登录:用户通过用户名和密码进行登录
  3. 短信验证码获取:当用户通过手机号注册或登录的时候,需要获取短信验证码
  4. 手机号注册:用户输入手机号和短信验证码进行手机号的用户注册
  5. 手机号登录:用户输入手机号和短信验证码进行手机号的用户登录
  6. 用户信息获取:当用户登录之后,获取个人信息进行展示
  7. 头像修改:设置用户头像
  8. 昵称修改:设置用户昵称
  9. 签名修改:设置用户签名
  10. 手机号修改:修改用户的绑定手机号

模块划分

  1. 参数/配置文件解析模块:基于 gflags 框架直接使用进行参数/配置文件解析。
  2. 日志模块:基于 spdlog 框架封装的模块直接使用进行日志输出。
  3. 服务注册模块:基于 etcd 框架封装的注册模块直接使用,进行聊天消息存储子服
    务的注册。
  4. 数据库数据操作模块:基于 odb-mysql 数据管理封装的模块,实现关系型数据库
    中数据的操作。
    a. 用户进行用户名/手机号注册的时候在数据库中进行新增信息
    b. 用户修改个人信息的时候修改数据库中的记录
    c. 用户登录的时候,在数据库中进行用户名密码的验证
  5. redis 客户端模块:基于 redis++封装的客户端进行内存数据库数据操作
    a. 当用户登录的时候需要为用户创建登录会话,会话信息保存在 redis 服务器中。
    b. 当用户手机号进行获取/验证验证码的时候,验证码与对应信息保存在 redis 服务器中
  6. rpc 服务模块:基于 brpc 框架搭建 rpc 服务器。
  7. rpc 服务发现与调用模块:基于 etcd 框架与 brpc 框架封装的服务发现与调用模块,
    a. 连接文件管理子服务:获取用户信息的时候,用户头像是通过文件的形式存
    储在文件子服务中的。
    b. 连接消息管理子服务:在打开聊天会话的时候,需要获取最近的一条消息进
    行展示。
  8. ES 客户端模块:基于 elasticsearch 框架实现访问客户端,向 ES 服务器中存储用户简息,以便于用户的搜索
  9. 短信平台客户端模块:基于短信平台 SDK 封装使用,用于向用户手机号发送指定验证码。

功能模块示意图:

在这里插入图片描述

数据管理

关系数据库数据管理:

在关系型数据库中,对于用户子服务来说,总体只进行了一个信息数据的存储与管理,那就是用户信息数据,因此只需要构建好用户信息表,提供好对应的操作即可可。

用户数据表:

包含字段:

  1. 主键 ID:自动生成
  2. 用户 ID:用户唯一标识
  3. 用户昵称:用户的昵称,也可用作登录用户名
  4. 用户签名:用户对自己的描述吧…
  5. 登录密码:登录验证
  6. 绑定手机号:用户可以绑定手机号,绑定后可以通过手机号登录、
  7. 用户头像文件 ID:头像文件存储的唯一标识,具体头像数据存储在文件子服务
    器中。
    提供的操作:
  8. 通过昵称获取用户信息
  9. 通过手机号获取用户信息
  10. 通过用户 ID 获取用信息
  11. 新增用户
  12. 更新用户信息

用户管理测试

我们根据模块进行测试,先测试我们的用户注册功能:

在这里插入图片描述

insert into user values(null,'用户1','小猪佩奇','这是一只小猪','123456','手机号1','小猪头像1');
insert into user values(null,'用户2','小猪乔治','这是一只小小猪','123456','手机号2','小猪头像2');

在这里插入图片描述
user_client.cc

#include "etcd.hpp"
#include "channel.hpp"
#include "utils.hpp"
#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include <thread>
#include "user.pb.h"
#include "base.pb.h"

DEFINE_bool(run_mode, false, "程序的运行模式,false-调试; true-发布;");
DEFINE_string(log_file, "", "发布模式下,用于指定日志的输出文件");
DEFINE_int32(log_level, 0, "发布模式下,用于指定日志输出等级");

DEFINE_string(etcd_host, "http://127.0.0.1:2379", "服务注册中心地址");
DEFINE_string(base_service, "/service", "服务监控根目录");
DEFINE_string(user_service, "/service/user_service", "服务监控根目录");

bite_im::ServiceManager::ptr _user_channels; // 定义智能指针

bite_im::UserInfo user_info; // 数据定义

std::string login_ssid;
std::string new_nickname = "亲爱的猪妈妈";

TEST(用户子服务测试, 用户注册测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);
    user_info.set_nickname("猪爸爸");

    bite_im::UserRegisterReq req;
    req.set_request_id(bite_im::uuid());
    req.set_nickname(user_info.nickname());
    req.set_password("123456");
    bite_im::UserRegisterRsp rsp;
    brpc::Controller cntl;
    // rpc调用
    bite_im::UserService_Stub stub(channel.get());
    stub.UserRegister(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}

int main(int argc, char *argv[])
{
    testing::InitGoogleTest(&argc, argv);
    google::ParseCommandLineFlags(&argc, &argv, true);
    bite_im::init_logger(FLAGS_run_mode, FLAGS_log_file, FLAGS_log_level);

    // 1. 先构造Rpc信道管理对象
    _user_channels = std::make_shared<bite_im::ServiceManager>(); // 构造
    _user_channels->declared(FLAGS_user_service);
    auto put_cb = std::bind(&bite_im::ServiceManager::onServiceOnline, _user_channels.get(), std::placeholders::_1, std::placeholders::_2);
    auto del_cb = std::bind(&bite_im::ServiceManager::onServiceOffline, _user_channels.get(), std::placeholders::_1, std::placeholders::_2);

    // 2. 构造服务发现对象
    bite_im::Discovery::ptr dclient = std::make_shared<bite_im::Discovery>(FLAGS_etcd_host, FLAGS_base_service, put_cb, del_cb);

    // user_info.set_nickname("猪妈妈");
    // user_info.set_user_id("1d56-513d8e49-0002");
    // user_info.set_description("这是一个美丽的猪妈妈");
    // user_info.set_phone("15929917272");
    // user_info.set_avatar("猪妈妈头像数据");

    LOG_DEBUG("开始测试!");
    return RUN_ALL_TESTS();
}

编译我们的程序:
在这里插入图片描述
编译成功之后,打开我们的文件服务,以及用户服务,测试客户端:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在es这边我们也是可以查新到数据的!
在这里插入图片描述
这里说明我们的用户注册模块式没问题的!

接下来测试用户登录,获取用户信息,设置用户头像,设置用户签名以及设置用户昵称昵称:
```user_client.cc``

#include "etcd.hpp"
#include "channel.hpp"
#include "utils.hpp"
#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include <thread>
#include "user.pb.h"
#include "base.pb.h"

DEFINE_bool(run_mode, false, "程序的运行模式,false-调试; true-发布;");
DEFINE_string(log_file, "", "发布模式下,用于指定日志的输出文件");
DEFINE_int32(log_level, 0, "发布模式下,用于指定日志输出等级");

DEFINE_string(etcd_host, "http://127.0.0.1:2379", "服务注册中心地址");
DEFINE_string(base_service, "/service", "服务监控根目录");
DEFINE_string(user_service, "/service/user_service", "服务监控根目录");

bite_im::ServiceManager::ptr _user_channels; // 定义智能指针

bite_im::UserInfo user_info; // 数据定义

std::string login_ssid;
std::string new_nickname = "亲爱的猪妈妈";

//这里我们数据已经添加好了,直接注释掉即可
// TEST(用户子服务测试, 用户注册测试)
// {
//     auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
//     ASSERT_TRUE(channel);
//     user_info.set_nickname("猪妈妈");

//     bite_im::UserRegisterReq req;
//     req.set_request_id(bite_im::uuid());
//     req.set_nickname(user_info.nickname());
//     req.set_password("123456");
//     bite_im::UserRegisterRsp rsp;
//     brpc::Controller cntl;
//     // rpc调用
//     bite_im::UserService_Stub stub(channel.get());
//     stub.UserRegister(&cntl, &req, &rsp, nullptr);
//     ASSERT_FALSE(cntl.Failed());
//     ASSERT_TRUE(rsp.success());
// }
TEST(用户子服务测试, 用户登录测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::UserLoginReq req;
    req.set_request_id(bite_im::uuid());
    req.set_nickname("猪妈妈");
    req.set_password("123456");
    bite_im::UserLoginRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.UserLogin(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    login_ssid = rsp.login_session_id();
}
TEST(用户子服务测试, 用户头像设置测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::SetUserAvatarReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(user_info.user_id());
    req.set_session_id(login_ssid);
    req.set_avatar(user_info.avatar());
    bite_im::SetUserAvatarRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.SetUserAvatar(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}
TEST(用户子服务测试, 用户签名设置测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::SetUserDescriptionReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(user_info.user_id());
    req.set_session_id(login_ssid);
    req.set_description(user_info.description());
    bite_im::SetUserDescriptionRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.SetUserDescription(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}
TEST(用户子服务测试, 用户昵称设置测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::SetUserNicknameReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(user_info.user_id());
    req.set_session_id(login_ssid);
    req.set_nickname(new_nickname);
    bite_im::SetUserNicknameRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.SetUserNickname(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}

TEST(用户子服务测试, 用户信息获取测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::GetUserInfoReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(user_info.user_id());
    req.set_session_id(login_ssid);
    bite_im::GetUserInfoRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.GetUserInfo(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    ASSERT_EQ(user_info.user_id(), rsp.user_info().user_id());
    ASSERT_EQ(new_nickname, rsp.user_info().nickname());
    ASSERT_EQ(user_info.description(), rsp.user_info().description());
    ASSERT_EQ("", rsp.user_info().phone());
    ASSERT_EQ(user_info.avatar(), rsp.user_info().avatar());
}
int main(int argc, char *argv[])
{

    google::ParseCommandLineFlags(&argc, &argv, true);
    bite_im::init_logger(FLAGS_run_mode, FLAGS_log_file, FLAGS_log_level);

    // 1. 先构造Rpc信道管理对象
    _user_channels = std::make_shared<bite_im::ServiceManager>(); // 构造
    _user_channels->declared(FLAGS_user_service);
    auto put_cb = std::bind(&bite_im::ServiceManager::onServiceOnline, _user_channels.get(), std::placeholders::_1, std::placeholders::_2);
    auto del_cb = std::bind(&bite_im::ServiceManager::onServiceOffline, _user_channels.get(), std::placeholders::_1, std::placeholders::_2);

    // 2. 构造服务发现对象
    bite_im::Discovery::ptr dclient = std::make_shared<bite_im::Discovery>(FLAGS_etcd_host, FLAGS_base_service, put_cb, del_cb);

    user_info.set_nickname("猪妈妈");
    user_info.set_user_id("1882-74802db0-0001");
    user_info.set_description("这是一个美丽的猪妈妈");
    user_info.set_phone("15929917272");
    user_info.set_avatar("猪妈妈头像数据");
    testing::InitGoogleTest(&argc, argv);
    LOG_DEBUG("开始测试!");
    return RUN_ALL_TESTS();
}

编译运行:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
接下来测试批量用户信息的获取测试:
user_client.cc

#include "etcd.hpp"
#include "channel.hpp"
#include "utils.hpp"
#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include <thread>
#include "user.pb.h"
#include "base.pb.h"

DEFINE_bool(run_mode, false, "程序的运行模式,false-调试; true-发布;");
DEFINE_string(log_file, "", "发布模式下,用于指定日志的输出文件");
DEFINE_int32(log_level, 0, "发布模式下,用于指定日志输出等级");

DEFINE_string(etcd_host, "http://127.0.0.1:2379", "服务注册中心地址");
DEFINE_string(base_service, "/service", "服务监控根目录");
DEFINE_string(user_service, "/service/user_service", "服务监控根目录");

bite_im::ServiceManager::ptr _user_channels; // 定义智能指针

bite_im::UserInfo user_info; // 数据定义

std::string login_ssid;
std::string new_nickname = "亲爱的猪妈妈";

// TEST(用户子服务测试, 用户注册测试)
// {
//     auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
//     ASSERT_TRUE(channel);
//     user_info.set_nickname("猪妈妈");

//     bite_im::UserRegisterReq req;
//     req.set_request_id(bite_im::uuid());
//     req.set_nickname(user_info.nickname());
//     req.set_password("123456");
//     bite_im::UserRegisterRsp rsp;
//     brpc::Controller cntl;
//     // rpc调用
//     bite_im::UserService_Stub stub(channel.get());
//     stub.UserRegister(&cntl, &req, &rsp, nullptr);
//     ASSERT_FALSE(cntl.Failed());
//     ASSERT_TRUE(rsp.success());
// }
TEST(用户子服务测试, 用户登录测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::UserLoginReq req;
    req.set_request_id(bite_im::uuid());
    req.set_nickname("亲爱的猪妈妈");
    req.set_password("123456");
    bite_im::UserLoginRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.UserLogin(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    login_ssid = rsp.login_session_id();
}
TEST(用户子服务测试, 用户头像设置测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::SetUserAvatarReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(user_info.user_id());
    req.set_session_id(login_ssid);
    req.set_avatar(user_info.avatar());
    bite_im::SetUserAvatarRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.SetUserAvatar(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}
TEST(用户子服务测试, 用户签名设置测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::SetUserDescriptionReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(user_info.user_id());
    req.set_session_id(login_ssid);
    req.set_description(user_info.description());
    bite_im::SetUserDescriptionRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.SetUserDescription(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}
TEST(用户子服务测试, 用户昵称设置测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::SetUserNicknameReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(user_info.user_id());
    req.set_session_id(login_ssid);
    req.set_nickname(new_nickname);
    bite_im::SetUserNicknameRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.SetUserNickname(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}

TEST(用户子服务测试, 用户信息获取测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::GetUserInfoReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(user_info.user_id());
    req.set_session_id(login_ssid);
    bite_im::GetUserInfoRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.GetUserInfo(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    ASSERT_EQ(user_info.user_id(), rsp.user_info().user_id());
    ASSERT_EQ(new_nickname, rsp.user_info().nickname());
    ASSERT_EQ(user_info.description(), rsp.user_info().description());
    ASSERT_EQ("", rsp.user_info().phone());
    ASSERT_EQ(user_info.avatar(), rsp.user_info().avatar());
}

// 设置用户头像接口
void set_user_avatar(const std::string &uid, const std::string &avatar)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);
    bite_im::SetUserAvatarReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(uid);
    req.set_session_id(login_ssid);
    req.set_avatar(avatar);
    bite_im::SetUserAvatarRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.SetUserAvatar(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}

TEST(用户子服务测试, 批量用户信息获取测试)
{
    set_user_avatar("用户1", "小猪佩奇的头像数据");
    set_user_avatar("用户2", "小猪乔治的头像数据");
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::GetMultiUserInfoReq req;
    req.set_request_id(bite_im::uuid());
    req.add_users_id("用户1");
    req.add_users_id("用户2");
    req.add_users_id("a83b-2d93ce70-0000");
    bite_im::GetMultiUserInfoRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.GetMultiUserInfo(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());

    auto users_map = rsp.mutable_users_info();
    bite_im::UserInfo fuser = (*users_map)["a83b-2d93ce70-0000"];
    ASSERT_EQ(fuser.user_id(), "a83b-2d93ce70-0000");
    ASSERT_EQ(fuser.nickname(), "猪爸爸");
    ASSERT_EQ(fuser.description(), "");
    ASSERT_EQ(fuser.phone(), "");
    ASSERT_EQ(fuser.avatar(), "");

    bite_im::UserInfo puser = (*users_map)["用户1"];
    ASSERT_EQ(puser.user_id(), "用户1");
    ASSERT_EQ(puser.nickname(), "小猪佩奇");
    ASSERT_EQ(puser.description(), "这是一只小猪");
    ASSERT_EQ(puser.phone(), "手机号1");
    ASSERT_EQ(puser.avatar(), "小猪佩奇的头像数据");

    bite_im::UserInfo quser = (*users_map)["用户2"];
    ASSERT_EQ(quser.user_id(), "用户2");
    ASSERT_EQ(quser.nickname(), "小猪乔治");
    ASSERT_EQ(quser.description(), "这是一只小小猪");
    ASSERT_EQ(quser.phone(), "手机号2");
    ASSERT_EQ(quser.avatar(), "小猪乔治的头像数据");
}
int main(int argc, char *argv[])
{

    google::ParseCommandLineFlags(&argc, &argv, true);
    bite_im::init_logger(FLAGS_run_mode, FLAGS_log_file, FLAGS_log_level);

    // 1. 先构造Rpc信道管理对象
    _user_channels = std::make_shared<bite_im::ServiceManager>(); // 构造
    _user_channels->declared(FLAGS_user_service);
    auto put_cb = std::bind(&bite_im::ServiceManager::onServiceOnline, _user_channels.get(), std::placeholders::_1, std::placeholders::_2);
    auto del_cb = std::bind(&bite_im::ServiceManager::onServiceOffline, _user_channels.get(), std::placeholders::_1, std::placeholders::_2);

    // 2. 构造服务发现对象
    bite_im::Discovery::ptr dclient = std::make_shared<bite_im::Discovery>(FLAGS_etcd_host, FLAGS_base_service, put_cb, del_cb);

    user_info.set_nickname("亲爱的猪妈妈");
    user_info.set_user_id("1882-74802db0-0001");
    user_info.set_description("这是一个美丽的猪妈妈");
    user_info.set_phone("15929917272");
    user_info.set_avatar("猪妈妈头像数据");
    testing::InitGoogleTest(&argc, argv);
    LOG_DEBUG("开始测试!");
    return RUN_ALL_TESTS();
}

编译运行:
在这里插入图片描述
在这里插入图片描述
接下来我们测试手机验证码的相关信息:
user_client.cc

#include "etcd.hpp"
#include "channel.hpp"
#include "utils.hpp"
#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include <thread>
#include "user.pb.h"
#include "base.pb.h"

DEFINE_bool(run_mode, false, "程序的运行模式,false-调试; true-发布;");
DEFINE_string(log_file, "", "发布模式下,用于指定日志的输出文件");
DEFINE_int32(log_level, 0, "发布模式下,用于指定日志输出等级");

DEFINE_string(etcd_host, "http://127.0.0.1:2379", "服务注册中心地址");
DEFINE_string(base_service, "/service", "服务监控根目录");
DEFINE_string(user_service, "/service/user_service", "服务监控根目录");

bite_im::ServiceManager::ptr _user_channels; // 定义智能指针

bite_im::UserInfo user_info; // 数据定义

std::string login_ssid;
std::string new_nickname = "亲爱的猪妈妈";

// TEST(用户子服务测试, 用户注册测试)
// {
//     auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
//     ASSERT_TRUE(channel);
//     user_info.set_nickname("猪妈妈");

//     bite_im::UserRegisterReq req;
//     req.set_request_id(bite_im::uuid());
//     req.set_nickname(user_info.nickname());
//     req.set_password("123456");
//     bite_im::UserRegisterRsp rsp;
//     brpc::Controller cntl;
//     // rpc调用
//     bite_im::UserService_Stub stub(channel.get());
//     stub.UserRegister(&cntl, &req, &rsp, nullptr);
//     ASSERT_FALSE(cntl.Failed());
//     ASSERT_TRUE(rsp.success());
// }
TEST(用户子服务测试, 用户登录测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::UserLoginReq req;
    req.set_request_id(bite_im::uuid());
    req.set_nickname("亲爱的猪妈妈");
    req.set_password("123456");
    bite_im::UserLoginRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.UserLogin(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    login_ssid = rsp.login_session_id();
}
TEST(用户子服务测试, 用户头像设置测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::SetUserAvatarReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(user_info.user_id());
    req.set_session_id(login_ssid);
    req.set_avatar(user_info.avatar());
    bite_im::SetUserAvatarRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.SetUserAvatar(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}
TEST(用户子服务测试, 用户签名设置测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::SetUserDescriptionReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(user_info.user_id());
    req.set_session_id(login_ssid);
    req.set_description(user_info.description());
    bite_im::SetUserDescriptionRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.SetUserDescription(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}
TEST(用户子服务测试, 用户昵称设置测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::SetUserNicknameReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(user_info.user_id());
    req.set_session_id(login_ssid);
    req.set_nickname(new_nickname);
    bite_im::SetUserNicknameRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.SetUserNickname(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}

TEST(用户子服务测试, 用户信息获取测试)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::GetUserInfoReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(user_info.user_id());
    req.set_session_id(login_ssid);
    bite_im::GetUserInfoRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.GetUserInfo(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    ASSERT_EQ(user_info.user_id(), rsp.user_info().user_id());
    ASSERT_EQ(new_nickname, rsp.user_info().nickname());
    ASSERT_EQ(user_info.description(), rsp.user_info().description());
    ASSERT_EQ("", rsp.user_info().phone());
    ASSERT_EQ(user_info.avatar(), rsp.user_info().avatar());
}

// 设置用户头像接口
void set_user_avatar(const std::string &uid, const std::string &avatar)
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);
    bite_im::SetUserAvatarReq req;
    req.set_request_id(bite_im::uuid());
    req.set_user_id(uid);
    req.set_session_id(login_ssid);
    req.set_avatar(avatar);
    bite_im::SetUserAvatarRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.SetUserAvatar(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}

TEST(用户子服务测试, 批量用户信息获取测试)
{
    set_user_avatar("用户1", "小猪佩奇的头像数据");
    set_user_avatar("用户2", "小猪乔治的头像数据");
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::GetMultiUserInfoReq req;
    req.set_request_id(bite_im::uuid());
    req.add_users_id("用户1");
    req.add_users_id("用户2");
    req.add_users_id("a83b-2d93ce70-0000");
    bite_im::GetMultiUserInfoRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.GetMultiUserInfo(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());

    auto users_map = rsp.mutable_users_info();
    bite_im::UserInfo fuser = (*users_map)["a83b-2d93ce70-0000"];
    ASSERT_EQ(fuser.user_id(), "a83b-2d93ce70-0000");
    ASSERT_EQ(fuser.nickname(), "猪爸爸");
    ASSERT_EQ(fuser.description(), "");
    ASSERT_EQ(fuser.phone(), "");
    ASSERT_EQ(fuser.avatar(), "");

    bite_im::UserInfo puser = (*users_map)["用户1"];
    ASSERT_EQ(puser.user_id(), "用户1");
    ASSERT_EQ(puser.nickname(), "小猪佩奇");
    ASSERT_EQ(puser.description(), "这是一只小猪");
    ASSERT_EQ(puser.phone(), "手机号1");
    ASSERT_EQ(puser.avatar(), "小猪佩奇的头像数据");

    bite_im::UserInfo quser = (*users_map)["用户2"];
    ASSERT_EQ(quser.user_id(), "用户2");
    ASSERT_EQ(quser.nickname(), "小猪乔治");
    ASSERT_EQ(quser.description(), "这是一只小小猪");
    ASSERT_EQ(quser.phone(), "手机号2");
    ASSERT_EQ(quser.avatar(), "小猪乔治的头像数据");
}

// 获取验证码接口
std::string code_id;
void get_code()
{
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::PhoneVerifyCodeReq req;
    req.set_request_id(bite_im::uuid());
    req.set_phone_number(user_info.phone());
    bite_im::PhoneVerifyCodeRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.GetPhoneVerifyCode(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    code_id = rsp.verify_code_id();
}

TEST(用户子服务测试, 手机号注册)
{
    get_code();
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::PhoneRegisterReq req;
    req.set_request_id(bite_im::uuid());
    req.set_phone_number(user_info.phone());
    req.set_verify_code_id(code_id);
    std::cout << "手机号注册,输入验证码:" << std::endl;
    std::string code;
    std::cin >> code;
    req.set_verify_code(code);
    bite_im::PhoneRegisterRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.PhoneRegister(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}
TEST(用户子服务测试, 手机号登录)
{
    std::this_thread::sleep_for(std::chrono::seconds(3)); // 睡上3秒钟
    get_code();
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::PhoneLoginReq req;
    req.set_request_id(bite_im::uuid());
    req.set_phone_number(user_info.phone());
    req.set_verify_code_id(code_id);
    std::cout << "手机号登录,输入验证码:" << std::endl;
    std::string code;
    std::cin >> code;
    req.set_verify_code(code);
    bite_im::PhoneLoginRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.PhoneLogin(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
    std::cout << "手机登录会话ID:" << rsp.login_session_id() << std::endl;
}

TEST(用户子服务测试, 手机号设置)
{
    std::this_thread::sleep_for(std::chrono::seconds(10));
    get_code();
    auto channel = _user_channels->choose(FLAGS_user_service); // 获取通信信道
    ASSERT_TRUE(channel);

    bite_im::SetUserPhoneNumberReq req;
    req.set_request_id(bite_im::uuid());
    std::cout << "手机号设置时,输入用户ID:" << std::endl;
    std::string user_id;
    std::cin >> user_id;
    req.set_user_id(user_id);
    req.set_phone_number("18888888888");
    req.set_phone_verify_code_id(code_id);
    std::cout << "手机号设置时,输入验证码:" << std::endl;
    std::string code;
    std::cin >> code;
    req.set_phone_verify_code(code);
    bite_im::SetUserPhoneNumberRsp rsp;
    brpc::Controller cntl;
    bite_im::UserService_Stub stub(channel.get());
    stub.SetUserPhoneNumber(&cntl, &req, &rsp, nullptr);
    ASSERT_FALSE(cntl.Failed());
    ASSERT_TRUE(rsp.success());
}

int main(int argc, char *argv[])
{

    google::ParseCommandLineFlags(&argc, &argv, true);
    bite_im::init_logger(FLAGS_run_mode, FLAGS_log_file, FLAGS_log_level);

    // 1. 先构造Rpc信道管理对象
    _user_channels = std::make_shared<bite_im::ServiceManager>(); // 构造
    _user_channels->declared(FLAGS_user_service);
    auto put_cb = std::bind(&bite_im::ServiceManager::onServiceOnline, _user_channels.get(), std::placeholders::_1, std::placeholders::_2);
    auto del_cb = std::bind(&bite_im::ServiceManager::onServiceOffline, _user_channels.get(), std::placeholders::_1, std::placeholders::_2);

    // 2. 构造服务发现对象
    bite_im::Discovery::ptr dclient = std::make_shared<bite_im::Discovery>(FLAGS_etcd_host, FLAGS_base_service, put_cb, del_cb);

    user_info.set_nickname("猪妈妈");
    user_info.set_user_id("1882-74802db0-0001");
    user_info.set_description("这是一个美丽的猪妈妈");
    user_info.set_phone("15929917272");
    user_info.set_avatar("猪妈妈头像数据");
    testing::InitGoogleTest(&argc, argv);
    LOG_DEBUG("开始测试!");
    return RUN_ALL_TESTS();
}

编译运行:
客户端:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐