Skip to content
This repository has been archived by the owner on Oct 9, 2023. It is now read-only.

Implement UserManager #47

Merged
merged 84 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from 77 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
f51ec62
fmt
dmikhalin May 31, 2023
e795331
fmt
dmikhalin May 31, 2023
cad83b4
wip
dmikhalin Jun 6, 2023
d806ca5
wip
dmikhalin Jun 6, 2023
f17cd62
get_user()
dmikhalin Jun 6, 2023
4f10b0a
`try_into_proto` for the rest requests
dmikhalin Jun 6, 2023
d517616
`from_proto` for responses
dmikhalin Jun 7, 2023
e58e701
users functions
dmikhalin Jun 7, 2023
2c3417e
Add UserManager to Context
dmikhalin Jun 7, 2023
8913203
`ServerConnection` methods for users
dmikhalin Jun 7, 2023
b227cca
wip
dmikhalin Jun 7, 2023
7c009ac
get_all() and contains()
dmikhalin Jun 8, 2023
c28ec59
fmt
dmikhalin Jun 9, 2023
6a2f20a
Context::set_connection() replaces connection in DatabaseManager and …
dmikhalin Jun 12, 2023
8eee27e
Delete all created users after scenario
dmikhalin Jun 12, 2023
62d28b9
Some UserManager functions and BDD steps for them
dmikhalin Jun 12, 2023
950ba14
fmt
dmikhalin Jun 15, 2023
136191e
Delete users after scanario only on cluster
dmikhalin Jun 19, 2023
a490fe8
Move auth connection step to connections
dmikhalin Jun 19, 2023
59a100a
Simplification
dmikhalin Jun 19, 2023
3ff7f33
debug.feature
dmikhalin Jun 19, 2023
4bdd6b7
UserManager::get()
dmikhalin Jun 21, 2023
3ca0453
Remove User::new()
dmikhalin Jun 21, 2023
6cae861
todos
dmikhalin Jun 21, 2023
0b23c8c
Store username in Connection
dmikhalin Jun 21, 2023
7be148e
"user expiry-seconds" step
dmikhalin Jun 21, 2023
ca66d13
Renaming
dmikhalin Jun 22, 2023
aba25a2
User::password_update()
dmikhalin Jun 22, 2023
844c0bd
"get connected user"
dmikhalin Jun 22, 2023
fc9b770
wip
dmikhalin Jun 22, 2023
30fb4a5
Fix rebase
dmikhalin Jun 26, 2023
7e15e03
Connect to at least one cluster node
dmikhalin Jun 26, 2023
cf534b6
User integration tests
dmikhalin Jun 26, 2023
c430bf0
Steps with "throws"
dmikhalin Jun 26, 2023
39eb5b6
fmt
dmikhalin Jun 26, 2023
af3f1c3
Steps for updating password
dmikhalin Jun 26, 2023
86e46f6
Cleanup
dmikhalin Jun 26, 2023
560fdc8
Connect to cluster by default, add tests to automation.yml
dmikhalin Jun 26, 2023
364a549
Set ROOT_CA for Factory BDD tests
dmikhalin Jun 27, 2023
6f5c0cd
Remove redundant TODO
dmikhalin Jun 27, 2023
48c3507
Always run after_scenario on cluster
dmikhalin Jun 27, 2023
7a218d8
Trying to sleep after create/delete db
dmikhalin Jun 27, 2023
a8bfe2f
Sleep for 2s
dmikhalin Jun 27, 2023
c10088b
Wait in steps until success or TL
dmikhalin Jun 28, 2023
2808f9b
Increase test TL
dmikhalin Jun 28, 2023
42040d2
Increase step TL
dmikhalin Jun 28, 2023
1486d0f
Wait on db creation step
dmikhalin Jun 29, 2023
9ecf43d
Wait on user steps
dmikhalin Jun 29, 2023
928a6a0
Wait on connection with auth
dmikhalin Jun 29, 2023
be6b0d6
Refactoring
dmikhalin Jun 29, 2023
ee0c340
Connect to at least one server (until cluster not fixed)
dmikhalin Jun 29, 2023
2b69505
fmt
dmikhalin Jun 29, 2023
02e3122
Cleanup
dmikhalin Jun 29, 2023
7c1b096
Fix "connection does not have any database" step
dmikhalin Jun 29, 2023
d880473
Add waiting to "connection create databases in parallel" step
dmikhalin Jun 29, 2023
0197ca9
Cleanup
dmikhalin Jun 29, 2023
3fa0e87
Step TL -> 15 ms
dmikhalin Jun 29, 2023
4d5ba4b
Wait in the beginning of after_scenario()
dmikhalin Jun 29, 2023
ca1c99e
Wait less after scenario but repeat cleaning in the "no databases" step
dmikhalin Jun 29, 2023
9172088
Cleanup
dmikhalin Jun 30, 2023
73ef364
Increase machine size for a large test
dmikhalin Jun 30, 2023
3d2d6ee
Refactoring
dmikhalin Jun 30, 2023
110cc52
Fix PR issues
dmikhalin Jul 3, 2023
77e6435
Fix PR issues, fmt
dmikhalin Jul 3, 2023
a0f345a
Fix PR issues
dmikhalin Jul 4, 2023
b4549d6
Fix PR issues
dmikhalin Jul 4, 2023
b3a0b16
Fix PR issues
dmikhalin Jul 4, 2023
d360d89
Fix PR issues
dmikhalin Jul 4, 2023
5cda74a
Fix PR issues
dmikhalin Jul 4, 2023
d3c7ea7
Testing connection (wip)
dmikhalin Jul 5, 2023
c4606d7
ConnectionError only if all connections fail, but store all server co…
dmikhalin Jul 5, 2023
17cb0d8
fmt
dmikhalin Jul 5, 2023
a63a5d4
UserManager::current_user()
dmikhalin Jul 5, 2023
3d24e29
Refactor assert_with_timeout!()
dmikhalin Jul 5, 2023
f794775
Ignore errors on cleanup
dmikhalin Jul 5, 2023
a36c1f7
Fix PR issues
dmikhalin Jul 5, 2023
e73fccf
Fix PR issues
dmikhalin Jul 5, 2023
6b20cd0
Run integration tests in serial
dmikhalin Jul 5, 2023
63f0ec3
Refactoring
dmikhalin Jul 5, 2023
0a2f461
Cleanup
dmikhalin Jul 5, 2023
0eb99a0
Remove redundant flag
dmikhalin Jul 6, 2023
04febdd
Rename constants
dmikhalin Jul 6, 2023
c154626
Delete user integration test
dmikhalin Jul 6, 2023
b71047b
Remove redundant flag
dmikhalin Jul 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions .factory/automation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ build:
export ARTIFACT_PASSWORD=$REPO_VATICLE_PASSWORD
bazel run @vaticle_dependencies//tool/bazelinstall:remote_cache_setup.sh
bazel run @vaticle_dependencies//distribution/artifact:create-netrc
tools/start-core-server.sh
bazel test //tests --test_arg=-- --test_arg=behaviour::concept --test_arg=--test-threads=1 --test_output=streamed && export TEST_SUCCESS=0 || export TEST_SUCCESS=1
tools/stop-core-server.sh
source tools/start-cluster-servers.sh # use source to receive export vars
bazel test //tests --test_env=ROOT_CA=$ROOT_CA --test_arg=-- --test_arg=behaviour::concept --test_arg=--test-threads=1 --test_output=streamed && export TEST_SUCCESS=0 || export TEST_SUCCESS=1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couple more extra --test-threads=1 here and below

