Skip to content

Latest commit

 

History

History
532 lines (411 loc) · 13.6 KB

File metadata and controls

532 lines (411 loc) · 13.6 KB

🧪 Testing Guide

A comprehensive guide for testing the OpenClaw Godot Plugin.

Table of Contents

  1. Test Environment Setup
  2. Manual Testing
  3. Automated Testing
  4. Tool-Specific Test Cases
  5. Integration Testing
  6. Performance Testing

Test Environment Setup

1. Create Test Project

# Create dedicated test project
mkdir -p /Users/Shared/godot-test-project
cd /Users/Shared/godot-test-project

# Copy plugin
cp -r /Users/Shared/openclaw-godot-plugin/addons .

# Create project.godot
cat > project.godot << 'EOF'
[gd_resource type="ProjectSettings" format=3]

[application]
config/name="OpenClaw Test Project"

[editor_plugins]
enabled=PackedStringArray("res://addons/openclaw/plugin.cfg")
EOF

2. Install Gateway Extension

# Install extension
cp -r /Users/Shared/openclaw-godot-plugin/OpenClawPlugin~/* ~/.openclaw/extensions/godot/

# Restart gateway
openclaw gateway restart

# Verify connection
openclaw godot status

3. Prepare Test Scenes

Create test scenes in Godot:

test_scene.tscn (2D testing):

Node2D (TestRoot)
├── Sprite2D (Player)
│   └── Camera2D (Cam)
├── Label (UI)
└── Area2D (TriggerZone)

test_3d_scene.tscn (3D testing):

Node3D (Level)
├── CharacterBody3D (Player3D)
│   └── Camera3D (Cam3D)
├── MeshInstance3D (Ground)
└── DirectionalLight3D (Sun)

Manual Testing

Connection Test

# 1. Check gateway status
openclaw gateway status

# 2. List Godot sessions
openclaw godot sessions

Expected output:

{
  "sessions": [
    {
      "sessionId": "godot_1234567890_abc123",
      "project": "OpenClaw Test Project",
      "version": "4.6-stable",
      "tools": 30
    }
  ]
}

Direct Testing via OpenClaw

You: Check Godot editor state

OpenClaw:
[Executes editor.getState]

Godot 4.6-stable running
- Project: OpenClaw Test Project
- Current scene: res://test_scene.tscn
- Play mode: inactive

Automated Testing

Test Script (GDScript)

addons/openclaw/tests/test_tools.gd:

@tool
extends EditorScript

## OpenClaw Tools Automated Test
## Usage: Script → Run (Ctrl+Shift+X)

var tools: Node
var passed = 0
var failed = 0
var results = []

func _run():
    print("\n" + "=".repeat(50))
    print("🧪 OpenClaw Tools Test Suite")
    print("=".repeat(50) + "\n")
    
    # Create Tools instance
    var Tools = load("res://addons/openclaw/tools.gd")
    tools = Tools.new()
    tools.editor_interface = get_editor_interface()
    
    # Run tests
    _test_editor_tools()
    _test_scene_tools()
    _test_node_tools()
    _test_transform_tools()
    _test_debug_tools()
    
    # Print results
    _print_summary()
    
    # Cleanup
    tools.queue_free()

func _test_editor_tools():
    _section("Editor Tools")
    
    # editor.getState
    var state = tools.execute("editor.getState", {})
    _assert(state.success, "editor.getState returns success")
    _assert(state.has("version"), "editor.getState has version")
    _assert(state.has("isPlaying"), "editor.getState has isPlaying")

func _test_scene_tools():
    _section("Scene Tools")
    
    # scene.list
    var list = tools.execute("scene.list", {})
    _assert(list.success, "scene.list returns success")
    _assert(list.has("scenes"), "scene.list has scenes array")
    
    # scene.getCurrent
    var current = tools.execute("scene.getCurrent", {})
    _assert(current.success, "scene.getCurrent returns success")
    _assert(current.has("path"), "scene.getCurrent has path")
    
    # scene.create
    var created = tools.execute("scene.create", {
        "rootType": "Node2D",
        "name": "AutoTestScene"
    })
    _assert(created.success, "scene.create creates scene")
    _assert(created.path == "res://auto_test_scene.tscn", "scene.create correct path")
    
    # scene.save
    var saved = tools.execute("scene.save", {})
    _assert(saved.success, "scene.save saves scene")

func _test_node_tools():
    _section("Node Tools")
    
    # Create clean scene
    tools.execute("scene.create", {"rootType": "Node2D", "name": "NodeTest"})
    
    # node.create
    var created = tools.execute("node.create", {
        "type": "Sprite2D",
        "name": "TestSprite"
    })
    _assert(created.success, "node.create creates node")
    _assert(created.name == "TestSprite", "node.create correct name")
    
    # node.find
    var found = tools.execute("node.find", {"name": "TestSprite"})
    _assert(found.success, "node.find finds node")
    _assert(found.nodes.size() > 0, "node.find returns results")
    
    # node.getData
    var data = tools.execute("node.getData", {"path": "TestSprite"})
    _assert(data.success, "node.getData returns data")
    _assert(data.data.type == "Sprite2D", "node.getData correct type")
    
    # node.setProperty
    var setProp = tools.execute("node.setProperty", {
        "path": "TestSprite",
        "property": "modulate",
        "value": {"r": 1.0, "g": 0.5, "b": 0.5, "a": 1.0}
    })
    _assert(setProp.success, "node.setProperty sets property")
    
    # node.getProperty
    var getProp = tools.execute("node.getProperty", {
        "path": "TestSprite",
        "property": "modulate"
    })
    _assert(getProp.success, "node.getProperty gets property")
    
    # node.delete
    var deleted = tools.execute("node.delete", {"path": "TestSprite"})
    _assert(deleted.success, "node.delete deletes node")
    
    # Confirm deletion
    var notFound = tools.execute("node.find", {"name": "TestSprite"})
    _assert(notFound.nodes.size() == 0, "node.delete confirmed")

func _test_transform_tools():
    _section("Transform Tools")
    
    # Create test node
    tools.execute("scene.create", {"rootType": "Node2D", "name": "TransformTest"})
    tools.execute("node.create", {"type": "Sprite2D", "name": "Mover"})
    
    # transform.setPosition
    var pos = tools.execute("transform.setPosition", {
        "path": "Mover",
        "x": 100,
        "y": 200
    })
    _assert(pos.success, "transform.setPosition works")
    
    # Verify position
    var data = tools.execute("node.getData", {"path": "Mover"})
    _assert(data.data.position.x == 100, "setPosition x correct")
    _assert(data.data.position.y == 200, "setPosition y correct")
    
    # transform.setRotation
    var rot = tools.execute("transform.setRotation", {
        "path": "Mover",
        "degrees": 45
    })
    _assert(rot.success, "transform.setRotation works")
    
    data = tools.execute("node.getData", {"path": "Mover"})
    _assert(abs(data.data.rotation - 45) < 0.1, "setRotation correct")
    
    # transform.setScale
    var scale = tools.execute("transform.setScale", {
        "path": "Mover",
        "x": 2.0,
        "y": 2.0
    })
    _assert(scale.success, "transform.setScale works")
    
    data = tools.execute("node.getData", {"path": "Mover"})
    _assert(data.data.scale.x == 2.0, "setScale x correct")
    _assert(data.data.scale.y == 2.0, "setScale y correct")

func _test_debug_tools():
    _section("Debug Tools")
    
    # debug.tree
    var tree = tools.execute("debug.tree", {})
    _assert(tree.success, "debug.tree returns success")
    _assert(tree.has("tree"), "debug.tree has tree string")
    
    # debug.log
    var log = tools.execute("debug.log", {"message": "Test log message"})
    _assert(log.success, "debug.log works")
    
    # debug.screenshot
    var screenshot = tools.execute("debug.screenshot", {})
    _assert(screenshot.success, "debug.screenshot works")
    _assert(screenshot.has("path"), "debug.screenshot returns path")
    
    # console.getLogs
    var logs = tools.execute("console.getLogs", {"limit": 10})
    _assert(logs.success, "console.getLogs works")
    _assert(logs.has("logs"), "console.getLogs has logs")

# Helper functions
func _section(name: String):
    print("\n📦 %s" % name)
    print("-".repeat(40))

func _assert(condition: bool, message: String):
    if condition:
        passed += 1
        print("  ✅ %s" % message)
    else:
        failed += 1
        print("  ❌ %s" % message)
    results.append({"pass": condition, "message": message})

func _print_summary():
    print("\n" + "=".repeat(50))
    print("📊 Test Results")
    print("=".repeat(50))
    print("  Passed: %d" % passed)
    print("  Failed: %d" % failed)
    print("  Total:  %d" % (passed + failed))
    print("")
    
    if failed == 0:
        print("🎉 All tests passed!")
    else:
        print("⚠️  Some tests failed:")
        for r in results:
            if not r.pass:
                print("    - %s" % r.message)

Running Tests

In Godot:

  1. Open addons/openclaw/tests/test_tools.gd
  2. Script → Run (Ctrl+Shift+X)

Expected output:

==================================================
🧪 OpenClaw Tools Test Suite
==================================================

📦 Editor Tools
----------------------------------------
  ✅ editor.getState returns success
  ✅ editor.getState has version
  ✅ editor.getState has isPlaying

📦 Scene Tools
----------------------------------------
  ✅ scene.list returns success
  ...

==================================================
📊 Test Results
==================================================
  Passed: 28
  Failed: 0
  Total:  28

🎉 All tests passed!

Tool-Specific Test Cases

Scene Tools

Tool Test Case Expected Result
scene.getCurrent Call with scene open Returns name, path, nodeCount
scene.getCurrent Call with no scene success: false, error message
scene.list Project has scenes Returns scenes array
scene.open Valid scene path Scene opens, success: true
scene.open Invalid path success: false, error message
scene.save Modified scene File saved, success: true
scene.create Node2D root New scene created, path returned
scene.create Node3D root 3D scene created
scene.create Duplicate name Overwrite or add number

Node Tools

Tool Test Case Expected Result
node.find Search by name Matching node list
node.find Search by type Nodes of that type
node.find Search by group Group members
node.find Nonexistent node Empty array
node.create Create Sprite2D Node added
node.create Create with parent Added under correct parent
node.delete Delete existing node Node removed
node.delete Delete root node Fail or warning
node.setProperty Set Vector2 Dictionary→Vector2 conversion
node.setProperty Set Color RGBA dictionary→Color conversion

Input Tools (Play Mode)

Tool Test Case Expected Result
input.keyPress "W" key Key event triggered
input.keyDown + keyUp SHIFT hold Modifier works
input.mouseClick Left click (400, 300) Click event triggered
input.mouseMove (0, 0) → (800, 600) Mouse moves
input.actionPress "jump" action Works if action mapped
input.actionPress Nonexistent action Warning or ignored

Integration Testing

Scenario 1: Scene Creation Workflow

1. scene.create {rootType: "Node2D", name: "Level1"}
2. node.create {type: "CharacterBody2D", name: "Player"}
3. node.create {type: "Camera2D", name: "Cam", parent: "Player"}
4. transform.setPosition {path: "Player", x: 400, y: 300}
5. scene.save
6. editor.play
7. input.keyPress {key: "W"}
8. debug.screenshot
9. editor.stop

Expected results:

  • Level1.tscn created
  • Player → Cam hierarchy
  • Screenshot shows player at (400, 300)

Scenario 2: Debugging Workflow

1. scene.open {path: "res://main.tscn"}
2. debug.tree
3. node.find {type: "Sprite2D"}
4. node.getData {path: "Player"}
5. console.getLogs {type: "error", limit: 20}
6. debug.screenshot

Scenario 3: Play Mode Stability

1. editor.play
2. (wait 30 seconds - heartbeat interval)
3. editor.getState  # Verify connection maintained
4. input.keyPress {key: "ESCAPE"}
5. editor.stop

Performance Testing

Connection Stability

# 10-minute connection maintenance test
for i in {1..20}; do
    echo "Iteration $i"
    openclaw godot execute editor.getState
    sleep 30
done

Command Processing Speed

# Add to tools.gd (development only)
var start_time: int

func execute(tool_name: String, args: Dictionary) -> Dictionary:
    start_time = Time.get_ticks_msec()
    
    var result = _execute_internal(tool_name, args)
    
    var elapsed = Time.get_ticks_msec() - start_time
    print("[OpenClaw] %s took %dms" % [tool_name, elapsed])
    
    return result

Expected Performance

Tool Expected Response Time
editor.getState < 10ms
scene.getCurrent < 20ms
node.find < 50ms (100 nodes)
debug.screenshot < 200ms
scene.save < 500ms

Test Checklist

Pre-Release Required Tests

  • Plugin enable/disable
  • Gateway connect/reconnect
  • All 30 tools basic operation
  • Connection maintained during Play mode transition
  • Command execution after 30s+ idle
  • Proper error messages on failures
  • No memory leaks (extended run)

Edge Cases

  • node.getData on empty scene
  • Node names with special characters
  • Very deep node hierarchy (10+)
  • Large scene (1000+ nodes)
  • Concurrent multiple commands
  • Reconnection after Gateway restart

Next Steps


Documentation Updated: 2026-02-08