mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 05:51:39 +00:00
Enhance two-way sync functionality and integration test coverage
- Improved the two-way sync pipeline by refining instance renaming logic, ensuring correct handling of directory-format scripts and adjacent meta file renaming. - Enhanced property persistence for non-Source properties, ensuring proper creation of meta files during updates. - Introduced comprehensive integration tests for critical two-way sync operations, including instance renames, ClassName transitions, and end-to-end workflows, addressing previously uncovered scenarios. - Updated logging for better insights during sync operations and file handling, aiding in debugging and user awareness of changes.
This commit is contained in:
parent
dc1a912982
commit
06d296ffba
4 changed files with 351 additions and 421 deletions
156
.cursor/plans/two-way_sync_integration_tests_0e4e4dfc.plan.md
Normal file
156
.cursor/plans/two-way_sync_integration_tests_0e4e4dfc.plan.md
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
---
|
||||
name: Two-way sync integration tests
|
||||
overview: "Add integration tests covering the critical untested two-way sync operations: instance rename, ClassName transitions, non-Source property persistence, removal with meta cleanup, and end-to-end bidirectional sync workflows. Tests validate that the plugin sync pipeline can eventually replace `rojo syncback` for keeping the filesystem in sync with Studio."
|
||||
todos:
|
||||
- id: create-test-file
|
||||
content: Create tests/tests/two_way_sync.rs with test module structure, imports, and helper functions
|
||||
status: pending
|
||||
- id: register-module
|
||||
content: Register two_way_sync module in tests/end_to_end.rs
|
||||
status: pending
|
||||
- id: basic-source-write
|
||||
content: "Test: update_source_writes_to_disk — verify Source property write to disk via InstanceUpdate"
|
||||
status: pending
|
||||
- id: property-persistence
|
||||
content: "Tests: update_non_source_property_creates_meta_file + update_properties_for_directory_script_writes_init_meta"
|
||||
status: pending
|
||||
- id: rename-tests
|
||||
content: "Tests: rename_standalone_script + rename_preserves_adjacent_meta_file"
|
||||
status: pending
|
||||
- id: classname-tests
|
||||
content: "Tests: classname_change_standalone_module_to_script + classname_change_directory_script_renames_init_file"
|
||||
status: pending
|
||||
- id: removal-tests
|
||||
content: "Tests: remove_instance_deletes_file_and_meta + remove_directory_instance"
|
||||
status: pending
|
||||
- id: round-trip
|
||||
content: "Test: round_trip_add_modify_rename_remove — end-to-end lifecycle"
|
||||
status: pending
|
||||
- id: edge-cases
|
||||
content: "Tests: property_update_skips_project_node_instances + echo_suppression_prevents_redundant_patches"
|
||||
status: pending
|
||||
- id: ci-verify
|
||||
content: Run /ci to verify all new tests pass alongside existing 606+397 tests
|
||||
status: pending
|
||||
isProject: false
|
||||
---
|
||||
|
||||
# Two-Way Sync Integration Tests
|
||||
|
||||
## Intent
|
||||
|
||||
The plugin's two-way sync (`POST /api/write`) should eventually supersede the `rojo syncback` command entirely. The goal is continuous bidirectional sync: connect to Studio, accept changes, and work in an external IDE while others work in Studio. These tests validate the core primitives that make this possible.
|
||||
|
||||
## Coverage Gaps Addressed
|
||||
|
||||
The existing tests cover format transitions (standalone/directory) and stress testing but have **zero coverage** for:
|
||||
|
||||
1. **Instance rename** (changed_name) — file/directory rename on disk, adjacent meta file rename
|
||||
2. **ClassName transitions** (changed_class_name) — script type changes, init file detection in directories
|
||||
3. **Non-Source property persistence** (changed_properties except Source) — writing to meta files
|
||||
4. **Instance removal with meta file cleanup** — deleting files plus their adjacent `.meta.json5`
|
||||
5. **End-to-end round-trip** — add instance, modify it, rename it, verify filesystem at each step
|
||||
|
||||
## Test Fixture
|
||||
|
||||
Use existing `syncback_write` fixture (`rojo-test/serve-tests/syncback_write/`). It has a minimal project: `ReplicatedStorage` mapped to `src/` with one existing `existing.luau` (ModuleScript). This is ideal for testing write operations without interference from complex file structures.
|
||||
|
||||
For rename tests, we also use `syncback_format_transitions` which has directory-format scripts with init files.
|
||||
|
||||
## New Test File
|
||||
|
||||
Add tests to `tests/tests/two_way_sync.rs` (new file). Register it via `tests/end_to_end.rs`.
|
||||
|
||||
All tests follow the established pattern:
|
||||
|
||||
- `run_serve_test(fixture_name, |session, _redactions| { ... })`
|
||||
- Find parent ID via `get_api_rojo()` + `get_api_read()`
|
||||
- Construct `WriteRequest` with `added`, `updated`, or `removed`
|
||||
- Call `session.post_api_write()`
|
||||
- Assert filesystem state
|
||||
|
||||
## Tests
|
||||
|
||||
### 1. `update_source_writes_to_disk` — Verify the basic Source write path
|
||||
|
||||
Send an `InstanceUpdate` with `changed_properties: { Source: "-- new content" }` for the existing `existing.luau`. Verify `fs::read_to_string` returns the new content. This is the most fundamental two-way sync operation.
|
||||
|
||||
### 2. `update_non_source_property_creates_meta_file` — Issue 2 coverage
|
||||
|
||||
Send an `InstanceUpdate` with a non-Source property (Attributes) for `existing.luau`. Verify:
|
||||
|
||||
- `existing.meta.json5` is created adjacent to `existing.luau`
|
||||
- The meta file contains the attribute value
|
||||
- `existing.luau` itself is unchanged
|
||||
|
||||
### 3. `update_properties_for_directory_script_writes_init_meta` — Issue 2 directory path
|
||||
|
||||
Use `syncback_format_transitions` fixture. Send property update for a directory-format script (`DirModuleWithChildren`). Verify `init.meta.json5` is created inside the directory.
|
||||
|
||||
### 4. `rename_standalone_script` — Issue 8 rename coverage
|
||||
|
||||
Add a new ModuleScript `OldName` via `added`, wait for it to appear on disk. Then send an `InstanceUpdate` with `changed_name: Some("NewName")`. Verify:
|
||||
|
||||
- `OldName.luau` is gone
|
||||
- `NewName.luau` exists with same content
|
||||
|
||||
### 5. `rename_preserves_adjacent_meta_file` — Issue 8 meta rename
|
||||
|
||||
Add a ModuleScript, send a property update to create its meta file, then rename it. Verify both the `.luau` and `.meta.json5` files are renamed together.
|
||||
|
||||
### 6. `classname_change_standalone_module_to_script` — Issue 8 ClassName coverage
|
||||
|
||||
Add a ModuleScript `MyModule`, then send `changed_class_name: Some("Script")`. Verify:
|
||||
|
||||
- `MyModule.luau` is gone
|
||||
- `MyModule.server.luau` exists
|
||||
|
||||
### 7. `classname_change_directory_script_renames_init_file` — Issue 8 directory ClassName
|
||||
|
||||
Use `syncback_format_transitions`. Send `changed_class_name` for `DirModuleWithChildren` (ModuleScript -> Script). Verify:
|
||||
|
||||
- Directory still exists
|
||||
- `init.luau` is gone
|
||||
- `init.server.luau` exists
|
||||
- Children still exist
|
||||
|
||||
### 8. `remove_instance_deletes_file_and_meta` — Issue 4 removal cleanup
|
||||
|
||||
Add a ModuleScript, create its meta file via property update, then remove it via `removed`. Verify both the `.luau` file and `.meta.json5` are deleted.
|
||||
|
||||
### 9. `remove_directory_instance` — Issue 4 directory removal
|
||||
|
||||
Use `syncback_format_transitions`. Remove a directory-format instance. Verify the entire directory is deleted recursively.
|
||||
|
||||
### 10. `round_trip_add_modify_rename_remove` — End-to-end workflow
|
||||
|
||||
This test validates the complete lifecycle that makes two-way sync viable as a `syncback` replacement:
|
||||
|
||||
1. **Add** a new Script `PlayerHandler` with children
|
||||
2. Verify directory created on disk
|
||||
3. **Modify** its Source property
|
||||
4. Verify file content updated
|
||||
5. **Rename** it to `GameHandler`
|
||||
6. Verify directory renamed
|
||||
7. **Remove** it
|
||||
8. Verify directory deleted
|
||||
|
||||
### 11. `property_update_skips_project_node_instances` — Post-fix coverage
|
||||
|
||||
Send property update for a Service (ReplicatedStorage) which has `InstigatingSource::ProjectNode`. Verify it does NOT corrupt the project file. The project file content should be unchanged.
|
||||
|
||||
### 12. `echo_suppression_prevents_redundant_patches` — Issue 7 coverage
|
||||
|
||||
Add a new instance, then immediately read the message queue. Count the WebSocket messages — there should be exactly one patch notification, not two (which would indicate echo from the VFS picking up the file write).
|
||||
|
||||
## Key Implementation Details
|
||||
|
||||
- `InstanceUpdate` requires `UstrMap<Option<Variant>>` for `changed_properties`. Import `rbx_dom_weak::{ustr, UstrMap}`.
|
||||
- Finding existing instance IDs: read tree via `get_api_read(root_id)`, traverse `instances` to find by class/name.
|
||||
- After `post_api_write`, sleep 200-500ms for change processor to handle VFS events.
|
||||
- Use `fs::read_to_string` to verify file content, `fs::metadata` to verify existence.
|
||||
- For rename/ClassName tests, the instance ID in `InstanceUpdate` must match the ID the server assigned (found via `get_api_read` after the initial add).
|
||||
|
||||
## File Registration
|
||||
|
||||
Add `mod two_way_sync;` to `tests/tests/mod.rs` (or the test harness entry point `tests/end_to_end.rs`).
|
||||
Loading…
Add table
Add a link
Reference in a new issue