150 行
4.9 KiB
C++
150 行
4.9 KiB
C++
#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");
|
|
}
|