tools/stop-cluster-servers.sh
Copy link
Member

@flyingsilverfin flyingsilverfin Jul 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should make two sets of tests in automation.yml: one for cluster (test-behaviour-concept-cluster) and (test-behaviour-concept-core)

Same pattern for behaviour-typeql and the rest

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We decided that it's out of the scope now. https://github.com/vaticle/typedb-client-rust/issues/52

exit $TEST_SUCCESS
test-behaviour-connection:
image: vaticle-ubuntu-22.04
Expand All @@ -110,9 +110,23 @@ build:
export ARTIFACT_PASSWORD=$REPO_VATICLE_PASSWORD
bazel run @vaticle_dependencies//tool/bazelinstall:remote_cache_setup.sh
bazel run @vaticle_dependencies//distribution/artifact:create-netrc
tools/start-core-server.sh
bazel test //tests --test_arg=-- --test_arg=behaviour::connection --test_arg=--test-threads=1 --test_output=streamed && export TEST_SUCCESS=0 || export TEST_SUCCESS=1
tools/stop-core-server.sh
source tools/start-cluster-servers.sh # use source to receive export vars
bazel test //tests --test_env=ROOT_CA=$ROOT_CA --test_arg=-- --test_arg=behaviour::connection --test_arg=--test-threads=1 --test_output=streamed && export TEST_SUCCESS=0 || export TEST_SUCCESS=1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made a comment on typedb/typedb-common#147 to implement root CA & TLS support in the TypeDB runner. I don't think it currently is able to do that.

