From af29ba76cce0572533c018e08249ed06c4ded56b Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 15 Mar 2026 18:14:00 +0000 Subject: [PATCH 1/7] Add RustCFML feasibility assessment for Wheels framework Evaluates pixl8/RustCFML v0.4.0 as a potential alternative CFML runtime for Wheels. Key finding: not feasible today due to missing dynamic method dispatch (onMissingMethod), Java interop, and metadata introspection that Wheels' ActiveRecord ORM requires. Worth monitoring for future potential given its 3x throughput and 44x lower memory footprint vs Lucee. https://claude.ai/code/session_01FSAD6qjDXUNiNsBWJncK1N --- docs/plans/rustcfml-feasibility-assessment.md | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 docs/plans/rustcfml-feasibility-assessment.md diff --git a/docs/plans/rustcfml-feasibility-assessment.md b/docs/plans/rustcfml-feasibility-assessment.md new file mode 100644 index 0000000000..1e3dcee888 --- /dev/null +++ b/docs/plans/rustcfml-feasibility-assessment.md @@ -0,0 +1,154 @@ +# RustCFML Feasibility Assessment for Wheels Framework + +**Date:** 2026-03-15 +**Project:** [pixl8/RustCFML](https://github.com/pixl8/RustCFML) +**Version Evaluated:** 0.4.0 (released March 14, 2026) + +## Executive Summary + +RustCFML is a **complete CFML interpreter written in Rust** — not a library or extension for existing CFML engines. It aims to replace Lucee/ACF as a runtime, compiling CFML to bytecode executed on a stack-based VM with no JVM dependency. + +**Verdict: Not feasible today. Worth monitoring for future potential.** + +RustCFML is too early-stage to run Wheels in production, but its architecture and performance characteristics make it a compelling long-term target. The project would need to mature significantly in areas Wheels depends on (ORM-like dynamic method dispatch, complex component inheritance, Java interop) before Wheels could realistically target it. + +## What RustCFML Actually Is + +It is important to clarify: RustCFML is **not** a Rust extension library that adds functions to Lucee/ACF (like a ForgeBox package). It is a standalone CFML runtime that: + +- Parses CFML/CFScript source code +- Compiles it to custom bytecode +- Executes it on a Rust-based VM +- Includes a built-in web server (Axum-based) +- Ships as a single native binary (~8 MB memory footprint) + +This means the feasibility question is: **"Can Wheels run on RustCFML as an alternative to Lucee?"** — not "Can we add RustCFML to our Lucee stack?" + +## Performance Profile + +RustCFML's benchmarks are impressive for a Hello World page: + +| Metric | RustCFML | Lucee 7.0.1 | BoxLang 1.10 | +|--------|----------|-------------|--------------| +| Memory (RSS) | ~8 MB | ~350 MB | ~305 MB | +| Requests/sec | 1,949 | 635 | 293 | +| Avg response | 0.5 ms | 1.6 ms | 3.4 ms | +| Startup | Instant | ~15s | ~15s | + +These numbers are for trivial workloads. Real-world Wheels applications involve ORM queries, component inheritance chains, dynamic method resolution, and session management — none of which are benchmarked. + +## Wheels Dependencies vs RustCFML Capabilities + +### Supported (would work today) + +| Wheels Feature | RustCFML Support | +|---------------|-----------------| +| CFScript syntax | Full support, 50+ tags converted | +| Component inheritance (`extends`) | Supported with interfaces | +| Closures and arrow functions | Supported with scope capture | +| Built-in string/array/struct functions | 400+ functions implemented | +| `queryExecute` with params | MySQL, PostgreSQL, SQLite, MSSQL | +| `cfhttp` for external calls | GET/POST/PUT/DELETE/PATCH | +| Session/cookie management | Supported | +| `Hash()`, `Encrypt()`, `Decrypt()` | Supported (including bcrypt/scrypt/argon2) | +| `SerializeJSON`/`DeserializeJSON` | Supported | +| URL rewriting | Tuckey-compatible XML config | +| Application.cfc lifecycle | onApplicationStart, onRequestStart, etc. | +| File I/O operations | Supported | + +### Critical Gaps (blockers for Wheels) + +| Wheels Requirement | RustCFML Status | Impact | +|-------------------|----------------|--------| +| **Dynamic method dispatch** (`onMissingMethod`) | Unknown/unlikely | Wheels ORM relies heavily on dynamic finders like `findAllByEmail()` via `onMissingMethod`. This is fundamental to the ActiveRecord pattern. | +| **Complex `CreateObject("java", ...)`** | Not supported | Wheels uses `ConcurrentHashMap` in RateLimiter, and Lucee/ACF-specific Java objects throughout. No JVM = no Java interop. | +| **Query-of-Queries** | Explicitly unsupported | Wheels doesn't heavily use QoQ, but some internal operations may depend on it. | +| **`cflock` tag** | Unknown | Wheels uses `cflock` extensively for thread-safe rate limiting, caching, and initialization. | +| **Metadata introspection** (`GetMetadata`, `GetComponentMetaData`) | Unknown | Wheels inspects component metadata for model configuration, routing, and test discovery. | +| **`Evaluate()` / dynamic evaluation** | Unknown | Some Wheels internals use dynamic evaluation for scope resolution. | +| **ORM/Hibernate** | Not supported | Wheels has its own ActiveRecord ORM (not Hibernate), but it relies on deep CFML engine features for dynamic method resolution. | +| **Custom tag paths / mappings** | Partial (component mappings exist) | Wheels uses custom mappings for `vendor/`, `app/`, etc. | +| **`cfthread` (true concurrency)** | Sequential only | Background job processing (`wheels.Job`) needs real async. | +| **Transaction management** | Supported (`cftransaction`) | Wheels uses this — would need verification of rollback/savepoint behavior. | + +### Partially Supported (would need testing) + +| Feature | Notes | +|---------|-------| +| `CsrfGenerateToken()` / `CsrfVerifyToken()` | Wheels CSRF uses these Lucee/ACF built-ins. RustCFML has security functions but these specific ones are unconfirmed. | +| `cfheader` / `cfcookie` in middleware | RustCFML's web server handles these differently than servlet-based engines. | +| Application scope persistence | Wheels stores extensive config in `application.$wheels`. Behavior under RustCFML's Application.cfc lifecycle needs validation. | +| Error handling (`cftry`/`cfcatch`/`cfthrow`) | Basic support likely exists, but Wheels uses typed exceptions (`type="Wheels.InvalidAuthenticityToken"`) that need precise matching. | + +## Wheels-Specific Code Analysis + +### Crypto/Security Usage +Wheels uses these crypto operations that RustCFML would need to support identically: +- `GenerateSecretKey("AES")` — CSRF cookie encryption key generation +- `Encrypt()`/`Decrypt()` with AES algorithm — CSRF cookie values +- `Hash()` — Cache keys, asset fingerprinting, model IDs, transaction hashing +- `CsrfGenerateToken()`/`CsrfVerifyToken()` — Session-based CSRF (Lucee built-in) + +RustCFML claims bcrypt/scrypt/argon2 support, which is actually **better** than stock Lucee for password hashing, but the standard `Encrypt()`/`Decrypt()` output format must be byte-compatible with existing cookies. + +### Java Interop Dependencies +Found in Wheels core: +- `CreateObject("java", "java.util.concurrent.ConcurrentHashMap")` — RateLimiter middleware +- Various Lucee/ACF-specific internal APIs used implicitly + +### Dynamic Method Resolution +Wheels' ActiveRecord pattern is built on dynamic method dispatch: +```cfm +model("User").findAllByEmail("test@example.com") // via onMissingMethod +model("User").findOneByUsernameAndPassword(...) // compound dynamic finders +user.hasOrders() // dynamic association checker +``` +This is the single biggest compatibility concern. + +## Project Maturity Assessment + +| Indicator | Value | Assessment | +|-----------|-------|------------| +| Version | 0.4.0 | Pre-1.0, expect breaking changes | +| Stars | 3 | Minimal community adoption | +| Forks | 0 | No community contributions | +| Commits | 39 | Early development | +| Contributors | ~1 (Pixl8) | Single-maintainer risk | +| Test coverage | 1,181 assertions / 89 suites | Reasonable for scope | +| License | MIT | No licensing concerns | +| Last activity | March 2026 | Actively developed | + +## Recommendations + +### Short-term (Now): No action needed +- RustCFML cannot run Wheels today due to missing dynamic method dispatch, Java interop, and unverified CFML engine built-ins +- Do not invest engineering time in compatibility work + +### Medium-term (6-12 months): Monitor and engage +1. **Watch the repo** for releases that add `onMissingMethod`, metadata introspection, and `cflock` support +2. **Open a dialog** with the Pixl8 team about framework compatibility goals — if they want RustCFML to run real-world apps, Wheels is a good benchmark +3. **Create a compatibility test suite** — a minimal Wheels app that exercises core ORM, routing, CSRF, and middleware features, runnable against any CFML engine + +### Long-term (12+ months): Evaluate as a deployment target +If RustCFML reaches 1.0 with: +- Full `onMissingMethod` support +- Component metadata introspection +- Robust `cflock` implementation +- Compatible `Encrypt()`/`Decrypt()` output + +Then Wheels could potentially offer RustCFML as a **lightweight deployment target** — attractive for: +- Containerized/serverless deployments (8 MB vs 350 MB) +- Edge computing scenarios +- High-throughput API-only Wheels apps (no view layer) +- Development/CI environments (instant startup) + +### What Wheels could do to prepare +1. **Reduce Java interop dependence** — Replace `ConcurrentHashMap` in RateLimiter with pure CFML struct + cflock (already partially done) +2. **Abstract engine-specific built-ins** — Wrap `CsrfGenerateToken()` so alternative implementations can be swapped +3. **Document dynamic method contracts** — Clearly specify what `onMissingMethod` patterns Wheels requires, so runtime implementors know the target + +## Conclusion + +RustCFML represents an exciting direction for the CFML ecosystem — a modern, high-performance runtime with minimal resource requirements. However, it is a pre-1.0 single-maintainer project that lacks several features fundamental to how Wheels operates. The performance benefits are compelling but academic until the compatibility gap closes. + +**The right move is to watch, not adopt.** If the project gains momentum and addresses dynamic method dispatch and metadata introspection, it could become a viable lightweight runtime for Wheels applications within 12-18 months. From fd13e5c7bb2e5cec1762ca24a646c1e56cdbef70 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 15 Mar 2026 18:14:42 +0000 Subject: [PATCH 2/7] Update CSRF token support status in RustCFML assessment csrfGenerateToken/csrfVerifyToken confirmed as implemented in RustCFML, though behavioral compatibility with Lucee still needs verification. https://claude.ai/code/session_01FSAD6qjDXUNiNsBWJncK1N --- docs/plans/rustcfml-feasibility-assessment.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plans/rustcfml-feasibility-assessment.md b/docs/plans/rustcfml-feasibility-assessment.md index 1e3dcee888..3e69633c2b 100644 --- a/docs/plans/rustcfml-feasibility-assessment.md +++ b/docs/plans/rustcfml-feasibility-assessment.md @@ -75,7 +75,7 @@ These numbers are for trivial workloads. Real-world Wheels applications involve | Feature | Notes | |---------|-------| -| `CsrfGenerateToken()` / `CsrfVerifyToken()` | Wheels CSRF uses these Lucee/ACF built-ins. RustCFML has security functions but these specific ones are unconfirmed. | +| `CsrfGenerateToken()` / `CsrfVerifyToken()` | Confirmed supported in RustCFML. Behavioral compatibility with Lucee's implementation (session binding, token format) needs verification. | | `cfheader` / `cfcookie` in middleware | RustCFML's web server handles these differently than servlet-based engines. | | Application scope persistence | Wheels stores extensive config in `application.$wheels`. Behavior under RustCFML's Application.cfc lifecycle needs validation. | | Error handling (`cftry`/`cfcatch`/`cfthrow`) | Basic support likely exists, but Wheels uses typed exceptions (`type="Wheels.InvalidAuthenticityToken"`) that need precise matching. | From 65d05236c910ef532a2932ad09415d53448ea8d1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 15 Mar 2026 18:17:52 +0000 Subject: [PATCH 3/7] ci: add workflow results for test-lucee7-mysql [skip ci] --- .github/workflow-results/test-lucee7-mysql.md | 429 +++++++++++------- 1 file changed, 253 insertions(+), 176 deletions(-) diff --git a/.github/workflow-results/test-lucee7-mysql.md b/.github/workflow-results/test-lucee7-mysql.md index 14115da90e..4864f16bb3 100644 --- a/.github/workflow-results/test-lucee7-mysql.md +++ b/.github/workflow-results/test-lucee7-mysql.md @@ -1,17 +1,17 @@ # Workflow Results: Test Lucee 7 + MySQL **Status:** PASSED -**Run:** [#18](https://github.com/wheels-dev/wheels/actions/runs/22270240179) -**Commit:** ff8fe7c99be289e1e15b11cfb867e0b1c2fe7b24 -**Branch:** claude/fix-pr-1891-workflow-pGc9Z -**Date:** 2026-02-22 04:18:58 UTC +**Run:** [#22](https://github.com/wheels-dev/wheels/actions/runs/23116312830) +**Commit:** fd13e5c7bb2e5cec1762ca24a646c1e56cdbef70 +**Branch:** claude/evaluate-rustcfml-feasibility-40oUw +**Date:** 2026-03-15 18:17:51 UTC ## Test Results ``` -Bundle: wheels.tests_testbox.specs.BasicsSpec +Bundle: wheels.tests.specs.BasicsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 7ms +Duration: 6ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -20,9 +20,20 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.controller.cachingSpec +Bundle: wheels.tests.specs.channel.DatabaseAdapterSpec +CFML Engine: Lucee 7.0.1.100 +Duration: 213ms +Labels: +╔═══════════════════════════════════════════════════════════╗ +║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ +╠═══════════════════════════════════════════════════════════╣ +║ 1 ║ 8 ║ 8 ║ 0 ║ 0 ║ 0 ║ +╚═══════════════════════════════════════════════════════════╝ + + +Bundle: wheels.tests.specs.controller.cachingSpec CFML Engine: Lucee 7.0.1.100 -Duration: 102ms +Duration: 82ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -31,9 +42,20 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.controller.csrf.cookieSpec +Bundle: wheels.tests.specs.controller.channelSpec CFML Engine: Lucee 7.0.1.100 -Duration: 298ms +Duration: 100ms +Labels: +╔═══════════════════════════════════════════════════════════╗ +║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ +╠═══════════════════════════════════════════════════════════╣ +║ 3 ║ 22 ║ 22 ║ 0 ║ 0 ║ 0 ║ +╚═══════════════════════════════════════════════════════════╝ + + +Bundle: wheels.tests.specs.controller.csrf.cookieSpec +CFML Engine: Lucee 7.0.1.100 +Duration: 320ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -42,9 +64,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.controller.csrf.sessionSpec +Bundle: wheels.tests.specs.controller.csrf.sessionSpec CFML Engine: Lucee 7.0.1.100 -Duration: 219ms +Duration: 203ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -53,9 +75,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.controller.filtersSpec +Bundle: wheels.tests.specs.controller.filtersSpec CFML Engine: Lucee 7.0.1.100 -Duration: 68ms +Duration: 58ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -64,9 +86,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.controller.flashSpec +Bundle: wheels.tests.specs.controller.flashSpec CFML Engine: Lucee 7.0.1.100 -Duration: 132ms +Duration: 114ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -75,9 +97,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.controller.initializationSpec +Bundle: wheels.tests.specs.controller.initializationSpec CFML Engine: Lucee 7.0.1.100 -Duration: 41ms +Duration: 27ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -86,9 +108,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.controller.miscellaneousSpec +Bundle: wheels.tests.specs.controller.miscellaneousSpec CFML Engine: Lucee 7.0.1.100 -Duration: 188ms +Duration: 126ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -97,9 +119,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.controller.providesSpec +Bundle: wheels.tests.specs.controller.providesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 64ms +Duration: 39ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -108,9 +130,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.controller.redirectionSpec +Bundle: wheels.tests.specs.controller.redirectionSpec CFML Engine: Lucee 7.0.1.100 -Duration: 99ms +Duration: 66ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -119,9 +141,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.controller.renderingSpec +Bundle: wheels.tests.specs.controller.renderingSpec CFML Engine: Lucee 7.0.1.100 -Duration: 1126ms +Duration: 1003ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -130,9 +152,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.controller.requestSpec +Bundle: wheels.tests.specs.controller.requestSpec CFML Engine: Lucee 7.0.1.100 -Duration: 23ms +Duration: 30ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -141,9 +163,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.controller.sseSpec +Bundle: wheels.tests.specs.controller.sseSpec CFML Engine: Lucee 7.0.1.100 -Duration: 46ms +Duration: 52ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -152,9 +174,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.controller.verifiesSpec +Bundle: wheels.tests.specs.controller.verifiesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 30ms +Duration: 38ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -163,9 +185,20 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.dispatch.createParamsSpec +Bundle: wheels.tests.specs.di.InjectorSpec CFML Engine: Lucee 7.0.1.100 -Duration: 17ms +Duration: 49ms +Labels: +╔═══════════════════════════════════════════════════════════╗ +║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ +╠═══════════════════════════════════════════════════════════╣ +║ 8 ║ 25 ║ 25 ║ 0 ║ 0 ║ 0 ║ +╚═══════════════════════════════════════════════════════════╝ + + +Bundle: wheels.tests.specs.dispatch.createParamsSpec +CFML Engine: Lucee 7.0.1.100 +Duration: 19ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -174,9 +207,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.dispatch.findMatchingRouteMegaSpec +Bundle: wheels.tests.specs.dispatch.findMatchingRouteMegaSpec CFML Engine: Lucee 7.0.1.100 -Duration: 741ms +Duration: 919ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -185,9 +218,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.dispatch.findMatchingRouteSpec +Bundle: wheels.tests.specs.dispatch.findMatchingRouteSpec CFML Engine: Lucee 7.0.1.100 -Duration: 35ms +Duration: 40ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -196,9 +229,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.dispatch.getrequestmethodSpec +Bundle: wheels.tests.specs.dispatch.getrequestmethodSpec CFML Engine: Lucee 7.0.1.100 -Duration: 5ms +Duration: 7ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -207,9 +240,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.dispatch.requestSpec +Bundle: wheels.tests.specs.dispatch.requestSpec CFML Engine: Lucee 7.0.1.100 -Duration: 9ms +Duration: 10ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -218,7 +251,7 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.dispatch.setCorsHeadersSpec +Bundle: wheels.tests.specs.dispatch.setCorsHeadersSpec CFML Engine: Lucee 7.0.1.100 Duration: 1ms Labels: @@ -229,9 +262,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.environment.ipbasedaccessSpec +Bundle: wheels.tests.specs.environment.ipbasedaccessSpec CFML Engine: Lucee 7.0.1.100 -Duration: 4ms +Duration: 6ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -240,9 +273,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.events.onerrorSpec +Bundle: wheels.tests.specs.events.onerrorSpec CFML Engine: Lucee 7.0.1.100 -Duration: 237ms +Duration: 256ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -251,9 +284,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.global.cachingSpec +Bundle: wheels.tests.specs.global.cachingSpec CFML Engine: Lucee 7.0.1.100 -Duration: 5ms +Duration: 4ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -262,9 +295,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.global.dbinfoSpec +Bundle: wheels.tests.specs.global.dbinfoSpec CFML Engine: Lucee 7.0.1.100 -Duration: 84ms +Duration: 80ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -273,9 +306,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.global.internalSpec +Bundle: wheels.tests.specs.global.internalSpec CFML Engine: Lucee 7.0.1.100 -Duration: 60ms +Duration: 82ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -284,9 +317,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.global.listcleanSpec +Bundle: wheels.tests.specs.global.listcleanSpec CFML Engine: Lucee 7.0.1.100 -Duration: 6ms +Duration: 3ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -295,9 +328,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.global.publicSpec +Bundle: wheels.tests.specs.global.publicSpec CFML Engine: Lucee 7.0.1.100 -Duration: 42ms +Duration: 55ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -306,9 +339,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.global.stringsSpec +Bundle: wheels.tests.specs.global.stringsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 28ms +Duration: 21ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -317,9 +350,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.global.urlforSpec +Bundle: wheels.tests.specs.global.urlforSpec CFML Engine: Lucee 7.0.1.100 -Duration: 45ms +Duration: 38ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -328,9 +361,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.internal.model.validationsSpec +Bundle: wheels.tests.specs.internal.model.validationsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 31ms +Duration: 41ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -339,9 +372,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.jobs.JobQueueSpec +Bundle: wheels.tests.specs.jobs.JobQueueSpec CFML Engine: Lucee 7.0.1.100 -Duration: 63ms +Duration: 156ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -350,9 +383,20 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.mapper.MapperSpec +Bundle: wheels.tests.specs.jobs.JobWorkerSpec CFML Engine: Lucee 7.0.1.100 -Duration: 11ms +Duration: 156ms +Labels: +╔═══════════════════════════════════════════════════════════╗ +║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ +╠═══════════════════════════════════════════════════════════╣ +║ 8 ║ 33 ║ 33 ║ 0 ║ 0 ║ 0 ║ +╚═══════════════════════════════════════════════════════════╝ + + +Bundle: wheels.tests.specs.mapper.MapperSpec +CFML Engine: Lucee 7.0.1.100 +Duration: 13ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -361,9 +405,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.mapper.MappingSpec +Bundle: wheels.tests.specs.mapper.MappingSpec CFML Engine: Lucee 7.0.1.100 -Duration: 9ms +Duration: 13ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -372,9 +416,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.mapper.MatchingSpec +Bundle: wheels.tests.specs.mapper.MatchingSpec CFML Engine: Lucee 7.0.1.100 -Duration: 39ms +Duration: 51ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -383,9 +427,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.mapper.NestedResourcesSpec +Bundle: wheels.tests.specs.mapper.NestedResourcesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 101ms +Duration: 126ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -394,9 +438,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.mapper.ResourcesSpec +Bundle: wheels.tests.specs.mapper.ResourcesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 31ms +Duration: 50ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -405,7 +449,7 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.mapper.RootSpec +Bundle: wheels.tests.specs.mapper.RootSpec CFML Engine: Lucee 7.0.1.100 Duration: 7ms Labels: @@ -416,9 +460,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.mapper.UtilsSpec +Bundle: wheels.tests.specs.mapper.UtilsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 15ms +Duration: 21ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -427,9 +471,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.mapper.WildcardSpec +Bundle: wheels.tests.specs.mapper.WildcardSpec CFML Engine: Lucee 7.0.1.100 -Duration: 17ms +Duration: 27ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -438,9 +482,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.mapperModernSpec +Bundle: wheels.tests.specs.mapperModernSpec CFML Engine: Lucee 7.0.1.100 -Duration: 50ms +Duration: 77ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -449,9 +493,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.mapperSpec +Bundle: wheels.tests.specs.mapperSpec CFML Engine: Lucee 7.0.1.100 -Duration: 125ms +Duration: 186ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -460,9 +504,31 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.migrator.migration.mysqlTextSizesSpec +Bundle: wheels.tests.specs.middleware.MultiTenantIntegrationSpec CFML Engine: Lucee 7.0.1.100 -Duration: 222ms +Duration: 128ms +Labels: +╔═══════════════════════════════════════════════════════════╗ +║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ +╠═══════════════════════════════════════════════════════════╣ +║ 1 ║ 9 ║ 9 ║ 0 ║ 0 ║ 0 ║ +╚═══════════════════════════════════════════════════════════╝ + + +Bundle: wheels.tests.specs.middleware.TenantResolverSpec +CFML Engine: Lucee 7.0.1.100 +Duration: 15ms +Labels: +╔═══════════════════════════════════════════════════════════╗ +║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ +╠═══════════════════════════════════════════════════════════╣ +║ 5 ║ 10 ║ 10 ║ 0 ║ 0 ║ 0 ║ +╚═══════════════════════════════════════════════════════════╝ + + +Bundle: wheels.tests.specs.migrator.migration.mysqlTextSizesSpec +CFML Engine: Lucee 7.0.1.100 +Duration: 316ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -471,9 +537,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.migrator.migrationSpec +Bundle: wheels.tests.specs.migrator.migrationSpec CFML Engine: Lucee 7.0.1.100 -Duration: 1021ms +Duration: 1055ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -482,9 +548,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.migrator.migratorSpec +Bundle: wheels.tests.specs.migrator.migratorSpec CFML Engine: Lucee 7.0.1.100 -Duration: 426ms +Duration: 344ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -493,9 +559,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.associationsSpec +Bundle: wheels.tests.specs.model.associationsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 605ms +Duration: 734ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -504,9 +570,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.calculationsSpec +Bundle: wheels.tests.specs.model.calculationsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 189ms +Duration: 158ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -515,9 +581,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.callbacksSpec +Bundle: wheels.tests.specs.model.callbacksSpec CFML Engine: Lucee 7.0.1.100 -Duration: 429ms +Duration: 500ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -526,9 +592,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.crudSpec +Bundle: wheels.tests.specs.model.crudSpec CFML Engine: Lucee 7.0.1.100 -Duration: 1210ms +Duration: 1295ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -537,9 +603,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.deleteSpec +Bundle: wheels.tests.specs.model.deleteSpec CFML Engine: Lucee 7.0.1.100 -Duration: 139ms +Duration: 147ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -548,9 +614,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.errorsSpec +Bundle: wheels.tests.specs.model.errorsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 86ms +Duration: 71ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -559,9 +625,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.miscellaneousSpec +Bundle: wheels.tests.specs.model.miscellaneousSpec CFML Engine: Lucee 7.0.1.100 -Duration: 74ms +Duration: 87ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -570,9 +636,20 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.nestedpropertiesSpec +Bundle: wheels.tests.specs.model.MultiTenantSpec CFML Engine: Lucee 7.0.1.100 -Duration: 610ms +Duration: 14ms +Labels: +╔═══════════════════════════════════════════════════════════╗ +║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ +╠═══════════════════════════════════════════════════════════╣ +║ 7 ║ 14 ║ 14 ║ 0 ║ 0 ║ 0 ║ +╚═══════════════════════════════════════════════════════════╝ + + +Bundle: wheels.tests.specs.model.nestedpropertiesSpec +CFML Engine: Lucee 7.0.1.100 +Duration: 654ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -581,9 +658,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.onmissingmethod.belongsToSpec +Bundle: wheels.tests.specs.model.onmissingmethod.belongsToSpec CFML Engine: Lucee 7.0.1.100 -Duration: 36ms +Duration: 49ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -592,9 +669,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.onmissingmethod.hasManySpec +Bundle: wheels.tests.specs.model.onmissingmethod.hasManySpec CFML Engine: Lucee 7.0.1.100 -Duration: 163ms +Duration: 219ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -603,9 +680,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.onmissingmethod.hasOneSpec +Bundle: wheels.tests.specs.model.onmissingmethod.hasOneSpec CFML Engine: Lucee 7.0.1.100 -Duration: 111ms +Duration: 127ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -614,9 +691,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.propertiesSpec +Bundle: wheels.tests.specs.model.propertiesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 429ms +Duration: 619ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -625,9 +702,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.raceconditionSpec +Bundle: wheels.tests.specs.model.raceconditionSpec CFML Engine: Lucee 7.0.1.100 -Duration: 133ms +Duration: 121ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -636,20 +713,20 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.raisedErrorsSpec +Bundle: wheels.tests.specs.model.raisedErrorsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 26ms +Duration: 41ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ ╠═══════════════════════════════════════════════════════════╣ -║ 1 ║ 5 ║ 5 ║ 0 ║ 0 ║ 0 ║ +║ 1 ║ 6 ║ 6 ║ 0 ║ 0 ║ 0 ║ ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.readSpec +Bundle: wheels.tests.specs.model.readSpec CFML Engine: Lucee 7.0.1.100 -Duration: 277ms +Duration: 380ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -658,20 +735,20 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.sqlSpec +Bundle: wheels.tests.specs.model.sqlSpec CFML Engine: Lucee 7.0.1.100 -Duration: 74ms +Duration: 59ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ ╠═══════════════════════════════════════════════════════════╣ -║ 1 ║ 10 ║ 10 ║ 0 ║ 0 ║ 0 ║ +║ 1 ║ 11 ║ 11 ║ 0 ║ 0 ║ 0 ║ ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.transactionsSpec +Bundle: wheels.tests.specs.model.transactionsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 477ms +Duration: 488ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -680,9 +757,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.useindexSpec +Bundle: wheels.tests.specs.model.useindexSpec CFML Engine: Lucee 7.0.1.100 -Duration: 70ms +Duration: 61ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -691,9 +768,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.validationsSpec +Bundle: wheels.tests.specs.model.validationsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 1516ms +Duration: 1680ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -702,9 +779,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.model.viewsSpec +Bundle: wheels.tests.specs.model.viewsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 74ms +Duration: 58ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -713,9 +790,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.pluginsSpec +Bundle: wheels.tests.specs.pluginsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 399ms +Duration: 372ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -724,9 +801,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.routingSpec +Bundle: wheels.tests.specs.routingSpec CFML Engine: Lucee 7.0.1.100 -Duration: 36ms +Duration: 20ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -735,9 +812,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.assetsSpec +Bundle: wheels.tests.specs.view.assetsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 788ms +Duration: 570ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -746,9 +823,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.autoLinkSpec +Bundle: wheels.tests.specs.view.autoLinkSpec CFML Engine: Lucee 7.0.1.100 -Duration: 8ms +Duration: 7ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -757,9 +834,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.checkboxSpec +Bundle: wheels.tests.specs.view.checkboxSpec CFML Engine: Lucee 7.0.1.100 -Duration: 30ms +Duration: 35ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -768,9 +845,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.contentSpec +Bundle: wheels.tests.specs.view.contentSpec CFML Engine: Lucee 7.0.1.100 -Duration: 97ms +Duration: 100ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -779,9 +856,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.csrfSpec +Bundle: wheels.tests.specs.view.csrfSpec CFML Engine: Lucee 7.0.1.100 -Duration: 9ms +Duration: 31ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -790,9 +867,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.dateselectSpec +Bundle: wheels.tests.specs.view.dateselectSpec CFML Engine: Lucee 7.0.1.100 -Duration: 111ms +Duration: 106ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -801,9 +878,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.datesSpec +Bundle: wheels.tests.specs.view.datesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 51ms +Duration: 28ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -812,9 +889,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.errorsSpec +Bundle: wheels.tests.specs.view.errorsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 56ms +Duration: 34ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -823,9 +900,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.flashMessagesSpec +Bundle: wheels.tests.specs.view.flashMessagesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 10ms +Duration: 7ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -834,9 +911,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.formsdateobjectSpec +Bundle: wheels.tests.specs.view.formsdateobjectSpec CFML Engine: Lucee 7.0.1.100 -Duration: 172ms +Duration: 131ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -845,9 +922,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.formsdateplainSpec +Bundle: wheels.tests.specs.view.formsdateplainSpec CFML Engine: Lucee 7.0.1.100 -Duration: 353ms +Duration: 177ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -856,9 +933,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.formsdateSpec +Bundle: wheels.tests.specs.view.formsdateSpec CFML Engine: Lucee 7.0.1.100 -Duration: 23ms +Duration: 2ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -867,9 +944,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.formsSpec +Bundle: wheels.tests.specs.view.formsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 334ms +Duration: 353ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -878,9 +955,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.html5FormHelpersSpec +Bundle: wheels.tests.specs.view.html5FormHelpersSpec CFML Engine: Lucee 7.0.1.100 -Duration: 53ms +Duration: 47ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -889,9 +966,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.linksSpec +Bundle: wheels.tests.specs.view.linksSpec CFML Engine: Lucee 7.0.1.100 -Duration: 117ms +Duration: 114ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -900,9 +977,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.miscellaneousSpec +Bundle: wheels.tests.specs.view.miscellaneousSpec CFML Engine: Lucee 7.0.1.100 -Duration: 51ms +Duration: 52ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -911,9 +988,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.sanitizeSpec +Bundle: wheels.tests.specs.view.sanitizeSpec CFML Engine: Lucee 7.0.1.100 -Duration: 13ms +Duration: 12ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -922,9 +999,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.textfieldSpec +Bundle: wheels.tests.specs.view.textfieldSpec CFML Engine: Lucee 7.0.1.100 -Duration: 11ms +Duration: 12ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -933,9 +1010,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.textSpec +Bundle: wheels.tests.specs.view.textSpec CFML Engine: Lucee 7.0.1.100 -Duration: 32ms +Duration: 28ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -944,9 +1021,9 @@ Labels: ╚═══════════════════════════════════════════════════════════╝ -Bundle: wheels.tests_testbox.specs.view.urlsSpec +Bundle: wheels.tests.specs.view.urlsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 100ms +Duration: 114ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ From 6b6d1acc0e60fe9cb42d3d731cd80a1d1a6f4829 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 18 May 2026 12:00:30 +0000 Subject: [PATCH 4/7] =?UTF-8?q?docs:=20update=20RustCFML=20feasibility=20a?= =?UTF-8?q?ssessment=20(v0.4.0=20=E2=86=92=20v0.9.1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-evaluated pixl8/RustCFML after two months of rapid development. Three of four critical blockers now resolved: - onMissingMethod: implemented (enables dynamic finders) - cflock: implemented with RwLock-based concurrency - getMetadata: implemented (enables model config/test discovery) Only Java interop remains, affecting 2-3 call sites with easy fixes. Project grew 3→20 stars, 39→108 commits, 14 releases in 2 months. Recommendation upgraded from "watch and wait" to "proof-of-concept." https://claude.ai/code/session_01FSAD6qjDXUNiNsBWJncK1N --- docs/plans/rustcfml-feasibility-assessment.md | 327 ++++++++++-------- 1 file changed, 184 insertions(+), 143 deletions(-) diff --git a/docs/plans/rustcfml-feasibility-assessment.md b/docs/plans/rustcfml-feasibility-assessment.md index 3e69633c2b..6944da9c31 100644 --- a/docs/plans/rustcfml-feasibility-assessment.md +++ b/docs/plans/rustcfml-feasibility-assessment.md @@ -1,154 +1,195 @@ # RustCFML Feasibility Assessment for Wheels Framework -**Date:** 2026-03-15 +**Date:** 2026-05-18 (updated from initial 2026-03-15 evaluation) **Project:** [pixl8/RustCFML](https://github.com/pixl8/RustCFML) -**Version Evaluated:** 0.4.0 (released March 14, 2026) +**Version Evaluated:** 0.9.1 (released May 3, 2026) +**Previous Version Evaluated:** 0.4.0 (March 14, 2026) ## Executive Summary -RustCFML is a **complete CFML interpreter written in Rust** — not a library or extension for existing CFML engines. It aims to replace Lucee/ACF as a runtime, compiling CFML to bytecode executed on a stack-based VM with no JVM dependency. - -**Verdict: Not feasible today. Worth monitoring for future potential.** - -RustCFML is too early-stage to run Wheels in production, but its architecture and performance characteristics make it a compelling long-term target. The project would need to mature significantly in areas Wheels depends on (ORM-like dynamic method dispatch, complex component inheritance, Java interop) before Wheels could realistically target it. - -## What RustCFML Actually Is - -It is important to clarify: RustCFML is **not** a Rust extension library that adds functions to Lucee/ACF (like a ForgeBox package). It is a standalone CFML runtime that: - -- Parses CFML/CFScript source code -- Compiles it to custom bytecode -- Executes it on a Rust-based VM -- Includes a built-in web server (Axum-based) -- Ships as a single native binary (~8 MB memory footprint) - -This means the feasibility question is: **"Can Wheels run on RustCFML as an alternative to Lucee?"** — not "Can we add RustCFML to our Lucee stack?" - -## Performance Profile - -RustCFML's benchmarks are impressive for a Hello World page: - -| Metric | RustCFML | Lucee 7.0.1 | BoxLang 1.10 | -|--------|----------|-------------|--------------| -| Memory (RSS) | ~8 MB | ~350 MB | ~305 MB | -| Requests/sec | 1,949 | 635 | 293 | -| Avg response | 0.5 ms | 1.6 ms | 3.4 ms | -| Startup | Instant | ~15s | ~15s | - -These numbers are for trivial workloads. Real-world Wheels applications involve ORM queries, component inheritance chains, dynamic method resolution, and session management — none of which are benchmarked. - -## Wheels Dependencies vs RustCFML Capabilities - -### Supported (would work today) - -| Wheels Feature | RustCFML Support | -|---------------|-----------------| -| CFScript syntax | Full support, 50+ tags converted | -| Component inheritance (`extends`) | Supported with interfaces | -| Closures and arrow functions | Supported with scope capture | -| Built-in string/array/struct functions | 400+ functions implemented | -| `queryExecute` with params | MySQL, PostgreSQL, SQLite, MSSQL | -| `cfhttp` for external calls | GET/POST/PUT/DELETE/PATCH | -| Session/cookie management | Supported | -| `Hash()`, `Encrypt()`, `Decrypt()` | Supported (including bcrypt/scrypt/argon2) | -| `SerializeJSON`/`DeserializeJSON` | Supported | -| URL rewriting | Tuckey-compatible XML config | -| Application.cfc lifecycle | onApplicationStart, onRequestStart, etc. | -| File I/O operations | Supported | - -### Critical Gaps (blockers for Wheels) - -| Wheels Requirement | RustCFML Status | Impact | -|-------------------|----------------|--------| -| **Dynamic method dispatch** (`onMissingMethod`) | Unknown/unlikely | Wheels ORM relies heavily on dynamic finders like `findAllByEmail()` via `onMissingMethod`. This is fundamental to the ActiveRecord pattern. | -| **Complex `CreateObject("java", ...)`** | Not supported | Wheels uses `ConcurrentHashMap` in RateLimiter, and Lucee/ACF-specific Java objects throughout. No JVM = no Java interop. | -| **Query-of-Queries** | Explicitly unsupported | Wheels doesn't heavily use QoQ, but some internal operations may depend on it. | -| **`cflock` tag** | Unknown | Wheels uses `cflock` extensively for thread-safe rate limiting, caching, and initialization. | -| **Metadata introspection** (`GetMetadata`, `GetComponentMetaData`) | Unknown | Wheels inspects component metadata for model configuration, routing, and test discovery. | -| **`Evaluate()` / dynamic evaluation** | Unknown | Some Wheels internals use dynamic evaluation for scope resolution. | -| **ORM/Hibernate** | Not supported | Wheels has its own ActiveRecord ORM (not Hibernate), but it relies on deep CFML engine features for dynamic method resolution. | -| **Custom tag paths / mappings** | Partial (component mappings exist) | Wheels uses custom mappings for `vendor/`, `app/`, etc. | -| **`cfthread` (true concurrency)** | Sequential only | Background job processing (`wheels.Job`) needs real async. | -| **Transaction management** | Supported (`cftransaction`) | Wheels uses this — would need verification of rollback/savepoint behavior. | - -### Partially Supported (would need testing) - -| Feature | Notes | -|---------|-------| -| `CsrfGenerateToken()` / `CsrfVerifyToken()` | Confirmed supported in RustCFML. Behavioral compatibility with Lucee's implementation (session binding, token format) needs verification. | -| `cfheader` / `cfcookie` in middleware | RustCFML's web server handles these differently than servlet-based engines. | -| Application scope persistence | Wheels stores extensive config in `application.$wheels`. Behavior under RustCFML's Application.cfc lifecycle needs validation. | -| Error handling (`cftry`/`cfcatch`/`cfthrow`) | Basic support likely exists, but Wheels uses typed exceptions (`type="Wheels.InvalidAuthenticityToken"`) that need precise matching. | - -## Wheels-Specific Code Analysis - -### Crypto/Security Usage -Wheels uses these crypto operations that RustCFML would need to support identically: -- `GenerateSecretKey("AES")` — CSRF cookie encryption key generation -- `Encrypt()`/`Decrypt()` with AES algorithm — CSRF cookie values -- `Hash()` — Cache keys, asset fingerprinting, model IDs, transaction hashing -- `CsrfGenerateToken()`/`CsrfVerifyToken()` — Session-based CSRF (Lucee built-in) - -RustCFML claims bcrypt/scrypt/argon2 support, which is actually **better** than stock Lucee for password hashing, but the standard `Encrypt()`/`Decrypt()` output format must be byte-compatible with existing cookies. - -### Java Interop Dependencies -Found in Wheels core: -- `CreateObject("java", "java.util.concurrent.ConcurrentHashMap")` — RateLimiter middleware -- Various Lucee/ACF-specific internal APIs used implicitly - -### Dynamic Method Resolution -Wheels' ActiveRecord pattern is built on dynamic method dispatch: -```cfm -model("User").findAllByEmail("test@example.com") // via onMissingMethod -model("User").findOneByUsernameAndPassword(...) // compound dynamic finders -user.hasOrders() // dynamic association checker +RustCFML is a **complete CFML interpreter written in Rust** — not a library or extension. It replaces Lucee/ACF as a runtime, compiling CFML to bytecode executed on a stack-based VM with no JVM dependency. + +**Updated Verdict: Feasibility has improved significantly. Several previous blockers are now resolved. A proof-of-concept trial is now reasonable.** + +Since the initial evaluation two months ago, RustCFML has gone from v0.4.0 to v0.9.1 (14 releases, 108 commits), addressing three of the four critical blockers identified previously. The project has also grown from 3 to 20 stars and gained its first fork, indicating rising community awareness. + +## Progress Since Initial Evaluation (March 2026) + +### Previously Identified Blockers — Status Update + +| Blocker | March Status | May Status | Impact | +|---------|-------------|------------|--------| +| **`onMissingMethod`** | Unknown/unlikely | **Implemented** | Wheels' dynamic finders (`findAllByEmail()`) may now work | +| **`cflock`** | Unknown | **Implemented** (RwLock-based) | Thread-safe rate limiting, caching, initialization possible | +| **`getMetadata`** | Unknown | **Implemented** | Model configuration, routing, test discovery possible | +| **`CreateObject`** | Not supported | **Implemented** (for components) | Component instantiation works | +| **Java interop (`CreateObject("java", ...)`)** | Not supported | **Still not supported** | Remains a blocker for `ConcurrentHashMap` usage | +| **`cfthread` (true concurrency)** | Sequential only | **Still sequential** | Background jobs would block | +| **Query-of-Queries** | Not supported | **Still not supported** | Low impact for Wheels | + +### New Capabilities Since v0.4.0 + +- **`cflock`** with real named locks using RwLock-based concurrency +- **`onMissingMethod`** for dynamic method dispatch +- **`getMetadata`** for component introspection +- **`createObject`** for component instantiation +- **`cfinvoke`** tag support +- **Session lifecycle** (`onSessionStart`/`onSessionEnd`) +- **`cfthread`** tag (sequential model) +- **`cfzip`** operations +- **`cfexecute`** for OS command execution +- **`cfstoredproc`/`cfprocparam`** for stored procedures +- **Custom tags** with `cf_` prefix +- **`cfimport`** with `.tld` support +- **Bytecode caching** with modification-time tracking (no recompilation for unchanged files) +- **Performance tuning** across VM hot paths (v0.8.0-v0.9.0 focus) +- **CFMX_COMPAT** encryption algorithm support +- **Taffy framework** compatibility (claimed feature-complete) + +### Project Growth Metrics + +| Indicator | March 2026 | May 2026 | Change | +|-----------|-----------|----------|--------| +| Version | 0.4.0 | 0.9.1 | 14 releases in 2 months | +| Stars | 3 | 20 | 7x increase | +| Forks | 0 | 1 | First community fork | +| Commits | 39 | 108 | 69 new commits | +| Test assertions | 1,181 / 89 suites | 1,181+ / 89+ suites | Baseline maintained | +| Release cadence | ~weekly | ~weekly | Consistent | + +## Revised Compatibility Analysis + +### Now Supported (previously blocked or unknown) + +| Wheels Feature | RustCFML Support | Notes | +|---------------|-----------------|-------| +| Dynamic finders (`findAllByEmail`) | `onMissingMethod` implemented | Needs behavioral verification | +| Thread-safe middleware | `cflock` with RwLock | Real concurrency, not just advisory | +| Component metadata inspection | `getMetadata` implemented | Model config, test discovery | +| Component instantiation | `createObject` for components | CFC creation works | +| CSRF tokens | `csrfGenerateToken`/`csrfVerifyToken` | Behavioral compat with Lucee TBD | +| Encrypt/Decrypt | AES, DES, DESEDE, Blowfish, CFMX_COMPAT | Cookie compat needs testing | +| Session management | Full lifecycle with CFID cookie | `onSessionStart`/`onSessionEnd` | +| Transaction management | `cftransaction` | Rollback/savepoint needs testing | +| Named locks | `cflock` (read/write) | RwLock-based, real concurrency | +| Password hashing | bcrypt, scrypt, argon2, PBKDF2 | Better than stock Lucee | +| Stored procedures | `cfstoredproc`/`cfprocparam` | Database-dependent | +| File operations | 23+ file I/O functions | Upload, read, write, directory ops | +| Caching | 8 cache functions | `cachePut`, `cacheGet`, etc. | +| Error context | `cfcatch.tagContext` with stack traces | Line/column/template info | + +### Remaining Blockers + +| Wheels Requirement | Status | Severity | Workaround | +|-------------------|--------|----------|------------| +| **`CreateObject("java", ...)`** | Not supported | **Medium** | Replace `ConcurrentHashMap` with CFML struct + `cflock`. Replace `StringBuilder` with string concatenation or array join. Only 2-3 call sites in Wheels core. | +| **`cfthread` true concurrency** | Sequential only | **Low** | Background jobs (`wheels.Job`) would block, but most Wheels apps don't use in-request threading. Worker processes are typically separate. | +| **Query-of-Queries** | Not supported | **Low** | Wheels rarely uses QoQ. Any instances could be rewritten as database queries. | +| **`GetComponentMetaData`** (as distinct from `getMetadata`) | Unconfirmed | **Low** | `getMetadata` is confirmed; `GetComponentMetaData` may work as an alias or may not be needed. | + +### Critical Behavioral Questions (need testing) + +These features are nominally supported but Wheels depends on specific behavioral contracts: + +1. **`onMissingMethod` argument passing**: Wheels passes `missingMethodName` and `missingMethodArguments` — does RustCFML match this signature exactly? +2. **`getMetadata` depth**: Wheels inspects `functions`, `extends`, `name`, `fullname`, `path` from metadata. How complete is the returned struct? +3. **`Encrypt`/`Decrypt` output format**: CSRF cookies encrypted on Lucee must be decryptable on RustCFML if migrating a running app (probably not a concern for fresh deploys). +4. **Application scope persistence**: Wheels stores extensive config in `application.$wheels`. Does `application` scope persist correctly across requests with the same semantics? +5. **`cflock` timeout behavior**: Wheels uses `timeout=1` on rate limiter locks. Does RustCFML respect lock timeout and fail gracefully? +6. **Scope resolution order**: Wheels depends on specific scope precedence (`local` > `arguments` > `variables`). CFML engines vary subtly here. +7. **`isInstanceOf` behavior**: Wheels uses this for type checking in DI and model resolution. +8. **Interface `implements` enforcement**: Wheels middleware uses `implements="wheels.middleware.MiddlewareInterface"`. + +## Wheels Code Changes Needed + +### Minimal changes (to eliminate remaining blockers) + +``` +vendor/wheels/middleware/RateLimiter.cfc (line 55): + - CreateObject("java", "java.util.concurrent.ConcurrentHashMap").init() + + StructNew() // with cflock protection (already present) + +vendor/wheels/Channel.cfc: + - Same ConcurrentHashMap replacement + +vendor/wheels/model/read.cfc (if StringBuilder used): + - Replace java.lang.StringBuilder with array + ArrayToList ``` -This is the single biggest compatibility concern. - -## Project Maturity Assessment - -| Indicator | Value | Assessment | -|-----------|-------|------------| -| Version | 0.4.0 | Pre-1.0, expect breaking changes | -| Stars | 3 | Minimal community adoption | -| Forks | 0 | No community contributions | -| Commits | 39 | Early development | -| Contributors | ~1 (Pixl8) | Single-maintainer risk | -| Test coverage | 1,181 assertions / 89 suites | Reasonable for scope | -| License | MIT | No licensing concerns | -| Last activity | March 2026 | Actively developed | - -## Recommendations - -### Short-term (Now): No action needed -- RustCFML cannot run Wheels today due to missing dynamic method dispatch, Java interop, and unverified CFML engine built-ins -- Do not invest engineering time in compatibility work - -### Medium-term (6-12 months): Monitor and engage -1. **Watch the repo** for releases that add `onMissingMethod`, metadata introspection, and `cflock` support -2. **Open a dialog** with the Pixl8 team about framework compatibility goals — if they want RustCFML to run real-world apps, Wheels is a good benchmark -3. **Create a compatibility test suite** — a minimal Wheels app that exercises core ORM, routing, CSRF, and middleware features, runnable against any CFML engine - -### Long-term (12+ months): Evaluate as a deployment target -If RustCFML reaches 1.0 with: -- Full `onMissingMethod` support -- Component metadata introspection -- Robust `cflock` implementation -- Compatible `Encrypt()`/`Decrypt()` output - -Then Wheels could potentially offer RustCFML as a **lightweight deployment target** — attractive for: -- Containerized/serverless deployments (8 MB vs 350 MB) -- Edge computing scenarios -- High-throughput API-only Wheels apps (no view layer) -- Development/CI environments (instant startup) - -### What Wheels could do to prepare -1. **Reduce Java interop dependence** — Replace `ConcurrentHashMap` in RateLimiter with pure CFML struct + cflock (already partially done) -2. **Abstract engine-specific built-ins** — Wrap `CsrfGenerateToken()` so alternative implementations can be swapped -3. **Document dynamic method contracts** — Clearly specify what `onMissingMethod` patterns Wheels requires, so runtime implementors know the target + +These are 2-3 small, isolated changes that would make the Wheels core Java-interop-free without affecting Lucee/ACF compatibility (struct + cflock works on all engines). + +### No changes needed for + +- CSRF protection (uses standard `Encrypt`/`Decrypt`/`GenerateSecretKey`/`CsrfGenerateToken`) +- Hash-based cache keys (uses standard `Hash()`) +- Model identification and transactions (uses standard `Hash()`) +- Route matching and dispatch (pure CFML) +- View rendering (pure CFML) +- Migration system (uses `queryExecute` which is supported) +- Validation framework (pure CFML) +- Association/relationship definitions (pure CFML, depends on `onMissingMethod`) + +## Performance Implications for Wheels + +| Scenario | Expected Benefit | Confidence | +|----------|-----------------|------------| +| Cold start (container/serverless) | **Massive** — instant vs ~15s JVM warmup | High | +| Memory per instance | **44x reduction** — 8 MB vs 350 MB | High (trivial workloads verified) | +| Simple page renders | **3x throughput** — 1,949 vs 635 req/s | High | +| ORM-heavy pages | **Unknown** — dynamic method dispatch overhead not benchmarked | Low | +| Complex model graphs | **Unknown** — component instantiation + metadata perf not tested | Low | +| Concurrent requests | **Uncertain** — Axum is async but cfthread is sequential | Medium | + +## Recommendations (Updated) + +### Immediate (now): Proof-of-concept trial + +The resolution of `onMissingMethod`, `cflock`, and `getMetadata` makes a PoC reasonable: + +1. **Build RustCFML from source** and attempt to boot the Wheels demo app (`app/`) +2. **Run the core test suite** against RustCFML to get a compatibility baseline +3. **Document failures** — categorize as (a) missing function, (b) behavioral difference, (c) Java interop dependency +4. **Estimate gap size** — if >80% of tests pass, active pursuit is justified + +### Short-term (1-3 months): Eliminate Java interop in Wheels core + +Regardless of RustCFML adoption, removing `CreateObject("java", ...)` from the framework core is good hygiene: + +- Makes Wheels more portable across all CFML engines (including BoxLang) +- Only 2-3 call sites need changes +- The `cflock`-protected struct pattern already exists alongside the Java calls + +### Medium-term (3-6 months): Engage with Pixl8 + +If the PoC shows >80% compatibility: + +1. **File issues** for specific behavioral gaps discovered during testing +2. **Contribute test cases** from Wheels' test suite that exercise edge cases +3. **Explore adding Wheels/RustCFML to the CI compat matrix** as a soft-fail target (like Oracle) +4. **Document the "Wheels on RustCFML" story** for containerized/edge deployments + +### Long-term (6-12 months): Lightweight deployment target + +Position RustCFML as an optional deployment runtime for: +- **Docker/Kubernetes** — 8 MB image vs 350+ MB +- **Serverless/edge functions** — instant cold start +- **CI/test environments** — faster test cycles +- **API-only Wheels apps** — no view layer complexity + +## Risk Assessment + +| Risk | Likelihood | Impact | Mitigation | +|------|-----------|--------|------------| +| Project abandoned (single maintainer) | Medium | High | MIT license allows forking; Pixl8 is an established CFML shop | +| Behavioral incompatibilities surface at scale | High | Medium | Incremental adoption starting with simple apps | +| Performance gains disappear with complex apps | Medium | Low | Still wins on memory/startup even if throughput is similar | +| Breaking changes in pre-1.0 releases | High | Low | Pin versions; don't depend on internals | +| Community doesn't grow | Medium | Medium | Wheels adoption would itself grow the community | ## Conclusion -RustCFML represents an exciting direction for the CFML ecosystem — a modern, high-performance runtime with minimal resource requirements. However, it is a pre-1.0 single-maintainer project that lacks several features fundamental to how Wheels operates. The performance benefits are compelling but academic until the compatibility gap closes. +RustCFML has made remarkable progress in two months. The three most critical Wheels blockers — `onMissingMethod`, `cflock`, and `getMetadata` — are now implemented. The remaining gap (Java interop) affects only 2-3 isolated call sites in Wheels core, and the fix is straightforward and engine-agnostic. + +**The project has moved from "watch and wait" to "try it and see."** A proof-of-concept attempt to boot Wheels on RustCFML is now the right next step. The outcome will determine whether this becomes a real deployment option or needs another 6-12 months of runtime maturation. -**The right move is to watch, not adopt.** If the project gains momentum and addresses dynamic method dispatch and metadata introspection, it could become a viable lightweight runtime for Wheels applications within 12-18 months. +The 44x memory reduction and instant cold start alone would make RustCFML a compelling option for containerized Wheels deployments — if the compatibility gap can be bridged. From 8b2dda3d6ee1a6b138c66a06ee93ff0eb6c43143 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 18 May 2026 12:03:32 +0000 Subject: [PATCH 5/7] ci: add workflow results for test-lucee7-mysql [skip ci] --- .github/workflow-results/test-lucee7-mysql.md | 186 +++++++++--------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/.github/workflow-results/test-lucee7-mysql.md b/.github/workflow-results/test-lucee7-mysql.md index 4864f16bb3..13a9ea6da9 100644 --- a/.github/workflow-results/test-lucee7-mysql.md +++ b/.github/workflow-results/test-lucee7-mysql.md @@ -1,17 +1,17 @@ # Workflow Results: Test Lucee 7 + MySQL **Status:** PASSED -**Run:** [#22](https://github.com/wheels-dev/wheels/actions/runs/23116312830) -**Commit:** fd13e5c7bb2e5cec1762ca24a646c1e56cdbef70 +**Run:** [#23](https://github.com/wheels-dev/wheels/actions/runs/26032173536) +**Commit:** 6b6d1acc0e60fe9cb42d3d731cd80a1d1a6f4829 **Branch:** claude/evaluate-rustcfml-feasibility-40oUw -**Date:** 2026-03-15 18:17:51 UTC +**Date:** 2026-05-18 12:03:32 UTC ## Test Results ``` Bundle: wheels.tests.specs.BasicsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 6ms +Duration: 7ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -22,7 +22,7 @@ Labels: Bundle: wheels.tests.specs.channel.DatabaseAdapterSpec CFML Engine: Lucee 7.0.1.100 -Duration: 213ms +Duration: 203ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -33,7 +33,7 @@ Labels: Bundle: wheels.tests.specs.controller.cachingSpec CFML Engine: Lucee 7.0.1.100 -Duration: 82ms +Duration: 76ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -44,7 +44,7 @@ Labels: Bundle: wheels.tests.specs.controller.channelSpec CFML Engine: Lucee 7.0.1.100 -Duration: 100ms +Duration: 88ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -55,7 +55,7 @@ Labels: Bundle: wheels.tests.specs.controller.csrf.cookieSpec CFML Engine: Lucee 7.0.1.100 -Duration: 320ms +Duration: 277ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -66,7 +66,7 @@ Labels: Bundle: wheels.tests.specs.controller.csrf.sessionSpec CFML Engine: Lucee 7.0.1.100 -Duration: 203ms +Duration: 211ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -77,7 +77,7 @@ Labels: Bundle: wheels.tests.specs.controller.filtersSpec CFML Engine: Lucee 7.0.1.100 -Duration: 58ms +Duration: 61ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -88,7 +88,7 @@ Labels: Bundle: wheels.tests.specs.controller.flashSpec CFML Engine: Lucee 7.0.1.100 -Duration: 114ms +Duration: 152ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -99,7 +99,7 @@ Labels: Bundle: wheels.tests.specs.controller.initializationSpec CFML Engine: Lucee 7.0.1.100 -Duration: 27ms +Duration: 43ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -110,7 +110,7 @@ Labels: Bundle: wheels.tests.specs.controller.miscellaneousSpec CFML Engine: Lucee 7.0.1.100 -Duration: 126ms +Duration: 146ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -121,7 +121,7 @@ Labels: Bundle: wheels.tests.specs.controller.providesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 39ms +Duration: 43ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -132,7 +132,7 @@ Labels: Bundle: wheels.tests.specs.controller.redirectionSpec CFML Engine: Lucee 7.0.1.100 -Duration: 66ms +Duration: 68ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -143,7 +143,7 @@ Labels: Bundle: wheels.tests.specs.controller.renderingSpec CFML Engine: Lucee 7.0.1.100 -Duration: 1003ms +Duration: 955ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -154,7 +154,7 @@ Labels: Bundle: wheels.tests.specs.controller.requestSpec CFML Engine: Lucee 7.0.1.100 -Duration: 30ms +Duration: 28ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -176,7 +176,7 @@ Labels: Bundle: wheels.tests.specs.controller.verifiesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 38ms +Duration: 40ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -187,7 +187,7 @@ Labels: Bundle: wheels.tests.specs.di.InjectorSpec CFML Engine: Lucee 7.0.1.100 -Duration: 49ms +Duration: 44ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -209,7 +209,7 @@ Labels: Bundle: wheels.tests.specs.dispatch.findMatchingRouteMegaSpec CFML Engine: Lucee 7.0.1.100 -Duration: 919ms +Duration: 859ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -220,7 +220,7 @@ Labels: Bundle: wheels.tests.specs.dispatch.findMatchingRouteSpec CFML Engine: Lucee 7.0.1.100 -Duration: 40ms +Duration: 25ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -231,7 +231,7 @@ Labels: Bundle: wheels.tests.specs.dispatch.getrequestmethodSpec CFML Engine: Lucee 7.0.1.100 -Duration: 7ms +Duration: 5ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -242,7 +242,7 @@ Labels: Bundle: wheels.tests.specs.dispatch.requestSpec CFML Engine: Lucee 7.0.1.100 -Duration: 10ms +Duration: 8ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -253,7 +253,7 @@ Labels: Bundle: wheels.tests.specs.dispatch.setCorsHeadersSpec CFML Engine: Lucee 7.0.1.100 -Duration: 1ms +Duration: 0ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -264,7 +264,7 @@ Labels: Bundle: wheels.tests.specs.environment.ipbasedaccessSpec CFML Engine: Lucee 7.0.1.100 -Duration: 6ms +Duration: 4ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -275,7 +275,7 @@ Labels: Bundle: wheels.tests.specs.events.onerrorSpec CFML Engine: Lucee 7.0.1.100 -Duration: 256ms +Duration: 246ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -286,7 +286,7 @@ Labels: Bundle: wheels.tests.specs.global.cachingSpec CFML Engine: Lucee 7.0.1.100 -Duration: 4ms +Duration: 5ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -297,7 +297,7 @@ Labels: Bundle: wheels.tests.specs.global.dbinfoSpec CFML Engine: Lucee 7.0.1.100 -Duration: 80ms +Duration: 66ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -308,7 +308,7 @@ Labels: Bundle: wheels.tests.specs.global.internalSpec CFML Engine: Lucee 7.0.1.100 -Duration: 82ms +Duration: 62ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -330,7 +330,7 @@ Labels: Bundle: wheels.tests.specs.global.publicSpec CFML Engine: Lucee 7.0.1.100 -Duration: 55ms +Duration: 46ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -341,7 +341,7 @@ Labels: Bundle: wheels.tests.specs.global.stringsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 21ms +Duration: 17ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -352,7 +352,7 @@ Labels: Bundle: wheels.tests.specs.global.urlforSpec CFML Engine: Lucee 7.0.1.100 -Duration: 38ms +Duration: 32ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -363,7 +363,7 @@ Labels: Bundle: wheels.tests.specs.internal.model.validationsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 41ms +Duration: 31ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -374,7 +374,7 @@ Labels: Bundle: wheels.tests.specs.jobs.JobQueueSpec CFML Engine: Lucee 7.0.1.100 -Duration: 156ms +Duration: 126ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -385,7 +385,7 @@ Labels: Bundle: wheels.tests.specs.jobs.JobWorkerSpec CFML Engine: Lucee 7.0.1.100 -Duration: 156ms +Duration: 101ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -396,7 +396,7 @@ Labels: Bundle: wheels.tests.specs.mapper.MapperSpec CFML Engine: Lucee 7.0.1.100 -Duration: 13ms +Duration: 11ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -407,7 +407,7 @@ Labels: Bundle: wheels.tests.specs.mapper.MappingSpec CFML Engine: Lucee 7.0.1.100 -Duration: 13ms +Duration: 11ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -418,7 +418,7 @@ Labels: Bundle: wheels.tests.specs.mapper.MatchingSpec CFML Engine: Lucee 7.0.1.100 -Duration: 51ms +Duration: 47ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -429,7 +429,7 @@ Labels: Bundle: wheels.tests.specs.mapper.NestedResourcesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 126ms +Duration: 97ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -440,7 +440,7 @@ Labels: Bundle: wheels.tests.specs.mapper.ResourcesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 50ms +Duration: 31ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -451,7 +451,7 @@ Labels: Bundle: wheels.tests.specs.mapper.RootSpec CFML Engine: Lucee 7.0.1.100 -Duration: 7ms +Duration: 5ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -462,7 +462,7 @@ Labels: Bundle: wheels.tests.specs.mapper.UtilsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 21ms +Duration: 15ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -473,7 +473,7 @@ Labels: Bundle: wheels.tests.specs.mapper.WildcardSpec CFML Engine: Lucee 7.0.1.100 -Duration: 27ms +Duration: 17ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -484,7 +484,7 @@ Labels: Bundle: wheels.tests.specs.mapperModernSpec CFML Engine: Lucee 7.0.1.100 -Duration: 77ms +Duration: 64ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -495,7 +495,7 @@ Labels: Bundle: wheels.tests.specs.mapperSpec CFML Engine: Lucee 7.0.1.100 -Duration: 186ms +Duration: 124ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -506,7 +506,7 @@ Labels: Bundle: wheels.tests.specs.middleware.MultiTenantIntegrationSpec CFML Engine: Lucee 7.0.1.100 -Duration: 128ms +Duration: 96ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -517,7 +517,7 @@ Labels: Bundle: wheels.tests.specs.middleware.TenantResolverSpec CFML Engine: Lucee 7.0.1.100 -Duration: 15ms +Duration: 9ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -528,7 +528,7 @@ Labels: Bundle: wheels.tests.specs.migrator.migration.mysqlTextSizesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 316ms +Duration: 213ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -539,7 +539,7 @@ Labels: Bundle: wheels.tests.specs.migrator.migrationSpec CFML Engine: Lucee 7.0.1.100 -Duration: 1055ms +Duration: 920ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -550,7 +550,7 @@ Labels: Bundle: wheels.tests.specs.migrator.migratorSpec CFML Engine: Lucee 7.0.1.100 -Duration: 344ms +Duration: 299ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -561,7 +561,7 @@ Labels: Bundle: wheels.tests.specs.model.associationsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 734ms +Duration: 600ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -572,7 +572,7 @@ Labels: Bundle: wheels.tests.specs.model.calculationsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 158ms +Duration: 117ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -583,7 +583,7 @@ Labels: Bundle: wheels.tests.specs.model.callbacksSpec CFML Engine: Lucee 7.0.1.100 -Duration: 500ms +Duration: 297ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -594,7 +594,7 @@ Labels: Bundle: wheels.tests.specs.model.crudSpec CFML Engine: Lucee 7.0.1.100 -Duration: 1295ms +Duration: 1082ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -605,7 +605,7 @@ Labels: Bundle: wheels.tests.specs.model.deleteSpec CFML Engine: Lucee 7.0.1.100 -Duration: 147ms +Duration: 170ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -616,7 +616,7 @@ Labels: Bundle: wheels.tests.specs.model.errorsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 71ms +Duration: 111ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -627,7 +627,7 @@ Labels: Bundle: wheels.tests.specs.model.miscellaneousSpec CFML Engine: Lucee 7.0.1.100 -Duration: 87ms +Duration: 107ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -638,7 +638,7 @@ Labels: Bundle: wheels.tests.specs.model.MultiTenantSpec CFML Engine: Lucee 7.0.1.100 -Duration: 14ms +Duration: 16ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -649,7 +649,7 @@ Labels: Bundle: wheels.tests.specs.model.nestedpropertiesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 654ms +Duration: 686ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -660,7 +660,7 @@ Labels: Bundle: wheels.tests.specs.model.onmissingmethod.belongsToSpec CFML Engine: Lucee 7.0.1.100 -Duration: 49ms +Duration: 65ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -671,7 +671,7 @@ Labels: Bundle: wheels.tests.specs.model.onmissingmethod.hasManySpec CFML Engine: Lucee 7.0.1.100 -Duration: 219ms +Duration: 224ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -682,7 +682,7 @@ Labels: Bundle: wheels.tests.specs.model.onmissingmethod.hasOneSpec CFML Engine: Lucee 7.0.1.100 -Duration: 127ms +Duration: 125ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -693,7 +693,7 @@ Labels: Bundle: wheels.tests.specs.model.propertiesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 619ms +Duration: 544ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -704,7 +704,7 @@ Labels: Bundle: wheels.tests.specs.model.raceconditionSpec CFML Engine: Lucee 7.0.1.100 -Duration: 121ms +Duration: 162ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -715,7 +715,7 @@ Labels: Bundle: wheels.tests.specs.model.raisedErrorsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 41ms +Duration: 28ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -726,7 +726,7 @@ Labels: Bundle: wheels.tests.specs.model.readSpec CFML Engine: Lucee 7.0.1.100 -Duration: 380ms +Duration: 271ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -737,7 +737,7 @@ Labels: Bundle: wheels.tests.specs.model.sqlSpec CFML Engine: Lucee 7.0.1.100 -Duration: 59ms +Duration: 49ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -748,7 +748,7 @@ Labels: Bundle: wheels.tests.specs.model.transactionsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 488ms +Duration: 408ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -759,7 +759,7 @@ Labels: Bundle: wheels.tests.specs.model.useindexSpec CFML Engine: Lucee 7.0.1.100 -Duration: 61ms +Duration: 59ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -770,7 +770,7 @@ Labels: Bundle: wheels.tests.specs.model.validationsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 1680ms +Duration: 1328ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -781,7 +781,7 @@ Labels: Bundle: wheels.tests.specs.model.viewsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 58ms +Duration: 74ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -792,7 +792,7 @@ Labels: Bundle: wheels.tests.specs.pluginsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 372ms +Duration: 363ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -803,7 +803,7 @@ Labels: Bundle: wheels.tests.specs.routingSpec CFML Engine: Lucee 7.0.1.100 -Duration: 20ms +Duration: 21ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -814,7 +814,7 @@ Labels: Bundle: wheels.tests.specs.view.assetsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 570ms +Duration: 705ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -825,7 +825,7 @@ Labels: Bundle: wheels.tests.specs.view.autoLinkSpec CFML Engine: Lucee 7.0.1.100 -Duration: 7ms +Duration: 8ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -836,7 +836,7 @@ Labels: Bundle: wheels.tests.specs.view.checkboxSpec CFML Engine: Lucee 7.0.1.100 -Duration: 35ms +Duration: 27ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -847,7 +847,7 @@ Labels: Bundle: wheels.tests.specs.view.contentSpec CFML Engine: Lucee 7.0.1.100 -Duration: 100ms +Duration: 96ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -858,7 +858,7 @@ Labels: Bundle: wheels.tests.specs.view.csrfSpec CFML Engine: Lucee 7.0.1.100 -Duration: 31ms +Duration: 9ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -869,7 +869,7 @@ Labels: Bundle: wheels.tests.specs.view.dateselectSpec CFML Engine: Lucee 7.0.1.100 -Duration: 106ms +Duration: 84ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -880,7 +880,7 @@ Labels: Bundle: wheels.tests.specs.view.datesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 28ms +Duration: 44ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -891,7 +891,7 @@ Labels: Bundle: wheels.tests.specs.view.errorsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 34ms +Duration: 38ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -902,7 +902,7 @@ Labels: Bundle: wheels.tests.specs.view.flashMessagesSpec CFML Engine: Lucee 7.0.1.100 -Duration: 7ms +Duration: 15ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -913,7 +913,7 @@ Labels: Bundle: wheels.tests.specs.view.formsdateobjectSpec CFML Engine: Lucee 7.0.1.100 -Duration: 131ms +Duration: 144ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -924,7 +924,7 @@ Labels: Bundle: wheels.tests.specs.view.formsdateplainSpec CFML Engine: Lucee 7.0.1.100 -Duration: 177ms +Duration: 271ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -935,7 +935,7 @@ Labels: Bundle: wheels.tests.specs.view.formsdateSpec CFML Engine: Lucee 7.0.1.100 -Duration: 2ms +Duration: 5ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -946,7 +946,7 @@ Labels: Bundle: wheels.tests.specs.view.formsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 353ms +Duration: 436ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -957,7 +957,7 @@ Labels: Bundle: wheels.tests.specs.view.html5FormHelpersSpec CFML Engine: Lucee 7.0.1.100 -Duration: 47ms +Duration: 46ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -968,7 +968,7 @@ Labels: Bundle: wheels.tests.specs.view.linksSpec CFML Engine: Lucee 7.0.1.100 -Duration: 114ms +Duration: 126ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -979,7 +979,7 @@ Labels: Bundle: wheels.tests.specs.view.miscellaneousSpec CFML Engine: Lucee 7.0.1.100 -Duration: 52ms +Duration: 35ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -990,7 +990,7 @@ Labels: Bundle: wheels.tests.specs.view.sanitizeSpec CFML Engine: Lucee 7.0.1.100 -Duration: 12ms +Duration: 8ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -1001,7 +1001,7 @@ Labels: Bundle: wheels.tests.specs.view.textfieldSpec CFML Engine: Lucee 7.0.1.100 -Duration: 12ms +Duration: 8ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -1012,7 +1012,7 @@ Labels: Bundle: wheels.tests.specs.view.textSpec CFML Engine: Lucee 7.0.1.100 -Duration: 28ms +Duration: 20ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ @@ -1023,7 +1023,7 @@ Labels: Bundle: wheels.tests.specs.view.urlsSpec CFML Engine: Lucee 7.0.1.100 -Duration: 114ms +Duration: 84ms Labels: ╔═══════════════════════════════════════════════════════════╗ ║ Suites ║ Specs ║ Passed ║ Failed ║ Errored ║ Skipped ║ From bc0c04c68ec548a7d3a5cb056869ccf1b389d68c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 18 May 2026 12:36:01 +0000 Subject: [PATCH 6/7] ci: add RustCFML as experimental non-blocking CI target Add RustCFML (pixl8/RustCFML) to the test matrix as an experimental, non-blocking engine. This gives visibility into how Wheels behaves on a non-JVM CFML runtime without affecting CI pass/fail status. Changes: - Add rustcfml to matrix with experimental: true (continue-on-error) - Create tools/docker/rustcfml/ with Dockerfile, settings, datasource config - Add rustcfml service to compose.yml on port 60100 - Add standalone test-rustcfml.yml workflow for claude/* branches - Test against SQLite only (RustCFML uses native Rust DB drivers, not JDBC) - Allow Docker layer caching for Rust source builds - Add rustcfml row to test matrix summary grid - Update feasibility assessment with latest v0.9.1 findings Expected: many test failures initially. The goal is to measure the compatibility gap and track progress over time. https://claude.ai/code/session_01FSAD6qjDXUNiNsBWJncK1N --- .github/workflows/test-rustcfml.yml | 239 ++++++++++++++++++++++++++++ .github/workflows/tests.yml | 18 ++- compose.yml | 18 +++ tools/docker/rustcfml/Dockerfile | 33 ++++ tools/docker/rustcfml/app.cfm | 17 ++ tools/docker/rustcfml/settings.cfm | 15 ++ 6 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/test-rustcfml.yml create mode 100644 tools/docker/rustcfml/Dockerfile create mode 100644 tools/docker/rustcfml/app.cfm create mode 100644 tools/docker/rustcfml/settings.cfm diff --git a/.github/workflows/test-rustcfml.yml b/.github/workflows/test-rustcfml.yml new file mode 100644 index 0000000000..ee747ecea4 --- /dev/null +++ b/.github/workflows/test-rustcfml.yml @@ -0,0 +1,239 @@ +name: Test RustCFML Compatibility (Experimental) + +on: + push: + branches: + - 'claude/**' + workflow_dispatch: + +permissions: + contents: write + +jobs: + test-rustcfml: + name: RustCFML + SQLite (experimental) + runs-on: ubuntu-latest + continue-on-error: true + env: + PORT: 60100 + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Build RustCFML image + id: build + continue-on-error: true + run: | + echo "Building RustCFML Docker image (this may take several minutes on first run)..." + docker compose build rustcfml 2>&1 | tail -20 + echo "build_ok=$?" >> $GITHUB_OUTPUT + + - name: Start RustCFML + if: steps.build.outcome == 'success' + run: docker compose up -d rustcfml + + - name: Wait for RustCFML to be ready + if: steps.build.outcome == 'success' + id: health + continue-on-error: true + run: | + echo "Waiting for RustCFML on port ${PORT}..." + MAX_WAIT=30 + WAIT_COUNT=0 + while [ "$WAIT_COUNT" -lt "$MAX_WAIT" ]; do + WAIT_COUNT=$((WAIT_COUNT + 1)) + HTTP_CODE=$(curl -s -o /dev/null --connect-timeout 2 --max-time 5 \ + -w "%{http_code}" "http://localhost:${PORT}/" 2>/dev/null || echo "000") + echo "Attempt ${WAIT_COUNT}/${MAX_WAIT}: HTTP ${HTTP_CODE}" + if echo "$HTTP_CODE" | grep -q "200\|404\|302\|500"; then + echo "RustCFML is responding (HTTP ${HTTP_CODE})" + echo "ready=true" >> $GITHUB_OUTPUT + exit 0 + fi + sleep 3 + done + echo "RustCFML did not become ready within ${MAX_WAIT} attempts" + echo "ready=false" >> $GITHUB_OUTPUT + + - name: Smoke test - basic CFML execution + if: steps.health.outcome == 'success' && steps.health.outputs.ready == 'true' + id: smoke + continue-on-error: true + run: | + echo "=== Smoke test: basic page load ===" + HTTP_CODE=$(curl -s -o /tmp/smoke-result.txt --max-time 30 \ + -w "%{http_code}" "http://localhost:${PORT}/" || echo "000") + echo "Root page: HTTP ${HTTP_CODE}" + if [ -f /tmp/smoke-result.txt ]; then + head -50 /tmp/smoke-result.txt + fi + + echo "" + echo "=== Smoke test: reload request ===" + HTTP_CODE=$(curl -s -o /tmp/reload-result.txt --max-time 60 \ + -w "%{http_code}" "http://localhost:${PORT}/?reload=true" || echo "000") + echo "Reload: HTTP ${HTTP_CODE}" + if [ -f /tmp/reload-result.txt ]; then + head -50 /tmp/reload-result.txt + fi + + - name: Run test suite + if: steps.health.outcome == 'success' && steps.health.outputs.ready == 'true' + id: run-tests + continue-on-error: true + run: | + TEST_URL="http://localhost:${PORT}/wheels/core/tests?db=sqlite&format=json" + RESULT_FILE="/tmp/rustcfml-sqlite-result.txt" + + echo "Running test suite: ${TEST_URL}" + echo "This may take several minutes..." + + HTTP_CODE=$(curl -s -o "${RESULT_FILE}" \ + --max-time 900 \ + --write-out "%{http_code}" \ + "${TEST_URL}" || echo "000") + + echo "HTTP Code: ${HTTP_CODE}" + echo "http_code=${HTTP_CODE}" >> $GITHUB_OUTPUT + + if [ -f "$RESULT_FILE" ]; then + # Try to parse as JSON for summary stats + python3 -c " + import json, sys + try: + d = json.load(open('$RESULT_FILE')) + total = int(d.get('totalSpecs', 0)) + passed = int(d.get('totalPass', 0)) + failed = int(d.get('totalFail', 0)) + errors = int(d.get('totalError', 0)) + skipped = int(d.get('totalSkipped', 0)) + print(f'Total: {total} | Passed: {passed} | Failed: {failed} | Errors: {errors} | Skipped: {skipped}') + pct = round(passed / total * 100, 1) if total > 0 else 0 + print(f'Pass rate: {pct}%') + except Exception as e: + print(f'Could not parse JSON results: {e}') + # Show first 200 chars of response + with open('$RESULT_FILE') as f: + content = f.read() + print(f'Response preview ({len(content)} bytes):') + print(content[:500]) + " 2>&1 || echo "Result parsing failed" + else + echo "No result file generated" + fi + + - name: Generate compatibility report + if: always() + run: | + RESULTS_DIR=".github/workflow-results" + RESULTS_FILE="${RESULTS_DIR}/test-rustcfml.md" + mkdir -p "$RESULTS_DIR" + + { + echo "# RustCFML Compatibility Report (Experimental)" + echo "" + echo "**Date:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" + echo "**Commit:** ${{ github.sha }}" + echo "**Branch:** ${{ github.ref_name }}" + echo "**Run:** [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" + echo "" + echo "## Stage Results" + echo "" + echo "| Stage | Result |" + echo "|-------|--------|" + echo "| Docker build | ${{ steps.build.outcome }} |" + echo "| Server startup | ${{ steps.health.outcome }} |" + echo "| Smoke test | ${{ steps.smoke.outcome }} |" + echo "| Test suite | ${{ steps.run-tests.outcome }} |" + echo "" + } > "$RESULTS_FILE" + + # Add test results if available + if [ -f "/tmp/rustcfml-sqlite-result.txt" ]; then + { + echo "## Test Results" + echo "" + python3 -c " + import json, sys + try: + d = json.load(open('/tmp/rustcfml-sqlite-result.txt')) + total = int(d.get('totalSpecs', 0)) + passed = int(d.get('totalPass', 0)) + failed = int(d.get('totalFail', 0)) + errors = int(d.get('totalError', 0)) + skipped = int(d.get('totalSkipped', 0)) + pct = round(passed / total * 100, 1) if total > 0 else 0 + print(f'- **Total specs:** {total}') + print(f'- **Passed:** {passed} ({pct}%)') + print(f'- **Failed:** {failed}') + print(f'- **Errors:** {errors}') + print(f'- **Skipped:** {skipped}') + print() + # List first 20 failures + if failed > 0 or errors > 0: + print('### First failures/errors') + print() + count = 0 + for b in d.get('bundleStats', []): + for s in b.get('suiteStats', []): + for sp in s.get('specStats', []): + if sp.get('status') in ('Failed', 'Error') and count < 20: + print(f'- **{sp.get(\"name\", \"unknown\")}**: {sp.get(\"failMessage\", \"\")}') + count += 1 + if count == 0: + # Check nested suites + for b in d.get('bundleStats', []): + for s in b.get('suiteStats', []): + for child in s.get('suiteStats', []): + for sp in child.get('specStats', []): + if sp.get('status') in ('Failed', 'Error') and count < 20: + print(f'- **{sp.get(\"name\", \"unknown\")}**: {sp.get(\"failMessage\", \"\")}') + count += 1 + except Exception as e: + print(f'Could not parse results: {e}') + " 2>&1 || echo "Parse error" + } >> "$RESULTS_FILE" + fi + + # Add debug info + { + echo "" + echo "## Container Logs" + echo "" + echo '```' + docker logs wheels-rustcfml-1 2>&1 | tail -80 || echo "No container logs available" + echo '```' + } >> "$RESULTS_FILE" + + - name: Debug information + if: always() + run: | + echo "=== Docker Container Status ===" + docker ps -a --filter "name=rustcfml" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" + + echo -e "\n=== RustCFML Container Logs (last 80 lines) ===" + docker logs wheels-rustcfml-1 2>&1 | tail -80 || echo "No logs available" + + - name: Commit compatibility report + if: always() + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add ".github/workflow-results/test-rustcfml.md" + + if git diff --cached --quiet; then + echo "No changes to commit" + else + git commit -m "ci: add RustCFML compatibility report [skip ci]" + git push origin HEAD:${{ github.ref_name }} + fi + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: rustcfml-test-results + path: | + /tmp/rustcfml-sqlite-result.txt + /tmp/smoke-result.txt + /tmp/reload-result.txt diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 228d23d8e4..ea02d658bb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,6 +22,9 @@ jobs: cfengine: ["lucee5", "lucee6", "lucee7", "adobe2018", "adobe2021", "adobe2023", "adobe2025", "boxlang"] experimental: [false] + include: + - cfengine: rustcfml + experimental: true env: PORT_lucee5: 60005 PORT_lucee6: 60006 @@ -31,6 +34,7 @@ jobs: PORT_adobe2023: 62023 PORT_adobe2025: 62025 PORT_boxlang: 60001 + PORT_rustcfml: 60100 steps: - name: Checkout Repository uses: actions/checkout@v5 @@ -50,6 +54,10 @@ jobs: # adobe2018 also excludes sqlite DATABASES="mysql,postgres,sqlserver,oracle" ;; + rustcfml) + # RustCFML uses native Rust drivers, not JDBC — start with SQLite only + DATABASES="sqlite" + ;; esac echo "databases=${DATABASES}" >> $GITHUB_OUTPUT @@ -63,7 +71,13 @@ jobs: -O ./.engine/${{ matrix.cfengine }}/WEB-INF/lib/ojdbc10.jar - name: Start CF engine - run: docker compose build --no-cache ${{ matrix.cfengine }} && docker compose up -d ${{ matrix.cfengine }} + run: | + # RustCFML builds Rust from source — allow Docker layer caching to avoid 15+ min rebuild + if [ "${{ matrix.cfengine }}" = "rustcfml" ]; then + docker compose build ${{ matrix.cfengine }} && docker compose up -d ${{ matrix.cfengine }} + else + docker compose build --no-cache ${{ matrix.cfengine }} && docker compose up -d ${{ matrix.cfengine }} + fi - name: Start all databases run: | @@ -514,7 +528,7 @@ jobs: MATRIX_MD="${MATRIX_MD} |--------|:-----:|:----------:|:----------:|:--:|:------:|:------:|" - for engine in lucee5 lucee6 lucee7 adobe2018 adobe2021 adobe2023 adobe2025 boxlang; do + for engine in lucee5 lucee6 lucee7 adobe2018 adobe2021 adobe2023 adobe2025 boxlang rustcfml; do ROW="| **${engine}** |" for db in mysql postgres sqlserver h2 oracle sqlite; do FILE="results/test-results-${engine}/${engine}-${db}-result.txt" diff --git a/compose.yml b/compose.yml index f83279f205..c55aa61d27 100644 --- a/compose.yml +++ b/compose.yml @@ -259,6 +259,24 @@ services: networks: - wheels-network + rustcfml: + build: + context: ./ + dockerfile: ./tools/docker/rustcfml/Dockerfile + image: wheels-test-rustcfml:v0.1.0 + volumes: + - ./:/wheels-test-suite + - type: bind + source: ./tools/docker/rustcfml/settings.cfm + target: /wheels-test-suite/config/settings.cfm + - type: bind + source: ./tools/docker/rustcfml/app.cfm + target: /wheels-test-suite/config/app.cfm + ports: + - "60100:60100" + networks: + - wheels-network + mysql: image: mysql:9 restart: always diff --git a/tools/docker/rustcfml/Dockerfile b/tools/docker/rustcfml/Dockerfile new file mode 100644 index 0000000000..ad5544cd15 --- /dev/null +++ b/tools/docker/rustcfml/Dockerfile @@ -0,0 +1,33 @@ +# Stage 1: Build RustCFML from source +FROM rust:1.78-bookworm AS builder + +ARG RUSTCFML_VERSION=v0.9.1 + +RUN apt-get update && apt-get install -y \ + git pkg-config libssl-dev libsqlite3-dev \ + && rm -rf /var/lib/apt/lists/* + +RUN git clone --depth 1 --branch ${RUSTCFML_VERSION} \ + https://github.com/pixl8/RustCFML.git /build + +WORKDIR /build +RUN cargo build --release --features "database,xml" + +# Stage 2: Minimal runtime image +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y \ + sqlite3 libsqlite3-0 libssl3 curl ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /build/target/release/rustcfml /usr/local/bin/rustcfml + +RUN sqlite3 /app/wheelstestdb.db "SELECT 1;" \ + && sqlite3 /app/wheelstestdb_tenant_b.db "SELECT 1;" + +ENV PORT=60100 +WORKDIR /wheels-test-suite + +EXPOSE ${PORT} + +CMD ["rustcfml", "--serve", "public", "--port", "60100"] diff --git a/tools/docker/rustcfml/app.cfm b/tools/docker/rustcfml/app.cfm new file mode 100644 index 0000000000..c013ca66a7 --- /dev/null +++ b/tools/docker/rustcfml/app.cfm @@ -0,0 +1,17 @@ + + /* + RustCFML datasource configuration. + Overrides config/app.cfm for RustCFML which uses native Rust database + drivers (rusqlite) instead of JDBC. + */ + + this.datasources["wheelstestdb_sqlite"] = { + database: "/app/wheelstestdb.db", + type: "sqlite" + }; + + this.datasources["wheelstestdb_sqlite_tenant_b"] = { + database: "/app/wheelstestdb_tenant_b.db", + type: "sqlite" + }; + diff --git a/tools/docker/rustcfml/settings.cfm b/tools/docker/rustcfml/settings.cfm new file mode 100644 index 0000000000..fe61927c3c --- /dev/null +++ b/tools/docker/rustcfml/settings.cfm @@ -0,0 +1,15 @@ + + /* + RustCFML-specific settings for the Wheels test suite. + Only SQLite is configured — RustCFML uses native Rust database drivers, + not JDBC, so the datasource configuration differs from Lucee/ACF. + */ + + set(coreTestDataSourceName="wheelstestdb_sqlite"); + set(dataSourceName="wheelstestdb_sqlite"); + + set(URLRewriting="On"); + set(reloadPassword=""); + + // CLI-Appends-Here + From cfae9d1e3e6a954d0b77bc63d7cd7444838ad140 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 18 May 2026 12:36:58 +0000 Subject: [PATCH 7/7] ci: add RustCFML compatibility report [skip ci] --- .github/workflow-results/test-rustcfml.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflow-results/test-rustcfml.md diff --git a/.github/workflow-results/test-rustcfml.md b/.github/workflow-results/test-rustcfml.md new file mode 100644 index 0000000000..9e84dbef0c --- /dev/null +++ b/.github/workflow-results/test-rustcfml.md @@ -0,0 +1,22 @@ +# RustCFML Compatibility Report (Experimental) + +**Date:** 2026-05-18 12:36:58 UTC +**Commit:** bc0c04c68ec548a7d3a5cb056869ccf1b389d68c +**Branch:** claude/evaluate-rustcfml-feasibility-40oUw +**Run:** [#1](https://github.com/wheels-dev/wheels/actions/runs/26033864937) + +## Stage Results + +| Stage | Result | +|-------|--------| +| Docker build | success | +| Server startup | skipped | +| Smoke test | skipped | +| Test suite | skipped | + + +## Container Logs + +``` +Error response from daemon: No such container: wheels-rustcfml-1 +```