mirror of
https://github.com/clockworklabs/SpacetimeDB.git
synced 2026-05-06 07:26:43 -04:00
[bfops/cargo-test-all]: Merge branch 'bfops/cargo-test-all' of github.com:clockworklabs/SpacetimeDB into bfops/cargo-test-all
This commit is contained in:
@@ -835,6 +835,10 @@ jobs:
|
||||
const publicRef = (context.eventName === 'pull_request') ? context.payload.pull_request.head.ref : context.sha;
|
||||
const publicPrNumber = context.payload.pull_request?.number ?? context.payload.inputs?.pr_number;
|
||||
const preDispatch = new Date().toISOString();
|
||||
const inputs = { public_ref: publicRef };
|
||||
if (publicPrNumber) {
|
||||
inputs.public_pr_number = String(publicPrNumber);
|
||||
}
|
||||
|
||||
// Dispatch the workflow in the target repository
|
||||
await github.rest.actions.createWorkflowDispatch({
|
||||
@@ -842,7 +846,7 @@ jobs:
|
||||
repo: targetRepo,
|
||||
workflow_id: workflowId,
|
||||
ref: targetRef,
|
||||
inputs: { public_ref: publicRef, public_pr_number: String(publicPrNumber) }
|
||||
inputs,
|
||||
});
|
||||
|
||||
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
||||
|
||||
@@ -97,17 +97,22 @@ public:
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* auto module_id = ctx.identity();
|
||||
* auto module_id = ctx.database_identity();
|
||||
* std::string url = "http://localhost:3000/v1/database/" +
|
||||
* module_id.to_hex() + "/schema?version=9";
|
||||
* @endcode
|
||||
*/
|
||||
Identity identity() const {
|
||||
Identity database_identity() const {
|
||||
std::array<uint8_t, 32> id_bytes;
|
||||
::identity(id_bytes.data());
|
||||
return Identity(id_bytes);
|
||||
}
|
||||
|
||||
[[deprecated("Use database_identity() instead.")]]
|
||||
Identity identity() const {
|
||||
return database_identity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the random number generator for this procedure call
|
||||
*
|
||||
|
||||
@@ -58,11 +58,16 @@ public:
|
||||
return *rng_instance;
|
||||
}
|
||||
|
||||
Identity identity() const {
|
||||
Identity database_identity() const {
|
||||
std::array<uint8_t, 32> buffer;
|
||||
::identity(buffer.data());
|
||||
return Identity(buffer);
|
||||
}
|
||||
|
||||
[[deprecated("Use database_identity() instead.")]]
|
||||
Identity identity() const {
|
||||
return database_identity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new random UUID v4.
|
||||
|
||||
@@ -69,7 +69,9 @@ public:
|
||||
// Access to ReducerContext methods
|
||||
Identity sender() const { return ctx_.sender(); }
|
||||
const AuthCtx& sender_auth() const { return ctx_.sender_auth(); }
|
||||
Identity identity() const { return ctx_.identity(); }
|
||||
Identity database_identity() const { return ctx_.database_identity(); }
|
||||
[[deprecated("Use database_identity() instead.")]]
|
||||
Identity identity() const { return database_identity(); }
|
||||
StdbRng& rng() const { return ctx_.rng(); }
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
namespace SpacetimeDB;
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using SpacetimeDB.BSATN;
|
||||
#if !NET5_0_OR_GREATER
|
||||
using System.Diagnostics;
|
||||
#endif
|
||||
|
||||
internal static class Util
|
||||
{
|
||||
|
||||
@@ -877,10 +877,14 @@ internal static class SqlFormat
|
||||
|
||||
public static string FormatHexLiteral(string hex)
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
ArgumentNullException.ThrowIfNull(hex);
|
||||
#else
|
||||
if (hex is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(hex));
|
||||
}
|
||||
#endif
|
||||
|
||||
var s = hex;
|
||||
if (s.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
+6
-2
@@ -655,9 +655,13 @@ namespace SpacetimeDB
|
||||
|
||||
// **Note:** must be 0..=u32::MAX
|
||||
internal int CounterUuid;
|
||||
public Identity DatabaseIdentity => Internal.IReducerContext.GetDatabaseIdentity();
|
||||
|
||||
// We need this property to be non-static for parity with client SDK.
|
||||
public Identity Identity => Internal.IReducerContext.GetIdentity();
|
||||
// We keep this property for compatibility with existing module code.
|
||||
[global::System.Obsolete(
|
||||
"ReducerContext.Identity is deprecated. Use DatabaseIdentity instead."
|
||||
)]
|
||||
public Identity Identity => DatabaseIdentity;
|
||||
|
||||
internal ReducerContext(
|
||||
Identity identity,
|
||||
|
||||
+6
-2
@@ -57,9 +57,13 @@ namespace SpacetimeDB
|
||||
|
||||
// **Note:** must be 0..=u32::MAX
|
||||
internal int CounterUuid;
|
||||
public Identity DatabaseIdentity => Internal.IReducerContext.GetDatabaseIdentity();
|
||||
|
||||
// We need this property to be non-static for parity with client SDK.
|
||||
public Identity Identity => Internal.IReducerContext.GetIdentity();
|
||||
// We keep this property for compatibility with existing module code.
|
||||
[global::System.Obsolete(
|
||||
"ReducerContext.Identity is deprecated. Use DatabaseIdentity instead."
|
||||
)]
|
||||
public Identity Identity => DatabaseIdentity;
|
||||
|
||||
internal ReducerContext(
|
||||
Identity identity,
|
||||
|
||||
+6
-2
@@ -499,9 +499,13 @@ namespace SpacetimeDB
|
||||
|
||||
// **Note:** must be 0..=u32::MAX
|
||||
internal int CounterUuid;
|
||||
public Identity DatabaseIdentity => Internal.IReducerContext.GetDatabaseIdentity();
|
||||
|
||||
// We need this property to be non-static for parity with client SDK.
|
||||
public Identity Identity => Internal.IReducerContext.GetIdentity();
|
||||
// We keep this property for compatibility with existing module code.
|
||||
[global::System.Obsolete(
|
||||
"ReducerContext.Identity is deprecated. Use DatabaseIdentity instead."
|
||||
)]
|
||||
public Identity Identity => DatabaseIdentity;
|
||||
|
||||
internal ReducerContext(
|
||||
Identity identity,
|
||||
|
||||
@@ -2189,8 +2189,10 @@ public class Module : IIncrementalGenerator
|
||||
public readonly AuthCtx SenderAuth;
|
||||
// **Note:** must be 0..=u32::MAX
|
||||
internal int CounterUuid;
|
||||
// We need this property to be non-static for parity with client SDK.
|
||||
public Identity Identity => Internal.IReducerContext.GetIdentity();
|
||||
public Identity DatabaseIdentity => Internal.IReducerContext.GetDatabaseIdentity();
|
||||
// We keep this property for compatibility with existing module code.
|
||||
[global::System.Obsolete("ReducerContext.Identity is deprecated. Use DatabaseIdentity instead.")]
|
||||
public Identity Identity => DatabaseIdentity;
|
||||
|
||||
internal ReducerContext(Identity identity, ConnectionId? connectionId, Random random,
|
||||
Timestamp time, AuthCtx? senderAuth = null)
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
namespace SpacetimeDB.Internal;
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using SpacetimeDB.BSATN;
|
||||
|
||||
public interface IReducerContext
|
||||
{
|
||||
public static Identity GetIdentity()
|
||||
public static Identity GetDatabaseIdentity()
|
||||
{
|
||||
FFI.identity(out var identity);
|
||||
return identity;
|
||||
}
|
||||
|
||||
[Obsolete("IReducerContext.GetIdentity() is deprecated. Use GetDatabaseIdentity() instead.")]
|
||||
public static Identity GetIdentity() => GetDatabaseIdentity();
|
||||
}
|
||||
|
||||
public interface IReducer
|
||||
|
||||
@@ -103,6 +103,8 @@ export interface JwtClaims {
|
||||
*/
|
||||
export type ReducerCtx<SchemaDef extends UntypedSchemaDef> = Readonly<{
|
||||
sender: Identity;
|
||||
databaseIdentity: Identity;
|
||||
/** @deprecated Use `databaseIdentity` instead. */
|
||||
identity: Identity;
|
||||
timestamp: Timestamp;
|
||||
connectionId: ConnectionId | null;
|
||||
|
||||
@@ -75,6 +75,8 @@ export interface ProcedureOpts {
|
||||
|
||||
export interface ProcedureCtx<S extends UntypedSchemaDef> {
|
||||
readonly sender: Identity;
|
||||
readonly databaseIdentity: Identity;
|
||||
/** @deprecated Use `databaseIdentity` instead. */
|
||||
readonly identity: Identity;
|
||||
readonly timestamp: Timestamp;
|
||||
readonly connectionId: ConnectionId | null;
|
||||
@@ -195,10 +197,14 @@ const ProcedureCtxImpl = class ProcedureCtx<S extends UntypedSchemaDef>
|
||||
this.#dbView = dbView;
|
||||
}
|
||||
|
||||
get identity() {
|
||||
get databaseIdentity() {
|
||||
return (this.#identity ??= new Identity(sys.identity()));
|
||||
}
|
||||
|
||||
get identity() {
|
||||
return this.databaseIdentity;
|
||||
}
|
||||
|
||||
get random() {
|
||||
return (this.#random ??= makeRandom(this.timestamp));
|
||||
}
|
||||
|
||||
@@ -221,10 +221,14 @@ export const ReducerCtxImpl = class ReducerCtx<
|
||||
me.#senderAuth = undefined;
|
||||
}
|
||||
|
||||
get identity() {
|
||||
get databaseIdentity() {
|
||||
return (this.#identity ??= new Identity(sys.identity()));
|
||||
}
|
||||
|
||||
get identity() {
|
||||
return this.databaseIdentity;
|
||||
}
|
||||
|
||||
get senderAuth() {
|
||||
return (this.#senderAuth ??= AuthCtxImpl.fromSystemTables(
|
||||
this.connectionId,
|
||||
|
||||
@@ -687,7 +687,7 @@ pub use spacetimedb_bindings_macro::table;
|
||||
///
|
||||
/// #[reducer]
|
||||
/// fn scheduled(ctx: &ReducerContext, args: ScheduledArgs) -> Result<(), String> {
|
||||
/// if ctx.sender() != ctx.identity() {
|
||||
/// if ctx.sender() != ctx.database_identity() {
|
||||
/// return Err("Reducer `scheduled` may not be invoked by clients, only via scheduling.".into());
|
||||
/// }
|
||||
/// // Reducer body...
|
||||
@@ -1081,7 +1081,7 @@ impl ReducerContext {
|
||||
}
|
||||
|
||||
/// Read the current module's [`Identity`].
|
||||
pub fn identity(&self) -> Identity {
|
||||
pub fn database_identity(&self) -> Identity {
|
||||
// Hypothetically, we *could* read the module identity out of the system tables.
|
||||
// However, this would be:
|
||||
// - Onerous, because we have no tooling to inspect the system tables from module code.
|
||||
@@ -1093,6 +1093,12 @@ impl ReducerContext {
|
||||
Identity::from_byte_array(spacetimedb_bindings_sys::identity())
|
||||
}
|
||||
|
||||
/// Read the current module's [`Identity`].
|
||||
#[deprecated(note = "Use `ReducerContext::database_identity` instead.")]
|
||||
pub fn identity(&self) -> Identity {
|
||||
self.database_identity()
|
||||
}
|
||||
|
||||
/// Create an anonymous (no sender) read-only view context
|
||||
pub fn as_anonymous_read_only(&self) -> AnonymousViewContext {
|
||||
AnonymousViewContext::default()
|
||||
|
||||
@@ -28,10 +28,97 @@ impl Uninstall {
|
||||
Ok(None) => {}
|
||||
Err(e) => tracing::warn!("{e:#}"),
|
||||
}
|
||||
let dir = paths.cli_bin_dir.version_dir(&version);
|
||||
if !dir.0.exists() {
|
||||
anyhow::bail!("v{version} is not installed");
|
||||
}
|
||||
if yes.confirm(format!("Uninstall v{version}?"))? {
|
||||
let dir = paths.cli_bin_dir.version_dir(&version);
|
||||
std::fs::remove_dir_all(dir)?;
|
||||
std::fs::remove_dir_all(&dir)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use spacetimedb_paths::FromPathUnchecked;
|
||||
use spacetimedb_paths::RootDir;
|
||||
|
||||
fn make_temp_paths() -> (tempfile::TempDir, SpacetimePaths) {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let base = tmp.path().join("spacetime");
|
||||
std::fs::create_dir_all(&base).unwrap();
|
||||
let root = RootDir::from_path_unchecked(base);
|
||||
let paths = SpacetimePaths::from_root_dir(&root);
|
||||
(tmp, paths)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uninstall_nonexistent_version_errors_before_prompt() {
|
||||
let (_tmp, paths) = make_temp_paths();
|
||||
let uninstall = Uninstall {
|
||||
version: "9.9.9".to_owned(),
|
||||
yes: ForceYes { yes: true },
|
||||
};
|
||||
let result = uninstall.exec(&paths);
|
||||
assert!(result.is_err());
|
||||
let err = result.unwrap_err();
|
||||
assert!(
|
||||
err.to_string().contains("9.9.9"),
|
||||
"error should mention the version number"
|
||||
);
|
||||
assert!(
|
||||
err.to_string().contains("not installed"),
|
||||
"error should say 'not installed'"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uninstall_current_version_errors() {
|
||||
let (_tmp, paths) = make_temp_paths();
|
||||
// Create the "current" symlink target so it exists on disk
|
||||
let current_dir = paths.cli_bin_dir.version_dir("2.0.0");
|
||||
std::fs::create_dir_all(¤t_dir.0).unwrap();
|
||||
paths.cli_bin_dir.set_current_version("2.0.0").unwrap();
|
||||
|
||||
let uninstall = Uninstall {
|
||||
version: "2.0.0".to_owned(),
|
||||
yes: ForceYes { yes: true },
|
||||
};
|
||||
let result = uninstall.exec(&paths);
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().to_string().contains("currently used version"),);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uninstall_current_keyword_errors() {
|
||||
let (_tmp, paths) = make_temp_paths();
|
||||
let uninstall = Uninstall {
|
||||
version: "current".to_owned(),
|
||||
yes: ForceYes { yes: true },
|
||||
};
|
||||
let result = uninstall.exec(&paths);
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().to_string().contains("cannot remove `current`"),);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uninstall_existing_version_with_yes() {
|
||||
let (_tmp, paths) = make_temp_paths();
|
||||
let version_dir = paths.cli_bin_dir.version_dir("1.0.0");
|
||||
std::fs::create_dir_all(&version_dir.0).unwrap();
|
||||
// Create a dummy file so we can verify the directory existed
|
||||
std::fs::write(version_dir.0.join("spacetime"), "dummy").unwrap();
|
||||
|
||||
assert!(version_dir.0.exists(), "version dir should exist before");
|
||||
|
||||
let uninstall = Uninstall {
|
||||
version: "1.0.0".to_owned(),
|
||||
yes: ForceYes { yes: true },
|
||||
};
|
||||
uninstall.exec(&paths).unwrap();
|
||||
|
||||
assert!(!version_dir.0.exists(), "version dir should be removed after uninstall");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ SPACETIMEDB_REDUCER(list_over_age, ReducerContext ctx, uint8_t age) {
|
||||
|
||||
// Log module identity
|
||||
SPACETIMEDB_REDUCER(log_module_identity, ReducerContext ctx) {
|
||||
LOG_INFO("Module identity: " + ctx.identity().to_string());
|
||||
LOG_INFO("Module identity: " + ctx.database_identity().to_string());
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@@ -550,8 +550,8 @@ SPACETIMEDB_REDUCER(test_btree_index_args, ReducerContext ctx) {
|
||||
|
||||
// Test reducer for assertions
|
||||
SPACETIMEDB_REDUCER(assert_caller_identity_is_module_identity, ReducerContext ctx) {
|
||||
LOG_INFO("Sender: " + ctx.sender().to_string() + " Identity: " + ctx.identity().to_string());
|
||||
if (ctx.sender() != ctx.identity()) {
|
||||
LOG_INFO("Sender: " + ctx.sender().to_string() + " Identity: " + ctx.database_identity().to_string());
|
||||
if (ctx.sender() != ctx.database_identity()) {
|
||||
LOG_ERROR("Assertion failed: caller identity does not match module identity");
|
||||
} else {
|
||||
LOG_INFO("Assertion passed: caller identity matches module identity");
|
||||
@@ -693,7 +693,7 @@ SPACETIMEDB_PROCEDURE(Unit, with_tx, ProcedureContext ctx) {
|
||||
|
||||
// Hit SpacetimeDB's schema HTTP route and return its result as a string
|
||||
SPACETIMEDB_PROCEDURE(std::string, get_my_schema_via_http, ProcedureContext ctx) {
|
||||
Identity module_identity = ctx.identity();
|
||||
Identity module_identity = ctx.database_identity();
|
||||
std::string url = "http://localhost:3000/v1/database/" + module_identity.to_string() + "/schema?version=9";
|
||||
|
||||
auto result = ctx.http.get(url);
|
||||
|
||||
@@ -300,7 +300,7 @@ static partial class Module
|
||||
public static void log_module_identity(ReducerContext ctx)
|
||||
{
|
||||
// Note: converting to lowercase to match the Rust formatting.
|
||||
Log.Info($"Module identity: {ctx.Identity.ToString().ToLower()}");
|
||||
Log.Info($"Module identity: {ctx.DatabaseIdentity.ToString().ToLower()}");
|
||||
}
|
||||
|
||||
[Reducer]
|
||||
@@ -492,7 +492,7 @@ static partial class Module
|
||||
public static void assert_caller_identity_is_module_identity(ReducerContext ctx)
|
||||
{
|
||||
var caller = ctx.Sender;
|
||||
var owner = ctx.Identity;
|
||||
var owner = ctx.DatabaseIdentity;
|
||||
if (!caller.Equals(owner))
|
||||
{
|
||||
throw new Exception($"Caller {caller} is not the owner {owner}");
|
||||
|
||||
@@ -331,7 +331,7 @@ export const listOverAge = spacetimedb.reducer(
|
||||
|
||||
// log_module_identity()
|
||||
export const log_module_identity = spacetimedb.reducer(ctx => {
|
||||
console.info(`Module identity: ${ctx.identity}`);
|
||||
console.info(`Module identity: ${ctx.databaseIdentity}`);
|
||||
});
|
||||
|
||||
// test(arg: TestAlias(TestA), arg2: TestB, arg3: TestC, arg4: TestF)
|
||||
@@ -494,7 +494,7 @@ export const test_btree_index_args = spacetimedb.reducer(ctx => {
|
||||
export const assert_caller_identity_is_module_identity = spacetimedb.reducer(
|
||||
ctx => {
|
||||
const caller = ctx.sender;
|
||||
const owner = ctx.identity;
|
||||
const owner = ctx.databaseIdentity;
|
||||
if (String(caller) !== String(owner)) {
|
||||
throw new Error(`Caller ${caller} is not the owner ${owner}`);
|
||||
} else {
|
||||
@@ -507,7 +507,7 @@ export const assert_caller_identity_is_module_identity = spacetimedb.reducer(
|
||||
//
|
||||
// This is a silly thing to do, but an effective test of the procedure HTTP API.
|
||||
export const getMySchemaViaHttp = spacetimedb.procedure(t.string(), ctx => {
|
||||
const module_identity = ctx.identity;
|
||||
const module_identity = ctx.databaseIdentity;
|
||||
try {
|
||||
const response = ctx.http.fetch(
|
||||
`http://localhost:3000/v1/database/${module_identity}/schema?version=9`
|
||||
|
||||
@@ -295,7 +295,7 @@ pub fn list_over_age(ctx: &ReducerContext, age: u8) {
|
||||
|
||||
#[spacetimedb::reducer]
|
||||
fn log_module_identity(ctx: &ReducerContext) {
|
||||
log::info!("Module identity: {}", ctx.identity());
|
||||
log::info!("Module identity: {}", ctx.database_identity());
|
||||
}
|
||||
|
||||
#[spacetimedb::reducer]
|
||||
@@ -508,7 +508,7 @@ fn test_btree_index_args(ctx: &ReducerContext) {
|
||||
#[spacetimedb::reducer]
|
||||
fn assert_caller_identity_is_module_identity(ctx: &ReducerContext) {
|
||||
let caller = ctx.sender();
|
||||
let owner = ctx.identity();
|
||||
let owner = ctx.database_identity();
|
||||
if caller != owner {
|
||||
panic!("Caller {caller} is not the owner {owner}");
|
||||
} else {
|
||||
|
||||
@@ -142,7 +142,7 @@ SPACETIMEDB_PROCEDURE(Unit, insert_with_tx_rollback, ProcedureContext ctx) {
|
||||
// Test HTTP GET request to the module's own schema endpoint
|
||||
SPACETIMEDB_PROCEDURE(std::string, read_my_schema, ProcedureContext ctx) {
|
||||
// Get the module identity (database address)
|
||||
Identity module_identity = ctx.identity();
|
||||
Identity module_identity = ctx.database_identity();
|
||||
std::string identity_hex = module_identity.to_hex_string();
|
||||
|
||||
LOG_INFO("read_my_schema using identity: " + identity_hex);
|
||||
|
||||
@@ -91,7 +91,7 @@ export const will_panic = spacetimedb.procedure(t.unit(), _ctx => {
|
||||
});
|
||||
|
||||
export const read_my_schema = spacetimedb.procedure(t.string(), ctx => {
|
||||
const module_identity = ctx.identity;
|
||||
const module_identity = ctx.databaseIdentity;
|
||||
const response = ctx.http.fetch(
|
||||
`http://localhost:3000/v1/database/${module_identity}/schema?version=9`
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user