tools/stop-cluster-servers.sh
exit $TEST_SUCCESS
test-behaviour-typeql:
machine: 8-core-32-gb
image: vaticle-ubuntu-22.04
dependencies:
- build
command: |
export ARTIFACT_USERNAME=$REPO_VATICLE_USERNAME
export ARTIFACT_PASSWORD=$REPO_VATICLE_PASSWORD
bazel run @vaticle_dependencies//tool/bazelinstall:remote_cache_setup.sh
bazel run @vaticle_dependencies//distribution/artifact:create-netrc
source tools/start-cluster-servers.sh # use source to receive export vars
bazel test //tests --test_env=ROOT_CA=$ROOT_CA --test_arg=-- --test_arg=behaviour::typeql --test_arg=--test-threads=1 --test_output=streamed && export TEST_SUCCESS=0 || export TEST_SUCCESS=1
tools/stop-cluster-servers.sh
exit $TEST_SUCCESS
deploy-crate-snapshot:
filter:
Expand All @@ -124,7 +138,9 @@ build:
- test-integration-core
- test-integration-cluster
- test-integration-runtimes
- test-behaviour-concept
- test-behaviour-connection
- test-behaviour-typeql
command: |
export DEPLOY_CRATE_TOKEN=$REPO_VATICLE_CRATES_TOKEN
bazel run @vaticle_dependencies//tool/bazelinstall:remote_cache_setup.sh
Expand Down
92 changes: 84 additions & 8 deletions src/connection/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,23 @@ use crate::{
},
connection::message::{Request, Response, TransactionRequest},
error::InternalError,
user::User,
Credential, Options,
};

#[derive(Clone)]
pub struct Connection {
server_connections: HashMap<Address, ServerConnection>,
background_runtime: Arc<BackgroundRuntime>,
username: Option<String>,
}

