helper.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. use backend::{
  2. application::{get_connection_pool, Application},
  3. config::{get_configuration, DatabaseSettings},
  4. };
  5. use flowy_document::{
  6. entities::doc::{Doc, QueryDocParams},
  7. prelude::*,
  8. };
  9. use flowy_user::{errors::UserError, prelude::*};
  10. use flowy_workspace::prelude::{server::*, *};
  11. use sqlx::{Connection, Executor, PgConnection, PgPool};
  12. use uuid::Uuid;
  13. pub struct TestUserServer {
  14. pub host: String,
  15. pub port: u16,
  16. pub pg_pool: PgPool,
  17. pub user_token: Option<String>,
  18. pub user_id: Option<String>,
  19. }
  20. impl TestUserServer {
  21. pub async fn new() -> Self {
  22. let mut server: TestUserServer = spawn_server().await.into();
  23. let response = server.register_user().await;
  24. server.user_token = Some(response.token);
  25. server.user_id = Some(response.user_id);
  26. server
  27. }
  28. pub async fn sign_in(&self, params: SignInParams) -> Result<SignInResponse, UserError> {
  29. let url = format!("{}/api/auth", self.http_addr());
  30. user_sign_in_request(params, &url).await
  31. }
  32. pub async fn sign_out(&self) {
  33. let url = format!("{}/api/auth", self.http_addr());
  34. let _ = user_sign_out_request(self.user_token(), &url).await.unwrap();
  35. }
  36. pub fn user_token(&self) -> &str { self.user_token.as_ref().expect("must call register_user first ") }
  37. pub fn user_id(&self) -> &str { self.user_id.as_ref().expect("must call register_user first ") }
  38. pub async fn get_user_profile(&self) -> UserProfile {
  39. let url = format!("{}/api/user", self.http_addr());
  40. let user_profile = get_user_profile_request(self.user_token(), &url).await.unwrap();
  41. user_profile
  42. }
  43. pub async fn update_user_profile(&self, params: UpdateUserParams) -> Result<(), UserError> {
  44. let url = format!("{}/api/user", self.http_addr());
  45. update_user_profile_request(self.user_token(), params, &url).await
  46. }
  47. pub async fn create_workspace(&self, params: CreateWorkspaceParams) -> Workspace {
  48. let url = format!("{}/api/workspace", self.http_addr());
  49. let workspace = create_workspace_request(self.user_token(), params, &url).await.unwrap();
  50. workspace
  51. }
  52. pub async fn read_workspaces(&self, params: QueryWorkspaceParams) -> RepeatedWorkspace {
  53. let url = format!("{}/api/workspace", self.http_addr());
  54. let workspaces = read_workspaces_request(self.user_token(), params, &url).await.unwrap();
  55. workspaces
  56. }
  57. pub async fn update_workspace(&self, params: UpdateWorkspaceParams) {
  58. let url = format!("{}/api/workspace", self.http_addr());
  59. update_workspace_request(self.user_token(), params, &url).await.unwrap();
  60. }
  61. pub async fn delete_workspace(&self, params: DeleteWorkspaceParams) {
  62. let url = format!("{}/api/workspace", self.http_addr());
  63. delete_workspace_request(self.user_token(), params, &url).await.unwrap();
  64. }
  65. pub async fn create_app(&self, params: CreateAppParams) -> App {
  66. let url = format!("{}/api/app", self.http_addr());
  67. let app = create_app_request(self.user_token(), params, &url).await.unwrap();
  68. app
  69. }
  70. pub async fn read_app(&self, params: QueryAppParams) -> Option<App> {
  71. let url = format!("{}/api/app", self.http_addr());
  72. let app = read_app_request(self.user_token(), params, &url).await.unwrap();
  73. app
  74. }
  75. pub async fn update_app(&self, params: UpdateAppParams) {
  76. let url = format!("{}/api/app", self.http_addr());
  77. update_app_request(self.user_token(), params, &url).await.unwrap();
  78. }
  79. pub async fn delete_app(&self, params: DeleteAppParams) {
  80. let url = format!("{}/api/app", self.http_addr());
  81. delete_app_request(self.user_token(), params, &url).await.unwrap();
  82. }
  83. pub async fn create_view(&self, params: CreateViewParams) -> View {
  84. let url = format!("{}/api/view", self.http_addr());
  85. let view = create_view_request(self.user_token(), params, &url).await.unwrap();
  86. view
  87. }
  88. pub async fn read_view(&self, params: QueryViewParams) -> Option<View> {
  89. let url = format!("{}/api/view", self.http_addr());
  90. let view = read_view_request(self.user_token(), params, &url).await.unwrap();
  91. view
  92. }
  93. pub async fn update_view(&self, params: UpdateViewParams) {
  94. let url = format!("{}/api/view", self.http_addr());
  95. update_view_request(self.user_token(), params, &url).await.unwrap();
  96. }
  97. pub async fn delete_view(&self, params: DeleteViewParams) {
  98. let url = format!("{}/api/view", self.http_addr());
  99. delete_view_request(self.user_token(), params, &url).await.unwrap();
  100. }
  101. pub async fn read_doc(&self, params: QueryDocParams) -> Option<Doc> {
  102. let url = format!("{}/api/doc", self.http_addr());
  103. let doc = read_doc_request(self.user_token(), params, &url).await.unwrap();
  104. doc
  105. }
  106. pub async fn register_user(&self) -> SignUpResponse {
  107. let params = SignUpParams {
  108. email: "[email protected]".to_string(),
  109. name: "annie".to_string(),
  110. password: "HelloAppFlowy123!".to_string(),
  111. };
  112. self.register(params).await
  113. }
  114. pub async fn register(&self, params: SignUpParams) -> SignUpResponse {
  115. let url = format!("{}/api/register", self.http_addr());
  116. let response = user_sign_up_request(params, &url).await.unwrap();
  117. response
  118. }
  119. pub fn http_addr(&self) -> String { format!("http://{}", self.host) }
  120. pub fn ws_addr(&self) -> String { format!("ws://{}/ws/{}", self.host, self.user_token.as_ref().unwrap()) }
  121. }
  122. impl std::convert::From<TestServer> for TestUserServer {
  123. fn from(server: TestServer) -> Self {
  124. TestUserServer {
  125. host: server.host,
  126. port: server.port,
  127. pg_pool: server.pg_pool,
  128. user_token: None,
  129. user_id: None,
  130. }
  131. }
  132. }
  133. pub async fn spawn_user_server() -> TestUserServer {
  134. let server: TestUserServer = spawn_server().await.into();
  135. server
  136. }
  137. pub struct TestServer {
  138. pub host: String,
  139. pub port: u16,
  140. pub pg_pool: PgPool,
  141. }
  142. pub async fn spawn_server() -> TestServer {
  143. let database_name = format!("{}", Uuid::new_v4().to_string());
  144. let configuration = {
  145. let mut c = get_configuration().expect("Failed to read configuration.");
  146. c.database.database_name = database_name.clone();
  147. // Use a random OS port
  148. c.application.port = 0;
  149. c
  150. };
  151. let _ = configure_database(&configuration.database).await;
  152. let application = Application::build(configuration.clone())
  153. .await
  154. .expect("Failed to build application.");
  155. let application_port = application.port();
  156. let _ = tokio::spawn(async {
  157. let _ = application.run_until_stopped();
  158. // drop_test_database(database_name).await;
  159. });
  160. TestServer {
  161. host: format!("localhost:{}", application_port),
  162. port: application_port,
  163. pg_pool: get_connection_pool(&configuration.database)
  164. .await
  165. .expect("Failed to connect to the database"),
  166. }
  167. }
  168. async fn configure_database(config: &DatabaseSettings) -> PgPool {
  169. // Create database
  170. let mut connection = PgConnection::connect_with(&config.without_db())
  171. .await
  172. .expect("Failed to connect to Postgres");
  173. connection
  174. .execute(&*format!(r#"CREATE DATABASE "{}";"#, config.database_name))
  175. .await
  176. .expect("Failed to create database.");
  177. // Migrate database
  178. let connection_pool = PgPool::connect_with(config.with_db())
  179. .await
  180. .expect("Failed to connect to Postgres.");
  181. sqlx::migrate!("./migrations")
  182. .run(&connection_pool)
  183. .await
  184. .expect("Failed to migrate the database");
  185. connection_pool
  186. }
  187. #[allow(dead_code)]
  188. async fn drop_test_database(database_name: String) {
  189. // https://stackoverflow.com/questions/36502401/postgres-drop-database-error-pq-cannot-drop-the-currently-open-database?rq=1
  190. let configuration = {
  191. let mut c = get_configuration().expect("Failed to read configuration.");
  192. c.database.database_name = "flowy".to_owned();
  193. c.application.port = 0;
  194. c
  195. };
  196. let mut connection = PgConnection::connect_with(&configuration.database.without_db())
  197. .await
  198. .expect("Failed to connect to Postgres");
  199. connection
  200. .execute(&*format!(r#"Drop DATABASE "{}";"#, database_name))
  201. .await
  202. .expect("Failed to drop database.");
  203. }
  204. pub async fn create_test_workspace(server: &TestUserServer) -> Workspace {
  205. let params = CreateWorkspaceParams {
  206. name: "My first workspace".to_string(),
  207. desc: "This is my first workspace".to_string(),
  208. };
  209. let workspace = server.create_workspace(params).await;
  210. workspace
  211. }
  212. pub async fn create_test_app(server: &TestUserServer, workspace_id: &str) -> App {
  213. let params = CreateAppParams {
  214. workspace_id: workspace_id.to_owned(),
  215. name: "My first app".to_string(),
  216. desc: "This is my first app".to_string(),
  217. color_style: ColorStyle::default(),
  218. };
  219. let app = server.create_app(params).await;
  220. app
  221. }
  222. pub async fn create_test_view(application: &TestUserServer, app_id: &str) -> View {
  223. let name = "My first view".to_string();
  224. let desc = "This is my first view".to_string();
  225. let thumbnail = "http://1.png".to_string();
  226. let params = CreateViewParams::new(app_id.to_owned(), name, desc, ViewType::Doc, thumbnail);
  227. let app = application.create_view(params).await;
  228. app
  229. }
  230. pub struct WorkspaceTest {
  231. pub server: TestUserServer,
  232. pub workspace: Workspace,
  233. }
  234. impl WorkspaceTest {
  235. pub async fn new() -> Self {
  236. let server = TestUserServer::new().await;
  237. let workspace = create_test_workspace(&server).await;
  238. Self { server, workspace }
  239. }
  240. pub async fn create_app(&self) -> App { create_test_app(&self.server, &self.workspace.id).await }
  241. }
  242. pub struct AppTest {
  243. pub server: TestUserServer,
  244. pub workspace: Workspace,
  245. pub app: App,
  246. }
  247. impl AppTest {
  248. pub async fn new() -> Self {
  249. let server = TestUserServer::new().await;
  250. let workspace = create_test_workspace(&server).await;
  251. let app = create_test_app(&server, &workspace.id).await;
  252. Self { server, workspace, app }
  253. }
  254. }
  255. pub struct ViewTest {
  256. pub server: TestUserServer,
  257. pub workspace: Workspace,
  258. pub app: App,
  259. pub view: View,
  260. }
  261. impl ViewTest {
  262. pub async fn new() -> Self {
  263. let server = TestUserServer::new().await;
  264. let workspace = create_test_workspace(&server).await;
  265. let app = create_test_app(&server, &workspace.id).await;
  266. let view = create_test_view(&server, &app.id).await;
  267. Self {
  268. server,
  269. workspace,
  270. app,
  271. view,
  272. }
  273. }
  274. }