-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
364 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,4 +8,5 @@ members = [ | |
"cache", | ||
"mq", | ||
"todos", | ||
"perf-test", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "tardis-example-perf-test" | ||
version = "0.1.0" | ||
authors = ["gudaoxuri"] | ||
edition = "2021" | ||
|
||
[dependencies] | ||
# Tardis Functions | ||
tardis = { path = "../..", features = ["web-server", "reldb"] } | ||
# Web server dependencies | ||
poem-openapi = { version = "^1.3" } | ||
# Reldb dependencies | ||
sea-orm = { version = "^0.6", features = ["macros"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[app] | ||
id = "perf-test" | ||
name = "性能测试" | ||
desc = "性能测试" | ||
version = "1.0.0" | ||
|
||
[web_server] | ||
port = 8089 | ||
[[web_server.modules]] | ||
code = "" | ||
title = "性能测试" | ||
doc_urls = [["test env", "http://localhost:8089/"]] | ||
|
||
[db] | ||
url = "mysql://root:123456@localhost:3306/test" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.4.3"> | ||
<hashTree> | ||
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true"> | ||
<stringProp name="TestPlan.comments"></stringProp> | ||
<boolProp name="TestPlan.functional_mode">false</boolProp> | ||
<boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp> | ||
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp> | ||
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true"> | ||
<collectionProp name="Arguments.arguments"/> | ||
</elementProp> | ||
<stringProp name="TestPlan.user_define_classpath"></stringProp> | ||
</TestPlan> | ||
<hashTree> | ||
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true"> | ||
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp> | ||
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true"> | ||
<boolProp name="LoopController.continue_forever">false</boolProp> | ||
<intProp name="LoopController.loops">-1</intProp> | ||
</elementProp> | ||
<stringProp name="ThreadGroup.num_threads">40</stringProp> | ||
<stringProp name="ThreadGroup.ramp_time">1</stringProp> | ||
<boolProp name="ThreadGroup.scheduler">false</boolProp> | ||
<stringProp name="ThreadGroup.duration"></stringProp> | ||
<stringProp name="ThreadGroup.delay"></stringProp> | ||
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp> | ||
</ThreadGroup> | ||
<hashTree> | ||
<HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true"> | ||
<collectionProp name="HeaderManager.headers"> | ||
<elementProp name="" elementType="Header"> | ||
<stringProp name="Header.name">Content-Type</stringProp> | ||
<stringProp name="Header.value">application/json</stringProp> | ||
</elementProp> | ||
</collectionProp> | ||
</HeaderManager> | ||
<hashTree/> | ||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="post_data" enabled="false"> | ||
<boolProp name="HTTPSampler.postBodyRaw">true</boolProp> | ||
<elementProp name="HTTPsampler.Arguments" elementType="Arguments"> | ||
<collectionProp name="Arguments.arguments"> | ||
<elementProp name="" elementType="HTTPArgument"> | ||
<boolProp name="HTTPArgument.always_encode">false</boolProp> | ||
<stringProp name="Argument.value">{
 | ||
"description": "AA",
 | ||
"done": false
 | ||
}</stringProp> | ||
<stringProp name="Argument.metadata">=</stringProp> | ||
</elementProp> | ||
</collectionProp> | ||
</elementProp> | ||
<stringProp name="HTTPSampler.domain">127.0.0.1</stringProp> | ||
<stringProp name="HTTPSampler.port">8089</stringProp> | ||
<stringProp name="HTTPSampler.protocol"></stringProp> | ||
<stringProp name="HTTPSampler.contentEncoding"></stringProp> | ||
<stringProp name="HTTPSampler.path">todo</stringProp> | ||
<stringProp name="HTTPSampler.method">POST</stringProp> | ||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp> | ||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp> | ||
<boolProp name="HTTPSampler.use_keepalive">true</boolProp> | ||
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> | ||
<stringProp name="HTTPSampler.embedded_url_re"></stringProp> | ||
<stringProp name="HTTPSampler.connect_timeout"></stringProp> | ||
<stringProp name="HTTPSampler.response_timeout"></stringProp> | ||
</HTTPSamplerProxy> | ||
<hashTree/> | ||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="get_data" enabled="true"> | ||
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true"> | ||
<collectionProp name="Arguments.arguments"> | ||
<elementProp name="page_number" elementType="HTTPArgument"> | ||
<boolProp name="HTTPArgument.always_encode">false</boolProp> | ||
<stringProp name="Argument.value">1</stringProp> | ||
<stringProp name="Argument.metadata">=</stringProp> | ||
<boolProp name="HTTPArgument.use_equals">true</boolProp> | ||
<stringProp name="Argument.name">page_number</stringProp> | ||
</elementProp> | ||
<elementProp name="page_size" elementType="HTTPArgument"> | ||
<boolProp name="HTTPArgument.always_encode">false</boolProp> | ||
<stringProp name="Argument.value">10</stringProp> | ||
<stringProp name="Argument.metadata">=</stringProp> | ||
<boolProp name="HTTPArgument.use_equals">true</boolProp> | ||
<stringProp name="Argument.name">page_size</stringProp> | ||
</elementProp> | ||
</collectionProp> | ||
</elementProp> | ||
<stringProp name="HTTPSampler.domain">127.0.0.1</stringProp> | ||
<stringProp name="HTTPSampler.port">8089</stringProp> | ||
<stringProp name="HTTPSampler.protocol"></stringProp> | ||
<stringProp name="HTTPSampler.contentEncoding"></stringProp> | ||
<stringProp name="HTTPSampler.path">todo</stringProp> | ||
<stringProp name="HTTPSampler.method">GET</stringProp> | ||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp> | ||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp> | ||
<boolProp name="HTTPSampler.use_keepalive">true</boolProp> | ||
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> | ||
<stringProp name="HTTPSampler.embedded_url_re"></stringProp> | ||
<stringProp name="HTTPSampler.connect_timeout"></stringProp> | ||
<stringProp name="HTTPSampler.response_timeout"></stringProp> | ||
</HTTPSamplerProxy> | ||
<hashTree/> | ||
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="false"> | ||
<boolProp name="ResultCollector.error_logging">false</boolProp> | ||
<objProp> | ||
<name>saveConfig</name> | ||
<value class="SampleSaveConfiguration"> | ||
<time>true</time> | ||
<latency>true</latency> | ||
<timestamp>true</timestamp> | ||
<success>true</success> | ||
<label>true</label> | ||
<code>true</code> | ||
<message>true</message> | ||
<threadName>true</threadName> | ||
<dataType>true</dataType> | ||
<encoding>false</encoding> | ||
<assertions>true</assertions> | ||
<subresults>true</subresults> | ||
<responseData>false</responseData> | ||
<samplerData>false</samplerData> | ||
<xml>false</xml> | ||
<fieldNames>true</fieldNames> | ||
<responseHeaders>false</responseHeaders> | ||
<requestHeaders>false</requestHeaders> | ||
<responseDataOnError>false</responseDataOnError> | ||
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage> | ||
<assertionsResultsToSave>0</assertionsResultsToSave> | ||
<bytes>true</bytes> | ||
<sentBytes>true</sentBytes> | ||
<url>true</url> | ||
<threadCounts>true</threadCounts> | ||
<idleTime>true</idleTime> | ||
<connectTime>true</connectTime> | ||
</value> | ||
</objProp> | ||
<stringProp name="filename"></stringProp> | ||
</ResultCollector> | ||
<hashTree/> | ||
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true"> | ||
<boolProp name="ResultCollector.error_logging">false</boolProp> | ||
<objProp> | ||
<name>saveConfig</name> | ||
<value class="SampleSaveConfiguration"> | ||
<time>true</time> | ||
<latency>true</latency> | ||
<timestamp>true</timestamp> | ||
<success>true</success> | ||
<label>true</label> | ||
<code>true</code> | ||
<message>true</message> | ||
<threadName>true</threadName> | ||
<dataType>true</dataType> | ||
<encoding>false</encoding> | ||
<assertions>true</assertions> | ||
<subresults>true</subresults> | ||
<responseData>false</responseData> | ||
<samplerData>false</samplerData> | ||
<xml>false</xml> | ||
<fieldNames>true</fieldNames> | ||
<responseHeaders>false</responseHeaders> | ||
<requestHeaders>false</requestHeaders> | ||
<responseDataOnError>false</responseDataOnError> | ||
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage> | ||
<assertionsResultsToSave>0</assertionsResultsToSave> | ||
<bytes>true</bytes> | ||
<sentBytes>true</sentBytes> | ||
<url>true</url> | ||
<threadCounts>true</threadCounts> | ||
<idleTime>true</idleTime> | ||
<connectTime>true</connectTime> | ||
</value> | ||
</objProp> | ||
<stringProp name="filename"></stringProp> | ||
</ResultCollector> | ||
<hashTree/> | ||
</hashTree> | ||
</hashTree> | ||
</hashTree> | ||
</jmeterTestPlan> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod todos; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
use sea_orm::entity::prelude::*; | ||
|
||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] | ||
#[sea_orm(table_name = "todos")] | ||
pub struct Model { | ||
#[sea_orm(primary_key)] | ||
pub id: i32, | ||
pub description: String, | ||
pub done: bool, | ||
} | ||
|
||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] | ||
pub enum Relation {} | ||
|
||
impl ActiveModelBehavior for ActiveModel {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
use tardis::basic::result::TardisResult; | ||
use tardis::TardisFuns; | ||
|
||
use crate::domain; | ||
|
||
pub async fn init() -> TardisResult<()> { | ||
TardisFuns::reldb().create_table_from_entity(domain::todos::Entity).await?; | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
use std::env; | ||
|
||
use tardis::basic::config::NoneConfig; | ||
use tardis::basic::result::TardisResult; | ||
use tardis::tokio; | ||
use tardis::TardisFuns; | ||
|
||
use crate::processor::TodoApi; | ||
|
||
mod domain; | ||
mod initializer; | ||
mod processor; | ||
|
||
/// | ||
/// Visit: http://127.0.0.1:8089/ui | ||
/// | ||
#[tokio::main] | ||
async fn main() -> TardisResult<()> { | ||
env::set_var("RUST_LOG", "info"); | ||
// Initial | ||
TardisFuns::init::<NoneConfig>("config").await?; | ||
initializer::init().await?; | ||
// Register the processor and start the web service | ||
TardisFuns::web_server().add_module("", TodoApi).start().await | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use poem_openapi::param::Query; | ||
use poem_openapi::{param::Path, payload::Json, Object, OpenApi}; | ||
use sea_orm::sea_query::Expr; | ||
use sea_orm::ActiveValue::Set; | ||
use sea_orm::*; | ||
|
||
use tardis::db::reldb_client::TardisSeaORMExtend; | ||
use tardis::serde::{self, Deserialize, Serialize}; | ||
use tardis::web::web_resp::{TardisPage, TardisResp}; | ||
use tardis::TardisFuns; | ||
|
||
use crate::domain::todos; | ||
|
||
#[derive(Object, FromQueryResult, Serialize, Deserialize, Debug)] | ||
#[serde(crate = "self::serde")] | ||
struct TodoDetailResp { | ||
id: i32, | ||
description: String, | ||
done: bool, | ||
} | ||
|
||
#[derive(Object, Serialize, Deserialize, Debug)] | ||
#[serde(crate = "self::serde")] | ||
struct TodoAddReq { | ||
#[oai(validator(min_length = "2", max_length = "255"))] | ||
description: String, | ||
done: bool, | ||
} | ||
|
||
#[derive(Object, Serialize, Deserialize, Debug)] | ||
#[serde(crate = "self::serde")] | ||
struct TodoModifyReq { | ||
#[oai(validator(min_length = "2", max_length = "255"))] | ||
description: Option<String>, | ||
done: Option<bool>, | ||
} | ||
|
||
pub struct TodoApi; | ||
|
||
#[OpenApi] | ||
impl TodoApi { | ||
#[oai(path = "/todo", method = "post")] | ||
async fn add(&self, todo_add_req: Json<TodoAddReq>) -> TardisResp<i32> { | ||
let todo = todos::ActiveModel { | ||
description: Set(todo_add_req.description.to_string()), | ||
done: Set(todo_add_req.done), | ||
..Default::default() | ||
} | ||
.insert(TardisFuns::reldb().conn()) | ||
.await | ||
.unwrap(); | ||
TardisResp::ok(todo.id) | ||
} | ||
|
||
#[oai(path = "/todo/:id", method = "get")] | ||
async fn get(&self, id: Path<i32>) -> TardisResp<TodoDetailResp> { | ||
let todo_detail_resp = todos::Entity::find() | ||
.filter(todos::Column::Id.eq(id.0)) | ||
.select_only() | ||
.column(todos::Column::Id) | ||
.column(todos::Column::Description) | ||
.column(todos::Column::Done) | ||
.into_model::<TodoDetailResp>() | ||
.one(TardisFuns::reldb().conn()) | ||
.await | ||
.unwrap() | ||
.unwrap(); | ||
TardisResp::ok(todo_detail_resp) | ||
} | ||
|
||
#[oai(path = "/todo", method = "get")] | ||
async fn get_all(&self, page_number: Query<usize>, page_size: Query<usize>) -> TardisResp<TardisPage<TodoDetailResp>> { | ||
let result = todos::Entity::find() | ||
.select_only() | ||
.column(todos::Column::Id) | ||
.column(todos::Column::Description) | ||
.column(todos::Column::Done) | ||
.order_by_desc(todos::Column::Id) | ||
.into_model::<TodoDetailResp>() | ||
.paginate(TardisFuns::reldb().conn(), page_size.0); | ||
TardisResp::ok(TardisPage { | ||
page_size: page_size.0, | ||
page_number: result.num_pages().await.unwrap(), | ||
total_size: result.num_items().await.unwrap(), | ||
records: result.fetch_page(page_number.0 - 1).await.unwrap(), | ||
}) | ||
} | ||
|
||
#[oai(path = "/todo/:id", method = "delete")] | ||
async fn delete(&self, id: Path<i32>) -> TardisResp<usize> { | ||
let delete_num = todos::Entity::find().filter(todos::Column::Id.eq(id.0)).soft_delete(TardisFuns::reldb().conn(), "").await.unwrap(); | ||
TardisResp::ok(delete_num) | ||
} | ||
|
||
#[oai(path = "/todo/:id", method = "put")] | ||
async fn update(&self, id: Path<i32>, todo_modify_req: Json<TodoModifyReq>) -> TardisResp<usize> { | ||
let mut update = todos::Entity::update_many().filter(todos::Column::Id.eq(id.0)); | ||
if let Some(description) = &todo_modify_req.description { | ||
update = update.col_expr(todos::Column::Description, Expr::value(description.clone())); | ||
} | ||
if let Some(done) = todo_modify_req.done { | ||
update = update.col_expr(todos::Column::Done, Expr::value(done)); | ||
} | ||
let update_num = update.exec(TardisFuns::reldb().conn()).await.unwrap().rows_affected; | ||
TardisResp::ok(update_num as usize) | ||
} | ||
} |