[security] Introduce "allow-guests". Deny all caps by default (#2547)

This commit is contained in:
Salvador Girones Gil 2023-08-30 20:01:30 +02:00 committed by GitHub
parent 0d43e7a156
commit bdac1fae72
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 961 additions and 593 deletions

View file

@ -145,7 +145,7 @@ dependencies = ["build-surrealdb"]
script = """
#!/bin/bash -ex
target/debug/surreal start ${_START_SURREALDB_PATH} &>/tmp/surrealdb.log &
target/debug/surreal start ${_START_SURREALDB_PATH} --allow-all &>/tmp/surrealdb.log &
echo $! > /tmp/surreal.pid

View file

@ -65,11 +65,17 @@ category = "LOCAL USAGE"
command = "cargo"
args = ["bench", "--package", "surrealdb", "--no-default-features", "--features", "kv-mem,http,scripting"]
# Run
[tasks.run]
category = "LOCAL USAGE"
command = "cargo"
args = ["run", "--no-default-features", "--features", "${DEV_FEATURES}", "--", "${@}"]
# Serve
[tasks.serve]
category = "LOCAL USAGE"
command = "cargo"
args = ["run", "--no-default-features", "--features", "${DEV_FEATURES}", "--", "start", "${@}"]
args = ["run", "--no-default-features", "--features", "${DEV_FEATURES}", "--", "start", "--allow-all", "${@}"]
# SQL
[tasks.sql]

View file

@ -1,6 +1,9 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use pprof::criterion::{Output, PProfProfiler};
use surrealdb::{dbs::Session, kvs::Datastore};
use surrealdb::{
dbs::{Capabilities, Session},
kvs::Datastore,
};
macro_rules! query {
($c: expr, $name: ident, $query: expr) => {
@ -9,7 +12,8 @@ macro_rules! query {
($c: expr, $name: ident, $setup: expr, $query: expr) => {
$c.bench_function(stringify!($name), |b| {
let (dbs, ses) = futures::executor::block_on(async {
let dbs = Datastore::new("memory").await.unwrap();
let dbs =
Datastore::new("memory").await.unwrap().with_capabilities(Capabilities::all());
let ses = Session::owner().with_ns("test").with_db("test");
let setup = $setup;
if !setup.is_empty() {

View file

@ -228,6 +228,7 @@ pub fn connect(address: impl IntoEndpoint) -> Connect<Any, Surreal<Any>> {
#[cfg(all(test, feature = "kv-mem"))]
mod tests {
use super::*;
use crate::dbs::Capabilities;
use crate::opt::auth::Root;
use crate::sql::{test::Parse, value::Value};
@ -264,7 +265,9 @@ mod tests {
username: "root",
password: "root",
};
let db = connect(("memory", Config::new().user(creds))).await.unwrap();
let db = connect(("memory", Config::new().user(creds).capabilities(Capabilities::all())))
.await
.unwrap();
db.use_ns("N").use_db("D").await.unwrap();
// The client needs to sign in before it can access anything

View file

@ -140,7 +140,8 @@ pub(crate) fn router(
let kvs = kvs
.with_strict_mode(address.config.strict)
.with_query_timeout(address.config.query_timeout)
.with_transaction_timeout(address.config.transaction_timeout);
.with_transaction_timeout(address.config.transaction_timeout)
.with_capabilities(address.config.capabilities);
let kvs = match address.config.notifications {
true => kvs.with_notifications(),

View file

@ -1,4 +1,4 @@
use crate::iam::Level;
use crate::{dbs::Capabilities, iam::Level};
use std::time::Duration;
/// Configuration for server connection, including: strictness, notifications, query_timeout, transaction_timeout
@ -16,6 +16,7 @@ pub struct Config {
pub(crate) username: String,
pub(crate) password: String,
pub(crate) tick_interval: Option<Duration>,
pub(crate) capabilities: Capabilities,
}
impl Config {
@ -89,4 +90,10 @@ impl Config {
self.tick_interval = interval.into().filter(|x| !x.is_zero());
self
}
/// Set the capabilities for the database
pub fn capabilities(mut self, capabilities: Capabilities) -> Self {
self.capabilities = capabilities;
self
}
}

View file

@ -220,7 +220,7 @@ impl<'a> Context<'a> {
/// Check if scripting is allowed
#[allow(dead_code)]
pub fn check_allowed_scripting(&self) -> Result<(), Error> {
if !self.capabilities.is_allowed_scripting() {
if !self.capabilities.allows_scripting() {
return Err(Error::ScriptingNotAllowed);
}
Ok(())
@ -233,7 +233,7 @@ impl<'a> Context<'a> {
message: "Invalid function name".to_string(),
})?;
if !self.capabilities.is_allowed_func(&func_target) {
if !self.capabilities.allows_function(&func_target) {
return Err(Error::FunctionNotAllowed(target.to_string()));
}
Ok(())
@ -244,7 +244,7 @@ impl<'a> Context<'a> {
pub fn check_allowed_net(&self, target: &Url) -> Result<(), Error> {
match target.host() {
Some(host)
if self.capabilities.is_allowed_net(&NetTarget::Host(
if self.capabilities.allows_network_target(&NetTarget::Host(
host.to_owned(),
target.port_or_known_default(),
)) =>

View file

@ -12,6 +12,15 @@ pub trait Target {
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct FuncTarget(pub String, pub Option<String>);
impl std::fmt::Display for FuncTarget {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.1 {
Some(name) => write!(f, "{}:{}", self.0, name),
None => write!(f, "{}::*", self.0),
}
}
}
impl Target for FuncTarget {
fn matches(&self, elem: &Self) -> bool {
match self {
@ -44,6 +53,17 @@ pub enum NetTarget {
IPNet(ipnet::IpNet),
}
// impl display
impl std::fmt::Display for NetTarget {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Host(host, Some(port)) => write!(f, "{}:{}", host, port),
Self::Host(host, None) => write!(f, "{}", host),
Self::IPNet(ipnet) => write!(f, "{}", ipnet),
}
}
}
impl Target for NetTarget {
fn matches(&self, elem: &Self) -> bool {
match self {
@ -109,7 +129,7 @@ pub enum Targets<T: Target + Hash + Eq + PartialEq> {
All,
}
impl<T: Target + Hash + Eq + PartialEq + std::fmt::Debug> Targets<T> {
impl<T: Target + Hash + Eq + PartialEq + std::fmt::Debug + std::fmt::Display> Targets<T> {
fn matches(&self, elem: &T) -> bool {
match self {
Self::None => false,
@ -119,17 +139,33 @@ impl<T: Target + Hash + Eq + PartialEq + std::fmt::Debug> Targets<T> {
}
}
impl<T: Target + Hash + Eq + PartialEq + std::fmt::Display> std::fmt::Display for Targets<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::None => write!(f, "none"),
Self::All => write!(f, "all"),
Self::Some(targets) => {
let targets =
targets.iter().map(|t| t.to_string()).collect::<Vec<String>>().join(", ");
write!(f, "{}", targets)
}
}
}
}
/// Capabilities are used to limit what a user can do to the system.
///
/// Capabilities are split into 3 categories:
/// Capabilities are split into 4 categories:
/// - Scripting: Whether or not the user can execute scripts
/// - Guest access: Whether or not a non-authenticated user can execute queries on the system when authentication is enabled.
/// - Functions: Whether or not the user can execute certain functions
/// - Network: Whether or not the user can access certain network addresses
///
/// Capabilities are configured globally. By default, capabilities are configured as:
/// - Scripting: true
/// - Functions: All functions are allowed
/// - Network: All network addresses are allowed
/// - Scripting: false
/// - Guest access: false
/// - Functions: No function is allowed nor denied, hence all functions are denied unless explicitly allowed
/// - Network: No network address is allowed nor denied, hence all network addresses are denied unless explicitly allowed
///
/// The capabilities are defined using allow/deny lists for fine-grained control.
///
@ -141,6 +177,7 @@ impl<T: Target + Hash + Eq + PartialEq + std::fmt::Debug> Targets<T> {
#[derive(Debug, Clone)]
pub struct Capabilities {
scripting: bool,
guest_access: bool,
allow_funcs: Arc<Targets<FuncTarget>>,
deny_funcs: Arc<Targets<FuncTarget>>,
@ -148,11 +185,39 @@ pub struct Capabilities {
deny_net: Arc<Targets<NetTarget>>,
}
impl std::fmt::Display for Capabilities {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"scripting={}, guest_access={}, allow_funcs={}, deny_funcs={}, allow_net={}, deny_net={}",
self.scripting, self.guest_access, self.allow_funcs, self.deny_funcs, self.allow_net, self.deny_net
)
}
}
impl Default for Capabilities {
// By default, enable all capabilities
fn default() -> Self {
Self::none()
}
}
impl Capabilities {
fn none() -> Self {
Self {
scripting: false,
guest_access: false,
allow_funcs: Arc::new(Targets::None),
deny_funcs: Arc::new(Targets::None),
allow_net: Arc::new(Targets::None),
deny_net: Arc::new(Targets::None),
}
}
pub fn all() -> Self {
Self {
scripting: true,
guest_access: true,
allow_funcs: Arc::new(Targets::All),
deny_funcs: Arc::new(Targets::None),
@ -160,43 +225,50 @@ impl Default for Capabilities {
deny_net: Arc::new(Targets::None),
}
}
}
impl Capabilities {
pub fn with_scripting(mut self, scripting: bool) -> Self {
self.scripting = scripting;
self
}
pub fn with_allow_funcs(mut self, allow_funcs: Targets<FuncTarget>) -> Self {
pub fn with_guest_access(mut self, guest_access: bool) -> Self {
self.guest_access = guest_access;
self
}
pub fn with_functions(mut self, allow_funcs: Targets<FuncTarget>) -> Self {
self.allow_funcs = Arc::new(allow_funcs);
self
}
pub fn with_deny_funcs(mut self, deny_funcs: Targets<FuncTarget>) -> Self {
pub fn without_functions(mut self, deny_funcs: Targets<FuncTarget>) -> Self {
self.deny_funcs = Arc::new(deny_funcs);
self
}
pub fn with_allow_net(mut self, allow_net: Targets<NetTarget>) -> Self {
pub fn with_network_targets(mut self, allow_net: Targets<NetTarget>) -> Self {
self.allow_net = Arc::new(allow_net);
self
}
pub fn with_deny_net(mut self, deny_net: Targets<NetTarget>) -> Self {
pub fn without_network_targets(mut self, deny_net: Targets<NetTarget>) -> Self {
self.deny_net = Arc::new(deny_net);
self
}
pub fn is_allowed_scripting(&self) -> bool {
pub fn allows_scripting(&self) -> bool {
self.scripting
}
pub fn is_allowed_func(&self, target: &FuncTarget) -> bool {
pub fn allows_guest_access(&self) -> bool {
self.guest_access
}
pub fn allows_function(&self, target: &FuncTarget) -> bool {
self.allow_funcs.matches(target) && !self.deny_funcs.matches(target)
}
pub fn is_allowed_net(&self, target: &NetTarget) -> bool {
pub fn allows_network_target(&self, target: &NetTarget) -> bool {
self.allow_net.matches(target) && !self.deny_net.matches(target)
}
}
@ -403,77 +475,89 @@ mod tests {
// When scripting is allowed
{
let caps = Capabilities::default().with_scripting(true);
assert!(caps.is_allowed_scripting());
assert!(caps.allows_scripting());
}
// When scripting is denied
{
let caps = Capabilities::default().with_scripting(false);
assert!(!caps.is_allowed_scripting());
assert!(!caps.allows_scripting());
}
// When guest access is allowed
{
let caps = Capabilities::default().with_guest_access(true);
assert!(caps.allows_guest_access());
}
// When guest access is denied
{
let caps = Capabilities::default().with_guest_access(false);
assert!(!caps.allows_guest_access());
}
// When all nets are allowed
{
let caps = Capabilities::default()
.with_allow_net(Targets::<NetTarget>::All)
.with_deny_net(Targets::<NetTarget>::None);
assert!(caps.is_allowed_net(&NetTarget::from_str("example.com").unwrap()));
assert!(caps.is_allowed_net(&NetTarget::from_str("example.com:80").unwrap()));
.with_network_targets(Targets::<NetTarget>::All)
.without_network_targets(Targets::<NetTarget>::None);
assert!(caps.allows_network_target(&NetTarget::from_str("example.com").unwrap()));
assert!(caps.allows_network_target(&NetTarget::from_str("example.com:80").unwrap()));
}
// When all nets are allowed and denied at the same time
{
let caps = Capabilities::default()
.with_allow_net(Targets::<NetTarget>::All)
.with_deny_net(Targets::<NetTarget>::All);
assert!(!caps.is_allowed_net(&NetTarget::from_str("example.com").unwrap()));
assert!(!caps.is_allowed_net(&NetTarget::from_str("example.com:80").unwrap()));
.with_network_targets(Targets::<NetTarget>::All)
.without_network_targets(Targets::<NetTarget>::All);
assert!(!caps.allows_network_target(&NetTarget::from_str("example.com").unwrap()));
assert!(!caps.allows_network_target(&NetTarget::from_str("example.com:80").unwrap()));
}
// When some nets are allowed and some are denied, deny overrides the allow rules
{
let caps = Capabilities::default()
.with_allow_net(Targets::<NetTarget>::Some(
.with_network_targets(Targets::<NetTarget>::Some(
[NetTarget::from_str("example.com").unwrap()].into(),
))
.with_deny_net(Targets::<NetTarget>::Some(
.without_network_targets(Targets::<NetTarget>::Some(
[NetTarget::from_str("example.com:80").unwrap()].into(),
));
assert!(caps.is_allowed_net(&NetTarget::from_str("example.com").unwrap()));
assert!(caps.is_allowed_net(&NetTarget::from_str("example.com:443").unwrap()));
assert!(!caps.is_allowed_net(&NetTarget::from_str("example.com:80").unwrap()));
assert!(caps.allows_network_target(&NetTarget::from_str("example.com").unwrap()));
assert!(caps.allows_network_target(&NetTarget::from_str("example.com:443").unwrap()));
assert!(!caps.allows_network_target(&NetTarget::from_str("example.com:80").unwrap()));
}
// When all funcs are allowed
{
let caps = Capabilities::default()
.with_allow_funcs(Targets::<FuncTarget>::All)
.with_deny_funcs(Targets::<FuncTarget>::None);
assert!(caps.is_allowed_func(&FuncTarget::from_str("http::get").unwrap()));
assert!(caps.is_allowed_func(&FuncTarget::from_str("http::post").unwrap()));
.with_functions(Targets::<FuncTarget>::All)
.without_functions(Targets::<FuncTarget>::None);
assert!(caps.allows_function(&FuncTarget::from_str("http::get").unwrap()));
assert!(caps.allows_function(&FuncTarget::from_str("http::post").unwrap()));
}
// When all funcs are allowed and denied at the same time
{
let caps = Capabilities::default()
.with_allow_funcs(Targets::<FuncTarget>::All)
.with_deny_funcs(Targets::<FuncTarget>::All);
assert!(!caps.is_allowed_func(&FuncTarget::from_str("http::get").unwrap()));
assert!(!caps.is_allowed_func(&FuncTarget::from_str("http::post").unwrap()));
.with_functions(Targets::<FuncTarget>::All)
.without_functions(Targets::<FuncTarget>::All);
assert!(!caps.allows_function(&FuncTarget::from_str("http::get").unwrap()));
assert!(!caps.allows_function(&FuncTarget::from_str("http::post").unwrap()));
}
// When some funcs are allowed and some are denied, deny overrides the allow rules
{
let caps = Capabilities::default()
.with_allow_funcs(Targets::<FuncTarget>::Some(
.with_functions(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("http::*").unwrap()].into(),
))
.with_deny_funcs(Targets::<FuncTarget>::Some(
.without_functions(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("http::post").unwrap()].into(),
));
assert!(caps.is_allowed_func(&FuncTarget::from_str("http::get").unwrap()));
assert!(caps.is_allowed_func(&FuncTarget::from_str("http::put").unwrap()));
assert!(!caps.is_allowed_func(&FuncTarget::from_str("http::post").unwrap()));
assert!(caps.allows_function(&FuncTarget::from_str("http::get").unwrap()));
assert!(caps.allows_function(&FuncTarget::from_str("http::put").unwrap()));
assert!(!caps.allows_function(&FuncTarget::from_str("http::post").unwrap()));
}
}
}

View file

@ -19,7 +19,6 @@ pub use self::options::*;
pub use self::response::*;
pub use self::session::*;
pub(crate) use self::capabilities::Capabilities;
pub(crate) use self::executor::*;
pub(crate) use self::iterator::*;
pub(crate) use self::statement::*;
@ -27,6 +26,7 @@ pub(crate) use self::transaction::*;
pub(crate) use self::variables::*;
pub mod capabilities;
pub use self::capabilities::Capabilities;
pub mod node;
mod processor;

View file

@ -370,6 +370,9 @@ pub async fn asynchronous(
#[cfg(test)]
mod tests {
#[cfg(all(feature = "scripting", feature = "kv-mem"))]
use crate::dbs::Capabilities;
#[test]
fn implementations_are_present() {
// Accumulate and display all problems at once to avoid a test -> fix -> test -> fix cycle.
@ -399,7 +402,10 @@ mod tests {
let name = name.replace("::", ".");
let sql =
format!("RETURN function() {{ return typeof surrealdb.functions.{name}; }}");
let dbs = crate::kvs::Datastore::new("memory").await.unwrap();
let dbs = crate::kvs::Datastore::new("memory")
.await
.unwrap()
.with_capabilities(Capabilities::all());
let ses = crate::dbs::Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None).await.unwrap();
let tmp = res.remove(0).result.unwrap();

View file

@ -26,7 +26,7 @@ async fn test_fetch_get() {
.await;
// Execute test
let ds = Datastore::new("memory").await.unwrap();
let ds = Datastore::new("memory").await.unwrap().with_capabilities(Capabilities::all());
let sess = Session::owner();
let sql = format!(
r#"
@ -71,7 +71,7 @@ async fn test_fetch_put() {
.await;
// Execute test
let ds = Datastore::new("memory").await.unwrap();
let ds = Datastore::new("memory").await.unwrap().with_capabilities(Capabilities::all());
let sess = Session::owner();
let sql = format!(
r#"
@ -121,7 +121,7 @@ async fn test_fetch_error() {
.await;
// Execute test
let ds = Datastore::new("memory").await.unwrap();
let ds = Datastore::new("memory").await.unwrap().with_capabilities(Capabilities::all());
let sess = Session::owner();
let sql = format!(
r#"
@ -168,7 +168,7 @@ async fn test_fetch_denied() {
// Execute test
let ds = Datastore::new("memory").await.unwrap().with_capabilities(
Capabilities::default().with_deny_net(Targets::Some(
Capabilities::all().without_network_targets(Targets::Some(
[NetTarget::from_str(&server.address().to_string()).unwrap()].into(),
)),
);

View file

@ -12,7 +12,7 @@ use crate::dbs::Session;
use crate::dbs::Variables;
use crate::err::Error;
use crate::iam::ResourceKind;
use crate::iam::{Action, Auth, Role};
use crate::iam::{Action, Auth, Error as IamError, Role};
use crate::key::root::hb::Hb;
use crate::opt::auth::Root;
use crate::sql;
@ -751,6 +751,17 @@ impl Datastore {
sess: &Session,
vars: Variables,
) -> Result<Vec<Response>, Error> {
// Check if anonymous actors can execute queries when auth is enabled
// TODO(sgirones): Check this as part of the authoritzation layer
if self.auth_enabled && sess.au.is_anon() && !self.capabilities.allows_guest_access() {
return Err(IamError::NotAllowed {
actor: "anonymous".to_string(),
action: "process".to_string(),
resource: "query".to_string(),
}
.into());
}
// Create a new query options
let opt = Options::default()
.with_id(self.id.0)
@ -806,6 +817,17 @@ impl Datastore {
sess: &Session,
vars: Variables,
) -> Result<Value, Error> {
// Check if anonymous actors can compute values when auth is enabled
// TODO(sgirones): Check this as part of the authoritzation layer
if self.auth_enabled && !self.capabilities.allows_guest_access() {
return Err(IamError::NotAllowed {
actor: "anonymous".to_string(),
action: "compute".to_string(),
resource: "value".to_string(),
}
.into());
}
// Create a new query options
let opt = Options::default()
.with_id(self.id.0)

View file

@ -10,6 +10,7 @@ mod api_integration {
use std::sync::Arc;
use std::sync::Mutex;
use std::time::Duration;
use surrealdb::dbs::capabilities::Capabilities;
use surrealdb::error::Api as ApiError;
use surrealdb::error::Db as DbError;
use surrealdb::opt::auth::Database;
@ -134,7 +135,10 @@ mod api_integration {
username: ROOT_USER,
password: ROOT_PASS,
};
let config = Config::new().user(root).tick_interval(TICK_INTERVAL);
let config = Config::new()
.user(root)
.tick_interval(TICK_INTERVAL)
.capabilities(Capabilities::all());
let db = Surreal::new::<Mem>(config).await.unwrap();
db.signin(root).await.unwrap();
db
@ -224,7 +228,10 @@ mod api_integration {
username: ROOT_USER,
password: ROOT_PASS,
};
let config = Config::new().user(root).tick_interval(TICK_INTERVAL);
let config = Config::new()
.user(root)
.tick_interval(TICK_INTERVAL)
.capabilities(Capabilities::all());
let db = Surreal::new::<File>((path, config)).await.unwrap();
db.signin(root).await.unwrap();
db
@ -248,7 +255,10 @@ mod api_integration {
username: ROOT_USER,
password: ROOT_PASS,
};
let config = Config::new().user(root).tick_interval(TICK_INTERVAL);
let config = Config::new()
.user(root)
.tick_interval(TICK_INTERVAL)
.capabilities(Capabilities::all());
let db = Surreal::new::<RocksDb>((path, config)).await.unwrap();
db.signin(root).await.unwrap();
db
@ -272,7 +282,10 @@ mod api_integration {
username: ROOT_USER,
password: ROOT_PASS,
};
let config = Config::new().user(root).tick_interval(TICK_INTERVAL);
let config = Config::new()
.user(root)
.tick_interval(TICK_INTERVAL)
.capabilities(Capabilities::all());
let db = Surreal::new::<SpeeDb>((path, config)).await.unwrap();
db.signin(root).await.unwrap();
db
@ -295,7 +308,10 @@ mod api_integration {
username: ROOT_USER,
password: ROOT_PASS,
};
let config = Config::new().user(root).tick_interval(TICK_INTERVAL);
let config = Config::new()
.user(root)
.tick_interval(TICK_INTERVAL)
.capabilities(Capabilities::all());
let db = Surreal::new::<TiKv>(("127.0.0.1:2379", config)).await.unwrap();
db.signin(root).await.unwrap();
db
@ -318,7 +334,10 @@ mod api_integration {
username: ROOT_USER,
password: ROOT_PASS,
};
let config = Config::new().user(root).tick_interval(TICK_INTERVAL);
let config = Config::new()
.user(root)
.tick_interval(TICK_INTERVAL)
.capabilities(Capabilities::all());
let db = Surreal::new::<FDb>(("/etc/foundationdb/fdb.cluster", config)).await.unwrap();
db.signin(root).await.unwrap();
db

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -15,7 +16,7 @@ async fn clear_transaction_cache_table() -> Result<(), Error> {
COMMIT;
SELECT * FROM other;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 4);
@ -71,7 +72,7 @@ async fn clear_transaction_cache_field() -> Result<(), Error> {
SELECT * FROM person;
COMMIT;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 6);

View file

@ -1,9 +1,10 @@
mod parse;
use chrono::DateTime;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -33,7 +34,7 @@ async fn table_change_feeds() -> Result<(), Error> {
CREATE person:1000 SET name = 'Yusuke';
SHOW CHANGES FOR TABLE person SINCE 0;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let start_ts = 0u64;
let end_ts = start_ts + 1;
@ -179,7 +180,7 @@ async fn table_change_feeds() -> Result<(), Error> {
#[tokio::test]
async fn changefeed_with_ts() -> Result<(), Error> {
let db = Datastore::new("memory").await?;
let db = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
// Enable change feeds
let sql = "

View file

@ -1,7 +1,7 @@
mod parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -17,7 +17,7 @@ async fn compare_empty() -> Result<(), Error> {
RETURN 0 = 0.0;
RETURN 0 = 0.1;
"#;
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 9);

View file

@ -2,11 +2,12 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use std::future::Future;
use std::thread::Builder;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[test]
@ -204,7 +205,7 @@ async fn run_queries(
impl Iterator<Item = Result<Value, Error>> + ExactSizeIterator + DoubleEndedIterator + 'static,
Error,
> {
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
dbs.execute(sql, &ses, None).await.map(|v| v.into_iter().map(|res| res.result))
}

View file

@ -1,9 +1,10 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::iam::Role;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Part;
use surrealdb::sql::Thing;
use surrealdb::sql::Value;
@ -29,7 +30,7 @@ async fn create_with_id() -> Result<(), Error> {
CREATE person:other SET id = 'tobie';
CREATE person:other CONTENT { id: 'tobie', name: 'Tester' };
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 14);
@ -177,7 +178,7 @@ async fn create_with_custom_function() -> Result<(), Error> {
RETURN fn::record::create({ test: true, name: 'Tobie' });
RETURN fn::record::create({ test: true, name: 'Jaime' });
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -214,7 +215,7 @@ async fn create_or_insert_with_permissions() -> Result<(), Error> {
DEFINE TABLE demo SCHEMAFULL PERMISSIONS FOR select, create, update WHERE user = $auth.id;
DEFINE FIELD user ON TABLE demo VALUE $auth.id;
";
let dbs = Datastore::new("memory").await?.with_auth_enabled(true);
let dbs = new_ds().await?.with_auth_enabled(true);
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 4);
@ -272,7 +273,7 @@ async fn create_on_none_values_with_unique_index() -> Result<(), Error> {
CREATE foo SET name = 'Jane Doe';
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -293,7 +294,7 @@ async fn create_with_unique_index_with_two_flattened_fields() -> Result<(), Erro
CREATE user:4 SET account = 'Apple', tags = ['two', 'three'], emails = ['a@example.com', 'b@example.com'];
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -326,7 +327,7 @@ async fn create_with_unique_index_with_one_flattened_field() -> Result<(), Error
CREATE user:2 SET account = 'Apple', tags = ['two', 'three'], emails = ['a@example.com', 'b@example.com'];
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -352,7 +353,7 @@ async fn create_with_unique_index_on_one_field_with_flattened_sub_values() -> Re
CREATE user:2 SET account = 'Apple', tags = ['two', 'three'], emails = [ { value:'a@example.com'} , { value:'b@example.com' } ];
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -378,7 +379,7 @@ async fn create_with_unique_index_on_two_fields() -> Result<(), Error> {
CREATE user:2 SET account = 'Apple', tags = ['two', 'one'], emails = ['b@example.com', 'c@example.com'];
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -433,7 +434,7 @@ async fn common_permissions_checks(auth_enabled: bool) {
let sess = Session::for_level(level, role).with_ns(ns).with_db(db);
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds.execute(statement, &sess, None).await.unwrap();
let res = resp.remove(0).output();
@ -458,7 +459,7 @@ async fn common_permissions_checks(auth_enabled: bool) {
// Test the CREATE statement when the table already exists
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute("CREATE person", &Session::owner().with_ns("NS").with_db("DB"), None)
@ -528,7 +529,7 @@ async fn check_permissions_auth_enabled() {
// When the table doesn't exist
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute("CREATE person", &Session::default().with_ns("NS").with_db("DB"), None)
@ -546,7 +547,7 @@ async fn check_permissions_auth_enabled() {
// When the table exists but grants no permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -570,7 +571,7 @@ async fn check_permissions_auth_enabled() {
// When the table exists and grants full permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -607,7 +608,7 @@ async fn check_permissions_auth_disabled() {
// When the table doesn't exist
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute("CREATE person", &Session::default().with_ns("NS").with_db("DB"), None)
@ -624,7 +625,7 @@ async fn check_permissions_auth_disabled() {
// When the table exists but grants no permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -647,7 +648,7 @@ async fn check_permissions_auth_disabled() {
}
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
// When the table exists and grants full permissions
let mut resp = ds

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -12,7 +13,7 @@ async fn datetimes_conversion() -> Result<(), Error> {
SELECT * FROM <datetime> "2012-01-01";
SELECT * FROM <string> "2012-01-01T08:00:00Z" + "-test";
"#;
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);

View file

@ -1,15 +1,14 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::*;
use std::collections::HashMap;
use parse::Parse;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::iam::Role;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Idiom;
use surrealdb::sql::{Part, Value};
@ -19,7 +18,7 @@ async fn define_statement_namespace() -> Result<(), Error> {
DEFINE NAMESPACE test;
INFO FOR ROOT;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);
@ -45,7 +44,7 @@ async fn define_statement_database() -> Result<(), Error> {
DEFINE DATABASE test;
INFO FOR NS;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);
@ -74,7 +73,7 @@ async fn define_statement_function() -> Result<(), Error> {
};
INFO FOR DB;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);
@ -107,7 +106,7 @@ async fn define_statement_table_drop() -> Result<(), Error> {
DEFINE TABLE test DROP;
INFO FOR DB;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);
@ -138,7 +137,7 @@ async fn define_statement_table_schemaless() -> Result<(), Error> {
DEFINE TABLE test SCHEMALESS;
INFO FOR DB;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);
@ -170,7 +169,7 @@ async fn define_statement_table_schemafull() -> Result<(), Error> {
DEFINE TABLE test SCHEMAFULL;
INFO FOR DB;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -204,7 +203,7 @@ async fn define_statement_table_schemaful() -> Result<(), Error> {
DEFINE TABLE test SCHEMAFUL;
INFO FOR DB;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);
@ -240,7 +239,7 @@ async fn define_statement_table_foreigntable() -> Result<(), Error> {
INFO FOR DB;
INFO FOR TB test;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -327,7 +326,7 @@ async fn define_statement_event() -> Result<(), Error> {
UPDATE user:test SET email = 'test@surrealdb.com', updated_at = time::now();
SELECT count() FROM activity GROUP ALL;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -384,7 +383,7 @@ async fn define_statement_event_when_event() -> Result<(), Error> {
UPDATE user:test SET email = 'test@surrealdb.com', updated_at = time::now();
SELECT count() FROM activity GROUP ALL;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -441,7 +440,7 @@ async fn define_statement_event_when_logic() -> Result<(), Error> {
UPDATE user:test SET email = 'test@surrealdb.com', updated_at = time::now();
SELECT count() FROM activity GROUP ALL;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -490,7 +489,7 @@ async fn define_statement_field() -> Result<(), Error> {
DEFINE FIELD test ON TABLE user;
INFO FOR TABLE user;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -522,7 +521,7 @@ async fn define_statement_field_type() -> Result<(), Error> {
DEFINE FIELD test ON TABLE user TYPE string;
INFO FOR TABLE user;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -554,7 +553,7 @@ async fn define_statement_field_value() -> Result<(), Error> {
DEFINE FIELD test ON TABLE user VALUE $value OR 'GBR';
INFO FOR TABLE user;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -586,7 +585,7 @@ async fn define_statement_field_assert() -> Result<(), Error> {
DEFINE FIELD test ON TABLE user ASSERT $value != NONE AND $value = /[A-Z]{3}/;
INFO FOR TABLE user;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -618,7 +617,7 @@ async fn define_statement_field_type_value_assert() -> Result<(), Error> {
DEFINE FIELD test ON TABLE user TYPE string VALUE $value OR 'GBR' ASSERT $value != NONE AND $value = /[A-Z]{3}/;
INFO FOR TABLE user;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -654,7 +653,7 @@ async fn define_statement_index_single_simple() -> Result<(), Error> {
UPDATE user:1 SET age = 24;
UPDATE user:2 SET age = 11;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -702,7 +701,7 @@ async fn define_statement_index_single() -> Result<(), Error> {
CREATE user:1 SET email = 'test@surrealdb.com';
CREATE user:2 SET email = 'test@surrealdb.com';
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -746,7 +745,7 @@ async fn define_statement_index_multiple() -> Result<(), Error> {
CREATE user:3 SET account = 'apple', email = 'test@surrealdb.com';
CREATE user:4 SET account = 'tesla', email = 'test@surrealdb.com';
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -798,7 +797,7 @@ async fn define_statement_index_single_unique() -> Result<(), Error> {
DELETE user:1;
CREATE user:2 SET email = 'test@surrealdb.com';
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -856,7 +855,7 @@ async fn define_statement_index_multiple_unique() -> Result<(), Error> {
DELETE user:2;
CREATE user:4 SET account = 'tesla', email = 'test@surrealdb.com';
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 12);
@ -931,7 +930,7 @@ async fn define_statement_index_single_unique_existing() -> Result<(), Error> {
DEFINE INDEX test ON user COLUMNS email UNIQUE;
INFO FOR TABLE user;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 6);
@ -978,7 +977,7 @@ async fn define_statement_index_multiple_unique_existing() -> Result<(), Error>
DEFINE INDEX test ON user COLUMNS account, email UNIQUE;
INFO FOR TABLE user;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -1023,7 +1022,7 @@ async fn define_statement_index_single_unique_embedded_multiple() -> Result<(),
CREATE user:1 SET tags = ['one', 'two'];
CREATE user:2 SET tags = ['two', 'three'];
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -1073,7 +1072,7 @@ async fn define_statement_index_multiple_unique_embedded_multiple() -> Result<()
CREATE user:3 SET account = 'apple', tags = ['two', 'three'];
CREATE user:4 SET account = 'tesla', tags = ['two', 'three'];
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -1133,7 +1132,7 @@ async fn define_statement_analyzer() -> Result<(), Error> {
DEFINE ANALYZER autocomplete FILTERS lowercase,edgengram(2,10);
INFO FOR DB;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -1177,7 +1176,7 @@ async fn define_statement_search_index() -> Result<(), Error> {
ANALYZE INDEX blog_title ON blog;
"#;
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 8);
@ -1230,7 +1229,7 @@ async fn define_statement_user_root() -> Result<(), Error> {
INFO FOR ROOT;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner();
let res = &mut dbs.execute(sql, &ses, None).await?;
@ -1252,7 +1251,7 @@ async fn define_statement_user_root() -> Result<(), Error> {
#[tokio::test]
async fn define_statement_user_ns() -> Result<(), Error> {
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner();
// Create a NS user and retrieve it.
@ -1308,7 +1307,7 @@ async fn define_statement_user_ns() -> Result<(), Error> {
#[tokio::test]
async fn define_statement_user_db() -> Result<(), Error> {
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner();
// Create a NS user and retrieve it.

View file

@ -1,11 +1,12 @@
mod parse;
use parse::Parse;
use channel::{Receiver, TryRecvError};
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::{Action, Notification, Session};
use surrealdb::err::Error;
use surrealdb::iam::Role;
use surrealdb::kvs::Datastore;
use surrealdb::sql::{Id, Thing, Value};
#[tokio::test]
@ -15,7 +16,7 @@ async fn delete() -> Result<(), Error> {
DELETE person:test;
SELECT * FROM person;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -79,7 +80,7 @@ async fn common_permissions_checks(auth_enabled: bool) {
let sess = Session::for_level(level, role).with_ns(ns).with_db(db);
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute("CREATE person:test", &Session::owner().with_ns("NS").with_db("DB"), None)
@ -191,7 +192,7 @@ async fn check_permissions_auth_enabled() {
// When the table exists but grants no permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -233,7 +234,7 @@ async fn check_permissions_auth_enabled() {
// When the table exists and grants full permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -290,7 +291,7 @@ async fn check_permissions_auth_disabled() {
// When the table exists but grants no permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -331,7 +332,7 @@ async fn check_permissions_auth_disabled() {
}
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
// When the table exists and grants full permissions
let mut resp = ds
@ -375,7 +376,7 @@ async fn check_permissions_auth_disabled() {
#[tokio::test]
async fn delete_filtered_live_notification() -> Result<(), Error> {
let dbs = Datastore::new("memory").await?.with_notifications();
let dbs = new_ds().await?.with_notifications();
let ses = Session::owner().with_ns("test").with_db("test").with_rt(true);
let res = &mut dbs.execute("CREATE person:test_true SET condition = true", &ses, None).await?;
assert_eq!(res.len(), 1);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -16,7 +17,7 @@ async fn complex_ids() -> Result<(), Error> {
CREATE person:`100`;
SELECT * FROM person;
"#;
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -94,7 +95,7 @@ async fn complex_strings() -> Result<(), Error> {
RETURN "String with some \"escaped double quoted\" characters";
RETURN "String with some 'single' and \"double\" quoted characters";
"#;
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -21,7 +22,7 @@ async fn create_relate_select() -> Result<(), Error> {
SELECT *, ->bought AS products FROM user FETCH products;
SELECT *, ->(bought AS purchases) FROM user FETCH purchases, purchases.out;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 12);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Thing;
use surrealdb::sql::Value;
@ -19,7 +20,7 @@ async fn field_definition_value_assert_failure() -> Result<(), Error> {
CREATE person:test SET email = 'info@surrealdb.com', other = 'ignore', age = 0;
CREATE person:test SET email = 'info@surrealdb.com', other = 'ignore', age = 13;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 9);
@ -102,7 +103,7 @@ async fn field_definition_value_assert_success() -> Result<(), Error> {
DEFINE FIELD name ON person TYPE option<string> VALUE $value OR 'No name';
CREATE person:test SET email = 'info@surrealdb.com', other = 'ignore', age = 22;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -151,7 +152,7 @@ async fn field_definition_empty_nested_objects() -> Result<(), Error> {
};
SELECT * FROM person;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 4);
@ -205,7 +206,7 @@ async fn field_definition_empty_nested_arrays() -> Result<(), Error> {
};
SELECT * FROM person;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 4);
@ -257,7 +258,7 @@ async fn field_definition_empty_nested_flexible() -> Result<(), Error> {
};
SELECT * FROM person;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 4);
@ -322,7 +323,7 @@ async fn field_definition_default_value() -> Result<(), Error> {
UPDATE product:test SET secondary = false;
UPDATE product:test SET tertiary = 'something';
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 11);
@ -435,7 +436,7 @@ async fn field_definition_value_reference() -> Result<(), Error> {
UPDATE product;
SELECT * FROM product;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -536,7 +537,7 @@ async fn field_definition_value_reference_with_future() -> Result<(), Error> {
UPDATE product;
SELECT * FROM product;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -638,7 +639,7 @@ async fn field_definition_edge_permissions() -> Result<(), Error> {
INSERT INTO user (id, name) VALUES (user:one, 'John'), (user:two, 'Lucy');
INSERT INTO business (id, owner) VALUES (business:one, user:one), (business:two, user:two);
";
let dbs = Datastore::new("memory").await?.with_auth_enabled(true);
let dbs = new_ds().await?.with_auth_enabled(true);
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 6);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -30,7 +31,7 @@ async fn foreach() -> Result<(), Error> {
};
SELECT * FROM person;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 6);

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -12,7 +13,7 @@ async fn future_function_simple() -> Result<(), Error> {
UPDATE person:test SET birthday = <datetime> '2007-06-22';
UPDATE person:test SET birthday = <datetime> '2001-06-22';
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -44,7 +45,7 @@ async fn future_function_arguments() -> Result<(), Error> {
y = 'b-' + parse::email::user(b)
;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -91,7 +92,7 @@ async fn concurrency() -> Result<(), Error> {
/// Returns `true` iif `limit` futures are concurrently executed.
async fn test_limit(limit: usize) -> Result<bool, Error> {
let sql = query(limit, MILLIS);
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = dbs.execute(&sql, &ses, None).await;

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -11,7 +12,7 @@ async fn geometry_point() -> Result<(), Error> {
UPDATE city:london SET centre = (-0.118092, 51.509865);
SELECT * FROM city:london;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);
@ -68,7 +69,7 @@ async fn geometry_polygon() -> Result<(), Error> {
};
SELECT * FROM city:london;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -161,7 +162,7 @@ async fn geometry_multipoint() -> Result<(), Error> {
};
SELECT * FROM city:london;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -239,7 +240,7 @@ async fn geometry_multipolygon() -> Result<(), Error> {
};
SELECT * FROM university:oxford;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -344,7 +345,7 @@ async fn geometry_inner_access() -> Result<(), Error> {
],
};
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 4);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -20,7 +21,7 @@ async fn select_limit_fetch() -> Result<(), Error> {
SELECT *, time::year(time) AS year FROM temperature;
SELECT count(), time::year(time) AS year, country FROM temperature GROUP BY country, year;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 11);
@ -244,7 +245,7 @@ async fn select_multi_aggregate() -> Result<(), Error> {
SELECT group, math::sum(one) AS one, math::sum(two) AS two FROM test GROUP BY group;
SELECT group, math::sum(two) AS two, math::sum(one) AS one FROM test GROUP BY group;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 6);
@ -349,7 +350,7 @@ async fn select_multi_aggregate_composed() -> Result<(), Error> {
SELECT group, math::sum(math::round(one)) AS one, math::sum(math::round(two)) AS two FROM test GROUP BY group;
SELECT group, math::sum(math::ceil(one)) AS one, math::sum(math::ceil(two)) AS two FROM test GROUP BY group;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);

View file

@ -1,10 +1,17 @@
use std::collections::HashMap;
use std::sync::Arc;
use surrealdb::dbs::capabilities::Capabilities;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::iam::{Auth, Level, Role};
use surrealdb::kvs::Datastore;
pub async fn new_ds() -> Result<Datastore, Error> {
Ok(Datastore::new("memory").await?.with_capabilities(Capabilities::all()))
}
#[allow(dead_code)]
pub async fn iam_run_case(
prepare: &str,
test: &str,
@ -86,6 +93,7 @@ pub async fn iam_run_case(
Ok(())
}
#[allow(dead_code)]
pub async fn iam_check_cases(
cases: std::slice::Iter<'_, ((Level, Role), (&str, &str), bool)>,
scenario: &HashMap<&str, &str>,
@ -105,14 +113,14 @@ pub async fn iam_check_cases(
};
// Auth enabled
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(true);
let ds = new_ds().await.unwrap().with_auth_enabled(true);
iam_run_case(prepare, test, check, &expected_result, &ds, &sess, *should_succeed)
.await?;
}
// Auth disabled
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(false);
let ds = new_ds().await.unwrap().with_auth_enabled(false);
iam_run_case(prepare, test, check, &expected_result, &ds, &sess, *should_succeed)
.await?;
}
@ -128,7 +136,7 @@ pub async fn iam_check_cases(
auth_enabled =
auth_enabled.then(|| "auth enabled").unwrap_or_else(|| "auth disabled")
);
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let expected_result = if auth_enabled {
check_results.get(1).unwrap()
} else {

View file

@ -1,5 +1,3 @@
mod parse;
mod helpers;
use helpers::*;
@ -8,7 +6,6 @@ use std::collections::HashMap;
use regex::Regex;
use surrealdb::dbs::Session;
use surrealdb::iam::Role;
use surrealdb::kvs::Datastore;
#[tokio::test]
async fn info_for_root() {
@ -17,7 +14,7 @@ async fn info_for_root() {
DEFINE USER user ON ROOT PASSWORD 'pass';
INFO FOR ROOT
"#;
let dbs = Datastore::new("memory").await.unwrap();
let dbs = new_ds().await.unwrap();
let ses = Session::owner();
let mut res = dbs.execute(sql, &ses, None).await.unwrap();
@ -45,7 +42,7 @@ async fn info_for_ns() {
DEFINE TOKEN token ON NS TYPE HS512 VALUE 'secret';
INFO FOR NS
"#;
let dbs = Datastore::new("memory").await.unwrap();
let dbs = new_ds().await.unwrap();
let ses = Session::owner().with_ns("ns");
let mut res = dbs.execute(sql, &ses, None).await.unwrap();
@ -79,7 +76,7 @@ async fn info_for_db() {
DEFINE ANALYZER analyzer TOKENIZERS BLANK;
INFO FOR DB
"#;
let dbs = Datastore::new("memory").await.unwrap();
let dbs = new_ds().await.unwrap();
let ses = Session::owner().with_ns("ns").with_db("db");
let mut res = dbs.execute(sql, &ses, None).await.unwrap();
@ -105,7 +102,7 @@ async fn info_for_scope() {
DEFINE TOKEN token ON SCOPE account TYPE HS512 VALUE 'secret';
INFO FOR SCOPE account;
"#;
let dbs = Datastore::new("memory").await.unwrap();
let dbs = new_ds().await.unwrap();
let ses = Session::owner().with_ns("ns").with_db("db");
let mut res = dbs.execute(sql, &ses, None).await.unwrap();
@ -133,7 +130,7 @@ async fn info_for_table() {
DEFINE INDEX index ON TABLE TB FIELDS field;
INFO FOR TABLE TB;
"#;
let dbs = Datastore::new("memory").await.unwrap();
let dbs = new_ds().await.unwrap();
let ses = Session::owner().with_ns("ns").with_db("db");
let mut res = dbs.execute(sql, &ses, None).await.unwrap();
@ -162,7 +159,7 @@ async fn info_for_user() {
DEFINE USER user ON NS PASSWORD 'pass';
DEFINE USER user ON DB PASSWORD 'pass';
"#;
let dbs = Datastore::new("memory").await.unwrap();
let dbs = new_ds().await.unwrap();
let ses = Session::owner().with_ns("ns").with_db("db");
let res = dbs.execute(sql, &ses, None).await.unwrap();

View file

@ -1,9 +1,10 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::iam::Role;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Part;
use surrealdb::sql::Value;
@ -16,7 +17,7 @@ async fn insert_statement_object_single() -> Result<(), Error> {
something: 'other',
};
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -44,7 +45,7 @@ async fn insert_statement_object_multiple() -> Result<(), Error> {
},
];
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -66,7 +67,7 @@ async fn insert_statement_values_single() -> Result<(), Error> {
let sql = "
INSERT INTO test (id, test, something) VALUES ('tester', true, 'other');
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -83,7 +84,7 @@ async fn insert_statement_values_multiple() -> Result<(), Error> {
let sql = "
INSERT INTO test (id, test, something) VALUES (1, true, 'other'), (2, false, 'else');
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -105,7 +106,7 @@ async fn insert_statement_values_retable_id() -> Result<(), Error> {
let sql = "
INSERT INTO test (id, test, something) VALUES (person:1, true, 'other'), (person:2, false, 'else');
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -128,7 +129,7 @@ async fn insert_statement_on_duplicate_key() -> Result<(), Error> {
INSERT INTO test (id, test, something) VALUES ('tester', true, 'other');
INSERT INTO test (id, test, something) VALUES ('tester', true, 'other') ON DUPLICATE KEY UPDATE something = 'else';
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);
@ -149,7 +150,7 @@ async fn insert_statement_output() -> Result<(), Error> {
let sql = "
INSERT INTO test (id, test, something) VALUES ('tester', true, 'other') RETURN something;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -169,7 +170,7 @@ async fn insert_statement_duplicate_key_update() -> Result<(), Error> {
INSERT INTO company (name, founded) VALUES ('SurrealDB', '2021-09-11') ON DUPLICATE KEY UPDATE founded = $input.founded;
INSERT INTO company (name, founded) VALUES ('SurrealDB', '2021-09-12') ON DUPLICATE KEY UPDATE founded = $input.founded PARALLEL;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 4);
@ -229,7 +230,7 @@ async fn common_permissions_checks(auth_enabled: bool) {
// Test the INSERT statement when the table has to be created
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds.execute(statement, &sess, None).await.unwrap();
let res = resp.remove(0).output();
@ -252,7 +253,7 @@ async fn common_permissions_checks(auth_enabled: bool) {
// Test the INSERT statement when the table already exists
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute("CREATE person", &Session::owner().with_ns("NS").with_db("DB"), None)
@ -321,7 +322,7 @@ async fn check_permissions_auth_enabled() {
// When the table doesn't exist
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -343,7 +344,7 @@ async fn check_permissions_auth_enabled() {
// When the table exists but grants no permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -371,7 +372,7 @@ async fn check_permissions_auth_enabled() {
// When the table exists and grants full permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -412,7 +413,7 @@ async fn check_permissions_auth_disabled() {
// When the table doesn't exist
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -433,7 +434,7 @@ async fn check_permissions_auth_disabled() {
// When the table exists but grants no permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -461,7 +462,7 @@ async fn check_permissions_auth_disabled() {
// When the table exists and grants full permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -15,7 +16,7 @@ async fn select_limit_fetch() -> Result<(), Error> {
CREATE person:jaime SET tags = [tag:js];
SELECT * FROM person LIMIT 1 FETCH tags;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 6);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -14,7 +15,7 @@ async fn select_where_matches_using_index() -> Result<(), Error> {
SELECT id FROM blog WHERE title @1@ 'Hello' EXPLAIN;
SELECT id, search::highlight('<em>', '</em>', 1) AS title FROM blog WHERE title @1@ 'Hello';
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -62,7 +63,7 @@ async fn select_where_matches_without_using_index_iterator() -> Result<(), Error
SELECT id FROM blog WHERE (title @0@ 'hello' AND identifier > 0) OR (title @1@ 'world' AND identifier < 99) EXPLAIN FULL;
SELECT id,search::highlight('<em>', '</em>', 1) AS title FROM blog WHERE (title @0@ 'hello' AND identifier > 0) OR (title @1@ 'world' AND identifier < 99);
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 6);
@ -117,7 +118,7 @@ async fn select_where_matches_using_index_and_arrays(parallel: bool) -> Result<(
SELECT id, search::highlight('<em>', '</em>', 1) AS content FROM blog WHERE content @1@ 'Hello Bãr' {p};
"
);
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -186,7 +187,7 @@ async fn select_where_matches_using_index_and_objects(parallel: bool) -> Result<
SELECT id, search::highlight('<em>', '</em>', 1) AS content FROM blog WHERE content @1@ 'Hello Bãr' {p};
"
);
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -250,7 +251,7 @@ async fn select_where_matches_using_index_offsets() -> Result<(), Error> {
DEFINE INDEX blog_content ON blog FIELDS content SEARCH ANALYZER simple BM25 HIGHLIGHTS;
SELECT id, search::offsets(0) AS title, search::offsets(1) AS content FROM blog WHERE title @0@ 'title' AND content @1@ 'Hello Bãr';
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -288,7 +289,7 @@ async fn select_where_matches_using_index_and_score() -> Result<(), Error> {
DEFINE INDEX blog_title ON blog FIELDS title SEARCH ANALYZER simple BM25(1.2,0.75) HIGHLIGHTS;
SELECT id,search::score(1) AS score FROM blog WHERE title @1@ 'animals';
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -326,7 +327,7 @@ async fn select_where_matches_without_using_index_and_score() -> Result<(), Erro
WHERE (title @1@ 'dummy1' AND label = 'test')
OR (title @2@ 'dummy2' AND label = 'test');
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None).await?;
assert_eq!(res.len(), 9);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -17,7 +18,7 @@ async fn merge_record() -> Result<(), Error> {
}
};
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -11,7 +12,7 @@ async fn model_count() -> Result<(), Error> {
CREATE |test:1000| SET time = time::now();
SELECT count() FROM test GROUP ALL;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);
@ -36,7 +37,7 @@ async fn model_range() -> Result<(), Error> {
CREATE |test:101..1100| SET time = time::now();
SELECT count() FROM test GROUP ALL;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -14,7 +15,7 @@ async fn define_global_param() -> Result<(), Error> {
LET $test = 56789;
SELECT * FROM $test;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -57,7 +58,7 @@ async fn define_protected_param() -> Result<(), Error> {
SELECT * FROM $test WHERE some = 'thing';
LET $auth = { ID: admin:tester };
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);

View file

@ -1,9 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::{Response, Session};
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -118,7 +118,7 @@ async fn select_where_iterate_two_no_index() -> Result<(), Error> {
}
async fn execute_test(sql: &str, expected_result: usize) -> Result<Vec<Response>, Error> {
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let mut res = dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), expected_result);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -13,7 +14,7 @@ async fn query_basic() -> Result<(), Error> {
RETURN $test;
$test;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 4);
@ -45,7 +46,7 @@ async fn query_basic_with_modification() -> Result<(), Error> {
RETURN $test + 11369;
$test + 11369;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 4);
@ -77,7 +78,7 @@ async fn query_root_function() -> Result<(), Error> {
string::lowercase($test);
string::slug($test);
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 4);
@ -110,7 +111,7 @@ async fn query_root_record() -> Result<(), Error> {
<future> { person:tobie->knows->person.name };
person:tobie->knows->person.name;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -12,7 +13,7 @@ async fn relate_with_parameters() -> Result<(), Error> {
LET $jaime = person:jaime;
RELATE $tobie->knows->$jaime SET id = knows:test, brother = true;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -50,7 +51,7 @@ async fn relate_and_overwrite() -> Result<(), Error> {
UPDATE knows:test CONTENT { test: true };
SELECT * FROM knows:test;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);

View file

@ -1,4 +1,5 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::*;
@ -8,11 +9,9 @@ mod util;
use std::collections::HashMap;
use parse::Parse;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::iam::Role;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -22,7 +21,7 @@ async fn remove_statement_table() -> Result<(), Error> {
REMOVE TABLE test;
INFO FOR DB;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -56,7 +55,7 @@ async fn remove_statement_analyzer() -> Result<(), Error> {
REMOVE ANALYZER english;
INFO FOR DB;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -96,7 +95,7 @@ async fn remove_statement_index() -> Result<(), Error> {
REMOVE INDEX ft_title ON book;
INFO FOR TABLE book;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 9);

View file

@ -2,9 +2,10 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -17,7 +18,7 @@ async fn script_function_error() -> Result<(), Error> {
throw new Error('error');
};
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);
@ -46,7 +47,7 @@ async fn script_function_simple() -> Result<(), Error> {
return "Line 1\nLine 2";
};
"#;
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -75,7 +76,7 @@ async fn script_function_context() -> Result<(), Error> {
}
;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -109,7 +110,7 @@ async fn script_function_arguments() -> Result<(), Error> {
return `${arguments[0]} is ${arguments[1].join(', ')}`;
};
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -152,7 +153,7 @@ async fn script_function_types() -> Result<(), Error> {
}
;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -182,7 +183,7 @@ async fn script_function_module_os() -> Result<(), Error> {
return platform();
};
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -200,7 +201,7 @@ async fn script_query_from_script_select() -> Result<(), Error> {
CREATE test SET name = "b", number = 1;
CREATE test SET name = "c", number = 2;
"#;
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
// direct query
@ -254,7 +255,7 @@ async fn script_query_from_script() -> Result<(), Error> {
return await surrealdb.query(`CREATE article:test SET name = "The daily news", issue_number = 3`)
}
"#;
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -293,7 +294,7 @@ async fn script_value_function_params() -> Result<(), Error> {
return await surrealdb.value(`$test.name`)
}
"#;
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);
@ -318,7 +319,7 @@ async fn script_value_function_inline_values() -> Result<(), Error> {
}
}
"#;
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);

View file

@ -1,9 +1,10 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::iam::Role;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -14,7 +15,7 @@ async fn select_field_value() -> Result<(), Error> {
SELECT VALUE name FROM person;
SELECT name FROM person;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 4);
@ -74,7 +75,7 @@ async fn select_field_and_omit() -> Result<(), Error> {
SELECT * OMIT password, opts.security FROM person;
SELECT * FROM person;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 4);
@ -161,7 +162,7 @@ async fn select_expression_value() -> Result<(), Error> {
SELECT VALUE !boolean FROM thing;
SELECT VALUE !boolean FROM thing EXPLAIN FULL;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -260,7 +261,7 @@ async fn select_dynamic_array_keys_and_object_keys() -> Result<(), Error> {
-- Selecting an object or array index value using the value of another document field as a key
SELECT languages[primarylang] AS content FROM documentation;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 8);
@ -359,7 +360,7 @@ async fn select_writeable_subqueries() -> Result<(), Error> {
LET $id = (SELECT VALUE id FROM (UPDATE tester:test))[0];
RETURN $id;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 6);
@ -403,7 +404,7 @@ async fn select_where_field_is_bool() -> Result<(), Error> {
SELECT * FROM test WHERE active = true;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 6);
@ -495,7 +496,7 @@ async fn select_where_field_is_thing_and_with_index() -> Result<(), Error> {
SELECT * FROM post WHERE author = person:tobie EXPLAIN;
SELECT * FROM post WHERE author = person:tobie EXPLAIN FULL;
SELECT * FROM post WHERE author = person:tobie;";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -572,7 +573,7 @@ async fn select_where_and_with_index() -> Result<(), Error> {
DEFINE INDEX person_name ON TABLE person COLUMNS name;
SELECT name FROM person WHERE name = 'Tobie' AND genre = 'm' EXPLAIN;
SELECT name FROM person WHERE name = 'Tobie' AND genre = 'm';";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -619,7 +620,7 @@ async fn select_where_and_with_unique_index() -> Result<(), Error> {
DEFINE INDEX person_name ON TABLE person COLUMNS name UNIQUE;
SELECT name FROM person WHERE name = 'Jaime' AND genre = 'm' EXPLAIN;
SELECT name FROM person WHERE name = 'Jaime' AND genre = 'm';";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -667,7 +668,7 @@ async fn select_where_and_with_fulltext_index() -> Result<(), Error> {
DEFINE INDEX ft_name ON TABLE person COLUMNS name SEARCH ANALYZER simple BM25(1.2,0.75);
SELECT name FROM person WHERE name @@ 'Jaime' AND genre = 'm' EXPLAIN;
SELECT name FROM person WHERE name @@ 'Jaime' AND genre = 'm';";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 6);
@ -715,7 +716,7 @@ async fn select_where_explain() -> Result<(), Error> {
CREATE software:surreal SET name = 'SurrealDB';
SELECT * FROM person,software EXPLAIN;
SELECT * FROM person,software EXPLAIN FULL;";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -807,7 +808,7 @@ async fn common_permissions_checks(auth_enabled: bool) {
let sess = Session::for_level(level, role).with_ns(ns).with_db(db);
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
// Prepare datastore
let mut resp = ds
@ -869,7 +870,7 @@ async fn check_permissions_auth_enabled() {
// When the table grants no permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -897,7 +898,7 @@ async fn check_permissions_auth_enabled() {
// When the table exists and grants full permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -939,7 +940,7 @@ async fn check_permissions_auth_disabled() {
// When the table grants no permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -967,7 +968,7 @@ async fn check_permissions_auth_disabled() {
// When the table exists and grants full permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -15,7 +16,7 @@ async fn strict_mode_no_namespace() -> Result<(), Error> {
CREATE test:tester;
SELECT * FROM test;
";
let dbs = Datastore::new("memory").await?.with_strict_mode(true);
let dbs = new_ds().await?.with_strict_mode(true);
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -73,7 +74,7 @@ async fn strict_mode_no_database() -> Result<(), Error> {
CREATE test:tester;
SELECT * FROM test;
";
let dbs = Datastore::new("memory").await?.with_strict_mode(true);
let dbs = new_ds().await?.with_strict_mode(true);
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -126,7 +127,7 @@ async fn strict_mode_no_table() -> Result<(), Error> {
CREATE test:tester;
SELECT * FROM test;
";
let dbs = Datastore::new("memory").await?.with_strict_mode(true);
let dbs = new_ds().await?.with_strict_mode(true);
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
@ -174,7 +175,7 @@ async fn strict_mode_all_ok() -> Result<(), Error> {
CREATE test:tester;
SELECT * FROM test;
";
let dbs = Datastore::new("memory").await?.with_strict_mode(true);
let dbs = new_ds().await?.with_strict_mode(true);
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 6);
@ -213,7 +214,7 @@ async fn loose_mode_all_ok() -> Result<(), Error> {
INFO FOR DB;
INFO FOR TABLE test;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -23,7 +24,7 @@ async fn subquery_select() -> Result<(), Error> {
-- Using an outer SELECT, select a specific record in a subquery, returning an array
SELECT * FROM (SELECT age >= 18 AS adult FROM person:test) WHERE adult = true;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -135,7 +136,7 @@ async fn subquery_ifelse_set() -> Result<(), Error> {
UPDATE person:test SET sport = ['basketball'] RETURN sport;
END;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 9);
@ -250,7 +251,7 @@ async fn subquery_ifelse_array() -> Result<(), Error> {
UPDATE person:test SET sport = ['basketball'] RETURN sport;
END;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 9);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -26,7 +27,7 @@ async fn define_foreign_table() -> Result<(), Error> {
UPDATE person:two SET age = 39, score = 90;
SELECT * FROM person_by_age;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 9);

View file

@ -1,14 +1,14 @@
mod parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
#[tokio::test]
async fn throw_basic() -> Result<(), Error> {
let sql = "
THROW 'there was an error';
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -13,7 +14,7 @@ async fn transaction_basic() -> Result<(), Error> {
CREATE person:jaime;
COMMIT;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 2);
@ -50,7 +51,7 @@ async fn transaction_with_return() -> Result<(), Error> {
RETURN { tobie: person:tobie, jaime: person:jaime };
COMMIT;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -76,7 +77,7 @@ async fn transaction_with_failure() -> Result<(), Error> {
CREATE person:tobie;
COMMIT;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -112,7 +113,7 @@ async fn transaction_with_failure_and_return() -> Result<(), Error> {
RETURN { tobie: person:tobie, jaime: person:jaime };
COMMIT;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);
@ -135,7 +136,7 @@ async fn transaction_with_throw() -> Result<(), Error> {
THROW 'there was an error';
COMMIT;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -171,7 +172,7 @@ async fn transaction_with_throw_and_return() -> Result<(), Error> {
RETURN { tobie: person:tobie, jaime: person:jaime };
COMMIT;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 1);

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -18,7 +19,7 @@ async fn strict_typing_inline() -> Result<(), Error> {
UPDATE person:test SET scores = <set<float, 5>> [1,1,2,2,3,3,4,4,5,5];
UPDATE person:test SET scores = <array<float, 5>> [1,1,2,2,3,3,4,4,5,5];
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 9);
@ -134,7 +135,7 @@ async fn strict_typing_defined() -> Result<(), Error> {
UPDATE person:test SET age = 18, enabled = true, name = NONE, scored = [1,1,2,2,3,3,4,4,5,5];
UPDATE person:test SET age = 18, enabled = true, name = 'Tobie Morgan Hitchcock', scores = [1,1,2,2,3,3,4,4,5,5];
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 8);
@ -207,7 +208,7 @@ async fn strict_typing_none_null() -> Result<(), Error> {
UPDATE person:test SET name = NULL;
UPDATE person:test SET name = NONE;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 15);

View file

@ -1,9 +1,10 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::iam::Role;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -30,7 +31,7 @@ async fn update_simple_with_input() -> Result<(), Error> {
UPDATE person:test SET name = 'Tobie';
SELECT * FROM person:test;
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
@ -110,7 +111,7 @@ async fn update_complex_with_input() -> Result<(), Error> {
;
CREATE product:test SET images = [' test.png '];
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -173,7 +174,7 @@ async fn common_permissions_checks(auth_enabled: bool) {
// Test the statement when the table has to be created
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds.execute(statement, &sess, None).await.unwrap();
let res = resp.remove(0).output();
@ -196,7 +197,7 @@ async fn common_permissions_checks(auth_enabled: bool) {
// Test the statement when the table already exists
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
// Prepare datastore
let mut resp = ds
@ -294,7 +295,7 @@ async fn check_permissions_auth_enabled() {
// When the table doesn't exist
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(statement, &Session::default().with_ns("NS").with_db("DB"), None)
@ -312,7 +313,7 @@ async fn check_permissions_auth_enabled() {
// When the table grants no permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -360,7 +361,7 @@ async fn check_permissions_auth_enabled() {
// When the table exists and grants full permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -424,7 +425,7 @@ async fn check_permissions_auth_disabled() {
// When the table doesn't exist
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(statement, &Session::default().with_ns("NS").with_db("DB"), None)
@ -441,7 +442,7 @@ async fn check_permissions_auth_disabled() {
// When the table grants no permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(
@ -489,7 +490,7 @@ async fn check_permissions_auth_disabled() {
// When the table exists and grants full permissions
{
let ds = Datastore::new("memory").await.unwrap().with_auth_enabled(auth_enabled);
let ds = new_ds().await.unwrap().with_auth_enabled(auth_enabled);
let mut resp = ds
.execute(

View file

@ -1,8 +1,9 @@
mod parse;
use parse::Parse;
mod helpers;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
#[tokio::test]
@ -12,7 +13,7 @@ async fn use_statement_set_ns() -> Result<(), Error> {
USE NS my_ns;
SELECT * FROM $session.ns, session::ns(), $session.db, session::db();
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -38,7 +39,7 @@ async fn use_statement_set_db() -> Result<(), Error> {
USE DB my_db;
SELECT * FROM $session.ns, session::ns(), $session.db, session::db();
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);
@ -64,7 +65,7 @@ async fn use_statement_set_both() -> Result<(), Error> {
USE NS my_ns DB my_db;
SELECT * FROM $session.ns, session::ns(), $session.db, session::db();
";
let dbs = Datastore::new("memory").await?;
let dbs = new_ds().await?;
let ses = Session::owner().with_ns("test").with_db("test");
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 3);

View file

@ -44,14 +44,20 @@ struct DbsCapabilities {
allow_all: bool,
#[cfg(feature = "scripting")]
#[arg(help = "Allow execution of scripting functions")]
#[arg(help = "Allow execution of embedded scripting functions")]
#[arg(env = "SURREAL_CAPS_ALLOW_SCRIPT", long, conflicts_with = "allow_all")]
#[arg(default_missing_value_os = "true", action = ArgAction::Set, num_args = 0..)]
#[arg(default_value_t = true, hide_default_value = true)]
#[arg(default_value_t = false, hide_default_value = true)]
allow_scripting: bool,
#[arg(help = "Allow guest users to execute queries")]
#[arg(env = "SURREAL_CAPS_ALLOW_GUESTS", long, conflicts_with = "allow_all")]
#[arg(default_missing_value_os = "true", action = ArgAction::Set, num_args = 0..)]
#[arg(default_value_t = false, hide_default_value = true)]
allow_guests: bool,
#[arg(
help = "Allow execution of functions. Optionally, you can provide a comma-separated list of function names to allow",
help = "Allow execution of all functions. Optionally, you can provide a comma-separated list of function names to allow",
long_help = r#"Allow execution of functions. Optionally, you can provide a comma-separated list of function names to allow.
Function names must be in the form <family>[::<name>]. For example:
- 'http' or 'http::*' -> Include all functions in the 'http' family
@ -60,7 +66,7 @@ Function names must be in the form <family>[::<name>]. For example:
)]
#[arg(env = "SURREAL_CAPS_ALLOW_FUNC", long, conflicts_with = "allow_all")]
// If the arg is provided without value, then assume it's "", which gets parsed into Targets::All
#[arg(default_value_os = "", default_missing_value_os = "", num_args = 0..)]
#[arg(default_missing_value_os = "", num_args = 0..)]
#[arg(value_parser = super::cli::validator::func_targets)]
allow_funcs: Option<Targets<FuncTarget>>,
@ -75,7 +81,7 @@ Targets must be in the form of <host>[:<port>], <ipv4|ipv6>[/<mask>]. For exampl
)]
#[arg(env = "SURREAL_CAPS_ALLOW_NET", long, conflicts_with = "allow_all")]
// If the arg is provided without value, then assume it's "", which gets parsed into Targets::All
#[arg(default_value_os = "", default_missing_value_os = "", num_args = 0..)]
#[arg(default_missing_value_os = "", num_args = 0..)]
#[arg(value_parser = super::cli::validator::net_targets)]
allow_net: Option<Targets<NetTarget>>,
@ -89,14 +95,20 @@ Targets must be in the form of <host>[:<port>], <ipv4|ipv6>[/<mask>]. For exampl
deny_all: bool,
#[cfg(feature = "scripting")]
#[arg(help = "Deny execution of scripting functions")]
#[arg(help = "Deny execution of embedded scripting functions")]
#[arg(env = "SURREAL_CAPS_DENY_SCRIPT", long, conflicts_with = "deny_all")]
#[arg(default_missing_value_os = "true", action = ArgAction::Set, num_args = 0..)]
#[arg(default_value_t = false, hide_default_value = true)]
deny_scripting: bool,
#[arg(help = "Deny guest users to execute queries")]
#[arg(env = "SURREAL_CAPS_DENY_GUESTS", long, conflicts_with = "deny_all")]
#[arg(default_missing_value_os = "true", action = ArgAction::Set, num_args = 0..)]
#[arg(default_value_t = false, hide_default_value = true)]
deny_guests: bool,
#[arg(
help = "Deny execution of functions. Optionally, you can provide a comma-separated list of function names to deny",
help = "Deny execution of all functions. Optionally, you can provide a comma-separated list of function names to deny",
long_help = r#"Deny execution of functions. Optionally, you can provide a comma-separated list of function names to deny.
Function names must be in the form <family>[::<name>]. For example:
- 'http' or 'http::*' -> Include all functions in the 'http' family
@ -121,8 +133,6 @@ Targets must be in the form of <host>[:<port>], <ipv4|ipv6>[/<mask>]. For exampl
#[arg(env = "SURREAL_CAPS_DENY_NET", long, conflicts_with = "deny_all")]
// If the arg is provided without value, then assume it's "", which gets parsed into Targets::All
#[arg(default_missing_value_os = "", num_args = 0..)]
// If deny_all is true, disable this arg and assume a default of Targets::All
#[arg(conflicts_with = "deny_all", default_value_if("deny_all", "true", ""))]
#[arg(value_parser = super::cli::validator::net_targets)]
deny_net: Option<Targets<NetTarget>>,
}
@ -138,6 +148,10 @@ impl DbsCapabilities {
false
}
fn get_allow_guests(&self) -> bool {
(self.allow_all || self.allow_guests) && !(self.deny_all || self.deny_guests)
}
fn get_allow_funcs(&self) -> Targets<FuncTarget> {
if self.deny_all || matches!(self.deny_funcs, Some(Targets::All)) {
return Targets::None;
@ -187,10 +201,11 @@ impl From<DbsCapabilities> for Capabilities {
fn from(caps: DbsCapabilities) -> Self {
Capabilities::default()
.with_scripting(caps.get_scripting())
.with_allow_funcs(caps.get_allow_funcs())
.with_deny_funcs(caps.get_deny_funcs())
.with_allow_net(caps.get_allow_net())
.with_deny_net(caps.get_deny_net())
.with_guest_access(caps.get_allow_guests())
.with_functions(caps.get_allow_funcs())
.without_functions(caps.get_deny_funcs())
.with_network_targets(caps.get_allow_net())
.without_network_targets(caps.get_deny_net())
}
}
@ -221,6 +236,10 @@ pub async fn init(
} else {
warn!("❌🔒 IMPORTANT: Authentication is disabled. This is not recommended for production use. 🔒❌");
}
let caps = caps.into();
debug!("Server capabilities: {caps}");
// Parse and setup the desired kv datastore
let dbs = Datastore::new(&opt.path)
.await?
@ -229,7 +248,7 @@ pub async fn init(
.with_query_timeout(query_timeout)
.with_transaction_timeout(transaction_timeout)
.with_auth_enabled(auth_enabled)
.with_capabilities(caps.into());
.with_capabilities(caps);
dbs.bootstrap().await?;
@ -314,12 +333,8 @@ mod tests {
let get = Mock::given(method("GET"))
.respond_with(ResponseTemplate::new(200).set_body_string("SUCCESS"))
.expect(1);
let head =
Mock::given(method("HEAD")).respond_with(ResponseTemplate::new(200)).expect(1);
s.register(get).await;
s.register(head).await;
s
};
@ -337,13 +352,18 @@ mod tests {
s
};
// (Capabilities, Query, Succeeds, Response Contains)
// (Datastore, Session, Query, Succeeds, Response Contains)
let cases = vec![
//
// Functions and Networking are allowed
//
(
Capabilities::default(),
Datastore::new("memory").await.unwrap().with_capabilities(
Capabilities::default()
.with_functions(Targets::<FuncTarget>::All)
.with_network_targets(Targets::<NetTarget>::All),
),
Session::owner(),
format!("RETURN http::get('{}')", server1.uri()),
true,
"SUCCESS".to_string(),
@ -352,7 +372,11 @@ mod tests {
// Scripting is allowed
//
(
Capabilities::default(),
Datastore::new("memory")
.await
.unwrap()
.with_capabilities(Capabilities::default().with_scripting(true)),
Session::owner(),
"RETURN function() { return '1' }".to_string(),
true,
"1".to_string(),
@ -361,109 +385,199 @@ mod tests {
// Scripting is not allowed
//
(
Capabilities::default().with_scripting(false),
Datastore::new("memory")
.await
.unwrap()
.with_capabilities(Capabilities::default().with_scripting(false)),
Session::owner(),
"RETURN function() { return '1' }".to_string(),
false,
"Scripting functions are not allowed".to_string(),
),
//
// Anonymous actor when guest access is allowed and auth is enabled, succeeds
//
(
Datastore::new("memory")
.await
.unwrap()
.with_auth_enabled(true)
.with_capabilities(Capabilities::default().with_guest_access(true)),
Session::default(),
"RETURN 1".to_string(),
true,
"1".to_string(),
),
//
// Anonymous actor when guest access is not allowed and auth is enabled, throws error
//
(
Datastore::new("memory")
.await
.unwrap()
.with_auth_enabled(true)
.with_capabilities(Capabilities::default().with_guest_access(false)),
Session::default(),
"RETURN 1".to_string(),
false,
"Not enough permissions to perform this action".to_string(),
),
//
// Anonymous actor when guest access is not allowed and auth is disabled, succeeds
//
(
Datastore::new("memory")
.await
.unwrap()
.with_auth_enabled(false)
.with_capabilities(Capabilities::default().with_guest_access(false)),
Session::default(),
"RETURN 1".to_string(),
true,
"1".to_string(),
),
//
// Authenticated user when guest access is not allowed and auth is enabled, succeeds
//
(
Datastore::new("memory")
.await
.unwrap()
.with_auth_enabled(true)
.with_capabilities(Capabilities::default().with_guest_access(false)),
Session::viewer(),
"RETURN 1".to_string(),
true,
"1".to_string(),
),
//
// Some functions are not allowed
//
(
Capabilities::default()
.with_allow_funcs(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("http::*").unwrap()].into(),
))
.with_deny_funcs(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("http::get").unwrap()].into(),
)),
format!("RETURN http::get('{}')", server1.uri()),
false,
"Function 'http::get' is not allowed".to_string(),
),
(
Capabilities::default()
.with_allow_funcs(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("http::*").unwrap()].into(),
))
.with_deny_funcs(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("http::get").unwrap()].into(),
)),
format!("RETURN http::head('{}')", server1.uri()),
true,
"NONE".to_string(),
),
(
Capabilities::default()
.with_allow_funcs(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("http::*").unwrap()].into(),
))
.with_deny_funcs(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("http::get").unwrap()].into(),
)),
Datastore::new("memory").await.unwrap().with_capabilities(
Capabilities::default()
.with_functions(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("string::*").unwrap()].into(),
))
.without_functions(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("string::len").unwrap()].into(),
)),
),
Session::owner(),
"RETURN string::len('a')".to_string(),
false,
"Function 'string::len' is not allowed".to_string(),
),
(
Datastore::new("memory").await.unwrap().with_capabilities(
Capabilities::default()
.with_functions(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("string::*").unwrap()].into(),
))
.without_functions(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("string::len").unwrap()].into(),
)),
),
Session::owner(),
"RETURN string::lowercase('A')".to_string(),
true,
"a".to_string(),
),
(
Datastore::new("memory").await.unwrap().with_capabilities(
Capabilities::default()
.with_functions(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("string::*").unwrap()].into(),
))
.without_functions(Targets::<FuncTarget>::Some(
[FuncTarget::from_str("string::len").unwrap()].into(),
)),
),
Session::owner(),
"RETURN time::now()".to_string(),
false,
"Function 'time::now' is not allowed".to_string(),
),
//
// Some net targets are not allowed
//
(
Capabilities::default()
.with_allow_net(Targets::<NetTarget>::Some(
[
NetTarget::from_str(&server1.address().to_string()).unwrap(),
NetTarget::from_str(&server2.address().to_string()).unwrap(),
]
.into(),
))
.with_deny_net(Targets::<NetTarget>::Some(
[NetTarget::from_str(&server1.address().to_string()).unwrap()].into(),
)),
Datastore::new("memory").await.unwrap().with_capabilities(
Capabilities::default()
.with_functions(Targets::<FuncTarget>::All)
.with_network_targets(Targets::<NetTarget>::Some(
[
NetTarget::from_str(&server1.address().to_string()).unwrap(),
NetTarget::from_str(&server2.address().to_string()).unwrap(),
]
.into(),
))
.without_network_targets(Targets::<NetTarget>::Some(
[NetTarget::from_str(&server1.address().to_string()).unwrap()].into(),
)),
),
Session::owner(),
format!("RETURN http::get('{}')", server1.uri()),
false,
format!("Access to network target '{}/' is not allowed", server1.uri()),
),
(
Capabilities::default()
.with_allow_net(Targets::<NetTarget>::Some(
[
NetTarget::from_str(&server1.address().to_string()).unwrap(),
NetTarget::from_str(&server2.address().to_string()).unwrap(),
]
.into(),
))
.with_deny_net(Targets::<NetTarget>::Some(
[NetTarget::from_str(&server1.address().to_string()).unwrap()].into(),
)),
Datastore::new("memory").await.unwrap().with_capabilities(
Capabilities::default()
.with_functions(Targets::<FuncTarget>::All)
.with_network_targets(Targets::<NetTarget>::Some(
[
NetTarget::from_str(&server1.address().to_string()).unwrap(),
NetTarget::from_str(&server2.address().to_string()).unwrap(),
]
.into(),
))
.without_network_targets(Targets::<NetTarget>::Some(
[NetTarget::from_str(&server1.address().to_string()).unwrap()].into(),
)),
),
Session::owner(),
"RETURN http::get('http://1.1.1.1')".to_string(),
false,
"Access to network target 'http://1.1.1.1/' is not allowed".to_string(),
),
(
Capabilities::default()
.with_allow_net(Targets::<NetTarget>::Some(
[
NetTarget::from_str(&server1.address().to_string()).unwrap(),
NetTarget::from_str(&server2.address().to_string()).unwrap(),
]
.into(),
))
.with_deny_net(Targets::<NetTarget>::Some(
[NetTarget::from_str(&server1.address().to_string()).unwrap()].into(),
)),
Datastore::new("memory").await.unwrap().with_capabilities(
Capabilities::default()
.with_functions(Targets::<FuncTarget>::All)
.with_network_targets(Targets::<NetTarget>::Some(
[
NetTarget::from_str(&server1.address().to_string()).unwrap(),
NetTarget::from_str(&server2.address().to_string()).unwrap(),
]
.into(),
))
.without_network_targets(Targets::<NetTarget>::Some(
[NetTarget::from_str(&server1.address().to_string()).unwrap()].into(),
)),
),
Session::owner(),
format!("RETURN http::get('{}')", server2.uri()),
true,
"SUCCESS".to_string(),
),
];
for (idx, (caps, query, succeeds, contains)) in cases.into_iter().enumerate() {
let ds = Datastore::new("memory").await.unwrap().with_capabilities(caps);
let sess = Session::owner();
for (idx, (ds, sess, query, succeeds, contains)) in cases.into_iter().enumerate() {
info!("Test case {idx}: query={query}, succeeds={succeeds}");
let res = ds.execute(&query, &sess, None).await;
if !succeeds && res.is_err() {
let res = res.unwrap_err();
assert!(
res.to_string().contains(&contains),
"Unexpected error for test case {}: {:?}",
idx,
res.to_string()
);
continue;
}
let res = res.unwrap().remove(0).output();
let res = if succeeds {
assert!(res.is_ok(), "Unexpected error for test case {}: {:?}", idx, res);

View file

@ -38,7 +38,13 @@ mod cli_integration {
#[test(tokio::test)]
async fn all_commands() {
// Commands without credentials when auth is disabled, should succeed
let (addr, _server) = common::start_server_without_auth().await.unwrap();
let (addr, _server) = common::start_server(StartServerArguments {
auth: false,
args: "--allow-all".to_string(),
..Default::default()
})
.await
.unwrap();
let creds = ""; // Anonymous user
info!("* Create a record");
@ -498,31 +504,17 @@ mod cli_integration {
#[test(tokio::test)]
async fn test_capabilities() {
info!("* When all capabilities are enabled by default");
{
let (addr, _server) = common::start_server_without_auth().await.unwrap();
let cmd = format!("sql --conn ws://{addr} --ns N --db D --multi");
let query = format!("RETURN http::get('http://{}/version');\n\n", addr);
let output = common::run(&cmd).input(&query).output().unwrap();
assert!(output.starts_with("['surrealdb"), "unexpected output: {output:?}");
let query = "RETURN function() { return '1' };";
let output = common::run(&cmd).input(query).output().unwrap();
assert!(output.starts_with("['1']"), "unexpected output: {output:?}");
}
info!("* When all capabilities are denied");
// Deny all, denies all users to execute functions and access any network address
info!("* When all capabilities are denied by default");
{
let (addr, _server) = common::start_server(StartServerArguments {
args: "--deny-all".to_owned(),
args: "".to_owned(),
..Default::default()
})
.await
.unwrap();
let cmd = format!("sql --conn ws://{addr} --ns N --db D --multi");
let cmd = format!("sql --conn ws://{addr} -u root -p root --ns N --db D --multi");
let query = format!("RETURN http::get('http://{}/version');\n\n", addr);
let output = common::run(&cmd).input(&query).output().unwrap();
@ -539,6 +531,27 @@ mod cli_integration {
);
}
// When all capabilities are allowed, anyone (including non-authenticated users) can execute functions and access any network address
info!("* When all capabilities are allowed");
{
let (addr, _server) = common::start_server(StartServerArguments {
args: "--allow-all".to_owned(),
..Default::default()
})
.await
.unwrap();
let cmd = format!("sql --conn ws://{addr} --ns N --db D --multi");
let query = format!("RETURN http::get('http://{}/version');\n\n", addr);
let output = common::run(&cmd).input(&query).output().unwrap();
assert!(output.starts_with("['surrealdb"), "unexpected output: {output:?}");
let query = "RETURN function() { return '1' };";
let output = common::run(&cmd).input(query).output().unwrap();
assert!(output.starts_with("['1']"), "unexpected output: {output:?}");
}
info!("* When scripting is denied");
{
let (addr, _server) = common::start_server(StartServerArguments {
@ -548,7 +561,7 @@ mod cli_integration {
.await
.unwrap();
let cmd = format!("sql --conn ws://{addr} --ns N --db D --multi");
let cmd = format!("sql --conn ws://{addr} -u root -p root --ns N --db D --multi");
let query = "RETURN function() { return '1' };";
let output = common::run(&cmd).input(query).output().unwrap();
@ -567,7 +580,7 @@ mod cli_integration {
.await
.unwrap();
let cmd = format!("sql --conn ws://{addr} --ns N --db D --multi");
let cmd = format!("sql --conn ws://{addr} -u root -p root --ns N --db D --multi");
let query = format!("RETURN http::get('http://{}/version');\n\n", addr);
let output = common::run(&cmd).input(&query).output().unwrap();
@ -583,13 +596,14 @@ mod cli_integration {
info!("* When net is enabled for an IP and also denied for a specific port that doesn't match");
{
let (addr, _server) = common::start_server(StartServerArguments {
args: "--allow-net 127.0.0.1 --deny-net 127.0.0.1:80".to_owned(),
args: "--allow-net 127.0.0.1 --deny-net 127.0.0.1:80 --allow-funcs http::get"
.to_owned(),
..Default::default()
})
.await
.unwrap();
let cmd = format!("sql --conn ws://{addr} --ns N --db D --multi");
let cmd = format!("sql --conn ws://{addr} -u root -p root --ns N --db D --multi");
let query = format!("RETURN http::get('http://{}/version');\n\n", addr);
let output = common::run(&cmd).input(&query).output().unwrap();
@ -605,7 +619,7 @@ mod cli_integration {
.await
.unwrap();
let cmd = format!("sql --conn ws://{addr} --ns N --db D --multi");
let cmd = format!("sql --conn ws://{addr} -u root -p root --ns N --db D --multi");
let query = "RETURN http::get('https://surrealdb.com');\n\n";
let output = common::run(&cmd).input(query).output().unwrap();
@ -614,5 +628,59 @@ mod cli_integration {
"unexpected output: {output:?}"
);
}
info!("* When auth is enabled and guest access is allowed");
{
let (addr, _server) = common::start_server(StartServerArguments {
auth: true,
args: "--allow-guests".to_owned(),
..Default::default()
})
.await
.unwrap();
let cmd = format!("sql --conn ws://{addr} --ns N --db D --multi");
let query = "RETURN 1;\n\n";
let output = common::run(&cmd).input(query).output().unwrap();
assert!(output.contains("[1]"), "unexpected output: {output:?}");
}
info!("* When auth is enabled and guest access is denied");
{
let (addr, _server) = common::start_server(StartServerArguments {
auth: true,
args: "--deny-guests".to_owned(),
..Default::default()
})
.await
.unwrap();
let cmd = format!("sql --conn ws://{addr} --ns N --db D --multi");
let query = "RETURN 1;\n\n";
let output = common::run(&cmd).input(query).output().unwrap();
assert!(
output.contains("Not enough permissions to perform this action"),
"unexpected output: {output:?}"
);
}
info!("* When auth is disabled, guest access is always allowed");
{
let (addr, _server) = common::start_server(StartServerArguments {
auth: false,
args: "--deny-guests".to_owned(),
..Default::default()
})
.await
.unwrap();
let cmd = format!("sql --conn ws://{addr} --ns N --db D --multi");
let query = "RETURN 1;\n\n";
let output = common::run(&cmd).input(query).output().unwrap();
assert!(output.contains("[1]"), "unexpected output: {output:?}");
}
}
}

View file

@ -155,7 +155,7 @@ impl Default for StartServerArguments {
tls: false,
wait_is_ready: true,
tick_interval: time::Duration::new(1, 0),
args: String::default(),
args: "--allow-all".to_string(),
}
}
}