impl Connection {
pub fn new_plaintext(address: impl AsRef<str>) -> Result<Self> {
let address: Address = address.as_ref().parse()?;
let background_runtime = Arc::new(BackgroundRuntime::new()?);
let server_connection = ServerConnection::new_plaintext(background_runtime.clone(), address.clone())?;
Ok(Self { server_connections: [(address, server_connection)].into(), background_runtime })
Ok(Self { server_connections: [(address, server_connection)].into(), background_runtime, username: None })
}

pub fn new_encrypted<T: AsRef<str> + Sync>(init_addresses: &[T], credential: Credential) -> Result<Self> {
Expand All @@ -70,14 +72,23 @@ impl Connection {
let init_addresses = init_addresses.iter().map(|addr| addr.as_ref().parse()).try_collect()?;
let addresses = Self::fetch_current_addresses(background_runtime.clone(), init_addresses, credential.clone())?;

let mut server_connections = HashMap::with_capacity(addresses.len());
for address in addresses {
let server_connection =
ServerConnection::new_encrypted(background_runtime.clone(), address.clone(), credential.clone())?;
server_connections.insert(address, server_connection);
let server_connections: HashMap<Address, ServerConnection> = addresses
.into_iter()
.map(|address| {
ServerConnection::new_encrypted(background_runtime.clone(), address.clone(), credential.clone())
.map(|result| (address, result))
dmikhalin marked this conversation as resolved.
Show resolved Hide resolved
})
.try_collect()?;

let errors: Vec<Error> =
server_connections.iter().map(|(_addr, conn)| conn.validate()).filter_map(Result::err).collect();
if errors.len() == server_connections.len() {
Err(ConnectionError::ClusterAllNodesFailed(
errors.into_iter().map(|err| err.to_string()).collect::<Vec<_>>().join("\n"),
))?
} else {
Ok(Self { server_connections, background_runtime, username: Some(credential.username().to_string()) })
}

Ok(Self { server_connections, background_runtime })
}

fn fetch_current_addresses(
Expand Down Expand Up @@ -124,6 +135,10 @@ impl Connection {
self.server_connections.values()
}

pub(crate) fn username(&self) -> Option<&str> {
self.username.as_ref().and_then(|s| Some(s.as_ref()))
dmikhalin marked this conversation as resolved.
Show resolved Hide resolved
}

pub(crate) fn unable_to_connect_error(&self) -> Error {
Error::Connection(ConnectionError::ClusterUnableToConnect(
self.addresses().map(Address::to_string).collect::<Vec<_>>().join(","),
Expand Down Expand Up @@ -194,6 +209,13 @@ impl ServerConnection {
}
}

pub(crate) fn validate(&self) -> Result {
match self.request_blocking(Request::DatabasesAll)? {
Response::DatabasesAll { databases: _ } => Ok(()),
_other => Err(ConnectionError::UnableToConnect().into()),
}
}

pub(crate) async fn database_exists(&self, database_name: String) -> Result<bool> {
match self.request_async(Request::DatabasesContains { database_name }).await? {
Response::DatabasesContains { contains } => Ok(contains),
Expand Down Expand Up @@ -303,6 +325,60 @@ impl ServerConnection {
other => Err(InternalError::UnexpectedResponseType(format!("{other:?}")).into()),
}
}

pub(crate) async fn all_users(&self) -> Result<Vec<User>> {
match self.request_async(Request::UsersAll).await? {
Response::UsersAll { users } => Ok(users),
other => Err(InternalError::UnexpectedResponseType(format!("{other:?}")).into()),
}
}

pub(crate) async fn contains_user(&self, username: String) -> Result<bool> {
match self.request_async(Request::UsersContain { username }).await? {
Response::UsersContain { contains } => Ok(contains),
other => Err(InternalError::UnexpectedResponseType(format!("{other:?}")).into()),
}
}

pub(crate) async fn create_user(&self, username: String, password: String) -> Result {
match self.request_async(Request::UsersCreate { username, password }).await? {
Response::UsersCreate => Ok(()),
other => Err(InternalError::UnexpectedResponseType(format!("{other:?}")).into()),
}
}

pub(crate) async fn delete_user(&self, username: String) -> Result {
match self.request_async(Request::UsersDelete { username }).await? {
Response::UsersDelete => Ok(()),
other => Err(InternalError::UnexpectedResponseType(format!("{other:?}")).into()),
}
}

pub(crate) async fn get_user(&self, username: String) -> Result<Option<User>> {
match self.request_async(Request::UsersGet { username }).await? {
Response::UsersGet { user } => Ok(user),
other => Err(InternalError::UnexpectedResponseType(format!("{other:?}")).into()),
}
}

pub(crate) async fn set_user_password(&self, username: String, password: String) -> Result {
match self.request_async(Request::UsersPasswordSet { username, password }).await? {
Response::UsersPasswordSet => Ok(()),
other => Err(InternalError::UnexpectedResponseType(format!("{other:?}")).into()),
}
}

pub(crate) async fn update_user_password(
&self,
username: String,
password_old: String,
password_new: String,
) -> Result {
match self.request_async(Request::UserPasswordUpdate { username, password_old, password_new }).await? {
Response::UserPasswordUpdate => Ok(()),
other => Err(InternalError::UnexpectedResponseType(format!("{other:?}")).into()),
}
}
}

impl fmt::Debug for ServerConnection {
Expand Down
25 changes: 25 additions & 0 deletions src/connection/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use crate::{
Thing, ThingType, Transitivity, Value, ValueType,
},
logic::{Explanation, Rule},
user::User,
Options, SessionType, TransactionType,
};

Expand All @@ -56,6 +57,15 @@ pub(super) enum Request {
SessionPulse { session_id: SessionID },

Transaction(TransactionRequest),

UsersAll,
UsersContain { username: String },
UsersCreate { username: String, password: String },
UsersDelete { username: String },
UsersGet { username: String },
UsersPasswordSet { username: String, password: String },

UserPasswordUpdate { username: String, password_old: String, password_new: String },
}

#[derive(Debug)]
Expand Down Expand Up @@ -97,6 +107,21 @@ pub(super) enum Response {
request_sink: UnboundedSender<transaction::Client>,
response_source: Streaming<transaction::Server>,
},

UsersAll {
users: Vec<User>,
},
UsersContain {
contains: bool,
},
UsersCreate,
UsersDelete,
UsersGet {
user: Option<User>,
},
UsersPasswordSet,

UserPasswordUpdate,
}

#[derive(Debug)]
Expand Down
111 changes: 110 additions & 1 deletion src/connection/network/proto/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ use std::time::Duration;
use itertools::Itertools;
use typedb_protocol::{
attribute, attribute_type, concept_manager, database, database_manager, entity_type, logic_manager, query_manager,
r#type, relation, relation_type, role_type, rule, server_manager, session, thing, thing_type, transaction,
r#type, relation, relation_type, role_type, rule, server_manager, session, thing, thing_type, transaction, user,
user_manager,
};

use super::{FromProto, IntoProto, TryFromProto, TryIntoProto};
Expand All @@ -42,6 +43,7 @@ use crate::{
},
error::{ConnectionError, InternalError},
logic::{Explanation, Rule},
user::User,
};

impl TryIntoProto<server_manager::all::Req> for Request {
Expand Down Expand Up @@ -165,6 +167,71 @@ impl TryIntoProto<transaction::Client> for Request {
}
}

impl TryIntoProto<user_manager::all::Req> for Request {
fn try_into_proto(self) -> Result<user_manager::all::Req> {
match self {
Self::UsersAll => Ok(user_manager::all::Req {}),
other => Err(InternalError::UnexpectedRequestType(format!("{other:?}")).into()),
}
}
}

impl TryIntoProto<user_manager::contains::Req> for Request {
fn try_into_proto(self) -> Result<user_manager::contains::Req> {
match self {
Self::UsersContain { username } => Ok(user_manager::contains::Req { username }),
other => Err(InternalError::UnexpectedRequestType(format!("{other:?}")).into()),
}
}
}

impl TryIntoProto<user_manager::create::Req> for Request {
fn try_into_proto(self) -> Result<user_manager::create::Req> {
match self {
Self::UsersCreate { username, password } => Ok(user_manager::create::Req { username, password }),
other => Err(InternalError::UnexpectedRequestType(format!("{other:?}")).into()),
}
}
}

impl TryIntoProto<user_manager::delete::Req> for Request {
fn try_into_proto(self) -> Result<user_manager::delete::Req> {
match self {
Self::UsersDelete { username } => Ok(user_manager::delete::Req { username }),
other => Err(InternalError::UnexpectedRequestType(format!("{other:?}")).into()),
}
}
}

impl TryIntoProto<user_manager::get::Req> for Request {
fn try_into_proto(self) -> Result<user_manager::get::Req> {
match self {
Self::UsersGet { username } => Ok(user_manager::get::Req { username }),
other => Err(InternalError::UnexpectedRequestType(format!("{other:?}")).into()),
}
}
}

impl TryIntoProto<user_manager::password_set::Req> for Request {
fn try_into_proto(self) -> Result<user_manager::password_set::Req> {
match self {
Self::UsersPasswordSet { username, password } => Ok(user_manager::password_set::Req { username, password }),
other => Err(InternalError::UnexpectedRequestType(format!("{other:?}")).into()),
}
}
}

impl TryIntoProto<user::password_update::Req> for Request {
fn try_into_proto(self) -> Result<user::password_update::Req> {
match self {
Self::UserPasswordUpdate { username, password_old, password_new } => {
Ok(user::password_update::Req { username, password_old, password_new })
}
other => Err(InternalError::UnexpectedRequestType(format!("{other:?}")).into()),
}
}
}

impl TryFromProto<server_manager::all::Res> for Response {
fn try_from_proto(proto: server_manager::all::Res) -> Result<Self> {
let servers = proto.servers.into_iter().map(|server| server.address.parse()).try_collect()?;
Expand Down Expand Up @@ -335,6 +402,48 @@ impl TryFromProto<transaction::ResPart> for TransactionResponse {
}
}

impl FromProto<user_manager::all::Res> for Response {
fn from_proto(proto: user_manager::all::Res) -> Self {
Self::UsersAll { users: proto.users.into_iter().map(User::from_proto).collect() }
}
}

impl FromProto<user_manager::contains::Res> for Response {
fn from_proto(proto: user_manager::contains::Res) -> Self {
Self::UsersContain { contains: proto.contains }
}
}

impl FromProto<user_manager::create::Res> for Response {
fn from_proto(_proto: user_manager::create::Res) -> Self {
Self::UsersCreate
}
}

impl FromProto<user_manager::delete::Res> for Response {
fn from_proto(_proto: user_manager::delete::Res) -> Self {
Self::UsersDelete
}
}

impl FromProto<user_manager::get::Res> for Response {
fn from_proto(proto: user_manager::get::Res) -> Self {
Self::UsersGet { user: proto.user.map(User::from_proto) }
}
}

impl FromProto<user_manager::password_set::Res> for Response {
fn from_proto(_proto: user_manager::password_set::Res) -> Self {
Self::UsersPasswordSet
}
}

impl FromProto<user::password_update::Res> for Response {
fn from_proto(_proto: user::password_update::Res) -> Self {
Self::UserPasswordUpdate
}
}

impl IntoProto<query_manager::Req> for QueryRequest {
fn into_proto(self) -> query_manager::Req {
let (req, options) = match self {
Expand Down
1 change: 1 addition & 0 deletions src/connection/network/proto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod concept;
mod database;
mod logic;
mod message;
mod user;

use crate::Result;

Expand Down
Loading