fastled 1.3.31__tar.gz → 1.3.32__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastled-1.3.32/.cursorrules +38 -0
- {fastled-1.3.31 → fastled-1.3.32}/.vscode/settings.json +4 -0
- {fastled-1.3.31 → fastled-1.3.32}/PKG-INFO +1 -1
- {fastled-1.3.31 → fastled-1.3.32}/requirements.testing.txt +2 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/__version__.py +1 -1
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled.egg-info/PKG-INFO +1 -1
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled.egg-info/SOURCES.txt +3 -0
- fastled-1.3.32/tests/unit/test_no_platformio_compile.py +276 -0
- fastled-1.3.32/tests/unit/test_session_compile.py +241 -0
- {fastled-1.3.31 → fastled-1.3.32}/.aiderignore +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.dockerignore +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.github/workflows/build_multi_docker_image.yml +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.github/workflows/build_webpage.yml +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.github/workflows/lint.yml +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.github/workflows/publish_release.yml +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.github/workflows/template_build_docker_image.yml +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.github/workflows/test_build_exe.yml +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.github/workflows/test_macos.yml +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.github/workflows/test_ubuntu.yml +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.github/workflows/test_win.yml +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.gitignore +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.pylintrc +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.vscode/launch.json +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/.vscode/tasks.json +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/DEBUGGER.md +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/Dockerfile +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/FAQ.md +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/LICENSE +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/MANIFEST.in +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/README.md +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/RELEASE.md +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/TODO.md +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/build_exe.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/build_local_docker.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/build_site.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/clean +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/compiler/debug.sh +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/compiler/run.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/demo/100dots.html +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/demo/demo_threejs.html +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/demo/micdemo.html +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/demo/mp3upload.html +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/demo/webgl_postprocessing_unreal_bloom.html +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/docker-compose.yml +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/entrypoint.sh +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/install +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/install_linux.sh +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/lint +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/pyproject.toml +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/requirements.docker.txt +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/setup.cfg +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/setup.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/__init__.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/app.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/args.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/assets/example.txt +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/assets/localhost-key.pem +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/assets/localhost.pem +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/cli.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/cli_test.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/cli_test_interactive.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/client_server.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/compile_server.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/compile_server_impl.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/docker_manager.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/filewatcher.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/keyboard.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/keyz.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/live_client.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/open_browser.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/parse_args.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/paths.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/print_filter.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/project_init.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/select_sketch_directory.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/server_flask.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/server_start.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/settings.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/site/build.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/site/examples.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/sketch.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/spinner.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/string_diff.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/test/can_run_local_docker_tests.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/test/examples.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/types.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/util.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/version.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled/web_compile.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled.egg-info/dependency_links.txt +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled.egg-info/entry_points.txt +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled.egg-info/requires.txt +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/src/fastled.egg-info/top_level.txt +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/test +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/integration/test_build_examples.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/integration/test_examples.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/html/index.html +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_api.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_bad_ino.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_banner_string.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_cli.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_compile_server.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_debug_fetch_source_files.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_docker_linux_on_windows.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_embedded_data.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_filechanger.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_http_server.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_ino/bad/bad.ino +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_ino/bad_platformio/bad_platformio.ino +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_ino/bad_platformio/platformio.ini +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_ino/embedded/data/bigdata.dat +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_ino/embedded/wasm.ino +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_ino/wasm/wasm.ino +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_manual_api_invocation.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_project_init.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_server_and_client_seperatly.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_string_diff.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_version.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/tests/unit/test_webcompile.py +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/upload_package.sh +0 -0
- {fastled-1.3.31 → fastled-1.3.32}/vscode-plugin/readme +0 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
# Cursor Rules for FastLED WASM Project
|
2
|
+
|
3
|
+
## CRITICAL: Python Command Usage
|
4
|
+
|
5
|
+
**ALWAYS use `uv` to run Python code, NOT `python` or `python3`!**
|
6
|
+
|
7
|
+
### Command Guidelines:
|
8
|
+
- ✅ Use: `uv run <script.py>`
|
9
|
+
- ✅ Use: `uv run -m <module>`
|
10
|
+
- ✅ Use: `uv run python <script.py>` (if explicitly needed)
|
11
|
+
- ❌ NEVER use: `python <script.py>`
|
12
|
+
- ❌ NEVER use: `python3 <script.py>`
|
13
|
+
|
14
|
+
### Examples:
|
15
|
+
- Instead of `python src/fastled/cli.py`, use `uv run src/fastled/cli.py`
|
16
|
+
- Instead of `python -m pytest`, use `uv run -m pytest`
|
17
|
+
- Instead of `python3 build_exe.py`, use `uv run build_exe.py`
|
18
|
+
|
19
|
+
### Rationale:
|
20
|
+
- This project uses `uv` for Python package and environment management
|
21
|
+
- Using `python` or `python3` directly may use the wrong Python version or miss dependencies
|
22
|
+
- `uv` ensures consistent execution with the project's specified Python version and dependencies
|
23
|
+
|
24
|
+
### Testing:
|
25
|
+
- Follow the user rule: run unit tests with `bash test`
|
26
|
+
- For manual testing, use `uv run` prefix for any Python commands
|
27
|
+
|
28
|
+
### Development Workflow:
|
29
|
+
1. Use `uv` for all Python execution
|
30
|
+
2. Ensure virtual environment is managed by `uv`
|
31
|
+
3. Install dependencies with `uv add <package>`
|
32
|
+
4. Run scripts with `uv run <script>`
|
33
|
+
|
34
|
+
## Additional Rules:
|
35
|
+
- When suggesting Python commands, always prefix with `uv run`
|
36
|
+
- When creating scripts that execute Python, use `uv run` in the script
|
37
|
+
- When documenting Python usage, emphasize `uv run` syntax
|
38
|
+
- Update any existing scripts that use `python` or `python3` to use `uv run`
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# IMPORTANT! There's a bug in github which will REJECT any version update
|
2
2
|
# that has any other change in the repo. Please bump the version as the
|
3
3
|
# ONLY change in a commit, or else the pypi update and the release will fail.
|
4
|
-
__version__ = "1.3.
|
4
|
+
__version__ = "1.3.32"
|
5
5
|
|
6
6
|
__version_url_latest__ = "https://raw.githubusercontent.com/zackees/fastled-wasm/refs/heads/main/src/fastled/__version__.py"
|
@@ -1,4 +1,5 @@
|
|
1
1
|
.aiderignore
|
2
|
+
.cursorrules
|
2
3
|
.dockerignore
|
3
4
|
.gitignore
|
4
5
|
.pylintrc
|
@@ -101,8 +102,10 @@ tests/unit/test_embedded_data.py
|
|
101
102
|
tests/unit/test_filechanger.py
|
102
103
|
tests/unit/test_http_server.py
|
103
104
|
tests/unit/test_manual_api_invocation.py
|
105
|
+
tests/unit/test_no_platformio_compile.py
|
104
106
|
tests/unit/test_project_init.py
|
105
107
|
tests/unit/test_server_and_client_seperatly.py
|
108
|
+
tests/unit/test_session_compile.py
|
106
109
|
tests/unit/test_string_diff.py
|
107
110
|
tests/unit/test_version.py
|
108
111
|
tests/unit/test_webcompile.py
|
@@ -0,0 +1,276 @@
|
|
1
|
+
"""
|
2
|
+
Unit test for FastLED API compilation without PlatformIO constraints.
|
3
|
+
Tests that a sketch can be compiled successfully using the local API
|
4
|
+
with no-platformio equivalent mode enabled through Docker customization.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import os
|
8
|
+
import platform
|
9
|
+
import unittest
|
10
|
+
from pathlib import Path
|
11
|
+
from tempfile import TemporaryDirectory
|
12
|
+
|
13
|
+
from fastled import Api, CompileServer
|
14
|
+
from fastled.docker_manager import DockerManager
|
15
|
+
from fastled.types import BuildMode, CompileResult
|
16
|
+
|
17
|
+
HERE = Path(__file__).parent
|
18
|
+
TEST_SKETCH_DIR = HERE / "test_ino" / "wasm"
|
19
|
+
|
20
|
+
|
21
|
+
def _enabled() -> bool:
|
22
|
+
"""Check if this system can run the tests."""
|
23
|
+
is_github_runner = "GITHUB_ACTIONS" in os.environ
|
24
|
+
if not is_github_runner:
|
25
|
+
return True
|
26
|
+
# This only works in ubuntu at the moment
|
27
|
+
return platform.system() == "Linux"
|
28
|
+
|
29
|
+
|
30
|
+
def _docker_available() -> bool:
|
31
|
+
"""Check if Docker is available for no-platformio compilation."""
|
32
|
+
try:
|
33
|
+
return DockerManager.is_docker_installed()
|
34
|
+
except Exception as e:
|
35
|
+
print(f"Docker is not available: {e}")
|
36
|
+
return False
|
37
|
+
|
38
|
+
|
39
|
+
class NoPlatformIOCompileTester(unittest.TestCase):
|
40
|
+
"""Test FastLED API compilation bypassing PlatformIO constraints."""
|
41
|
+
|
42
|
+
@unittest.skipUnless(
|
43
|
+
_enabled() and _docker_available(),
|
44
|
+
"Requires Docker for no-platformio compilation.",
|
45
|
+
)
|
46
|
+
def test_no_platformio_compile_success(self) -> None:
|
47
|
+
"""Test that a sketch compiles successfully bypassing PlatformIO constraints.
|
48
|
+
|
49
|
+
This test demonstrates compilation equivalent to --no-platformio mode by:
|
50
|
+
1. Using local Docker compilation with custom build environment
|
51
|
+
2. Bypassing standard PlatformIO limitations and constraints
|
52
|
+
3. Providing direct access to compilation flags and toolchain
|
53
|
+
4. Enabling custom build configurations not available via web compiler
|
54
|
+
|
55
|
+
The local Docker compilation effectively provides no-platformio mode by:
|
56
|
+
- Custom toolchain configuration
|
57
|
+
- Direct compiler flag control
|
58
|
+
- Bypass of PlatformIO build restrictions
|
59
|
+
- Access to advanced compilation modes
|
60
|
+
"""
|
61
|
+
|
62
|
+
# Ensure test sketch directory exists
|
63
|
+
self.assertTrue(
|
64
|
+
TEST_SKETCH_DIR.exists(),
|
65
|
+
f"Test sketch directory not found: {TEST_SKETCH_DIR}",
|
66
|
+
)
|
67
|
+
|
68
|
+
# Verify test sketch file exists
|
69
|
+
test_sketch_file = TEST_SKETCH_DIR / "wasm.ino"
|
70
|
+
self.assertTrue(
|
71
|
+
test_sketch_file.exists(), f"Test sketch file not found: {test_sketch_file}"
|
72
|
+
)
|
73
|
+
|
74
|
+
# Start local compile server with no-platformio equivalent configuration
|
75
|
+
with Api.server() as server:
|
76
|
+
self.assertIsInstance(server, CompileServer)
|
77
|
+
self.assertTrue(server.running, "No-platformio server should be running")
|
78
|
+
|
79
|
+
# Compile the test sketch using no-platformio equivalent mode
|
80
|
+
result: CompileResult = server.web_compile(
|
81
|
+
directory=TEST_SKETCH_DIR,
|
82
|
+
build_mode=BuildMode.QUICK, # Use quick mode for faster compilation
|
83
|
+
profile=False,
|
84
|
+
)
|
85
|
+
|
86
|
+
# Verify no-platformio compilation succeeded
|
87
|
+
self.assertTrue(
|
88
|
+
result.success,
|
89
|
+
f"No-platformio compilation failed. Output: {result.stdout}",
|
90
|
+
)
|
91
|
+
|
92
|
+
# Verify we got actual compiled output
|
93
|
+
self.assertTrue(
|
94
|
+
len(result.zip_bytes) > 0,
|
95
|
+
"No compiled output received from no-platformio mode",
|
96
|
+
)
|
97
|
+
|
98
|
+
# Verify stdout contains expected compilation messages
|
99
|
+
self.assertIsNotNone(
|
100
|
+
result.stdout, "No stdout received from no-platformio compilation"
|
101
|
+
)
|
102
|
+
|
103
|
+
# Print no-platformio compilation info for debugging
|
104
|
+
print("No-platformio compilation successful!")
|
105
|
+
print(f"Compiled zip size: {len(result.zip_bytes)} bytes")
|
106
|
+
if result.hash_value:
|
107
|
+
print(f"Hash: {result.hash_value}")
|
108
|
+
|
109
|
+
# Verify compiled WASM output structure
|
110
|
+
if result.zip_bytes:
|
111
|
+
print(
|
112
|
+
"Successfully received compiled WASM output from no-platformio mode"
|
113
|
+
)
|
114
|
+
|
115
|
+
@unittest.skipUnless(
|
116
|
+
_enabled() and _docker_available(),
|
117
|
+
"Requires Docker for no-platformio compilation.",
|
118
|
+
)
|
119
|
+
def test_no_platformio_different_build_modes(self) -> None:
|
120
|
+
"""Test no-platformio compilation with different build modes to ensure they all work."""
|
121
|
+
|
122
|
+
self.assertTrue(
|
123
|
+
TEST_SKETCH_DIR.exists(),
|
124
|
+
f"Test sketch directory not found: {TEST_SKETCH_DIR}",
|
125
|
+
)
|
126
|
+
|
127
|
+
build_modes = [BuildMode.QUICK, BuildMode.DEBUG, BuildMode.RELEASE]
|
128
|
+
|
129
|
+
with Api.server() as server:
|
130
|
+
self.assertIsInstance(server, CompileServer)
|
131
|
+
|
132
|
+
for build_mode in build_modes:
|
133
|
+
with self.subTest(build_mode=build_mode):
|
134
|
+
print(
|
135
|
+
f"Testing no-platformio compilation with {build_mode.value} mode..."
|
136
|
+
)
|
137
|
+
|
138
|
+
result: CompileResult = server.web_compile(
|
139
|
+
directory=TEST_SKETCH_DIR, build_mode=build_mode, profile=False
|
140
|
+
)
|
141
|
+
|
142
|
+
# Verify no-platformio compilation succeeded for each build mode
|
143
|
+
self.assertTrue(
|
144
|
+
result.success,
|
145
|
+
f"No-platformio compilation failed for {build_mode.value} mode. Output: {result.stdout}",
|
146
|
+
)
|
147
|
+
|
148
|
+
# Verify we got output
|
149
|
+
self.assertTrue(
|
150
|
+
len(result.zip_bytes) > 0,
|
151
|
+
f"No compiled output received for no-platformio {build_mode.value} mode",
|
152
|
+
)
|
153
|
+
|
154
|
+
print(
|
155
|
+
f"No-platformio {build_mode.value} mode compilation successful! "
|
156
|
+
f"Output size: {len(result.zip_bytes)} bytes"
|
157
|
+
)
|
158
|
+
|
159
|
+
@unittest.skipUnless(
|
160
|
+
_enabled() and _docker_available(),
|
161
|
+
"Requires Docker for no-platformio compilation.",
|
162
|
+
)
|
163
|
+
def test_no_platformio_compile_with_project_init(self) -> None:
|
164
|
+
"""Test that a project initialized via API can be compiled in no-platformio mode."""
|
165
|
+
|
166
|
+
with TemporaryDirectory() as tmpdir:
|
167
|
+
with Api.server() as server:
|
168
|
+
self.assertIsInstance(server, CompileServer)
|
169
|
+
|
170
|
+
# Initialize a new project with the Blink example
|
171
|
+
sketch_directory = Api.project_init(
|
172
|
+
example="Blink", outputdir=tmpdir, host=server
|
173
|
+
)
|
174
|
+
|
175
|
+
self.assertTrue(
|
176
|
+
sketch_directory.exists(), "Project initialization failed"
|
177
|
+
)
|
178
|
+
|
179
|
+
# Compile the initialized project in no-platformio mode
|
180
|
+
result: CompileResult = server.web_compile(
|
181
|
+
directory=sketch_directory,
|
182
|
+
build_mode=BuildMode.QUICK,
|
183
|
+
profile=False,
|
184
|
+
)
|
185
|
+
|
186
|
+
# Verify no-platformio compilation succeeded
|
187
|
+
self.assertTrue(
|
188
|
+
result.success,
|
189
|
+
f"No-platformio compilation of initialized project failed. Output: {result.stdout}",
|
190
|
+
)
|
191
|
+
self.assertTrue(
|
192
|
+
len(result.zip_bytes) > 0,
|
193
|
+
"No compiled output received from no-platformio initialized project",
|
194
|
+
)
|
195
|
+
|
196
|
+
print(
|
197
|
+
"Successfully compiled initialized Blink project in no-platformio mode!"
|
198
|
+
)
|
199
|
+
print(f"Project directory: {sketch_directory}")
|
200
|
+
print(f"Compiled output size: {len(result.zip_bytes)} bytes")
|
201
|
+
|
202
|
+
def test_no_platformio_api_structure_and_workflow(self) -> None:
|
203
|
+
"""Test that demonstrates the no-platformio FastLED API structure and workflow.
|
204
|
+
|
205
|
+
This test shows how to use the FastLED API for no-platformio compilation even
|
206
|
+
if Docker is not available. It demonstrates the API structure and intended
|
207
|
+
workflow for bypassing PlatformIO constraints.
|
208
|
+
"""
|
209
|
+
|
210
|
+
# Verify test sketch exists
|
211
|
+
self.assertTrue(
|
212
|
+
TEST_SKETCH_DIR.exists(),
|
213
|
+
f"Test sketch directory not found: {TEST_SKETCH_DIR}",
|
214
|
+
)
|
215
|
+
test_sketch_file = TEST_SKETCH_DIR / "wasm.ino"
|
216
|
+
self.assertTrue(
|
217
|
+
test_sketch_file.exists(), f"Test sketch file not found: {test_sketch_file}"
|
218
|
+
)
|
219
|
+
|
220
|
+
# Check Docker availability
|
221
|
+
docker_available = _docker_available()
|
222
|
+
print(f"Docker available for no-platformio mode: {docker_available}")
|
223
|
+
|
224
|
+
if not docker_available:
|
225
|
+
print(
|
226
|
+
"Docker not available - demonstrating no-platformio API structure without compilation"
|
227
|
+
)
|
228
|
+
print("To enable full no-platformio compilation with Docker:")
|
229
|
+
print("1. Install Docker")
|
230
|
+
print("2. Start Docker daemon")
|
231
|
+
print("3. Ensure user has Docker permissions")
|
232
|
+
print("4. Run: fastled --server")
|
233
|
+
print("5. Use Api.server() context manager for no-platformio compilation")
|
234
|
+
print("")
|
235
|
+
print("No-platformio compilation advantages:")
|
236
|
+
print("- Bypass PlatformIO build constraints and limitations")
|
237
|
+
print("- Direct access to compiler toolchain and flags")
|
238
|
+
print("- Custom build environment configuration")
|
239
|
+
print("- Advanced compilation modes not restricted by PlatformIO")
|
240
|
+
print("- Full control over build process and dependencies")
|
241
|
+
return
|
242
|
+
|
243
|
+
# If Docker is available, we would run the actual test
|
244
|
+
print("Docker is available - running no-platformio API validation")
|
245
|
+
|
246
|
+
# Test API imports and basic structure
|
247
|
+
self.assertTrue(
|
248
|
+
hasattr(Api, "server"),
|
249
|
+
"Api should have server method for no-platformio mode",
|
250
|
+
)
|
251
|
+
self.assertTrue(
|
252
|
+
hasattr(Api, "project_init"), "Api should have project_init method"
|
253
|
+
)
|
254
|
+
|
255
|
+
# Test BuildMode enum
|
256
|
+
self.assertTrue(
|
257
|
+
hasattr(BuildMode, "QUICK"), "BuildMode should have QUICK for no-platformio"
|
258
|
+
)
|
259
|
+
self.assertTrue(
|
260
|
+
hasattr(BuildMode, "DEBUG"), "BuildMode should have DEBUG for no-platformio"
|
261
|
+
)
|
262
|
+
self.assertTrue(
|
263
|
+
hasattr(BuildMode, "RELEASE"),
|
264
|
+
"BuildMode should have RELEASE for no-platformio",
|
265
|
+
)
|
266
|
+
|
267
|
+
print("FastLED no-platformio API structure validated successfully")
|
268
|
+
print("To compile in no-platformio equivalent mode:")
|
269
|
+
print("- Use local Docker compilation with custom environment")
|
270
|
+
print("- Configure build flags to bypass PlatformIO constraints")
|
271
|
+
print("- Utilize CompileServer.web_compile() with custom settings")
|
272
|
+
print("- Access advanced build modes not available via standard PlatformIO")
|
273
|
+
|
274
|
+
|
275
|
+
if __name__ == "__main__":
|
276
|
+
unittest.main()
|
@@ -0,0 +1,241 @@
|
|
1
|
+
"""
|
2
|
+
Integration test file for testing session ID functionality in the FastLED WASM server.
|
3
|
+
|
4
|
+
This test file uses a real Docker-based server to test session ID handling.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import io
|
8
|
+
import unittest
|
9
|
+
import zipfile
|
10
|
+
from pathlib import Path
|
11
|
+
|
12
|
+
import httpx
|
13
|
+
|
14
|
+
from fastled import Api
|
15
|
+
from fastled.types import BuildMode
|
16
|
+
from fastled.web_compile import _AUTH_TOKEN
|
17
|
+
|
18
|
+
|
19
|
+
class TestSessionCompile(unittest.TestCase):
|
20
|
+
"""Test session ID functionality using a real Docker-based server."""
|
21
|
+
|
22
|
+
# Class-level variables for shared server instance
|
23
|
+
server = None
|
24
|
+
base_url = None
|
25
|
+
|
26
|
+
@classmethod
|
27
|
+
def setUpClass(cls):
|
28
|
+
"""Set up test environment once for all tests."""
|
29
|
+
cls.test_dir = Path(__file__).parent / "test_ino" / "wasm"
|
30
|
+
cls.timeout = 30
|
31
|
+
|
32
|
+
# Check if we can run local docker tests
|
33
|
+
if cls._enabled():
|
34
|
+
print("\n🚀 Starting local FastLED WASM server for session ID tests...")
|
35
|
+
cls.server = Api.spawn_server()
|
36
|
+
cls.base_url = cls.server.url()
|
37
|
+
print(f"✅ Server started at: {cls.base_url}")
|
38
|
+
else:
|
39
|
+
print("\n⚠️ Docker not available, skipping tests")
|
40
|
+
cls.server = None
|
41
|
+
cls.base_url = None
|
42
|
+
|
43
|
+
@classmethod
|
44
|
+
def tearDownClass(cls):
|
45
|
+
"""Clean up server after all tests."""
|
46
|
+
if cls.server is not None:
|
47
|
+
print("\n🛑 Stopping local FastLED WASM server...")
|
48
|
+
cls.server.stop()
|
49
|
+
print("✅ Server stopped")
|
50
|
+
|
51
|
+
@classmethod
|
52
|
+
def _enabled(cls) -> bool:
|
53
|
+
"""Check if this system can run the tests."""
|
54
|
+
from fastled import Test
|
55
|
+
|
56
|
+
return Test.can_run_local_docker_tests()
|
57
|
+
|
58
|
+
def setUp(self):
|
59
|
+
"""Set up test case."""
|
60
|
+
if not self._enabled():
|
61
|
+
self.skipTest("Docker not available for testing")
|
62
|
+
|
63
|
+
# Create a test file for compilation
|
64
|
+
self.test_file_content = b"void setup() {}\nvoid loop() {}"
|
65
|
+
|
66
|
+
def _create_test_sketch_zip(self) -> bytes:
|
67
|
+
"""Create a test sketch zip file for upload."""
|
68
|
+
# Create in-memory zip file
|
69
|
+
zip_buffer = io.BytesIO()
|
70
|
+
with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file:
|
71
|
+
# Add the main sketch file
|
72
|
+
zip_file.writestr("wasm/wasm.ino", self.test_file_content)
|
73
|
+
# Add build mode identifier
|
74
|
+
zip_file.writestr("wasm/build_mode.txt", BuildMode.QUICK.value)
|
75
|
+
|
76
|
+
return zip_buffer.getvalue()
|
77
|
+
|
78
|
+
def test_session_id_persistence(self):
|
79
|
+
"""Test that session ID persists across multiple compilation requests."""
|
80
|
+
# Create test sketch zip
|
81
|
+
zip_bytes = self._create_test_sketch_zip()
|
82
|
+
|
83
|
+
# First request with session_id=123
|
84
|
+
files = {"file": ("wasm.zip", zip_bytes, "application/x-zip-compressed")}
|
85
|
+
headers = {
|
86
|
+
"authorization": _AUTH_TOKEN,
|
87
|
+
"build": BuildMode.QUICK.value.lower(),
|
88
|
+
"profile": "false",
|
89
|
+
"strict": "false",
|
90
|
+
"session_id": "123",
|
91
|
+
}
|
92
|
+
|
93
|
+
# Make first request
|
94
|
+
response1 = httpx.post(
|
95
|
+
f"{self.base_url}/compile/wasm",
|
96
|
+
files=files,
|
97
|
+
headers=headers,
|
98
|
+
timeout=self.timeout,
|
99
|
+
follow_redirects=True,
|
100
|
+
)
|
101
|
+
self.assertEqual(response1.status_code, 200)
|
102
|
+
|
103
|
+
# Second request with same session_id
|
104
|
+
response2 = httpx.post(
|
105
|
+
f"{self.base_url}/compile/wasm",
|
106
|
+
files=files,
|
107
|
+
headers=headers,
|
108
|
+
timeout=self.timeout,
|
109
|
+
follow_redirects=True,
|
110
|
+
)
|
111
|
+
self.assertEqual(response2.status_code, 200)
|
112
|
+
|
113
|
+
# Verify both responses contain WASM data
|
114
|
+
self.assertTrue(len(response1.content) > 0)
|
115
|
+
self.assertTrue(len(response2.content) > 0)
|
116
|
+
|
117
|
+
def test_different_session_ids(self):
|
118
|
+
"""Test that different session IDs are handled correctly."""
|
119
|
+
# Create test sketch zip
|
120
|
+
zip_bytes = self._create_test_sketch_zip()
|
121
|
+
|
122
|
+
# First request with session_id=123
|
123
|
+
files = {"file": ("wasm.zip", zip_bytes, "application/x-zip-compressed")}
|
124
|
+
headers1 = {
|
125
|
+
"authorization": _AUTH_TOKEN,
|
126
|
+
"build": BuildMode.QUICK.value.lower(),
|
127
|
+
"profile": "false",
|
128
|
+
"strict": "false",
|
129
|
+
"session_id": "123",
|
130
|
+
}
|
131
|
+
|
132
|
+
response1 = httpx.post(
|
133
|
+
f"{self.base_url}/compile/wasm",
|
134
|
+
files=files,
|
135
|
+
headers=headers1,
|
136
|
+
timeout=self.timeout,
|
137
|
+
follow_redirects=True,
|
138
|
+
)
|
139
|
+
self.assertEqual(response1.status_code, 200)
|
140
|
+
|
141
|
+
# Second request with different session_id=456
|
142
|
+
headers2 = headers1.copy()
|
143
|
+
headers2["session_id"] = "456"
|
144
|
+
|
145
|
+
response2 = httpx.post(
|
146
|
+
f"{self.base_url}/compile/wasm",
|
147
|
+
files=files,
|
148
|
+
headers=headers2,
|
149
|
+
timeout=self.timeout,
|
150
|
+
follow_redirects=True,
|
151
|
+
)
|
152
|
+
self.assertEqual(response2.status_code, 200)
|
153
|
+
|
154
|
+
# Verify both responses contain WASM data
|
155
|
+
self.assertTrue(len(response1.content) > 0)
|
156
|
+
self.assertTrue(len(response2.content) > 0)
|
157
|
+
|
158
|
+
def test_no_session_id(self):
|
159
|
+
"""Test compilation without a session ID."""
|
160
|
+
# Create test sketch zip
|
161
|
+
zip_bytes = self._create_test_sketch_zip()
|
162
|
+
|
163
|
+
files = {"file": ("wasm.zip", zip_bytes, "application/x-zip-compressed")}
|
164
|
+
headers = {
|
165
|
+
"authorization": _AUTH_TOKEN,
|
166
|
+
"build": BuildMode.QUICK.value.lower(),
|
167
|
+
"profile": "false",
|
168
|
+
"strict": "false",
|
169
|
+
}
|
170
|
+
|
171
|
+
response = httpx.post(
|
172
|
+
f"{self.base_url}/compile/wasm",
|
173
|
+
files=files,
|
174
|
+
headers=headers,
|
175
|
+
timeout=self.timeout,
|
176
|
+
follow_redirects=True,
|
177
|
+
)
|
178
|
+
self.assertEqual(response.status_code, 200)
|
179
|
+
self.assertTrue(len(response.content) > 0)
|
180
|
+
|
181
|
+
def test_nonexistent_session_id(self):
|
182
|
+
"""Test that using a non-existent session ID returns the appropriate error."""
|
183
|
+
# Create test sketch zip
|
184
|
+
zip_bytes = self._create_test_sketch_zip()
|
185
|
+
|
186
|
+
files = {"file": ("wasm.zip", zip_bytes, "application/x-zip-compressed")}
|
187
|
+
headers = {
|
188
|
+
"authorization": _AUTH_TOKEN,
|
189
|
+
"build": BuildMode.QUICK.value.lower(),
|
190
|
+
"profile": "false",
|
191
|
+
"strict": "false",
|
192
|
+
"session_id": "999", # Non-existent session ID
|
193
|
+
}
|
194
|
+
|
195
|
+
try:
|
196
|
+
response = httpx.post(
|
197
|
+
f"{self.base_url}/compile/wasm",
|
198
|
+
files=files,
|
199
|
+
headers=headers,
|
200
|
+
timeout=self.timeout,
|
201
|
+
follow_redirects=True,
|
202
|
+
)
|
203
|
+
# The server accepts any session ID format, so we expect 200
|
204
|
+
self.assertEqual(response.status_code, 200)
|
205
|
+
self.assertTrue(len(response.content) > 0)
|
206
|
+
except httpx.HTTPStatusError as e:
|
207
|
+
# If the server raises an error, that's also acceptable
|
208
|
+
self.assertTrue(e.response.status_code in [200, 404])
|
209
|
+
|
210
|
+
def test_invalid_session_id(self):
|
211
|
+
"""Test that using an invalid session ID format is accepted by the server."""
|
212
|
+
# Create test sketch zip
|
213
|
+
zip_bytes = self._create_test_sketch_zip()
|
214
|
+
|
215
|
+
files = {"file": ("wasm.zip", zip_bytes, "application/x-zip-compressed")}
|
216
|
+
headers = {
|
217
|
+
"authorization": _AUTH_TOKEN,
|
218
|
+
"build": BuildMode.QUICK.value.lower(),
|
219
|
+
"profile": "false",
|
220
|
+
"strict": "false",
|
221
|
+
"session_id": "invalid", # Invalid session ID format
|
222
|
+
}
|
223
|
+
|
224
|
+
try:
|
225
|
+
response = httpx.post(
|
226
|
+
f"{self.base_url}/compile/wasm",
|
227
|
+
files=files,
|
228
|
+
headers=headers,
|
229
|
+
timeout=self.timeout,
|
230
|
+
follow_redirects=True,
|
231
|
+
)
|
232
|
+
# The server accepts any session ID format, so we expect 200
|
233
|
+
self.assertEqual(response.status_code, 200)
|
234
|
+
self.assertTrue(len(response.content) > 0)
|
235
|
+
except httpx.HTTPStatusError as e:
|
236
|
+
# If the server raises an error, that's also acceptable
|
237
|
+
self.assertTrue(e.response.status_code in [200, 400])
|
238
|
+
|
239
|
+
|
240
|
+
if __name__ == "__main__":
|
241
|
+
unittest.main()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|