Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 125 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,131 @@ public class <Language>StepDefinitionOpener implements IStepDefinitionOpener {
- Use Eclipse's IDE.openEditor() and text editor APIs
- Handle file path resolution (relative vs. absolute)

#### 2.8 Preferences
#### 2.8 Remote Test Execution (Message Endpoint)

Implement message endpoint for real-time test execution monitoring:

##### Message Endpoint Process

Create a process that receives Cucumber messages from the test framework:

```java
public class <Framework>MessageEndpointProcess implements IProcess, EnvelopeProvider,
ISuspendResume, IDisconnect {

private static final int HANDLED_MESSAGE = 0x01;
private static final int GOOD_BY_MESSAGE = 0x00;

private ServerSocket serverSocket;
private ILaunch launch;
private List<Envelope> envelopes = new ArrayList<>();
private List<EnvelopeListener> consumers = new ArrayList<>();

public <Framework>MessageEndpointProcess(ILaunch launch) throws IOException {
this.serverSocket = new ServerSocket(0);
this.launch = launch;
launch.addProcess(this);
}

public void start() {
// Create daemon thread to listen for incoming connections
// Accept connection and read messages in loop
// Deserialize using Jackson.OBJECT_MAPPER
// Notify all registered EnvelopeListeners
// Send acknowledgment byte after each message
}

public void addBehaveArguments(List<String> args) {
// Add framework-specific arguments to inject formatter
// Include port number for socket connection
}
}
```

##### Language-Specific Formatter/Plugin

Create a formatter in the target language that sends messages to Eclipse:

**For Python/Behave:**

```python
class CucumberEclipseFormatter(Formatter):
def __init__(self, stream_opener, config):
# Read port from environment variable or config
# Connect to Eclipse socket

def _send_message(self, envelope):
# Serialize to JSON
# Send 4-byte big-endian length
# Send JSON bytes
# Wait for acknowledgment (0x01)

def step(self, step):
# Create TestStepFinished envelope
# Send to Eclipse

def eof(self):
# Send TestRunFinished
# Send 0 length
# Close connection
```

**Protocol Requirements:**

1. Connect to Eclipse on specified port
2. For each message:
- Send message length as 4-byte big-endian integer
- Send JSON-encoded Cucumber Message
- Wait for acknowledgment byte (0x01)
- If received goodbye (0x00), close connection
3. After test run:
- Send TestRunFinished message
- Send 0 length to signal end
- Wait for acknowledgment
- Close socket

**Key Points:**
- Use standard Cucumber Messages format (JSON)
- Reuse Jackson ObjectMapper for deserialization (from java.plugins bundle)
- Package formatter/plugin with bundle (e.g., in `<language>-plugins/` directory)
- Update `build.properties` to include plugin directory
- Add formatter to language runtime's plugin path (e.g., PYTHONPATH)
- Pass port via environment variable or command-line argument
- No code changes required in user's test files

##### Update Launch Delegate

Integrate message endpoint with launch configuration:

```java
@Override
public void launch(ILaunchConfiguration config, String mode,
ILaunch launch, IProgressMonitor monitor) throws CoreException {

// Create message endpoint
<Framework>MessageEndpointProcess endpoint =
new <Framework>MessageEndpointProcess(launch);

// Build launcher arguments
List<String> args = new ArrayList<>();
endpoint.addArguments(args); // Adds formatter and port

// Start endpoint listener
endpoint.start();
launch.addProcess(endpoint);

try {
// Launch test process with injected arguments
Process process = launcher.launch(pluginPath);
IProcess iProcess = DebugPlugin.newProcess(launch, process, "...");
} catch (Exception e) {
endpoint.terminate();
throw e;
}
}
```

#### 2.9 Preferences

Provide user-configurable preferences:

Expand Down
2 changes: 2 additions & 0 deletions io.cucumber.eclipse.python/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
bin/
__pycache__/
*.pyc
77 changes: 75 additions & 2 deletions io.cucumber.eclipse.python/IMPLEMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,15 +143,88 @@ Created `examples/python-calculator/` demonstrating usage:
- Parallel execution support

4. **Step Definition Navigation**
- Jump from feature file to step definition
- Jump from feature file to step definition ✅ (Implemented)
- Step definition completion
- Unused step detection

5. **Test Results Integration**
5. **Test Results Integration** ✅ (Implemented)
- Eclipse test results view integration
- Visual representation of test execution
- Failed test navigation

## Recent Updates

### Remote Test Execution Support (v3.0.0)

Added support for real-time test execution monitoring using the Cucumber Messages protocol:

#### New Components

1. **BehaveMessageEndpointProcess**
- Located in `io.cucumber.eclipse.python.launching`
- Implements message endpoint for receiving Cucumber messages from Python
- Similar to Java's MessageEndpointProcess but tailored for Python/Behave
- Implements EnvelopeProvider interface for integration with Eclipse
- Creates server socket and listens for incoming test execution messages
- Handles message deserialization using Jackson ObjectMapper
- Distributes messages to registered EnvelopeListeners

2. **Python Formatter Plugin**
- Located in `python-plugins/behave_cucumber_eclipse.py`
- Custom Behave formatter that connects to Eclipse via socket
- Sends Cucumber Messages in JSON format
- Uses same protocol as Java CucumberEclipsePlugin:
- 4-byte big-endian integer for message length
- JSON-encoded message
- Waits for acknowledgment byte (0x01)
- Sends goodbye message (0x00) on completion
- Reads port from environment variable or Behave userdata (-D option)
- No additional Python dependencies beyond standard library

3. **Updated Launch Configuration**
- `CucumberBehaveLaunchConfigurationDelegate` now creates MessageEndpointProcess
- Automatically injects formatter arguments to Behave command
- Adds python-plugins directory to PYTHONPATH
- Coordinates between Eclipse and Python processes

4. **Enhanced BehaveProcessLauncher**
- Added support for setting PYTHONPATH environment variable
- New `launch(String pythonPluginPath)` method for custom environment setup
- Maintains backward compatibility with existing `launch()` method

#### Protocol Details

The Python formatter implements the same binary protocol as the Java backend:

```
1. Connect to Eclipse on specified port (passed via -D cucumber_eclipse_port=<port>)
2. For each test event:
a. Serialize event as Cucumber Message (JSON)
b. Send message length as 4-byte big-endian integer
c. Send JSON message bytes
d. Wait for acknowledgment (0x01) from Eclipse
e. If Eclipse sends goodbye (0x00), close connection
3. After test run completes:
a. Send TestRunFinished message
b. Send 0 length to signal end
c. Wait for final acknowledgment
d. Close socket
```

#### Integration Points

- **EnvelopeProvider**: MessageEndpointProcess implements this interface to distribute messages
- **EnvelopeListener**: Eclipse components can register as listeners to receive test events
- **Unittest View**: Messages are routed to Eclipse's unittest view for display
- **Jackson**: Reuses Jackson ObjectMapper from java.plugins bundle for JSON deserialization

#### Build Configuration

- Updated `build.properties` to include python-plugins directory in bundle
- Updated `MANIFEST.MF` to add dependency on io.cucumber.eclipse.java.plugins
- Python formatter is packaged with the plugin and added to PYTHONPATH automatically


## Testing

The implementation has been designed to follow the same patterns as the Java bundle, but requires a full Eclipse environment with the plugin installed to test:
Expand Down
3 changes: 2 additions & 1 deletion io.cucumber.eclipse.python/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ Require-Bundle: org.eclipse.ui,
org.eclipse.debug.core,
org.eclipse.core.variables,
io.cucumber.messages;bundle-version="13.2.1",
io.cucumber.tag-expressions;bundle-version="3.0.0"
io.cucumber.tag-expressions;bundle-version="3.0.0",
io.cucumber.eclipse.java.plugins;bundle-version="3.0.0"
Bundle-RequiredExecutionEnvironment: JavaSE-21
Automatic-Module-Name: io.cucumber.eclipse.python
Bundle-ActivationPolicy: lazy
Expand Down
25 changes: 24 additions & 1 deletion io.cucumber.eclipse.python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ This bundle provides support for launching Cucumber feature files using Python's
- No capture mode
- Dry run
- Tag-based test filtering
- **Real-time test execution monitoring** via Eclipse unittest view
- **Remote test execution support** using Cucumber Messages protocol

## Requirements

- Python 3.x installed on your system
- Python 3.6+
- Behave package installed (`pip install behave`)
- PyDev plugin (optional, but recommended)

Expand All @@ -31,6 +33,26 @@ This bundle provides support for launching Cucumber feature files using Python's
- **Tags**: Optional tag expression to filter scenarios
- **Behave Options**: Enable verbose, no-capture, or dry-run modes

## Remote Test Execution

The bundle automatically integrates with Eclipse's unittest view to provide real-time test execution feedback:

- Test results are streamed from Behave to Eclipse via socket connection
- Uses the Cucumber Messages protocol for standardized communication
- No code changes required in your test files
- The `behave_cucumber_eclipse.py` formatter is automatically injected

### How It Works

1. When you launch a feature file, Eclipse creates a message endpoint listening on a random port
2. The launch configuration automatically adds the Behave formatter and port number
3. The Python formatter connects to Eclipse and sends test execution events
4. Eclipse displays results in the unittest view in real-time

### Python Plugin

The Python formatter plugin is located in `python-plugins/behave_cucumber_eclipse.py` and is automatically added to your PYTHONPATH during test execution.

## Configuration

The launch configuration supports the following attributes:
Expand Down Expand Up @@ -59,3 +81,4 @@ my-python-project/
- Make sure Behave is installed in your Python environment
- The working directory should typically be the root of your project
- PyDev dependencies are optional and marked with `resolution:=optional` in the manifest
- The remote execution feature uses the same protocol as the Java backend for consistency
3 changes: 2 additions & 1 deletion io.cucumber.eclipse.python/build.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ bin.includes = META-INF/,\
.,\
plugin.xml,\
icons/,\
OSGI-INF/
OSGI-INF/,\
python-plugins/
56 changes: 56 additions & 0 deletions io.cucumber.eclipse.python/python-plugins/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Behave Cucumber Eclipse Plugin

This directory contains Python plugins that integrate Behave with Eclipse IDE.

## behave_cucumber_eclipse.py

A Behave formatter that enables real-time test execution monitoring in Eclipse.

### Features

- Sends test execution events to Eclipse via socket connection
- Uses the Cucumber Messages protocol
- Compatible with Eclipse unittest view
- No code changes required in test files

### Installation

1. Copy `behave_cucumber_eclipse.py` to your Python path or project directory
2. The plugin is automatically injected by Eclipse when launching tests

### Manual Usage

If you want to use the formatter outside of Eclipse:

```bash
# Set the port number via environment variable
export CUCUMBER_ECLIPSE_PORT=12345

# Run behave with the formatter
behave --format behave_cucumber_eclipse:CucumberEclipseFormatter features/
```

Or pass the port via userdata:

```bash
behave -D cucumber_eclipse_port=12345 --format behave_cucumber_eclipse:CucumberEclipseFormatter features/
```

### Protocol

The formatter implements the same socket protocol as the Java CucumberEclipsePlugin:

1. Connect to Eclipse on the specified port
2. For each message:
- Send message length as 4-byte big-endian integer
- Send JSON-encoded Cucumber message
- Wait for acknowledgment byte (0x01)
3. After TestRunFinished, send 0 length and wait for goodbye byte (0x00)

### Dependencies

- Python 3.6+
- behave
- Standard library only (socket, json, struct)

No additional dependencies required - the plugin uses only Python standard library for socket communication and JSON serialization.
Loading