From 23af2bf5da713515425eda4fc9af1a094ce765ed Mon Sep 17 00:00:00 2001 From: Cheng JIANG Date: Sun, 10 May 2020 12:58:56 +0200 Subject: [PATCH] Split code into features (#137) * upgrade async-std to 1.6 beta * add ip feature * add glob feature * add cacehd feature * fix runtime-tokio clippy warnings * add watcher feature * don't clone if watcher feature has been disabled * use https://github.com/async-rs/async-std/pull/768 for fixing tests * activate all features for bench test over previous version * benchmark pull_request and decrease the threshold * switch to github actions * fix typo * Fix: cargo test features doesn't like space * better management of feature:logging and feature:watcher * use async-std/master for testing * add basic wasm32 support * use runtime-async-std for wasm32 test * fix clippy warnings * fix typo * make other tests avalaible only on no-wasm32 target * finish split code into features && bump version --- .github/workflows/benchmark.yml | 4 +- .github/workflows/ci.yml | 70 +++++++++++ .github/workflows/coverage.yml | 33 ++++++ .travis.yml | 49 -------- Cargo.toml | 19 ++- README.md | 6 +- benches/benchmark.rs | 11 ++ src/adapter/mod.rs | 2 + src/cache/default_cache.rs | 71 ++++++------ src/cache/mod.rs | 11 +- src/cached_enforcer.rs | 13 ++- src/config.rs | 37 ++++-- src/convert.rs | 24 +++- src/core_api.rs | 12 +- src/emitter.rs | 43 +++---- src/enforcer.rs | 199 ++++++++++++++++++++++++++------ src/internal_api.rs | 147 +++++++++++++++++++---- src/lib.rs | 13 ++- src/management_api.rs | 66 +++++++++-- src/model/default_model.rs | 183 +++++++++++++++++++++++------ src/model/function_map.rs | 24 +++- src/prelude.rs | 14 ++- src/rbac_api.rs | 121 +++++++++++++++---- 23 files changed, 892 insertions(+), 280 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/coverage.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index e2845b98..da388b2a 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -1,5 +1,6 @@ name: Benchmark on: + pull_request: push: branches: - master @@ -23,7 +24,8 @@ jobs: github-token: ${{ secrets.PERSONAL_GITHUB_TOKEN }} auto-push: true # Show alert with commit comment on detecting possible performance regression - alert-threshold: '200%' + alert-threshold: '150%' comment-on-alert: true + comment-always: true fail-on-alert: true alert-comment-cc-users: '@GopherJ' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..3ed6460c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,70 @@ +name: CI + +on: + pull_request: + push: + branches: + - master + +jobs: + build: + name: Auto Build CI + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@master + + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + components: rustfmt, clippy + override: true + + - name: Install Dependencies + run: sudo apt-get install libssl-dev + + - name: Cargo Clean + uses: actions-rs/cargo@v1 + with: + command: clean + + - name: Cargo Build + uses: actions-rs/cargo@v1 + with: + command: build + + # Todo: https://github.com/rust-lang/cargo/issues/2980 + - name: Cargo Test For All Features Using async-std + uses: actions-rs/cargo@v1 + with: + command: test + args: --no-default-features --features runtime-async-std,cached,glob,ip,watcher,logging + + - name: Cargo Test For All Features Using tokio + uses: actions-rs/cargo@v1 + with: + command: test + args: --no-default-features --features runtime-tokio,cached,glob,ip,watcher,logging + + - name: Cargo Check Wasm + uses: actions-rs/cargo@v1 + with: + command: check + target: wasm32-unknown-unknown + override: true + args: --no-default-features --features runtime-async-std,cached,glob,ip,watcher,logging + + - name: Cargo Clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + args: -- -D warnings + + - name: Cargo Fmt Check + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 00000000..8c6e0f30 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,33 @@ +name: Coverage + +on: + pull_request: + push: + branches: + - master + +jobs: + cover: + name: Auto Codecov Coverage + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@master + + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - name: Run cargo-tarpaulin + uses: actions-rs/tarpaulin@v0.1 + with: + args: --out Xml + + - name: Upload to codecov.io + uses: codecov/codecov-action@v1 + with: + token: ${{secrets.CODECOV_TOKEN}} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f5d8a2c2..00000000 --- a/.travis.yml +++ /dev/null @@ -1,49 +0,0 @@ -language: rust -sudo: required -dist: trusty -addons: - apt: - packages: - - libssl-dev -cache: cargo -rust: - - stable - - nightly -matrix: - allow_failures: - - rust: nightly -before_script: -- rustup component add rustfmt -- rustup component add clippy -script: -- cargo clean -- cargo build -# Todo: https://github.com/rust-lang/cargo/issues/2980 -- cargo test --no-default-features --features runtime-async-std,logging -- cargo test --no-default-features --features runtime-tokio,logging -- cargo clippy -- -D warnings -- cargo fmt --all -- --check - -after_success: | - if [[ "$TRAVIS_RUST_VERSION" == nightly ]]; then - # upload report to codecov - docker run --security-opt seccomp=unconfined -v "$PWD:/volume" xd009642/tarpaulin sh -c "cargo tarpaulin --out Xml" - bash <(curl -s https://codecov.io/bash) - - if [[ "${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}" != "master" ]] && [[ "$TRAVIS_PULL_REQUEST" != false ]]; then - REMOTE_URL="$(git config --get remote.origin.url)"; - # Clone the repository fresh..for some reason checking out master fails - # from a normal PR build's provided directory - cd ${TRAVIS_BUILD_DIR}/.. && \ - git clone ${REMOTE_URL} "${TRAVIS_REPO_SLUG}-bench" && \ - cd "${TRAVIS_REPO_SLUG}-bench" && \ - git fetch origin +refs/pull/${TRAVIS_PULL_REQUEST}/merge - # Bench master - cargo bench > before && \ - # Bench PR - git checkout FETCH_HEAD && \ - cargo bench > after && \ - cargo install cargo-benchcmp --force && \ - cargo benchcmp before after - fi - fi diff --git a/Cargo.toml b/Cargo.toml index f66e7b89..aca1f74a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "casbin" -version = "0.7.1" +version = "0.7.2" authors = ["Joey ", "Cheng JIANG "] edition = "2018" license = "Apache-2.0" @@ -15,27 +15,34 @@ keywords = ["auth", "authorization", "rbac", "acl", "abac"] [dependencies] regex = "1.3.1" rhai = { version = "0.13.0", default-features = false, features = ["sync", "only_i32", "no_function", "no_float"] } -ip_network = "0.3.4" -ttl_cache = "0.5.1" +ip_network = { version = "0.3.4", optional = true } +ttl_cache = { version = "0.5.1", optional = true } lazy_static = "1.4.0" indexmap = "1.3.1" async-std = { version = "1.5.0", optional = true } async-trait = "0.1.24" log = { version = "0.4.8", optional = true } tokio = { version = "0.2.11", optional = true, default-features = false } -globset = "0.4.5" +globset = { version = "0.4.5", optional = true } thiserror = "1.0.14" [features] default = ["runtime-async-std"] -runtime-tokio = ["tokio/fs", "tokio/io-util", "tokio/stream", "tokio/rt-threaded", "tokio/blocking"] +runtime-tokio = ["tokio/fs", "tokio/io-util"] runtime-async-std = ["async-std"] logging = ["log"] +ip = ["ip_network"] +glob = ["globset"] +cached = ["ttl_cache"] +watcher = [] [profile.release.build-override] opt-level = 0 -[dev-dependencies] +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] async-std = { version = "1.5.0", features = [ "attributes" ] } + +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] tokio = { version = "0.2.11", features = [ "full" ] } +async-std = { version = "1.5.0", features = [ "attributes" ] } diff --git a/README.md b/README.md index 9c34b84d..7993157b 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ [![Crates.io](https://img.shields.io/crates/v/casbin.svg)](https://crates.io/crates/casbin) [![crates.io](https://img.shields.io/crates/d/casbin)](https://crates.io/crates/casbin) [![Docs](https://docs.rs/casbin/badge.svg)](https://docs.rs/casbin) -[![Build Status](https://travis-ci.org/casbin/casbin-rs.svg?branch=master)](https://travis-ci.org/casbin/casbin-rs) -[![codecov](https://codecov.io/gh/casbin/casbin-rs/branch/master/graph/badge.svg)](https://codecov.io/gh/casbin/casbin-rs) +[![CI](https://github.com/casbin/casbin-rs/workflows/CI/badge.svg)](https://github.com/casbin/casbin-rs/actions) +[![Codecov](https://codecov.io/gh/casbin/casbin-rs/branch/master/graph/badge.svg)](https://codecov.io/gh/casbin/casbin-rs) **Casbin-RS** is a powerful and efficient open-source access control library for Rust projects. It provides support for enforcing authorization based on various [access control models](https://en.wikipedia.org/wiki/Computer_security_model). @@ -27,7 +27,7 @@ Add this package to `Cargo.toml` of your project. (Check https://crates.io/crate ```toml [dependencies] -casbin = { version = "0.7.1", default-features = false, features = ["runtime-async-std", "logging"] } +casbin = { version = "0.7.2", default-features = false, features = ["runtime-async-std", "logging"] } async-std = { version = "1.5.0", features = ["attributes"] } env_logger = "0.7.1" ``` diff --git a/benches/benchmark.rs b/benches/benchmark.rs index fedf0a86..cb2e93a3 100644 --- a/benches/benchmark.rs +++ b/benches/benchmark.rs @@ -63,6 +63,7 @@ fn b_benchmark_basic_model(b: &mut Bencher) { }); } +#[cfg(feature = "cached")] #[bench] fn b_benmark_cached_basic_model(b: &mut Bencher) { let mut e = await_future(CachedEnforcer::new( @@ -89,6 +90,7 @@ fn b_benchmark_rbac_model(b: &mut Bencher) { }); } +#[cfg(feature = "cached")] #[bench] fn b_benchmark_cached_rbac_model(b: &mut Bencher) { let mut e = await_future(CachedEnforcer::new( @@ -139,6 +141,7 @@ fn b_benchmark_rbac_model_small(b: &mut Bencher) { b.iter(|| await_future(e.enforce(&["user501", "data9", "read"])).unwrap()); } +#[cfg(feature = "cached")] #[bench] fn b_benchmark_cached_rbac_model_small(b: &mut Bencher) { let mut e = await_future(CachedEnforcer::new("examples/rbac_model.conf", ())).unwrap(); @@ -213,6 +216,7 @@ fn b_benchmark_rbac_model_medium(b: &mut Bencher) { b.iter(|| await_future(e.enforce(&["user5001", "data15", "read"])).unwrap()); } +#[cfg(feature = "cached")] #[bench] fn b_benchmark_cached_rbac_model_medium(b: &mut Bencher) { let mut e = await_future(CachedEnforcer::new("examples/rbac_model.conf", ())).unwrap(); @@ -287,6 +291,7 @@ fn b_benchmark_rbac_model_large(b: &mut Bencher) { b.iter(|| await_future(e.enforce(&["user50001", "data1500", "read"])).unwrap()); } +#[cfg(feature = "cached")] #[bench] fn b_benchmark_cached_rbac_model_large(b: &mut Bencher) { let mut e = await_future(CachedEnforcer::new("examples/rbac_model.conf", ())).unwrap(); @@ -335,6 +340,7 @@ fn b_benchmark_rbac_with_resource_roles(b: &mut Bencher) { b.iter(|| await_future(e.enforce(&["alice", "data1", "read"])).unwrap()); } +#[cfg(feature = "cached")] #[bench] fn b_benchmark_cached_rbac_with_resource_roles(b: &mut Bencher) { let mut e = await_future(CachedEnforcer::new( @@ -357,6 +363,7 @@ fn b_benchmark_rbac_model_with_domains(b: &mut Bencher) { b.iter(|| await_future(e.enforce(&["alice", "domain1", "data1", "read"])).unwrap()); } +#[cfg(feature = "cached")] #[bench] fn b_benchmark_cached_rbac_model_with_domains(b: &mut Bencher) { let mut e = await_future(CachedEnforcer::new( @@ -375,6 +382,7 @@ fn b_benchmark_abac_model(b: &mut Bencher) { b.iter(|| await_future(e.enforce(&["alice", r#"{"Owner": "alice"}"#, "read"])).unwrap()); } +#[cfg(feature = "cached")] #[bench] fn b_benchmark_cached_abac_model(b: &mut Bencher) { let mut e = await_future(CachedEnforcer::new("examples/abac_model.conf", ())).unwrap(); @@ -393,6 +401,7 @@ fn b_benchmark_key_match(b: &mut Bencher) { b.iter(|| await_future(e.enforce(&["alice", "/alice_data/resource1", "GET"])).unwrap()); } +#[cfg(feature = "cached")] #[bench] fn b_benchmark_cached_key_match(b: &mut Bencher) { let mut e = await_future(CachedEnforcer::new( @@ -415,6 +424,7 @@ fn b_benchmark_rbac_with_deny(b: &mut Bencher) { b.iter(|| await_future(e.enforce(&["alice", "data1", "read"])).unwrap()); } +#[cfg(feature = "cached")] #[bench] fn b_benchmark_cached_rbac_with_deny(b: &mut Bencher) { let mut e = await_future(CachedEnforcer::new( @@ -437,6 +447,7 @@ fn b_benchmark_priority_model(b: &mut Bencher) { b.iter(|| await_future(e.enforce(&["alice", "data1", "read"])).unwrap()); } +#[cfg(feature = "cached")] #[bench] fn b_benchmark_cached_priority_model(b: &mut Bencher) { let mut e = await_future(CachedEnforcer::new( diff --git a/src/adapter/mod.rs b/src/adapter/mod.rs index e7633f78..b69d3f21 100644 --- a/src/adapter/mod.rs +++ b/src/adapter/mod.rs @@ -1,9 +1,11 @@ use async_trait::async_trait; +#[cfg(not(target_arch = "wasm32"))] pub mod file_adapter; pub mod memory_adapter; pub mod null_adapter; +#[cfg(not(target_arch = "wasm32"))] pub use file_adapter::FileAdapter; pub use memory_adapter::MemoryAdapter; pub use null_adapter::NullAdapter; diff --git a/src/cache/default_cache.rs b/src/cache/default_cache.rs index 035961cd..11efc463 100644 --- a/src/cache/default_cache.rs +++ b/src/cache/default_cache.rs @@ -1,10 +1,8 @@ use crate::cache::Cache; -use async_trait::async_trait; use ttl_cache::TtlCache; -use std::hash::Hash; -use std::time::Duration; +use std::{hash::Hash, time::Duration}; pub struct DefaultCache where @@ -28,7 +26,6 @@ where } } -#[async_trait] impl Cache for DefaultCache where K: Eq + Hash + Send + Sync + 'static, @@ -42,22 +39,22 @@ where self.ttl = ttl; } - async fn get<'a>(&'a self, k: &K) -> Option<&'a V> { + fn get<'a>(&'a self, k: &K) -> Option<&'a V> { self.cache.get(k) } - async fn has(&self, k: &K) -> bool { + fn has(&self, k: &K) -> bool { self.cache.contains_key(k) } - async fn set(&mut self, k: K, v: V) { - if self.has(&k).await { + fn set(&mut self, k: K, v: V) { + if self.has(&k) { self.cache.remove(&k); } self.cache.insert(k, v, self.ttl); } - async fn clear(&mut self) { + fn clear(&mut self) { self.cache.clear(); } } @@ -67,54 +64,52 @@ mod tests { use super::*; use std::thread::sleep; - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] - async fn test_set_and_get() { + #[cfg(feature = "cached")] + #[test] + fn test_set_and_get() { let mut cache = DefaultCache::new(1); - cache.set(vec!["alice", "/data1", "read"], false).await; - assert!(cache.get(&vec!["alice", "/data1", "read"]).await == Some(&false)); + cache.set(vec!["alice", "/data1", "read"], false); + assert!(cache.get(&vec!["alice", "/data1", "read"]) == Some(&false)); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] - async fn test_set_ttl() { + #[cfg(feature = "cached")] + #[test] + fn test_set_ttl() { let mut cache = DefaultCache::new(1); cache.set_ttl(Duration::from_secs(2)); - cache.set(vec!["alice", "/data1", "read"], false).await; + cache.set(vec!["alice", "/data1", "read"], false); sleep(Duration::from_secs(1)); - assert!(cache.get(&vec!["alice", "/data1", "read"]).await == Some(&false)); + assert!(cache.get(&vec!["alice", "/data1", "read"]) == Some(&false)); sleep(Duration::from_secs(2)); - assert!(!cache.has(&vec!["alice", "/data1", "read"]).await); + assert!(!cache.has(&vec!["alice", "/data1", "read"])); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] - async fn test_capacity() { + #[cfg(feature = "cached")] + #[test] + fn test_capacity() { let mut cache = DefaultCache::new(1); - cache.set(vec!["alice", "/data1", "read"], false).await; - cache.set(vec!["bob", "/data2", "write"], false).await; - assert!(!cache.has(&vec!["alice", "/data1", "read"]).await); - assert!(cache.has(&vec!["bob", "/data2", "write"]).await); + cache.set(vec!["alice", "/data1", "read"], false); + cache.set(vec!["bob", "/data2", "write"], false); + assert!(!cache.has(&vec!["alice", "/data1", "read"])); + assert!(cache.has(&vec!["bob", "/data2", "write"])); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] - async fn test_set_capacity() { + #[cfg(feature = "cached")] + #[test] + fn test_set_capacity() { let mut cache = DefaultCache::new(1); cache.set_capacity(2); - cache.set(vec!["alice", "/data1", "read"], false).await; - cache.set(vec!["bob", "/data2", "write"], false).await; - cache - .set(vec!["unknow", "/data3", "read_write"], false) - .await; - assert!(!cache.has(&vec!["alice", "/data1", "read"]).await); - assert!(cache.has(&vec!["bob", "/data2", "write"]).await); - assert!(cache.has(&vec!["unknow", "/data3", "read_write"]).await); + cache.set(vec!["alice", "/data1", "read"], false); + cache.set(vec!["bob", "/data2", "write"], false); + cache.set(vec!["unknow", "/data3", "read_write"], false); + assert!(!cache.has(&vec!["alice", "/data1", "read"])); + assert!(cache.has(&vec!["bob", "/data2", "write"])); + assert!(cache.has(&vec!["unknow", "/data3", "read_write"])); } } diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 0b2aecda..ee5cb998 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -1,7 +1,6 @@ use async_trait::async_trait; -use std::hash::Hash; -use std::time::Duration; +use std::{hash::Hash, time::Duration}; pub mod default_cache; @@ -14,8 +13,8 @@ where { fn set_capacity(&mut self, c: usize); fn set_ttl(&mut self, t: Duration); - async fn get(&self, k: &K) -> Option<&V>; - async fn has(&self, k: &K) -> bool; - async fn set(&mut self, k: K, v: V); - async fn clear(&mut self); + fn get(&self, k: &K) -> Option<&V>; + fn has(&self, k: &K) -> bool; + fn set(&mut self, k: K, v: V); + fn clear(&mut self); } diff --git a/src/cached_enforcer.rs b/src/cached_enforcer.rs index a48ed84d..d933c1e7 100644 --- a/src/cached_enforcer.rs +++ b/src/cached_enforcer.rs @@ -9,10 +9,12 @@ use crate::{ enforcer::Enforcer, model::Model, rbac::RoleManager, - watcher::Watcher, Result, }; +#[cfg(feature = "watcher")] +use crate::watcher::Watcher; + #[cfg(feature = "logging")] use crate::Logger; @@ -92,16 +94,19 @@ impl CoreApi for CachedEnforcer { self.enforcer.get_mut_adapter() } + #[cfg(feature = "watcher")] #[inline] fn set_watcher(&mut self, w: Box) { self.enforcer.set_watcher(w); } + #[cfg(feature = "watcher")] #[inline] fn get_watcher(&self) -> Option<&dyn Watcher> { self.enforcer.get_watcher() } + #[cfg(feature = "watcher")] #[inline] fn get_mut_watcher(&mut self) -> Option<&mut dyn Watcher> { self.enforcer.get_mut_watcher() @@ -169,11 +174,11 @@ impl CoreApi for CachedEnforcer { }; #[allow(unused_variables)] - let (res, is_cached) = if let Some(result) = self.cache.get(&key).await { + let (res, is_cached) = if let Some(result) = self.cache.get(&key) { (*result, true) } else { let result = self.enforcer.enforce(rvals).await?; - self.cache.set(key.clone(), result).await; + self.cache.set(key.clone(), result); (result, false) }; @@ -246,6 +251,7 @@ impl CoreApi for CachedEnforcer { .enable_auto_build_role_links(auto_build_role_links); } + #[cfg(feature = "watcher")] #[inline] fn enable_auto_notify_watcher(&mut self, auto_notify_watcher: bool) { self.enforcer @@ -257,6 +263,7 @@ impl CoreApi for CachedEnforcer { self.enforcer.has_auto_save_enabled() } + #[cfg(feature = "watcher")] #[inline] fn has_auto_notify_watcher_enabled(&self) -> bool { self.enforcer.has_auto_notify_watcher_enabled() diff --git a/src/config.rs b/src/config.rs index bea9cb26..da028483 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,19 +2,20 @@ use crate::Result; #[cfg(feature = "runtime-async-std")] use async_std::{ - fs::File, io::prelude::*, io::{BufReader, Cursor, Error as IoError, ErrorKind}, - path::Path, }; +#[cfg(all(feature = "runtime-async-std", not(target_arch = "wasm32")))] +use async_std::{fs::File, path::Path}; + #[cfg(feature = "runtime-tokio")] use std::{io::Cursor, path::Path}; #[cfg(feature = "runtime-tokio")] -use tokio::{ - fs::File, - io::{AsyncBufReadExt, AsyncReadExt, BufReader, Error as IoError, ErrorKind}, -}; +use tokio::io::{AsyncBufReadExt, AsyncReadExt, BufReader, Error as IoError, ErrorKind}; + +#[cfg(all(feature = "runtime-tokio", not(target_arch = "wasm32")))] +use tokio::fs::File; use std::collections::HashMap; @@ -28,6 +29,7 @@ pub(crate) struct Config { } impl Config { + #[cfg(not(target_arch = "wasm32"))] pub(crate) async fn from_file>(p: P) -> Result { let mut c = Config { data: HashMap::new(), @@ -47,6 +49,7 @@ impl Config { Ok(c) } + #[cfg(not(target_arch = "wasm32"))] async fn parse>(&mut self, p: P) -> Result<()> { let mut f = File::open(p).await?; let mut c = Vec::new(); @@ -211,8 +214,15 @@ impl Config { mod tests { use super::*; - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_get() { let mut config = Config::from_file("examples/testini.ini").await.unwrap(); @@ -255,8 +265,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_from_text() { let text: &str = r#" # test config diff --git a/src/convert.rs b/src/convert.rs index f6041a7d..e5b4f456 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -1,4 +1,7 @@ -use crate::{Adapter, DefaultModel, FileAdapter, Model, NullAdapter, Result}; +use crate::{Adapter, DefaultModel, Model, NullAdapter, Result}; + +#[cfg(not(target_arch = "wasm32"))] +use crate::FileAdapter; use async_trait::async_trait; @@ -15,7 +18,14 @@ pub trait TryIntoAdapter: Send + Sync { #[async_trait] impl TryIntoModel for &'static str { async fn try_into_model(self) -> Result> { - Ok(Box::new(DefaultModel::from_file(self).await?)) + #[cfg(not(target_arch = "wasm32"))] + { + Ok(Box::new(DefaultModel::from_file(self).await?)) + } + #[cfg(target_arch = "wasm32")] + { + Ok(Box::new(DefaultModel::from_str(self).await?)) + } } } @@ -36,7 +46,15 @@ where #[async_trait] impl TryIntoAdapter for &'static str { async fn try_into_adapter(self) -> Result> { - Ok(Box::new(FileAdapter::new(self))) + #[cfg(not(target_arch = "wasm32"))] + { + Ok(Box::new(FileAdapter::new(self))) + } + + #[cfg(target_arch = "wasm32")] + { + Ok(Box::new(NullAdapter)) + } } } diff --git a/src/core_api.rs b/src/core_api.rs index 63658e37..a1a55565 100644 --- a/src/core_api.rs +++ b/src/core_api.rs @@ -1,6 +1,7 @@ -use crate::{ - Adapter, Effector, Filter, Model, Result, RoleManager, TryIntoAdapter, TryIntoModel, Watcher, -}; +use crate::{Adapter, Effector, Filter, Model, Result, RoleManager, TryIntoAdapter, TryIntoModel}; + +#[cfg(feature = "watcher")] +use crate::Watcher; #[cfg(feature = "logging")] use crate::Logger; @@ -17,8 +18,11 @@ pub trait CoreApi: Sized + Send + Sync { fn get_mut_model(&mut self) -> &mut dyn Model; fn get_adapter(&self) -> &dyn Adapter; fn get_mut_adapter(&mut self) -> &mut dyn Adapter; + #[cfg(feature = "watcher")] fn set_watcher(&mut self, w: Box); + #[cfg(feature = "watcher")] fn get_watcher(&self) -> Option<&dyn Watcher>; + #[cfg(feature = "watcher")] fn get_mut_watcher(&mut self) -> Option<&mut dyn Watcher>; fn get_role_manager(&self) -> Arc>; fn set_role_manager(&mut self, rm: Arc>) -> Result<()>; @@ -43,7 +47,9 @@ pub trait CoreApi: Sized + Send + Sync { fn enable_auto_save(&mut self, auto_save: bool); fn enable_enforce(&mut self, enabled: bool); fn enable_auto_build_role_links(&mut self, auto_build_role_links: bool); + #[cfg(feature = "watcher")] fn enable_auto_notify_watcher(&mut self, auto_notify_watcher: bool); fn has_auto_save_enabled(&self) -> bool; + #[cfg(feature = "watcher")] fn has_auto_notify_watcher_enabled(&self) -> bool; } diff --git a/src/emitter.rs b/src/emitter.rs index da6d474e..4ac4af9f 100644 --- a/src/emitter.rs +++ b/src/emitter.rs @@ -1,4 +1,8 @@ -use crate::{cached_api::CachedApi, core_api::CoreApi}; +#[cfg(any(feature = "watcher", feature = "cached", feature = "logging"))] +use crate::core_api::CoreApi; + +#[cfg(feature = "cached")] +use crate::cached_api::CachedApi; use std::{fmt, hash::Hash}; @@ -48,37 +52,28 @@ where fn emit(&mut self, e: K, d: EventData); } -pub(crate) fn notify_watcher(e: &mut T, d: EventData) { +#[cfg(any(feature = "logging", feature = "watcher"))] +pub(crate) fn notify_logger_and_watcher(e: &mut T, d: EventData) { #[cfg(feature = "logging")] { e.get_logger().print_mgmt_log(&d); } - if let Some(w) = e.get_mut_watcher() { - w.update(d); + #[cfg(feature = "watcher")] + { + if let Some(w) = e.get_mut_watcher() { + w.update(d); + } } } -#[allow(unused_variables)] +#[cfg(all(feature = "cached", feature = "logging"))] pub(crate) fn clear_cache(ce: &mut T, d: EventData) { - #[cfg(feature = "logging")] - { - ce.get_logger().print_mgmt_log(&d); - } - - #[cfg(feature = "runtime-tokio")] - { - tokio::runtime::Builder::new() - .basic_scheduler() - .threaded_scheduler() - .enable_all() - .build() - .unwrap() - .block_on(async { ce.get_mut_cache().clear().await }); - } + ce.get_logger().print_mgmt_log(&d); + ce.get_mut_cache().clear(); +} - #[cfg(feature = "runtime-async-std")] - { - async_std::task::block_on(async { ce.get_mut_cache().clear().await }); - } +#[cfg(all(feature = "cached", not(feature = "logging")))] +pub(crate) fn clear_cache(ce: &mut T, _d: EventData) { + ce.get_mut_cache().clear(); } diff --git a/src/enforcer.rs b/src/enforcer.rs index ca9107c1..241dfc3f 100644 --- a/src/enforcer.rs +++ b/src/enforcer.rs @@ -3,16 +3,21 @@ use crate::{ convert::{TryIntoAdapter, TryIntoModel}, core_api::CoreApi, effector::{DefaultEffector, EffectKind, Effector}, - emitter::{notify_watcher, Event, EventData, EventEmitter}, + emitter::{Event, EventData, EventEmitter}, error::{Error, ModelError, PolicyError, RequestError}, management_api::MgmtApi, model::{FunctionMap, Model}, rbac::{DefaultRoleManager, RoleManager}, util::{escape_eval, ESC_E}, - watcher::Watcher, Result, }; +#[cfg(any(feature = "logging", feature = "watcher"))] +use crate::emitter::notify_logger_and_watcher; + +#[cfg(feature = "watcher")] +use crate::watcher::Watcher; + #[cfg(feature = "logging")] use crate::{DefaultLogger, Logger}; @@ -81,7 +86,9 @@ pub struct Enforcer { pub(crate) enabled: bool, pub(crate) auto_save: bool, pub(crate) auto_build_role_links: bool, + #[cfg(feature = "watcher")] pub(crate) auto_notify_watcher: bool, + #[cfg(feature = "watcher")] pub(crate) watcher: Option>, pub(crate) events: HashMap>, pub(crate) engine: Engine, @@ -246,7 +253,9 @@ impl CoreApi for Enforcer { enabled: true, auto_save: true, auto_build_role_links: true, + #[cfg(feature = "watcher")] auto_notify_watcher: true, + #[cfg(feature = "watcher")] watcher: None, events: HashMap::new(), engine, @@ -265,7 +274,9 @@ impl CoreApi for Enforcer { enabled: true, auto_save: true, auto_build_role_links: true, + #[cfg(feature = "watcher")] auto_notify_watcher: true, + #[cfg(feature = "watcher")] watcher: None, events: HashMap::new(), engine, @@ -273,7 +284,10 @@ impl CoreApi for Enforcer { } }; - e.on(Event::PolicyChange, notify_watcher); + #[cfg(any(feature = "logging", feature = "watcher"))] + { + e.on(Event::PolicyChange, notify_logger_and_watcher); + } e.load_policy().await?; @@ -313,6 +327,7 @@ impl CoreApi for Enforcer { &mut *self.adapter } + #[cfg(feature = "watcher")] #[inline] fn set_watcher(&mut self, w: Box) { self.watcher = Some(w); @@ -330,6 +345,7 @@ impl CoreApi for Enforcer { self.logger = l; } + #[cfg(feature = "watcher")] #[inline] fn get_watcher(&self) -> Option<&dyn Watcher> { if let Some(ref watcher) = self.watcher { @@ -339,6 +355,7 @@ impl CoreApi for Enforcer { } } + #[cfg(feature = "watcher")] #[inline] fn get_mut_watcher(&mut self) -> Option<&mut dyn Watcher> { if let Some(ref mut watcher) = self.watcher { @@ -481,7 +498,10 @@ impl CoreApi for Enforcer { policies.extend(gpolicies); - self.emit(Event::PolicyChange, EventData::SavePolicy(policies)); + #[cfg(any(feature = "logging", feature = "watcher"))] + { + self.emit(Event::PolicyChange, EventData::SavePolicy(policies)); + } Ok(()) } @@ -511,12 +531,13 @@ impl CoreApi for Enforcer { self.auto_build_role_links = auto_build_role_links; } + #[cfg(feature = "watcher")] #[inline] fn enable_auto_notify_watcher(&mut self, auto_notify_watcher: bool) { if !auto_notify_watcher { self.off(Event::PolicyChange); } else { - self.on(Event::PolicyChange, notify_watcher); + self.on(Event::PolicyChange, notify_logger_and_watcher); } self.auto_notify_watcher = auto_notify_watcher; } @@ -526,6 +547,7 @@ impl CoreApi for Enforcer { self.auto_save } + #[cfg(feature = "watcher")] #[inline] fn has_auto_notify_watcher_enabled(&self) -> bool { self.auto_notify_watcher @@ -551,8 +573,15 @@ mod tests { assert!(is_sync::()); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_enforcer_swap_adapter_type() { let mut m = DefaultModel::default(); m.add_def("r", "r", "sub, obj, act"); @@ -582,8 +611,15 @@ mod tests { .unwrap()) } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_key_match_model_in_memory() { let mut m = DefaultModel::default(); m.add_def("r", "r", "sub, obj, act"); @@ -715,8 +751,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_key_match_model_in_memory_deny() { let mut m = DefaultModel::default(); m.add_def("r", "r", "sub, obj, act"); @@ -739,8 +782,15 @@ mod tests { } use crate::RbacApi; - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_rbac_model_in_memory_indeterminate() { let mut m = DefaultModel::default(); m.add_def("r", "r", "sub, obj, act"); @@ -770,8 +820,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_rbac_model_in_memory() { let mut m = DefaultModel::default(); m.add_def("r", "r", "sub, obj, act"); @@ -860,8 +917,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_not_used_rbac_model_in_memory() { let mut m = DefaultModel::default(); m.add_def("r", "r", "sub, obj, act"); @@ -929,8 +993,16 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(feature = "ip")] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_ip_match_model() { let m = DefaultModel::from_file("examples/ipmatch_model.conf") .await @@ -1004,9 +1076,15 @@ mod tests { .unwrap()); } - use crate::MgmtApi; - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_enable_auto_save() { let m = DefaultModel::from_file("examples/basic_model.conf") .await @@ -1102,8 +1180,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_role_links() { let m = DefaultModel::from_file("examples/rbac_model.conf") .await @@ -1119,8 +1204,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_get_and_set_model() { let m1 = DefaultModel::from_file("examples/basic_model.conf") .await @@ -1146,8 +1238,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_get_and_set_adapter_in_mem() { let m1 = DefaultModel::from_file("examples/basic_model.conf") .await @@ -1182,8 +1281,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_keymatch_custom_model() { use crate::model::key_match; @@ -1236,8 +1342,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_filtered_file_adapter() { let mut e = Enforcer::new( "examples/rbac_with_domains_model.conf", @@ -1280,8 +1393,15 @@ mod tests { .unwrap()); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_set_role_manager() { let mut e = Enforcer::new( "examples/rbac_with_domains_model.conf", @@ -1312,8 +1432,15 @@ mod tests { .unwrap()); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_policy_abac() { let mut m = DefaultModel::default(); m.add_def("r", "r", "sub, obj, act"); diff --git a/src/internal_api.rs b/src/internal_api.rs index 4aa373ca..d97cecb1 100644 --- a/src/internal_api.rs +++ b/src/internal_api.rs @@ -1,11 +1,16 @@ use crate::{ - cached_enforcer::CachedEnforcer, core_api::CoreApi, - emitter::{Event, EventData, EventEmitter}, + emitter::{Event, EventEmitter}, enforcer::Enforcer, Result, }; +#[cfg(any(feature = "watcher", feature = "cached", feature = "logging"))] +use crate::emitter::EventData; + +#[cfg(feature = "cached")] +use crate::cached_enforcer::CachedEnforcer; + use async_trait::async_trait; #[async_trait] @@ -60,9 +65,30 @@ impl InternalApi for Enforcer { return Ok(false); } - let rule_added = self.get_mut_model().add_policy(sec, ptype, rule.clone()); - if rule_added && self.has_auto_notify_watcher_enabled() { - self.emit(Event::PolicyChange, EventData::AddPolicy(rule)); + let rule_added = self.get_mut_model().add_policy(sec, ptype, { + #[cfg(any(feature = "watcher", feature = "logging"))] + { + rule.clone() + } + #[cfg(all(not(feature = "watcher"), not(feature = "logging")))] + { + rule + } + }); + #[cfg(any(feature = "watcher", feature = "logging"))] + { + #[cfg(feature = "watcher")] + { + if rule_added && self.has_auto_notify_watcher_enabled() { + self.emit(Event::PolicyChange, EventData::AddPolicy(rule)); + } + } + #[cfg(not(feature = "watcher"))] + { + if rule_added { + self.emit(Event::PolicyChange, EventData::AddPolicy(rule)); + } + } } Ok(rule_added) @@ -83,9 +109,30 @@ impl InternalApi for Enforcer { return Ok(false); } - let rules_added = self.get_mut_model().add_policies(sec, ptype, rules.clone()); - if rules_added && self.has_auto_notify_watcher_enabled() { - self.emit(Event::PolicyChange, EventData::AddPolicies(rules)); + let rules_added = self.get_mut_model().add_policies(sec, ptype, { + #[cfg(any(feature = "watcher", feature = "logging"))] + { + rules.clone() + } + #[cfg(all(not(feature = "watcher"), not(feature = "logging")))] + { + rules + } + }); + #[cfg(any(feature = "watcher", feature = "logging"))] + { + #[cfg(feature = "watcher")] + { + if rules_added && self.has_auto_notify_watcher_enabled() { + self.emit(Event::PolicyChange, EventData::AddPolicies(rules)); + } + } + #[cfg(not(feature = "watcher"))] + { + if rules_added { + self.emit(Event::PolicyChange, EventData::AddPolicies(rules)); + } + } } Ok(rules_added) @@ -106,9 +153,30 @@ impl InternalApi for Enforcer { return Ok(false); } - let rule_removed = self.get_mut_model().remove_policy(sec, ptype, rule.clone()); - if rule_removed && self.has_auto_notify_watcher_enabled() { - self.emit(Event::PolicyChange, EventData::RemovePolicy(rule)); + let rule_removed = self.get_mut_model().remove_policy(sec, ptype, { + #[cfg(any(feature = "watcher", feature = "logging"))] + { + rule.clone() + } + #[cfg(all(not(feature = "watcher"), not(feature = "logging")))] + { + rule + } + }); + #[cfg(any(feature = "watcher", feature = "logging"))] + { + #[cfg(feature = "watcher")] + { + if rule_removed && self.has_auto_notify_watcher_enabled() { + self.emit(Event::PolicyChange, EventData::RemovePolicy(rule)); + } + } + #[cfg(not(feature = "watcher"))] + { + if rule_removed { + self.emit(Event::PolicyChange, EventData::RemovePolicy(rule)); + } + } } Ok(rule_removed) @@ -129,11 +197,31 @@ impl InternalApi for Enforcer { return Ok(false); } - let rules_removed = self - .get_mut_model() - .remove_policies(sec, ptype, rules.clone()); - if rules_removed && self.has_auto_notify_watcher_enabled() { - self.emit(Event::PolicyChange, EventData::RemovePolicies(rules)); + let rules_removed = self.get_mut_model().remove_policies(sec, ptype, { + #[cfg(any(feature = "watcher", feature = "logging"))] + { + rules.clone() + } + #[cfg(all(not(feature = "watcher"), not(feature = "logging")))] + { + rules + } + }); + + #[cfg(any(feature = "watcher", feature = "logging"))] + { + #[cfg(feature = "watcher")] + { + if rules_removed && self.has_auto_notify_watcher_enabled() { + self.emit(Event::PolicyChange, EventData::RemovePolicies(rules)); + } + } + #[cfg(not(feature = "watcher"))] + { + if rules_removed { + self.emit(Event::PolicyChange, EventData::RemovePolicies(rules)); + } + } } Ok(rules_removed) @@ -158,17 +246,34 @@ impl InternalApi for Enforcer { let (rules_removed, rules) = self.get_mut_model() .remove_filtered_policy(sec, ptype, field_index, field_values); - if rules_removed && self.has_auto_notify_watcher_enabled() { - self.emit( - Event::PolicyChange, - EventData::RemoveFilteredPolicy(rules.clone()), - ); + + #[cfg(any(feature = "watcher", feature = "logging"))] + { + #[cfg(feature = "watcher")] + { + if rules_removed && self.has_auto_notify_watcher_enabled() { + self.emit( + Event::PolicyChange, + EventData::RemoveFilteredPolicy(rules.clone()), + ); + } + } + #[cfg(not(feature = "watcher"))] + { + if rules_removed { + self.emit( + Event::PolicyChange, + EventData::RemoveFilteredPolicy(rules.clone()), + ); + } + } } Ok((rules_removed, rules)) } } +#[cfg(feature = "cached")] #[async_trait] impl InternalApi for CachedEnforcer { async fn add_policy_internal( diff --git a/src/lib.rs b/src/lib.rs index efa15f24..8082c915 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,9 @@ mod adapter; +#[cfg(feature = "cached")] mod cache; +#[cfg(feature = "cached")] mod cached_api; +#[cfg(feature = "cached")] mod cached_enforcer; mod config; mod convert; @@ -16,14 +19,21 @@ mod model; mod rbac; mod rbac_api; mod util; +#[cfg(feature = "watcher")] mod watcher; pub mod error; pub mod prelude; -pub use adapter::{Adapter, FileAdapter, Filter, MemoryAdapter, NullAdapter}; +#[cfg(not(target_arch = "wasm32"))] +pub use adapter::FileAdapter; +pub use adapter::{Adapter, Filter, MemoryAdapter, NullAdapter}; + +#[cfg(feature = "cached")] pub use cache::{Cache, DefaultCache}; +#[cfg(feature = "cached")] pub use cached_api::CachedApi; +#[cfg(feature = "cached")] pub use cached_enforcer::CachedEnforcer; pub use convert::{TryIntoAdapter, TryIntoModel}; pub use core_api::CoreApi; @@ -38,6 +48,7 @@ pub use management_api::MgmtApi; pub use model::{function_map, Assertion, DefaultModel, Model}; pub use rbac::{DefaultRoleManager, RoleManager}; pub use rbac_api::RbacApi; +#[cfg(feature = "watcher")] pub use watcher::Watcher; pub type Result = std::result::Result; diff --git a/src/management_api.rs b/src/management_api.rs index e76f14f1..657332e8 100644 --- a/src/management_api.rs +++ b/src/management_api.rs @@ -357,8 +357,15 @@ mod tests { v } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_modify_grouping_policy_api() { let m = DefaultModel::from_file("examples/rbac_model.conf") .await @@ -465,8 +472,15 @@ mod tests { assert_eq!(vec!["eve"], e.get_users_for_role("data3_admin", None)); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_modify_policy_api() { let m = DefaultModel::from_file("examples/rbac_model.conf") .await @@ -547,8 +561,15 @@ mod tests { assert_eq!(vec![vec!["eve", "data3", "read"],], e.get_policy()); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_get_policy_api() { let m = DefaultModel::from_file("examples/rbac_model.conf") .await @@ -751,8 +772,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_get_list() { let m = DefaultModel::from_file("examples/rbac_model.conf") .await @@ -770,8 +798,15 @@ mod tests { assert_eq!(vec!["data2_admin"], e.get_all_roles()); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_modify_policies_api() { let m = DefaultModel::from_file("examples/rbac_model.conf") .await @@ -931,8 +966,15 @@ mod tests { assert_eq!(vec![vec!["eve", "data3", "read"],], e.get_policy()); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_modify_grouping_policies_api() { let m = DefaultModel::from_file("examples/rbac_model.conf") .await diff --git a/src/model/default_model.rs b/src/model/default_model.rs index 69c0841e..ee465bfe 100644 --- a/src/model/default_model.rs +++ b/src/model/default_model.rs @@ -9,7 +9,7 @@ use crate::{ use indexmap::{IndexMap, IndexSet}; -#[cfg(feature = "runtime-async-std")] +#[cfg(all(feature = "runtime-async-std", not(target_arch = "wasm32")))] use async_std::path::Path; #[cfg(feature = "runtime-tokio")] @@ -26,6 +26,7 @@ pub struct DefaultModel { } impl DefaultModel { + #[cfg(not(target_arch = "wasm32"))] pub async fn from_file>(p: P) -> Result { let cfg = Config::from_file(p).await?; @@ -41,7 +42,8 @@ impl DefaultModel { Ok(model) } - pub async fn from_str(&mut self, s: &str) -> Result { + #[allow(clippy::should_implement_trait)] + pub async fn from_str(s: &str) -> Result { let cfg = Config::from_str(s).await?; let mut model = DefaultModel::default(); @@ -320,8 +322,15 @@ impl Model for DefaultModel { mod tests { use crate::prelude::*; - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_basic_model() { let m = DefaultModel::from_file("examples/basic_model.conf") .await @@ -340,8 +349,15 @@ mod tests { assert!(e.enforce(&vec!["bob", "data2", "write"]).await.unwrap()); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_basic_model_no_policy() { let m = DefaultModel::from_file("examples/basic_model.conf") .await @@ -360,8 +376,15 @@ mod tests { assert!(!e.enforce(&vec!["bob", "data2", "write"]).await.unwrap()); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_basic_model_with_root() { let m = DefaultModel::from_file("examples/basic_with_root_model.conf") .await @@ -384,8 +407,15 @@ mod tests { assert!(!e.enforce(&vec!["bob", "data2", "read"]).await.unwrap()); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_basic_model_with_root_no_policy() { let m = DefaultModel::from_file("examples/basic_with_root_model.conf") .await @@ -408,8 +438,15 @@ mod tests { assert!(!e.enforce(&vec!["bob", "data2", "read"]).await.unwrap()); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_basic_model_without_users() { let m = DefaultModel::from_file("examples/basic_without_users_model.conf") .await @@ -424,8 +461,15 @@ mod tests { assert!(e.enforce(&vec!["data2", "write"]).await.unwrap()); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_basic_model_without_resources() { let m = DefaultModel::from_file("examples/basic_without_resources_model.conf") .await @@ -440,8 +484,15 @@ mod tests { assert!(!e.enforce(&vec!["bob", "read"]).await.unwrap()); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_rbac_model() { let m = DefaultModel::from_file("examples/rbac_model.conf") .await @@ -484,8 +535,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_rbac_model_with_resource_roles() { let m = DefaultModel::from_file("examples/rbac_with_resource_roles_model.conf") .await @@ -528,8 +586,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_rbac_model_with_domains() { let m = DefaultModel::from_file("examples/rbac_with_domains_model.conf") .await @@ -588,9 +653,15 @@ mod tests { ); } - use crate::MgmtApi; - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_rbac_model_with_domains_runtime() { let m = DefaultModel::from_file("examples/rbac_with_domains_model.conf") .await @@ -821,8 +892,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_rbac_model_with_domains_at_runtime_mock_adapter() { let m = DefaultModel::from_file("examples/rbac_with_domains_model.conf") .await @@ -899,8 +977,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_rbac_model_with_deny() { let m = DefaultModel::from_file("examples/rbac_with_deny_model.conf") .await @@ -943,8 +1028,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_rbac_model_with_not_deny() { let m = DefaultModel::from_file("examples/rbac_with_not_deny_model.conf") .await @@ -959,8 +1051,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_rbac_model_with_custom_data() { let m = DefaultModel::from_file("examples/rbac_model.conf") .await @@ -1054,8 +1153,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_rbac_model_using_in_op() { let m = DefaultModel::from_file("examples/rbac_model_matcher_using_in_op.conf") .await @@ -1098,8 +1204,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_abac() { let m = DefaultModel::from_file("examples/abac_model.conf") .await diff --git a/src/model/function_map.rs b/src/model/function_map.rs index f48d040b..4d06c1c3 100644 --- a/src/model/function_map.rs +++ b/src/model/function_map.rs @@ -1,10 +1,12 @@ -#[cfg(feature = "runtime-async-std")] +#[cfg(all(feature = "runtime-async-std", feature = "ip"))] use async_std::net::IpAddr; -#[cfg(feature = "runtime-tokio")] +#[cfg(all(feature = "runtime-tokio", feature = "ip"))] use std::net::IpAddr; +#[cfg(feature = "glob")] use globset::GlobBuilder; +#[cfg(feature = "ip")] use ip_network::IpNetwork; use lazy_static::lazy_static; use regex::Regex; @@ -27,8 +29,16 @@ impl Default for FunctionMap { fm.insert("keyMatch2".to_owned(), key_match2); fm.insert("keyMatch3".to_owned(), key_match3); fm.insert("regexMatch".to_owned(), regex_match); - fm.insert("ipMatch".to_owned(), ip_match); - fm.insert("globMatch".to_owned(), glob_match); + + #[cfg(feature = "glob")] + { + fm.insert("globMatch".to_owned(), glob_match); + } + + #[cfg(feature = "ip")] + { + fm.insert("ipMatch".to_owned(), ip_match); + } FunctionMap { fm } } @@ -92,6 +102,7 @@ pub fn regex_match(key1: String, key2: String) -> bool { // ip_match determines whether IP address ip1 matches the pattern of IP address ip2, ip2 can be an IP address or a CIDR pattern. // For example, "192.168.2.123" matches "192.168.2.0/24" +#[cfg(feature = "ip")] pub fn ip_match(key1: String, key2: String) -> bool { let key2_split = key2.splitn(2, '/').collect::>(); let ip_addr2 = key2_split[0]; @@ -120,6 +131,7 @@ pub fn ip_match(key1: String, key2: String) -> bool { } // glob_match determines whether key1 matches the pattern of key2 using glob pattern +#[cfg(feature = "glob")] pub fn glob_match(key1: String, key2: String) -> bool { GlobBuilder::new(key2.as_str()) .literal_separator(true) @@ -169,6 +181,7 @@ mod tests { assert!(!key_match3("/baz".to_owned(), "/foo".to_owned())); } + #[cfg(feature = "ip")] #[test] fn test_ip_match() { assert!(ip_match("::1".to_owned(), "::0:1".to_owned())); @@ -188,18 +201,21 @@ mod tests { )); } + #[cfg(feature = "ip")] #[test] #[should_panic] fn test_ip_match_panic_1() { assert!(ip_match("I am alice".to_owned(), "127.0.0.1".to_owned())); } + #[cfg(feature = "ip")] #[test] #[should_panic] fn test_ip_match_panic_2() { assert!(ip_match("127.0.0.1".to_owned(), "I am alice".to_owned())); } + #[cfg(feature = "glob")] #[test] fn test_glob_match() { assert!(glob_match("/abc/123".to_owned(), "/abc/*".to_owned())); diff --git a/src/prelude.rs b/src/prelude.rs index f455735a..7ea7ff81 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,5 +1,13 @@ pub use crate::{ - CachedApi, CachedEnforcer, CoreApi, DefaultModel, Enforcer, EventData, FileAdapter, Filter, - InternalApi, MemoryAdapter, MgmtApi, Model, NullAdapter, RbacApi, Result, TryIntoAdapter, - TryIntoModel, Watcher, + CoreApi, DefaultModel, Enforcer, EventData, Filter, InternalApi, MemoryAdapter, MgmtApi, Model, + NullAdapter, RbacApi, Result, TryIntoAdapter, TryIntoModel, }; + +#[cfg(not(target_arch = "wasm32"))] +pub use crate::FileAdapter; + +#[cfg(feature = "cached")] +pub use crate::{CachedApi, CachedEnforcer}; + +#[cfg(feature = "watcher")] +pub use crate::Watcher; diff --git a/src/rbac_api.rs b/src/rbac_api.rs index fe32cdbb..d84ca5c6 100644 --- a/src/rbac_api.rs +++ b/src/rbac_api.rs @@ -322,8 +322,15 @@ mod tests { v } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_role_api() { let m = DefaultModel::from_file("examples/rbac_model.conf") .await @@ -479,8 +486,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_role_api_threads() { use std::sync::{Arc, RwLock}; use std::thread; @@ -823,8 +837,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_permission_api() { let m = DefaultModel::from_file("examples/basic_without_resources_model.conf") .await @@ -921,8 +942,15 @@ mod tests { assert_eq!(false, e.enforce(&vec!["eve", "write"]).await.unwrap()); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_implicit_role_api() { let m = DefaultModel::from_file("examples/rbac_model.conf") .await @@ -950,8 +978,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_implicit_permission_api() { let m = DefaultModel::from_file("examples/rbac_model.conf") .await @@ -985,8 +1020,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_implicit_user_api() { let m = DefaultModel::from_file("examples/rbac_model.conf") .await @@ -1039,8 +1081,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_implicit_permission_api_with_domain() { let m = DefaultModel::from_file("examples/rbac_with_domains_model.conf") .await @@ -1059,8 +1108,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_pattern_matching_fn() { let mut e = Enforcer::new( "examples/rbac_with_pattern_model.conf", @@ -1095,8 +1151,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_pattern_matching_fn_with_domain() { let mut e = Enforcer::new( "examples/rbac_with_pattern_domain_model.conf", @@ -1155,8 +1218,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_pattern_matching_basic_role() { let mut e = Enforcer::new( "examples/rbac_basic_role_model.conf", @@ -1197,8 +1267,15 @@ mod tests { ); } - #[cfg_attr(feature = "runtime-async-std", async_std::test)] - #[cfg_attr(feature = "runtime-tokio", tokio::test)] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr( + all(feature = "runtime-async-std", not(target_arch = "wasm32")), + async_std::test + )] + #[cfg_attr( + all(feature = "runtime-tokio", not(target_arch = "wasm32")), + tokio::test + )] async fn test_implicit_users_for_permission() { let mut m = DefaultModel::default(); m.add_def("r", "r", "sub, obj, act");