add wrappers for db
This commit is contained in:
parent
b36d999300
commit
3006214897
|
@ -16,16 +16,61 @@
|
||||||
|
|
||||||
namespace bserv {
|
namespace bserv {
|
||||||
|
|
||||||
|
using raw_db_connection_type = pqxx::connection;
|
||||||
|
using raw_db_transaction_type = pqxx::work;
|
||||||
|
|
||||||
|
class db_field {
|
||||||
|
private:
|
||||||
|
pqxx::field field_;
|
||||||
|
public:
|
||||||
|
db_field(const pqxx::field& field) : field_{field} {}
|
||||||
|
const char* c_str() const { return field_.c_str(); }
|
||||||
|
template <typename Type>
|
||||||
|
Type as() const { return field_.as<Type>(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class db_row {
|
||||||
|
private:
|
||||||
|
pqxx::row row_;
|
||||||
|
public:
|
||||||
|
db_row(const pqxx::row& row) : row_{row} {}
|
||||||
|
std::size_t size() const { return row_.size(); }
|
||||||
|
db_field operator[](std::size_t idx) const { return row_[idx]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class db_result {
|
||||||
|
private:
|
||||||
|
pqxx::result result_;
|
||||||
|
public:
|
||||||
|
class const_iterator {
|
||||||
|
private:
|
||||||
|
pqxx::result::const_iterator iterator_;
|
||||||
|
public:
|
||||||
|
const_iterator(
|
||||||
|
const pqxx::result::const_iterator& iterator
|
||||||
|
) : iterator_{iterator} {}
|
||||||
|
const_iterator& operator++() { ++iterator_; return *this; }
|
||||||
|
bool operator==(const const_iterator& rhs) const { return iterator_ == rhs.iterator_; }
|
||||||
|
bool operator!=(const const_iterator& rhs) const { return iterator_ != rhs.iterator_; }
|
||||||
|
db_row operator*() const { return *iterator_; }
|
||||||
|
};
|
||||||
|
db_result() = default;
|
||||||
|
db_result(const pqxx::result& result) : result_{result} {}
|
||||||
|
const_iterator begin() const { return result_.begin(); }
|
||||||
|
const_iterator end() const { return result_.end(); }
|
||||||
|
std::string query() const { return result_.query(); }
|
||||||
|
};
|
||||||
|
|
||||||
class db_connection_manager;
|
class db_connection_manager;
|
||||||
|
|
||||||
class db_connection {
|
class db_connection {
|
||||||
private:
|
private:
|
||||||
db_connection_manager& mgr_;
|
db_connection_manager& mgr_;
|
||||||
std::shared_ptr<pqxx::connection> conn_;
|
std::shared_ptr<raw_db_connection_type> conn_;
|
||||||
public:
|
public:
|
||||||
db_connection(
|
db_connection(
|
||||||
db_connection_manager& mgr,
|
db_connection_manager& mgr,
|
||||||
std::shared_ptr<pqxx::connection> conn)
|
std::shared_ptr<raw_db_connection_type> conn)
|
||||||
: mgr_{mgr}, conn_{conn} {}
|
: mgr_{mgr}, conn_{conn} {}
|
||||||
// non-copiable, non-assignable
|
// non-copiable, non-assignable
|
||||||
db_connection(const db_connection&) = delete;
|
db_connection(const db_connection&) = delete;
|
||||||
|
@ -33,13 +78,13 @@ public:
|
||||||
// during the destruction, it should put itself back to the
|
// during the destruction, it should put itself back to the
|
||||||
// manager's queue
|
// manager's queue
|
||||||
~db_connection();
|
~db_connection();
|
||||||
pqxx::connection& get() { return *conn_; }
|
raw_db_connection_type& get() { return *conn_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// provides the database connection pool functionality
|
// provides the database connection pool functionality
|
||||||
class db_connection_manager {
|
class db_connection_manager {
|
||||||
private:
|
private:
|
||||||
std::queue<std::shared_ptr<pqxx::connection>> queue_;
|
std::queue<std::shared_ptr<raw_db_connection_type>> queue_;
|
||||||
// this lock is for manipulating the `queue_`
|
// this lock is for manipulating the `queue_`
|
||||||
mutable std::mutex queue_lock_;
|
mutable std::mutex queue_lock_;
|
||||||
// since C++ 17 doesn't provide the semaphore functionality,
|
// since C++ 17 doesn't provide the semaphore functionality,
|
||||||
|
@ -52,7 +97,7 @@ public:
|
||||||
db_connection_manager(const std::string& conn_str, int n) {
|
db_connection_manager(const std::string& conn_str, int n) {
|
||||||
for (int i = 0; i < n; ++i)
|
for (int i = 0; i < n; ++i)
|
||||||
queue_.emplace(
|
queue_.emplace(
|
||||||
std::make_shared<pqxx::connection>(conn_str));
|
std::make_shared<raw_db_connection_type>(conn_str));
|
||||||
}
|
}
|
||||||
// if there are no available database connections, this function
|
// if there are no available database connections, this function
|
||||||
// blocks until there is any;
|
// blocks until there is any;
|
||||||
|
@ -68,7 +113,7 @@ public:
|
||||||
// `queue_lock_` is acquired so that only one thread will
|
// `queue_lock_` is acquired so that only one thread will
|
||||||
// modify the `queue_`
|
// modify the `queue_`
|
||||||
std::lock_guard<std::mutex> lg{queue_lock_};
|
std::lock_guard<std::mutex> lg{queue_lock_};
|
||||||
std::shared_ptr<pqxx::connection> conn = queue_.front();
|
std::shared_ptr<raw_db_connection_type> conn = queue_.front();
|
||||||
queue_.pop();
|
queue_.pop();
|
||||||
// if there are no connections in the `queue_`,
|
// if there are no connections in the `queue_`,
|
||||||
// `counter_lock_` remains to be locked
|
// `counter_lock_` remains to be locked
|
||||||
|
@ -93,7 +138,7 @@ inline db_connection::~db_connection() {
|
||||||
class db_parameter {
|
class db_parameter {
|
||||||
public:
|
public:
|
||||||
virtual ~db_parameter() = default;
|
virtual ~db_parameter() = default;
|
||||||
virtual std::string get_value(pqxx::work&) = 0;
|
virtual std::string get_value(raw_db_transaction_type&) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class db_name : public db_parameter {
|
class db_name : public db_parameter {
|
||||||
|
@ -102,8 +147,8 @@ private:
|
||||||
public:
|
public:
|
||||||
db_name(const std::string& value)
|
db_name(const std::string& value)
|
||||||
: value_{value} {}
|
: value_{value} {}
|
||||||
std::string get_value(pqxx::work& w) {
|
std::string get_value(raw_db_transaction_type& tx) {
|
||||||
return w.quote_name(value_);
|
return tx.quote_name(value_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -114,7 +159,7 @@ private:
|
||||||
public:
|
public:
|
||||||
db_value(const Type& value)
|
db_value(const Type& value)
|
||||||
: value_{value} {}
|
: value_{value} {}
|
||||||
std::string get_value(pqxx::work&) {
|
std::string get_value(raw_db_transaction_type&) {
|
||||||
return std::to_string(value_);
|
return std::to_string(value_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -126,8 +171,8 @@ private:
|
||||||
public:
|
public:
|
||||||
db_value(const std::string& value)
|
db_value(const std::string& value)
|
||||||
: value_{value} {}
|
: value_{value} {}
|
||||||
std::string get_value(pqxx::work& w) {
|
std::string get_value(raw_db_transaction_type& tx) {
|
||||||
return w.quote(value_);
|
return tx.quote(value_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -138,7 +183,7 @@ private:
|
||||||
public:
|
public:
|
||||||
db_value(const bool& value)
|
db_value(const bool& value)
|
||||||
: value_{value} {}
|
: value_{value} {}
|
||||||
std::string get_value(pqxx::work&) {
|
std::string get_value(raw_db_transaction_type&) {
|
||||||
return value_ ? "true" : "false";
|
return value_ ? "true" : "false";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -169,8 +214,8 @@ inline std::shared_ptr<db_parameter> convert_parameter(
|
||||||
|
|
||||||
template <typename ...Params>
|
template <typename ...Params>
|
||||||
std::vector<std::string> convert_parameters(
|
std::vector<std::string> convert_parameters(
|
||||||
pqxx::work& w, std::shared_ptr<Params>... params) {
|
raw_db_transaction_type& tx, std::shared_ptr<Params>... params) {
|
||||||
return {params->get_value(w)...};
|
return {params->get_value(tx)...};
|
||||||
}
|
}
|
||||||
|
|
||||||
// *************************************
|
// *************************************
|
||||||
|
@ -183,7 +228,7 @@ public:
|
||||||
: name_{name} {}
|
: name_{name} {}
|
||||||
virtual ~db_field_holder() = default;
|
virtual ~db_field_holder() = default;
|
||||||
virtual void add(
|
virtual void add(
|
||||||
const pqxx::row& row, size_t field_idx,
|
const db_row& row, std::size_t field_idx,
|
||||||
boost::json::object& obj) = 0;
|
boost::json::object& obj) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -192,7 +237,7 @@ class db_field : public db_field_holder {
|
||||||
public:
|
public:
|
||||||
using db_field_holder::db_field_holder;
|
using db_field_holder::db_field_holder;
|
||||||
void add(
|
void add(
|
||||||
const pqxx::row& row, size_t field_idx,
|
const db_row& row, std::size_t field_idx,
|
||||||
boost::json::object& obj) {
|
boost::json::object& obj) {
|
||||||
obj[name_] = row[field_idx].as<Type>();
|
obj[name_] = row[field_idx].as<Type>();
|
||||||
}
|
}
|
||||||
|
@ -203,7 +248,7 @@ class db_field<std::string> : public db_field_holder {
|
||||||
public:
|
public:
|
||||||
using db_field_holder::db_field_holder;
|
using db_field_holder::db_field_holder;
|
||||||
void add(
|
void add(
|
||||||
const pqxx::row& row, size_t field_idx,
|
const db_row& row, std::size_t field_idx,
|
||||||
boost::json::object& obj) {
|
boost::json::object& obj) {
|
||||||
obj[name_] = row[field_idx].c_str();
|
obj[name_] = row[field_idx].c_str();
|
||||||
}
|
}
|
||||||
|
@ -234,49 +279,63 @@ public:
|
||||||
const std::initializer_list<
|
const std::initializer_list<
|
||||||
std::shared_ptr<db_internal::db_field_holder>>& fields)
|
std::shared_ptr<db_internal::db_field_holder>>& fields)
|
||||||
: fields_{fields} {}
|
: fields_{fields} {}
|
||||||
boost::json::object convert_row(const pqxx::row& row) {
|
boost::json::object convert_row(const db_row& row) {
|
||||||
boost::json::object obj;
|
boost::json::object obj;
|
||||||
for (size_t i = 0; i < fields_.size(); ++i)
|
for (std::size_t i = 0; i < fields_.size(); ++i)
|
||||||
fields_[i]->add(row, i, obj);
|
fields_[i]->add(row, i, obj);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
std::vector<boost::json::object> convert_to_vector(
|
std::vector<boost::json::object> convert_to_vector(
|
||||||
const pqxx::result& result) {
|
const db_result& result) {
|
||||||
std::vector<boost::json::object> results;
|
std::vector<boost::json::object> results;
|
||||||
for (const auto& row : result)
|
for (const auto& row : result)
|
||||||
results.emplace_back(convert_row(row));
|
results.emplace_back(convert_row(row));
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
std::optional<boost::json::object> convert_to_optional(
|
std::optional<boost::json::object> convert_to_optional(
|
||||||
const pqxx::result& result) {
|
const db_result& result) {
|
||||||
if (result.size() == 0) return std::nullopt;
|
// result.size() == 0
|
||||||
if (result.size() == 1) return convert_row(result[0]);
|
if (result.begin() == result.end()) return std::nullopt;
|
||||||
|
auto iterator = result.begin();
|
||||||
|
auto first = iterator;
|
||||||
|
// result.size() == 1
|
||||||
|
if (++iterator == result.end())
|
||||||
|
return convert_row(*first);
|
||||||
// result.size() > 1
|
// result.size() > 1
|
||||||
throw invalid_operation_exception{
|
throw invalid_operation_exception{
|
||||||
"too many objects to convert"};
|
"too many objects to convert"};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class db_transaction {
|
||||||
|
private:
|
||||||
|
raw_db_transaction_type tx_;
|
||||||
|
public:
|
||||||
|
db_transaction(
|
||||||
|
std::shared_ptr<db_connection> connection_ptr
|
||||||
|
) : tx_{connection_ptr->get()} {}
|
||||||
|
// non-copiable, non-assignable
|
||||||
|
db_transaction(const db_transaction&) = delete;
|
||||||
|
db_transaction& operator=(const db_transaction&) = delete;
|
||||||
// Usage:
|
// Usage:
|
||||||
// db_exec(tx, "select * from ? where ? = ? and first_name = 'Name??'",
|
// exec("select * from ? where ? = ? and first_name = 'Name??'",
|
||||||
// db_name("auth_user"), db_name("is_active"), db_value<bool>(true));
|
// db_name("auth_user"), db_name("is_active"), db_value<bool>(true));
|
||||||
// -> SQL: select * from "auth_user" where "is_active" = true and first_name = 'Name?'
|
// -> SQL: select * from "auth_user" where "is_active" = true and first_name = 'Name?'
|
||||||
// ======================================================================================
|
// ======================================================================================
|
||||||
// db_exec(tx, "select * from ? where ? = ? and first_name = ?",
|
// exec("select * from ? where ? = ? and first_name = ?",
|
||||||
// db_name("auth_user"), db_name("is_active"), false, "Name??");
|
// db_name("auth_user"), db_name("is_active"), false, "Name??");
|
||||||
// -> SQL: select * from "auth_user" where "is_active" = false and first_name = 'Name??'
|
// -> SQL: select * from "auth_user" where "is_active" = false and first_name = 'Name??'
|
||||||
// ======================================================================================
|
// ======================================================================================
|
||||||
// Note: "?" is the placeholder for parameters, and "??" will be converted to "?" in SQL.
|
// Note: "?" is the placeholder for parameters, and "??" will be converted to "?" in SQL.
|
||||||
// But, "??" in the parameters remains.
|
// But, "??" in the parameters remains.
|
||||||
template <typename ...Params>
|
template <typename ...Params>
|
||||||
pqxx::result db_exec(pqxx::work& w,
|
db_result exec(const std::string& s, const Params&... params) {
|
||||||
const std::string& s, const Params&... params) {
|
|
||||||
std::vector<std::string> param_vec =
|
std::vector<std::string> param_vec =
|
||||||
db_internal::convert_parameters(
|
db_internal::convert_parameters(
|
||||||
w, db_internal::convert_parameter(params)...);
|
tx_, db_internal::convert_parameter(params)...);
|
||||||
size_t idx = 0;
|
std::size_t idx = 0;
|
||||||
std::string query;
|
std::string query;
|
||||||
for (size_t i = 0; i < s.length(); ++i) {
|
for (std::size_t i = 0; i < s.length(); ++i) {
|
||||||
if (s[i] == '?') {
|
if (s[i] == '?') {
|
||||||
if (i + 1 < s.length() && s[i + 1] == '?') {
|
if (i + 1 < s.length() && s[i + 1] == '?') {
|
||||||
query += s[++i];
|
query += s[++i];
|
||||||
|
@ -289,8 +348,11 @@ pqxx::result db_exec(pqxx::work& w,
|
||||||
}
|
}
|
||||||
if (idx != param_vec.size())
|
if (idx != param_vec.size())
|
||||||
throw invalid_operation_exception{"too many parameters"};
|
throw invalid_operation_exception{"too many parameters"};
|
||||||
return w.exec(query);
|
return tx_.exec(query);
|
||||||
}
|
}
|
||||||
|
void commit() { tx_.commit(); }
|
||||||
|
void abort() { tx_.abort(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// TODO: add support for time conversions between postgresql and c++, use timestamp?
|
// TODO: add support for time conversions between postgresql and c++, use timestamp?
|
||||||
|
|
29
handlers.hpp
29
handlers.hpp
|
@ -8,8 +8,6 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include <pqxx/pqxx>
|
|
||||||
|
|
||||||
#include "bserv/common.hpp"
|
#include "bserv/common.hpp"
|
||||||
|
|
||||||
// register an orm mapping (to convert the db query results into
|
// register an orm mapping (to convert the db query results into
|
||||||
|
@ -35,9 +33,9 @@ bserv::db_relation_to_object orm_user{
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<boost::json::object> get_user(
|
std::optional<boost::json::object> get_user(
|
||||||
pqxx::work& tx,
|
bserv::db_transaction& tx,
|
||||||
const std::string& username) {
|
const std::string& username) {
|
||||||
pqxx::result r = bserv::db_exec(tx,
|
bserv::db_result r = tx.exec(
|
||||||
"select * from auth_user where username = ?", username);
|
"select * from auth_user where username = ?", username);
|
||||||
lginfo << r.query(); // this is how you log info
|
lginfo << r.query(); // this is how you log info
|
||||||
return orm_user.convert_to_optional(r);
|
return orm_user.convert_to_optional(r);
|
||||||
|
@ -58,10 +56,20 @@ std::nullopt_t hello(
|
||||||
bserv::session_type& session = *session_ptr;
|
bserv::session_type& session = *session_ptr;
|
||||||
boost::json::object obj;
|
boost::json::object obj;
|
||||||
if (session.count("user")) {
|
if (session.count("user")) {
|
||||||
|
// NOTE: modifications to sessions must be performed
|
||||||
|
// BEFORE referencing objects in them. this is because
|
||||||
|
// modifications might invalidate referenced objects.
|
||||||
|
// in this example, "count" might be added to `session`,
|
||||||
|
// which should be performed first.
|
||||||
|
// then `user` can be referenced safely.
|
||||||
|
if (!session.count("count")) {
|
||||||
|
session["count"] = 0;
|
||||||
|
}
|
||||||
auto& user = session["user"].as_object();
|
auto& user = session["user"].as_object();
|
||||||
|
session["count"] = session["count"].as_int64() + 1;
|
||||||
obj = {
|
obj = {
|
||||||
{"msg", std::string{"welcome, "}
|
{"welcome", user["username"]},
|
||||||
+ user["username"].as_string().c_str() + "!"}
|
{"count", session["count"]}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
obj = {{"msg", "hello, world!"}};
|
obj = {{"msg", "hello, world!"}};
|
||||||
|
@ -97,7 +105,7 @@ boost::json::object user_register(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
auto username = params["username"].as_string();
|
auto username = params["username"].as_string();
|
||||||
pqxx::work tx{conn->get()};
|
bserv::db_transaction tx{conn};
|
||||||
auto opt_user = get_user(tx, username.c_str());
|
auto opt_user = get_user(tx, username.c_str());
|
||||||
if (opt_user.has_value()) {
|
if (opt_user.has_value()) {
|
||||||
return {
|
return {
|
||||||
|
@ -106,7 +114,7 @@ boost::json::object user_register(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
auto password = params["password"].as_string();
|
auto password = params["password"].as_string();
|
||||||
pqxx::result r = bserv::db_exec(tx,
|
bserv::db_result r = tx.exec(
|
||||||
"insert into ? "
|
"insert into ? "
|
||||||
"(?, password, is_superuser, "
|
"(?, password, is_superuser, "
|
||||||
"first_name, last_name, email, is_active) values "
|
"first_name, last_name, email, is_active) values "
|
||||||
|
@ -147,7 +155,7 @@ boost::json::object user_login(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
auto username = params["username"].as_string();
|
auto username = params["username"].as_string();
|
||||||
pqxx::work tx{conn->get()};
|
bserv::db_transaction tx{conn};
|
||||||
auto opt_user = get_user(tx, username.c_str());
|
auto opt_user = get_user(tx, username.c_str());
|
||||||
if (!opt_user.has_value()) {
|
if (!opt_user.has_value()) {
|
||||||
return {
|
return {
|
||||||
|
@ -182,7 +190,7 @@ boost::json::object user_login(
|
||||||
boost::json::object find_user(
|
boost::json::object find_user(
|
||||||
std::shared_ptr<bserv::db_connection> conn,
|
std::shared_ptr<bserv::db_connection> conn,
|
||||||
const std::string& username) {
|
const std::string& username) {
|
||||||
pqxx::work tx{conn->get()};
|
bserv::db_transaction tx{conn};
|
||||||
auto user = get_user(tx, username);
|
auto user = get_user(tx, username);
|
||||||
if (!user.has_value()) {
|
if (!user.has_value()) {
|
||||||
return {
|
return {
|
||||||
|
@ -190,6 +198,7 @@ boost::json::object find_user(
|
||||||
{"message", "requested user does not exist"}
|
{"message", "requested user does not exist"}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
user.value().erase("id");
|
||||||
user.value().erase("password");
|
user.value().erase("password");
|
||||||
return {
|
return {
|
||||||
{"success", true},
|
{"success", true},
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
import uuid
|
||||||
|
import string
|
||||||
|
import secrets
|
||||||
|
import random
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from multiprocessing import Process
|
||||||
|
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
|
||||||
|
char_string = string.ascii_letters + string.digits
|
||||||
|
|
||||||
|
def get_password(n):
|
||||||
|
return ''.join(secrets.choice(char_string) for _ in range(n))
|
||||||
|
|
||||||
|
def get_string(n):
|
||||||
|
return ''.join(random.choice(char_string) for _ in range(n))
|
||||||
|
|
||||||
|
def create_user():
|
||||||
|
return {
|
||||||
|
"username": str(uuid.uuid4()),
|
||||||
|
"password": get_password(16),
|
||||||
|
"first_name": get_string(5),
|
||||||
|
"last_name": get_string(5),
|
||||||
|
"email": get_string(5) + "@" + get_string(5) + ".com"
|
||||||
|
}
|
||||||
|
|
||||||
|
# pprint(create_user())
|
||||||
|
# exit()
|
||||||
|
|
||||||
|
def session_test():
|
||||||
|
session = requests.session()
|
||||||
|
user = create_user()
|
||||||
|
res = session.post("http://localhost:8080").json()
|
||||||
|
if res != {'msg': 'hello, world!'}:
|
||||||
|
print('test failed')
|
||||||
|
# print(res)
|
||||||
|
res = session.post("http://localhost:8080/register", json=user).json()
|
||||||
|
if res != {'success': True, 'message': 'user registered'}:
|
||||||
|
print('test failed')
|
||||||
|
# print(res)
|
||||||
|
res = session.post("http://localhost:8080/login", json={
|
||||||
|
"username": user["username"],
|
||||||
|
"password": user["password"]
|
||||||
|
}).json()
|
||||||
|
if res != {'success': True, 'message': 'login successfully'}:
|
||||||
|
print('test failed')
|
||||||
|
# print(res)
|
||||||
|
n = random.randint(1, 5)
|
||||||
|
for i in range(1, n + 1):
|
||||||
|
res = session.post("http://localhost:8080").json()
|
||||||
|
if res != {'welcome': user["username"], 'count': i}:
|
||||||
|
print('test failed')
|
||||||
|
# print(res)
|
||||||
|
res = session.post("http://localhost:8080/find/" + user["username"]).json()
|
||||||
|
if res != {
|
||||||
|
'success': True,
|
||||||
|
'user': {
|
||||||
|
'username': user["username"],
|
||||||
|
'is_active': True,
|
||||||
|
'is_superuser': False,
|
||||||
|
'first_name': user["first_name"],
|
||||||
|
'last_name': user["last_name"],
|
||||||
|
'email': user["email"]
|
||||||
|
}}:
|
||||||
|
print('test failed')
|
||||||
|
# print(res)
|
||||||
|
res = session.post("http://localhost:8080/logout").json()
|
||||||
|
if res != {'success': True, 'message': 'logout successfully'}:
|
||||||
|
print('test failed')
|
||||||
|
# print(res)
|
||||||
|
res = session.post("http://localhost:8080").json()
|
||||||
|
if res != {'msg': 'hello, world!'}:
|
||||||
|
print('test failed')
|
||||||
|
# print(res)
|
||||||
|
|
||||||
|
# session_test()
|
||||||
|
# exit()
|
||||||
|
|
||||||
|
P = 1000 # number of concurrent processes
|
||||||
|
|
||||||
|
processes = [Process(target=session_test) for i in range(P)]
|
||||||
|
|
||||||
|
print('starting')
|
||||||
|
|
||||||
|
start = time()
|
||||||
|
|
||||||
|
for p in processes:
|
||||||
|
p.start()
|
||||||
|
|
||||||
|
for p in processes:
|
||||||
|
p.join()
|
||||||
|
|
||||||
|
end = time()
|
||||||
|
|
||||||
|
print('test ended')
|
||||||
|
print('elapsed: ', end - start)
|
Loading…
Reference in New Issue