feat: 完成源晶权限与经验系统并优化 me/admin 交互
这个提交包含在:
149
backend/tests/lark_http_test.cc
普通文件
149
backend/tests/lark_http_test.cc
普通文件
@@ -0,0 +1,149 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "csp/app_state.h"
|
||||
#include "csp/controllers/lark_controller.h"
|
||||
#include "csp/services/crawler_service.h"
|
||||
#include "csp/services/lark_bot_service.h"
|
||||
|
||||
#include <drogon/HttpRequest.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <future>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
|
||||
class ScopedEnv {
|
||||
public:
|
||||
ScopedEnv(std::string key, std::optional<std::string> value)
|
||||
: key_(std::move(key)) {
|
||||
const char* old = std::getenv(key_.c_str());
|
||||
if (old) old_ = std::string(old);
|
||||
if (value.has_value()) {
|
||||
::setenv(key_.c_str(), value->c_str(), 1);
|
||||
} else {
|
||||
::unsetenv(key_.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
~ScopedEnv() {
|
||||
if (old_.has_value()) {
|
||||
::setenv(key_.c_str(), old_->c_str(), 1);
|
||||
} else {
|
||||
::unsetenv(key_.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::string key_;
|
||||
std::optional<std::string> old_;
|
||||
};
|
||||
|
||||
drogon::HttpResponsePtr CallEvents(csp::controllers::LarkController& ctl,
|
||||
const Json::Value& body) {
|
||||
auto req = drogon::HttpRequest::newHttpJsonRequest(body);
|
||||
req->setMethod(drogon::Post);
|
||||
std::promise<drogon::HttpResponsePtr> p;
|
||||
ctl.events(req, [&p](const drogon::HttpResponsePtr& resp) { p.set_value(resp); });
|
||||
return p.get_future().get();
|
||||
}
|
||||
|
||||
Json::Value MakeTextEventBody() {
|
||||
Json::Value body;
|
||||
body["header"]["event_type"] = "im.message.receive_v1";
|
||||
body["header"]["event_id"] = "evt-1";
|
||||
body["event"]["sender"]["sender_id"]["open_id"] = "ou_xxx";
|
||||
body["event"]["message"]["message_type"] = "text";
|
||||
body["event"]["message"]["message_id"] = "om_xxx";
|
||||
body["event"]["message"]["chat_id"] = "oc_xxx";
|
||||
Json::Value content;
|
||||
content["text"] = "你好";
|
||||
Json::StreamWriterBuilder wb;
|
||||
wb["indentation"] = "";
|
||||
body["event"]["message"]["content"] = Json::writeString(wb, content);
|
||||
return body;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("lark url verification challenge pass") {
|
||||
ScopedEnv enabled("CSP_LARK_BOT_ENABLED", "1");
|
||||
ScopedEnv token("CSP_LARK_VERIFICATION_TOKEN", "verify_token");
|
||||
ScopedEnv app_id("CSP_LARK_APP_ID", "cli_test");
|
||||
ScopedEnv app_secret("CSP_LARK_APP_SECRET", "secret_test");
|
||||
csp::services::LarkBotService::Instance().ConfigureFromEnv();
|
||||
|
||||
csp::controllers::LarkController ctl;
|
||||
Json::Value body;
|
||||
body["challenge"] = "challenge-abc";
|
||||
body["token"] = "verify_token";
|
||||
auto resp = CallEvents(ctl, body);
|
||||
|
||||
REQUIRE(resp->statusCode() == drogon::k200OK);
|
||||
const auto json = resp->jsonObject();
|
||||
REQUIRE(json != nullptr);
|
||||
REQUIRE((*json)["challenge"].asString() == "challenge-abc");
|
||||
}
|
||||
|
||||
TEST_CASE("lark url verification token mismatch") {
|
||||
ScopedEnv enabled("CSP_LARK_BOT_ENABLED", "1");
|
||||
ScopedEnv token("CSP_LARK_VERIFICATION_TOKEN", "verify_token");
|
||||
ScopedEnv app_id("CSP_LARK_APP_ID", "cli_test");
|
||||
ScopedEnv app_secret("CSP_LARK_APP_SECRET", "secret_test");
|
||||
csp::services::LarkBotService::Instance().ConfigureFromEnv();
|
||||
|
||||
csp::controllers::LarkController ctl;
|
||||
Json::Value body;
|
||||
body["challenge"] = "challenge-abc";
|
||||
body["token"] = "bad_token";
|
||||
auto resp = CallEvents(ctl, body);
|
||||
|
||||
REQUIRE(resp->statusCode() == drogon::k401Unauthorized);
|
||||
}
|
||||
|
||||
TEST_CASE("lark events ignored when bot disabled") {
|
||||
ScopedEnv enabled("CSP_LARK_BOT_ENABLED", "0");
|
||||
ScopedEnv token("CSP_LARK_VERIFICATION_TOKEN", std::nullopt);
|
||||
ScopedEnv app_id("CSP_LARK_APP_ID", std::nullopt);
|
||||
ScopedEnv app_secret("CSP_LARK_APP_SECRET", std::nullopt);
|
||||
csp::services::LarkBotService::Instance().ConfigureFromEnv();
|
||||
|
||||
csp::controllers::LarkController ctl;
|
||||
auto resp = CallEvents(ctl, MakeTextEventBody());
|
||||
|
||||
REQUIRE(resp->statusCode() == drogon::k200OK);
|
||||
const auto json = resp->jsonObject();
|
||||
REQUIRE(json != nullptr);
|
||||
REQUIRE((*json)["code"].asInt() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("lark text url queued into crawler targets") {
|
||||
csp::AppState::Instance().Init(":memory:");
|
||||
ScopedEnv enabled("CSP_LARK_BOT_ENABLED", "1");
|
||||
ScopedEnv token("CSP_LARK_VERIFICATION_TOKEN", std::nullopt);
|
||||
ScopedEnv app_id("CSP_LARK_APP_ID", "cli_test");
|
||||
ScopedEnv app_secret("CSP_LARK_APP_SECRET", "secret_test");
|
||||
ScopedEnv open_base("CSP_LARK_OPEN_BASE_URL", "invalid-url");
|
||||
csp::services::LarkBotService::Instance().ConfigureFromEnv();
|
||||
|
||||
csp::controllers::LarkController ctl;
|
||||
auto body = MakeTextEventBody();
|
||||
Json::Value content;
|
||||
content["text"] = "请收录 https://one.hao.work/news/?a=1";
|
||||
Json::StreamWriterBuilder wb;
|
||||
wb["indentation"] = "";
|
||||
body["event"]["message"]["content"] = Json::writeString(wb, content);
|
||||
|
||||
auto resp = CallEvents(ctl, body);
|
||||
REQUIRE(resp->statusCode() == drogon::k200OK);
|
||||
const auto json = resp->jsonObject();
|
||||
REQUIRE(json != nullptr);
|
||||
REQUIRE((*json)["code"].asInt() == 0);
|
||||
REQUIRE((*json)["msg"].asString() == "crawler targets queued");
|
||||
|
||||
csp::services::CrawlerService crawler(csp::AppState::Instance().db());
|
||||
const auto targets = crawler.ListTargets("", 10);
|
||||
REQUIRE(targets.size() == 1);
|
||||
REQUIRE(targets[0].normalized_url == "https://one.hao.work/news");
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户