use super::{database::ERROR, package::packages}; #[test] fn public_entry_checks_actual_storage_instead_of_component_membership() { let files = [ ("dever.database", ERROR), ( "demo.account.model", "global type Account { subject: Text }", ), ( "demo.account.app", "count() (value: Int) { value = model.count() }", ), ("demo.account.api", "public get count = app.count"), ("demo.note.model", "type Note { title: Text }"), ( "demo.note.app", "count() (value: Int) { value = model.count() }\nhealth() (value: Bool) { value = true }", ), ( "demo.note.api", "cmd count = app.count\npublic get health = app.health", ), ]; let program = packages(&files).unwrap(); assert!(program.check_tenant_entries().is_ok()); for entry in &program.http { let access = program.tenant_access(entry.function); assert!(!access.required); assert_eq!(access.components.into_iter().collect::>(), ["demo"]); } let access = program.tenant_access(program.commands[0].function); assert!(access.required); assert_eq!(access.components.into_iter().collect::>(), ["demo"]); let mut public = files; public[6].1 = "public get count = app.count\npublic get health = app.health"; let error = packages(&public) .unwrap() .check_tenant_entries() .unwrap_err(); assert!(error.contains("tenant storage"), "{error}"); } #[test] fn tenant_storage_follows_cross_component_calls() { let program = packages(&[ ("dever.database", ERROR), ("news.item.model", "type Item { title: Text }"), ( "news.item.app", "count() (value: Int) { value = model.count() }", ), ("notes.item.model", "type Item { title: Text }"), ( "notes.item.app", "count() (value: Int) { value = model.count() }", ), ( "report.items.app", "count() (value: Int) { value = news.item.count() + notes.item.count() }", ), ("report.items.api", "public get count = app.count"), ]) .unwrap(); let access = program.tenant_access(program.http[0].function); assert!(access.required); assert_eq!( access.components.into_iter().collect::>(), ["news", "notes"] ); let error = program.check_tenant_entries().unwrap_err(); assert!(error.contains("report/items"), "{error}"); } #[test] fn model_free_jobs_require_tenants_but_global_only_jobs_do_not() { for global in [false, true] { let mut files = vec![ ("dever.database", ERROR), ( "demo.queue.app", "submit(key: Text) (id: Id) { id = dever.job.enqueue(job.execute, key) }\napply() () {}", ), ( "demo.queue.job", "database default\njob execute() () retry(1) timeout(100) { app.apply() }", ), ("demo.queue.api", "cmd submit = app.submit"), ]; if global { files.push(( "demo.account.model", "global type Account { subject: Text }", )); } let program = packages(&files).unwrap(); let entry = program.commands[0].function; let access = program.tenant_access(entry); assert_eq!(access.required, !global); assert_eq!( access.components.into_iter().collect::>(), if global { vec![] } else { vec!["demo"] } ); } }