123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 |
- // Copyright (c) Jupyter Development Team.
- import 'jest';
- // Distributed under the terms of the Modified BSD License.
- import {
- Logger,
- LoggerOutputAreaModel,
- ILogPayload,
- LogLevel
- } from '@jupyterlab/logconsole';
- import { RenderMimeRegistry } from '@jupyterlab/rendermime';
- import { Signal, ISignal } from '@lumino/signaling';
- class SignalLogger<SENDER, ARGS> {
- constructor(signal: ISignal<SENDER, ARGS>) {
- signal.connect(this.slot, this);
- }
- slot(sender: SENDER, args: ARGS) {
- this.args.push(args);
- }
- dispose() {
- Signal.disconnectAll(this);
- }
- args: ARGS[] = [];
- }
- describe('LoggerOutputAreaModel', () => {
- let model: LoggerOutputAreaModel;
- beforeEach(() => {
- model = new LoggerOutputAreaModel({ maxLength: 10 });
- });
- afterEach(() => {
- model.dispose();
- });
- describe('#constructor()', () => {
- it('should create an LoggerOutputAreaModel', () => {
- expect(model).toBeInstanceOf(LoggerOutputAreaModel);
- });
- it('should set the max length', async () => {
- const model = new LoggerOutputAreaModel({ maxLength: 10 });
- expect(model.maxLength).toEqual(10);
- model.dispose();
- });
- });
- describe('#maxLength', () => {
- it('should set the maximum number of messages in the first-in first-out queue', () => {
- for (let i = 0; i < 12; i++) {
- model.add({
- output_type: 'display_data',
- data: { 'text/plain': i.toString() },
- timestamp: Date.now(),
- level: 'info'
- });
- }
- expect(model.length).toEqual(10);
- expect(model.get(0).data['text/plain']).toEqual('2');
- });
- it('setting maxLength should immediately apply and trim the message list', () => {
- for (let i = 0; i < 12; i++) {
- model.add({
- output_type: 'display_data',
- data: { 'text/plain': i.toString() },
- timestamp: Date.now(),
- level: 'info'
- });
- }
- expect(model.maxLength).toEqual(10);
- expect(model.length).toEqual(10);
- model.maxLength = 5;
- expect(model.maxLength).toEqual(5);
- expect(model.length).toEqual(5);
- expect(model.get(0).data['text/plain']).toEqual('7');
- });
- });
- });
- describe('Logger', () => {
- let logger: Logger;
- beforeEach(() => {
- logger = new Logger({ source: 'test source', maxLength: 10 });
- });
- afterEach(() => {
- logger.dispose();
- });
- describe('#constructor()', () => {
- it('should create a Logger with initial properties', () => {
- expect(logger).toBeInstanceOf(Logger);
- expect(logger.source).toEqual('test source');
- expect(logger.maxLength).toEqual(10);
- });
- });
- describe('#maxLength', () => {
- it('should set the maximum number of messages in the first-in first-out queue', () => {
- for (let i = 0; i < 12; i++) {
- logger.log({ type: 'text', data: i.toString(), level: 'critical' });
- }
- expect(logger.length).toEqual(10);
- expect(logger.outputAreaModel.get(0).data['text/plain']).toEqual('2');
- });
- it('setting maxLength should immediately apply and trim the message list', () => {
- for (let i = 0; i < 12; i++) {
- logger.log({ type: 'text', data: i.toString(), level: 'critical' });
- }
- const model = logger.outputAreaModel;
- expect(logger.maxLength).toEqual(10);
- expect(logger.length).toEqual(10);
- logger.maxLength = 5;
- expect(logger.maxLength).toEqual(5);
- expect(logger.length).toEqual(5);
- expect(model.get(0).data['text/plain']).toEqual('7');
- });
- });
- describe('#level', () => {
- const levels: LogLevel[] = [
- 'critical',
- 'error',
- 'warning',
- 'info',
- 'debug'
- ];
- it('should default to "warning"', () => {
- expect(logger.level).toEqual('warning');
- });
- it.each(levels)('filters for messages: %s', (level: LogLevel) => {
- logger.level = level;
- const messages: ILogPayload[] = levels.map(level => ({
- type: 'text',
- data: level,
- level
- }));
- messages.forEach(m => logger.log({ ...m }));
- const logged: string[] = [];
- for (let i = 0; i < logger.length; i++) {
- const msg = logger.outputAreaModel.get(i);
- logged.push(msg.level);
- }
- const shouldInclude = levels.slice(0, levels.indexOf(level) + 1);
- const shouldExclude = levels.slice(levels.indexOf(level) + 1);
- shouldInclude.forEach(x => {
- expect(logged).toContain(x);
- });
- shouldExclude.forEach(x => {
- expect(logged).not.toContain(x);
- });
- });
- it('logs a "metadata" level text message if changed', () => {
- logger.level = 'info';
- const msg = logger.outputAreaModel.get(0);
- expect(msg.level).toBe('metadata');
- expect(msg.data['text/plain']).toContain('info');
- });
- it('emits a stateChanged signal when changing', () => {
- const s = new SignalLogger(logger.stateChanged);
- logger.level = 'info';
- expect(s.args).toEqual([
- {
- name: 'level',
- oldValue: 'warning',
- newValue: 'info'
- }
- ]);
- s.dispose();
- });
- it('setting to its current value has no effect', () => {
- const s = new SignalLogger(logger.stateChanged);
- logger.level = logger.level; // eslint-disable-line
- expect(s.args.length).toBe(0);
- expect(logger.length).toBe(0);
- s.dispose();
- });
- });
- describe('#length', () => {
- it('records how many messages are stored', () => {
- logger.log({ type: 'text', data: 'message 1', level: 'warning' });
- logger.log({ type: 'text', data: 'message 2', level: 'warning' });
- expect(logger.length).toBe(2);
- logger.clear();
- expect(logger.length).toBe(0);
- });
- it('may be less than the messages logged if messages were combined', () => {
- logger.log({
- type: 'output',
- data: { output_type: 'stream', name: 'stdout', text: 'message 1' },
- level: 'critical'
- });
- logger.log({
- type: 'output',
- data: { output_type: 'stream', name: 'stdout', text: 'message 2' },
- level: 'critical'
- });
- expect(logger.length).toBe(1);
- });
- });
- describe('#rendermime', () => {
- it('initially is null', () => {
- expect(logger.rendermime).toBe(null);
- });
- it('sets the rendermime attribute', () => {
- const value = new RenderMimeRegistry();
- logger.rendermime = value;
- expect(logger.rendermime).toBe(value);
- });
- it('emits a stateChanged signal when changed', () => {
- const oldValue = (logger.rendermime = new RenderMimeRegistry());
- const newValue = oldValue.clone();
- const s = new SignalLogger(logger.stateChanged);
- logger.rendermime = newValue;
- expect(s.args).toEqual([{ name: 'rendermime', oldValue, newValue }]);
- s.dispose();
- });
- it('setting to current value has no effect', () => {
- logger.rendermime = new RenderMimeRegistry();
- const s = new SignalLogger(logger.stateChanged);
- logger.rendermime = logger.rendermime; // eslint-disable-line
- expect(s.args).toEqual([]);
- s.dispose();
- });
- });
- describe('#version', () => {
- it('starts at zero', () => {
- expect(logger.version).toBe(0);
- });
- it('increments every time a message is logged', () => {
- logger.log({ type: 'text', data: 'message 1', level: 'warning' });
- logger.log({ type: 'text', data: 'message 2', level: 'warning' });
- expect(logger.version).toBe(2);
- });
- it('increments even if messages are combined', () => {
- logger.log({
- type: 'output',
- data: { output_type: 'stream', name: 'stdout', text: 'message 1' },
- level: 'critical'
- });
- logger.log({
- type: 'output',
- data: { output_type: 'stream', name: 'stdout', text: 'message 2' },
- level: 'critical'
- });
- expect(logger.length).toBe(1);
- expect(logger.version).toBe(2);
- });
- it('does not increment on clearing messages', () => {
- logger.log({ type: 'text', data: 'message 1', level: 'warning' });
- logger.log({ type: 'text', data: 'message 2', level: 'warning' });
- expect(logger.version).toBe(2);
- logger.clear();
- expect(logger.length).toBe(0);
- expect(logger.version).toBe(2);
- });
- });
- describe('#log()', () => {
- it('logs text messages', () => {
- logger.log({ type: 'text', data: 'message', level: 'warning' });
- expect(logger.length).toBe(1);
- });
- it('logs html messages', () => {
- logger.log({ type: 'html', data: 'message', level: 'warning' });
- expect(logger.length).toBe(1);
- });
- it('logs output stream messages', () => {
- logger.log({
- type: 'output',
- data: { output_type: 'stream', name: 'stdout', text: 'message' },
- level: 'warning'
- });
- expect(logger.length).toBe(1);
- });
- it('logs display_data messages', () => {
- logger.log({
- type: 'output',
- data: {
- output_type: 'display_data',
- data: { 'text/plain': 'message' }
- },
- level: 'warning'
- });
- expect(logger.length).toBe(1);
- });
- it('logs execute_result messages', () => {
- logger.log({
- type: 'output',
- data: {
- output_type: 'execute_result',
- data: { 'text/plain': 'message', execution_count: 5 }
- },
- level: 'warning'
- });
- expect(logger.length).toBe(1);
- });
- it('logs error messages', () => {
- logger.log({
- type: 'output',
- data: {
- output_type: 'error',
- ename: 'Error',
- evalue: 'Error',
- traceback: ['level 1', 'level 2']
- },
- level: 'warning'
- });
- expect(logger.length).toBe(1);
- });
- it('emits an "append" content changed signal', () => {
- const s = new SignalLogger(logger.contentChanged);
- logger.log({ type: 'text', data: 'message 1', level: 'warning' });
- expect(s.args).toEqual(['append']);
- s.dispose();
- });
- it('emits an "append" content changed signal', () => {
- const s = new SignalLogger(logger.contentChanged);
- logger.log({
- type: 'output',
- data: { output_type: 'stream', name: 'stdout', text: 'message 1' },
- level: 'critical'
- });
- logger.log({
- type: 'output',
- data: { output_type: 'stream', name: 'stdout', text: 'message 2' },
- level: 'critical'
- });
- expect(s.args).toEqual(['append', 'append']);
- expect(logger.length).toBe(1);
- s.dispose();
- });
- it('adds a timestamp to the message', () => {
- const before = Date.now();
- logger.log({ type: 'text', data: 'message 1', level: 'warning' });
- const after = Date.now();
- const msgTime = logger.outputAreaModel.get(0).timestamp.getTime();
- expect(msgTime).toBeGreaterThanOrEqual(before);
- expect(msgTime).toBeLessThanOrEqual(after);
- });
- });
- describe('#clear()', () => {
- it('clears messages', () => {
- logger.log({ type: 'text', data: 'message 1', level: 'warning' });
- logger.log({ type: 'text', data: 'message 2', level: 'warning' });
- expect(logger.length).toBe(2);
- logger.clear();
- expect(logger.length).toBe(0);
- });
- it('emits a "clear" content changed signal', () => {
- const s = new SignalLogger(logger.contentChanged);
- logger.log({ type: 'text', data: 'message 1', level: 'warning' });
- logger.clear();
- expect(s.args).toEqual(['append', 'clear']);
- s.dispose();
- });
- });
- describe('#checkpoint()', () => {
- it('adds a metadata message to the message list', () => {
- logger.checkpoint();
- expect(logger.outputAreaModel.get(0).level).toBe('metadata');
- });
- it('emits an "append" content changed signal', () => {
- const s = new SignalLogger(logger.contentChanged);
- logger.checkpoint();
- expect(s.args).toEqual(['append']);
- s.dispose();
- });
- });
- });
|