Skip to content
This repository has been archived by the owner on Jan 26, 2022. It is now read-only.

Add tests for stackTrace, scopes, variables #13

Merged
merged 8 commits into from Aug 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 0 additions & 2 deletions README.md
Expand Up @@ -39,8 +39,6 @@ XEUS_LOG=1 jupyter lab --no-browser --watch

### Tests

Make sure `xeus-python` is installed and `jupyter --paths` points to where the kernel is installed.

To run the tests:

```bash
Expand Down
1 change: 0 additions & 1 deletion azure-pipelines.yml
Expand Up @@ -28,7 +28,6 @@ steps:

- bash: |
source activate jupyterlab-debugger
export JUPYTER_PATH=${CONDA_PREFIX}/share/jupyter
export XEUS_LOG=1
jlpm run test
displayName: Run the tests
Expand Down
1 change: 1 addition & 0 deletions src/tokens.ts
Expand Up @@ -114,6 +114,7 @@ export namespace IDebugger {
terminateThreads: DebugProtocol.TerminateThreadsArguments;
threads: {};
updateCell: IUpdateCellArguments;
variables: DebugProtocol.VariablesArguments;
};

/**
Expand Down
28 changes: 27 additions & 1 deletion tests/run-test.py
@@ -1,10 +1,36 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.

import json
import os
from jupyterlab.tests.test_app import run_jest
from os.path import join as pjoin

from jupyter_core import paths
from jupyterlab.tests.test_app import run_jest, JestApp

HERE = os.path.realpath(os.path.dirname(__file__))


def _install_xpython_kernel():
# Mimics: https://github.com/jupyterlab/jupyterlab/blob/cd2fb6ac3ecfae2bb4bcab84797932e625e9bb2f/jupyterlab/tests/test_app.py#L80-L95
kernel_json = {
'argv': [
'xpython',
'-f', '{connection_file}'
],
'display_name': "xpython",
'language': 'python'
}
kernel_dir = pjoin(paths.jupyter_data_dir(), 'kernels', 'xpython')
os.makedirs(kernel_dir)
with open(pjoin(kernel_dir, 'kernel.json'), 'w') as f:
f.write(json.dumps(kernel_json))


if __name__ == '__main__':
jest_app = JestApp.instance()

# install the kernel spec for xeus-python
_install_xpython_kernel()

run_jest(HERE)
166 changes: 164 additions & 2 deletions tests/src/session.spec.ts
Expand Up @@ -5,7 +5,15 @@ import { expect } from 'chai';

import { ClientSession, IClientSession } from '@jupyterlab/apputils';

import { createClientSession } from '@jupyterlab/testutils';
import { createClientSession, sleep } from '@jupyterlab/testutils';

import { find } from '@phosphor/algorithm';

import { PromiseDelegate } from '@phosphor/coreutils';

import { DebugProtocol } from 'vscode-debugprotocol';

import { IDebugger } from '../../lib/tokens';

import { DebugSession } from '../../lib/session';

Expand Down Expand Up @@ -71,7 +79,7 @@ describe('DebugSession', () => {
expect(reply.body.sourcePath).to.contain('.py');
});

it('should handle replies with success false', async () => {
it.skip('should handle replies with success false', async () => {
const reply = await debugSession.sendRequest('evaluate', {
expression: 'a'
});
Expand All @@ -81,3 +89,157 @@ describe('DebugSession', () => {
});
});
});

describe('protocol', () => {
const code = [
'i = 0',
'i += 1',
'i += 1',
'j = i**2',
'j += 1',
'print(i, j)'
].join('\n');

const breakpoints: DebugProtocol.SourceBreakpoint[] = [
{ line: 3 },
{ line: 5 }
];

let client: IClientSession;
let debugSession: DebugSession;
let threadId: number = 1;

beforeEach(async () => {
client = await createClientSession({
kernelPreference: {
name: 'xpython'
}
});
await (client as ClientSession).initialize();
await client.kernel.ready;
debugSession = new DebugSession({ client });
await debugSession.start();

debugSession.eventMessage.connect(
(sender: DebugSession, event: IDebugger.ISession.Event) => {
const eventName = event.event;
if (eventName === 'thread') {
const msg = event as DebugProtocol.ThreadEvent;
threadId = msg.body.threadId;
}
}
);

const reply = await debugSession.sendRequest('updateCell', {
cellId: 0,
nextId: 1,
code
});
await debugSession.sendRequest('setBreakpoints', {
breakpoints,
source: { path: reply.body.sourcePath },
sourceModified: false
});
await debugSession.sendRequest('configurationDone', {});

// trigger an execute_request
client.kernel.requestExecute({ code });

// TODO: handle events instead
await sleep(2000);
});

afterEach(async () => {
await debugSession.stop();
debugSession.dispose();
await client.shutdown();
client.dispose();
});

describe('#stackTrace', () => {
it('should return the correct stackframes', async () => {
const reply = await debugSession.sendRequest('stackTrace', {
threadId
});
expect(reply.success).to.be.true;
const stackFrames = reply.body.stackFrames;
expect(stackFrames.length).to.equal(2);
const frame = stackFrames[0];
// first breakpoint
expect(frame.line).to.equal(3);
});
});

describe('#scopes', () => {
it('should return the correct scopes', async () => {
const stackFramesReply = await debugSession.sendRequest('stackTrace', {
threadId
});
const frameId = stackFramesReply.body.stackFrames[0].id;
const scopesReply = await debugSession.sendRequest('scopes', {
frameId
});
const scopes = scopesReply.body.scopes;
expect(scopes.length).to.equal(1);
expect(scopes[0].name).to.equal('Locals');
});
});

const getVariables = async () => {
const stackFramesReply = await debugSession.sendRequest('stackTrace', {
threadId
});
const frameId = stackFramesReply.body.stackFrames[0].id;
const scopesReply = await debugSession.sendRequest('scopes', {
frameId
});
const scopes = scopesReply.body.scopes;
const variablesReference = scopes[0].variablesReference;
const variablesReply = await debugSession.sendRequest('variables', {
variablesReference
});
return variablesReply.body.variables;
};

describe('#variables', () => {
it('should return the variables and their values', async () => {
const variables = await getVariables();
expect(variables.length).to.be.greaterThan(0);
const i = find(variables, variable => variable.name === 'i');
expect(i).to.exist;
expect(i.type).to.equal('int');
expect(i.value).to.equal('1');
});
});

describe('#continue', () => {
it.skip('should proceed to the next breakpoint', async () => {
let events: string[] = [];
const eventsFuture = new PromiseDelegate<string[]>();
debugSession.eventMessage.connect((sender, event) => {
events.push(event.event);
// aggregate the next 2 debug events
if (events.length === 2) {
eventsFuture.resolve(events);
}
});

await debugSession.sendRequest('continue', { threadId });

// wait for debug events
const debugEvents = await eventsFuture.promise;
expect(debugEvents).to.deep.equal(['continued', 'stopped']);

const variables = await getVariables();
const i = find(variables, variable => variable.name === 'i');
expect(i).to.exist;
expect(i.type).to.equal('int');
expect(i.value).to.equal('2');

const j = find(variables, variable => variable.name === 'j');
expect(j).to.exist;
expect(j.type).to.equal('int');
expect(j.value).to.equal('4');
});
});
});