mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Introduce Trust Book in Book Viewlet (#9414)
This commit is contained in:
@@ -7,19 +7,20 @@ import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as constants from '../common/constants';
|
||||
import * as fsw from 'fs';
|
||||
import { IPrompter, QuestionTypes, IQuestion } from '../prompts/question';
|
||||
import CodeAdapter from '../prompts/adapter';
|
||||
import { BookTreeItem } from './bookTreeItem';
|
||||
import { BookModel } from './bookModel';
|
||||
import { Deferred } from '../common/promise';
|
||||
import { IBookTrustManager, BookTrustManager } from './bookTrustManager';
|
||||
import * as loc from '../common/localizedConstants';
|
||||
import { ApiWrapper } from '../common/apiWrapper';
|
||||
|
||||
const Content = 'content';
|
||||
|
||||
export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeItem> {
|
||||
|
||||
private _onDidChangeTreeData: vscode.EventEmitter<BookTreeItem | undefined> = new vscode.EventEmitter<BookTreeItem | undefined>();
|
||||
readonly onDidChangeTreeData: vscode.Event<BookTreeItem | undefined> = this._onDidChangeTreeData.event;
|
||||
private _throttleTimer: any;
|
||||
@@ -27,21 +28,22 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
private _extensionContext: vscode.ExtensionContext;
|
||||
private prompter: IPrompter;
|
||||
private _initializeDeferred: Deferred<void> = new Deferred<void>();
|
||||
private _bookViewer: vscode.TreeView<BookTreeItem>;
|
||||
private _openAsUntitled: boolean;
|
||||
private _apiWrapper: ApiWrapper;
|
||||
private _bookTrustManager: IBookTrustManager;
|
||||
|
||||
private _bookViewer: vscode.TreeView<BookTreeItem>;
|
||||
public viewId: string;
|
||||
public books: BookModel[];
|
||||
public currentBook: BookModel;
|
||||
|
||||
constructor(apiWrapper: ApiWrapper, workspaceFolders: vscode.WorkspaceFolder[], extensionContext: vscode.ExtensionContext, openAsUntitled: boolean, view: string) {
|
||||
constructor(private _apiWrapper: ApiWrapper, workspaceFolders: vscode.WorkspaceFolder[], extensionContext: vscode.ExtensionContext, openAsUntitled: boolean, view: string) {
|
||||
this._openAsUntitled = openAsUntitled;
|
||||
this._extensionContext = extensionContext;
|
||||
this.books = [];
|
||||
this.initialize(workspaceFolders).catch(e => console.error(e));
|
||||
this.viewId = view;
|
||||
this.prompter = new CodeAdapter();
|
||||
this._apiWrapper = apiWrapper ? apiWrapper : new ApiWrapper();
|
||||
this._bookTrustManager = new BookTrustManager(this.books, _apiWrapper);
|
||||
}
|
||||
|
||||
private async initialize(workspaceFolders: vscode.WorkspaceFolder[]): Promise<void> {
|
||||
@@ -60,6 +62,28 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
return this._initializeDeferred.promise;
|
||||
}
|
||||
|
||||
get _visitedNotebooks(): string[] {
|
||||
return this._extensionContext.globalState.get(constants.visitedNotebooksMementoKey, []);
|
||||
}
|
||||
|
||||
set _visitedNotebooks(value: string[]) {
|
||||
this._extensionContext.globalState.update(constants.visitedNotebooksMementoKey, value);
|
||||
}
|
||||
|
||||
trustBook(bookTreeItem?: BookTreeItem): void {
|
||||
let bookPathToTrust = bookTreeItem ? bookTreeItem.root : this.currentBook?.bookPath;
|
||||
|
||||
if (bookPathToTrust) {
|
||||
let trustChanged = this._bookTrustManager.setBookAsTrusted(bookPathToTrust);
|
||||
|
||||
if (trustChanged) {
|
||||
this._apiWrapper.showInfoMessage(loc.msgBookTrusted);
|
||||
} else {
|
||||
this._apiWrapper.showInfoMessage(loc.msgBookAlreadyTrusted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async openBook(bookPath: string, urlToOpen?: string): Promise<void> {
|
||||
try {
|
||||
let books: BookModel[] = this.books.filter(book => book.bookPath === bookPath) || [];
|
||||
@@ -157,6 +181,19 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
if (this._openAsUntitled) {
|
||||
this.openNotebookAsUntitled(resource);
|
||||
} else {
|
||||
// let us keep a list of already visited notebooks so that we do not trust them again, potentially
|
||||
// overriding user changes
|
||||
let normalizedResource = path.normalize(resource);
|
||||
|
||||
if (this._visitedNotebooks.indexOf(normalizedResource) === -1
|
||||
&& this._bookTrustManager.isNotebookTrustedByDefault(normalizedResource)) {
|
||||
let openDocumentListenerUnsubscriber = azdata.nb.onDidOpenNotebookDocument((document: azdata.nb.NotebookDocument) => {
|
||||
document.setTrusted(true);
|
||||
this._visitedNotebooks = this._visitedNotebooks.concat([normalizedResource]);
|
||||
openDocumentListenerUnsubscriber.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
let doc = await vscode.workspace.openTextDocument(resource);
|
||||
vscode.window.showTextDocument(doc);
|
||||
}
|
||||
@@ -377,6 +414,4 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
default: false
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
114
extensions/notebook/src/book/bookTrustManager.ts
Normal file
114
extensions/notebook/src/book/bookTrustManager.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import * as constants from './../common/constants';
|
||||
import { BookTreeItem } from './bookTreeItem';
|
||||
import { BookModel } from './bookModel';
|
||||
import { ApiWrapper } from '../common/apiWrapper';
|
||||
|
||||
export interface IBookTrustManager {
|
||||
isNotebookTrustedByDefault(notebookUri: string): boolean;
|
||||
setBookAsTrusted(bookRootPath: string): boolean;
|
||||
}
|
||||
|
||||
enum TrustBookOperation {
|
||||
Add,
|
||||
Remove
|
||||
}
|
||||
|
||||
export class BookTrustManager implements IBookTrustManager {
|
||||
constructor(private books: BookModel[], private apiWrapper: ApiWrapper) { }
|
||||
|
||||
isNotebookTrustedByDefault(notebookUri: string): boolean {
|
||||
let normalizedNotebookUri: string = path.normalize(notebookUri);
|
||||
let treeBookItems: BookTreeItem[] = this.getBookTreeItems();
|
||||
let trustableBookPaths = this.getTrustableBookPaths();
|
||||
let hasTrustedBookPath: boolean = treeBookItems
|
||||
.filter(bookItem => trustableBookPaths.some(trustableBookPath => trustableBookPath === path.join(bookItem.book.root, path.sep)))
|
||||
.some(bookItem => normalizedNotebookUri.startsWith(path.join(bookItem.root, 'content', path.sep)));
|
||||
let isNotebookTrusted = hasTrustedBookPath && this.books.some(bookModel => bookModel.getNotebook(normalizedNotebookUri));
|
||||
return isNotebookTrusted;
|
||||
}
|
||||
|
||||
getTrustableBookPaths() {
|
||||
let trustablePaths: string[];
|
||||
let bookPathsInConfig: string[] = this.getTrustedBookPathsInConfig();
|
||||
|
||||
if (this.hasWorkspaceFolders()) {
|
||||
let workspaceFolders = this.apiWrapper.getWorkspaceFolders();
|
||||
|
||||
trustablePaths = bookPathsInConfig
|
||||
.map(trustableBookPath => workspaceFolders
|
||||
.map(workspaceFolder => path.join(workspaceFolder.uri.fsPath, trustableBookPath)))
|
||||
.reduce((accumulator, currentTrustableBookPaths) => accumulator.concat(currentTrustableBookPaths), []);
|
||||
|
||||
} else {
|
||||
trustablePaths = bookPathsInConfig;
|
||||
}
|
||||
|
||||
return trustablePaths;
|
||||
}
|
||||
|
||||
getBookTreeItems(): BookTreeItem[] {
|
||||
return this.books
|
||||
.map(book => book.bookItems) // select all the books
|
||||
.reduce((accumulator, currentBookItemList) => accumulator.concat(currentBookItemList), []);
|
||||
}
|
||||
|
||||
setBookAsTrusted(bookRootPath: string): boolean {
|
||||
return this.updateTrustedBooks(bookRootPath, TrustBookOperation.Add);
|
||||
}
|
||||
|
||||
getTrustedBookPathsInConfig(): string[] {
|
||||
let config: vscode.WorkspaceConfiguration = this.apiWrapper.getConfiguration(constants.notebookConfigKey);
|
||||
let trustedBookDirectories: string[] = config.get(constants.trustedBooksConfigKey);
|
||||
|
||||
return trustedBookDirectories;
|
||||
}
|
||||
|
||||
setTrustedBookPathsInConfig(bookPaths: string[]) {
|
||||
let config: vscode.WorkspaceConfiguration = this.apiWrapper.getConfiguration(constants.notebookConfigKey);
|
||||
let storeInWorspace: boolean = this.hasWorkspaceFolders();
|
||||
|
||||
config.update(constants.trustedBooksConfigKey, bookPaths, storeInWorspace ? false : vscode.ConfigurationTarget.Global);
|
||||
}
|
||||
|
||||
hasWorkspaceFolders(): boolean {
|
||||
let workspaceFolders = this.apiWrapper.getWorkspaceFolders();
|
||||
return workspaceFolders && workspaceFolders.length > 0;
|
||||
}
|
||||
|
||||
updateTrustedBooks(bookPath: string, operation: TrustBookOperation) {
|
||||
let modifiedTrustedBooks = false;
|
||||
let bookPathToChange: string = path.join(bookPath, path.sep);
|
||||
|
||||
if (this.hasWorkspaceFolders()) {
|
||||
let workspaceFolders = this.apiWrapper.getWorkspaceFolders();
|
||||
let matchingWorkspaceFolder: vscode.WorkspaceFolder = workspaceFolders
|
||||
.find(ws => bookPathToChange.startsWith(path.normalize(ws.uri.fsPath)));
|
||||
|
||||
// if notebook is stored in a workspace folder, then store only the relative directory
|
||||
if (matchingWorkspaceFolder) {
|
||||
bookPathToChange = bookPathToChange.replace(path.normalize(matchingWorkspaceFolder.uri.fsPath), '');
|
||||
}
|
||||
}
|
||||
|
||||
let trustedBooks: string[] = this.getTrustedBookPathsInConfig();
|
||||
let existingBookIndex = trustedBooks.map(trustedBookPath => path.normalize(trustedBookPath)).indexOf(bookPathToChange);
|
||||
|
||||
if (existingBookIndex !== -1 && operation === TrustBookOperation.Remove) {
|
||||
trustedBooks.splice(existingBookIndex, 1);
|
||||
modifiedTrustedBooks = true;
|
||||
} else if (existingBookIndex === -1 && operation === TrustBookOperation.Add) {
|
||||
trustedBooks.push(bookPathToChange);
|
||||
modifiedTrustedBooks = true;
|
||||
}
|
||||
|
||||
this.setTrustedBookPathsInConfig(trustedBooks);
|
||||
|
||||
return modifiedTrustedBooks;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,10 @@ import { CommandContext, BuiltInCommands } from './constants';
|
||||
* this API from our code
|
||||
*/
|
||||
export class ApiWrapper {
|
||||
public getWorkspaceFolders(): vscode.WorkspaceFolder[] {
|
||||
return [].concat(vscode.workspace.workspaceFolders || []);
|
||||
}
|
||||
|
||||
public createOutputChannel(name: string): vscode.OutputChannel {
|
||||
return vscode.window.createOutputChannel(name);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ export const pythonVersion = '3.6.6';
|
||||
export const pythonPathConfigKey = 'pythonPath';
|
||||
export const existingPythonConfigKey = 'useExistingPython';
|
||||
export const notebookConfigKey = 'notebook';
|
||||
export const trustedBooksConfigKey = 'trustedBooks';
|
||||
export const maxBookSearchDepth = 'maxBookSearchDepth';
|
||||
|
||||
export const winPlatform = 'win32';
|
||||
@@ -33,6 +34,8 @@ export const localhostName = 'localhost';
|
||||
export const localhostTitle = localize('managePackages.localhost', "localhost");
|
||||
export const PackageNotFoundError = localize('managePackages.packageNotFound', "Could not find the specified package");
|
||||
|
||||
export const visitedNotebooksMementoKey = 'notebooks.visited';
|
||||
|
||||
export enum BuiltInCommands {
|
||||
SetContext = 'setContext'
|
||||
}
|
||||
|
||||
@@ -21,8 +21,12 @@ export const confirmReplace = localize('confirmReplace', "Folder already exists.
|
||||
export const openNotebookCommand = localize('openNotebookCommand', "Open Notebook");
|
||||
export const openMarkdownCommand = localize('openMarkdownCommand', "Open Markdown");
|
||||
export const openExternalLinkCommand = localize('openExternalLinkCommand', "Open External Link");
|
||||
|
||||
export const msgBookTrusted = localize('msgBookTrusted', "Book is now trusted in the workspace.");
|
||||
export const msgBookAlreadyTrusted = localize('msgBookAlreadyTrusted', "Book is already trusted in this workspace.");
|
||||
export const msgBookUntrusted = localize('msgBookUntrusted', "Book is no longer trusted in this workspace");
|
||||
export const msgBookAlreadyUntrusted = localize('msgBookAlreadyUntrusted', "Book is already untrusted in this workspace.");
|
||||
export const missingTocError = localize('bookInitializeFailed', "Failed to find a toc.yml.");
|
||||
|
||||
export function missingFileError(title: string): string { return localize('missingFileError', "Missing file : {0}", title); }
|
||||
export function invalidTocFileError(): string { return localize('InvalidError.tocFile', "Invalid toc file"); }
|
||||
export function invalidTocError(title: string): string { return localize('Invalid toc.yml', "Error: {0} has an incorrect toc.yml file", title); }
|
||||
|
||||
@@ -36,6 +36,7 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('bookTreeView.openMarkdown', (resource) => bookTreeViewProvider.openMarkdown(resource)));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('bookTreeView.openExternalLink', (resource) => bookTreeViewProvider.openExternalLink(resource)));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.saveBook', () => untitledBookTreeViewProvider.saveJupyterBooks()));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.trustBook', (resource) => bookTreeViewProvider.trustBook(resource)));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.searchBook', (item) => bookTreeViewProvider.searchJupyterBooks(item)));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.searchUntitledBook', () => untitledBookTreeViewProvider.searchJupyterBooks()));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.openBook', () => bookTreeViewProvider.openNewBook()));
|
||||
|
||||
328
extensions/notebook/src/test/book/bookTrustManager.test.ts
Normal file
328
extensions/notebook/src/test/book/bookTrustManager.test.ts
Normal file
@@ -0,0 +1,328 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as should from 'should';
|
||||
import * as path from 'path';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as constants from '../../common/constants';
|
||||
import { IBookTrustManager, BookTrustManager } from '../../book/bookTrustManager';
|
||||
import { BookTreeItem, BookTreeItemFormat, BookTreeItemType } from '../../book/bookTreeItem';
|
||||
import { ApiWrapper } from '../../common/apiWrapper';
|
||||
import { WorkspaceConfiguration, ConfigurationTarget } from 'vscode';
|
||||
import { BookModel } from '../../book/bookModel';
|
||||
|
||||
describe('BookTrustManagerTests', function () {
|
||||
|
||||
describe('TrustingInWorkspaces', () => {
|
||||
let bookTrustManager: IBookTrustManager;
|
||||
let trustedSubFolders: string[];
|
||||
let books: BookModel[];
|
||||
|
||||
beforeEach(() => {
|
||||
trustedSubFolders = ['/SubFolder/'];
|
||||
|
||||
// Mock Workspace Configuration
|
||||
let workspaceConfigurtionMock: TypeMoq.IMock<WorkspaceConfiguration> = TypeMoq.Mock.ofType<WorkspaceConfiguration>();
|
||||
workspaceConfigurtionMock.setup(config => config.get(TypeMoq.It.isValue(constants.trustedBooksConfigKey))).returns(() => [].concat(trustedSubFolders));
|
||||
workspaceConfigurtionMock.setup(config => config.update(TypeMoq.It.isValue(constants.trustedBooksConfigKey), TypeMoq.It.isAny(), TypeMoq.It.isValue(false))).returns((key: string, newValues: string[]) => {
|
||||
trustedSubFolders.splice(0, trustedSubFolders.length, ...newValues); // Replace
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
// Mock Api Wrapper
|
||||
let apiWrapperMock: TypeMoq.IMock<ApiWrapper> = TypeMoq.Mock.ofType<ApiWrapper>();
|
||||
|
||||
apiWrapperMock.setup(api => api.getWorkspaceFolders()).returns(() => [
|
||||
{
|
||||
// @ts-ignore - Don't need all URI properties for this tests
|
||||
uri: {
|
||||
fsPath: '/temp/'
|
||||
},
|
||||
},
|
||||
{
|
||||
// @ts-ignore - Don't need all URI properties for this tests
|
||||
uri: {
|
||||
fsPath: '/temp2/'
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
||||
apiWrapperMock.setup(api => api.getConfiguration(TypeMoq.It.isValue(constants.notebookConfigKey))).returns(() => workspaceConfigurtionMock.object);
|
||||
|
||||
// Mock Book Data
|
||||
let bookTreeItemFormat1: BookTreeItemFormat = {
|
||||
root: '/temp/SubFolder/',
|
||||
tableOfContents: {
|
||||
sections: [
|
||||
{
|
||||
url: path.join(path.sep, 'sample', 'notebook')
|
||||
},
|
||||
{
|
||||
url: path.join(path.sep, 'sample', 'notebook2')
|
||||
}
|
||||
]
|
||||
},
|
||||
isUntitled: undefined,
|
||||
page: undefined,
|
||||
title: undefined,
|
||||
treeItemCollapsibleState: undefined,
|
||||
type: BookTreeItemType.Book
|
||||
};
|
||||
|
||||
let bookTreeItemFormat2: BookTreeItemFormat = {
|
||||
root: '/temp/SubFolder2/',
|
||||
tableOfContents: {
|
||||
sections: [
|
||||
{
|
||||
url: path.join(path.sep, 'sample', 'notebook')
|
||||
}
|
||||
]
|
||||
},
|
||||
isUntitled: undefined,
|
||||
page: undefined,
|
||||
title: undefined,
|
||||
treeItemCollapsibleState: undefined,
|
||||
type: BookTreeItemType.Book
|
||||
};
|
||||
|
||||
let bookTreeItemFormat3: BookTreeItemFormat = {
|
||||
root: '/temp2/SubFolder3/',
|
||||
tableOfContents: {
|
||||
sections: [
|
||||
{
|
||||
url: path.join(path.sep, 'sample', 'notebook')
|
||||
}
|
||||
]
|
||||
},
|
||||
isUntitled: undefined,
|
||||
page: undefined,
|
||||
title: undefined,
|
||||
treeItemCollapsibleState: undefined,
|
||||
type: BookTreeItemType.Book
|
||||
};
|
||||
|
||||
let bookModel1Mock: TypeMoq.IMock<BookModel> = TypeMoq.Mock.ofType<BookModel>();
|
||||
bookModel1Mock.setup(model => model.bookItems).returns(() => [new BookTreeItem(bookTreeItemFormat1, undefined), new BookTreeItem(bookTreeItemFormat2, undefined)]);
|
||||
bookModel1Mock.setup(model => model.getNotebook(TypeMoq.It.isValue(path.join(path.sep,'temp','SubFolder','content','sample', 'notebook.ipynb')))).returns((uri: string) => TypeMoq.Mock.ofType<BookTreeItem>().object);
|
||||
bookModel1Mock.setup(model => model.getNotebook(TypeMoq.It.isValue(path.join(path.sep,'temp','SubFolder','content','sample', 'notebook2.ipynb')))).returns((uri: string) => TypeMoq.Mock.ofType<BookTreeItem>().object);
|
||||
bookModel1Mock.setup(model => model.getNotebook(TypeMoq.It.isValue(path.join(path.sep,'temp','SubFolder2','content','sample', 'notebook.ipynb')))).returns((uri: string) => TypeMoq.Mock.ofType<BookTreeItem>().object);
|
||||
bookModel1Mock.setup(model => model.getNotebook(TypeMoq.It.isAnyString())).returns((uri: string) => undefined);
|
||||
|
||||
let bookModel2Mock: TypeMoq.IMock<BookModel> = TypeMoq.Mock.ofType<BookModel>();
|
||||
bookModel2Mock.setup(model => model.bookItems).returns(() => [new BookTreeItem(bookTreeItemFormat3, undefined)]);
|
||||
bookModel2Mock.setup(model => model.getNotebook(TypeMoq.It.isValue(path.join(path.sep,'temp2','SubFolder','content','sample','notebook.ipynb')))).returns((uri: string) => TypeMoq.Mock.ofType<BookTreeItem>().object);
|
||||
bookModel2Mock.setup(model => model.getNotebook(TypeMoq.It.isAnyString())).returns((uri: string) => undefined);
|
||||
|
||||
books = [bookModel1Mock.object, bookModel2Mock.object];
|
||||
|
||||
bookTrustManager = new BookTrustManager(books, apiWrapperMock.object);
|
||||
});
|
||||
|
||||
it('should trust notebooks in a trusted book within a workspace', async () => {
|
||||
let notebookUri1 = path.join(path.sep,'temp','SubFolder','content','sample', 'notebook.ipynb');
|
||||
let notebookUri2 = path.join(path.sep,'temp','SubFolder','content','sample', 'notebook2.ipynb');
|
||||
|
||||
let isNotebook1Trusted = bookTrustManager.isNotebookTrustedByDefault(notebookUri1);
|
||||
let isNotebook2Trusted = bookTrustManager.isNotebookTrustedByDefault(notebookUri2);
|
||||
|
||||
should(isNotebook1Trusted).be.true("Notebook 1 should be trusted");
|
||||
should(isNotebook2Trusted).be.true("Notebook 2 should be trusted");
|
||||
|
||||
});
|
||||
|
||||
it('should NOT trust a notebook in an untrusted book within a workspace', async () => {
|
||||
let notebookUri = path.join(path.sep,'temp','SubFolder2','content', 'sample', 'notebook.ipynb');
|
||||
let isNotebookTrusted = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrusted).be.false("Notebook should be trusted");
|
||||
});
|
||||
|
||||
it('should trust notebook after book has been trusted within a workspace', async () => {
|
||||
let notebookUri = path.join(path.sep,'temp','SubFolder2','content', 'sample', 'notebook.ipynb');
|
||||
let isNotebookTrustedBeforeChange = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrustedBeforeChange).be.false("Notebook should NOT be trusted");
|
||||
|
||||
// add another book subfolder
|
||||
bookTrustManager.setBookAsTrusted('/SubFolder2/');
|
||||
|
||||
let isNotebookTrustedAfterChange = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrustedAfterChange).be.true("Notebook should be trusted");
|
||||
});
|
||||
|
||||
it('should NOT trust a notebook when untrusting a book within a workspace', async () => {
|
||||
let notebookUri = path.join(path.sep,'temp','SubFolder','content', 'sample', 'notebook.ipynb');
|
||||
let isNotebookTrusted = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrusted).be.true("Notebook should be trusted");
|
||||
|
||||
// remove trusted subfolders
|
||||
trustedSubFolders = [];
|
||||
|
||||
let isNotebookTrustedAfterChange = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrustedAfterChange).be.false("Notebook should not be trusted after book removal");
|
||||
});
|
||||
|
||||
it('should NOT trust an unknown book within a workspace', async () => {
|
||||
let notebookUri = path.join(path.sep, 'randomfolder', 'randomsubfolder', 'content', 'randomnotebook.ipynb');
|
||||
let isNotebookTrusted = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrusted).be.false("Random notebooks should not be trusted");
|
||||
});
|
||||
|
||||
it('should NOT trust notebook inside trusted subfolder when absent in table of contents ', async () => {
|
||||
bookTrustManager.setBookAsTrusted('/temp/SubFolder/');
|
||||
|
||||
let notebookUri = path.join(path.sep, 'temp', 'SubFolder', 'content', 'sample', 'notInToc.ipynb');
|
||||
let isNotebookTrusted = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrusted).be.false("Notebook should NOT be trusted");
|
||||
});
|
||||
});
|
||||
|
||||
describe('TrustingInFolder', () => {
|
||||
|
||||
let bookTrustManager: IBookTrustManager;
|
||||
let books: BookModel[];
|
||||
let trustedFolders: string[] = [];
|
||||
|
||||
beforeEach(() => {
|
||||
// Mock Workspace Configuration
|
||||
let workspaceConfigurtionMock: TypeMoq.IMock<WorkspaceConfiguration> = TypeMoq.Mock.ofType<WorkspaceConfiguration>();
|
||||
workspaceConfigurtionMock.setup(config => config.get(TypeMoq.It.isValue(constants.trustedBooksConfigKey))).returns(() => [].concat(trustedFolders));
|
||||
workspaceConfigurtionMock.setup(config => config.update(TypeMoq.It.isValue(constants.trustedBooksConfigKey), TypeMoq.It.isAny(), TypeMoq.It.isValue(ConfigurationTarget.Global))).returns((key: string, newValues: string[], target: ConfigurationTarget) => {
|
||||
trustedFolders.splice(0, trustedFolders.length, ...newValues); // Replace
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
|
||||
// Mock Api Wrapper
|
||||
let apiWrapperMock: TypeMoq.IMock<ApiWrapper> = TypeMoq.Mock.ofType<ApiWrapper>();
|
||||
|
||||
apiWrapperMock.setup(api => api.getWorkspaceFolders()).returns(() => []);
|
||||
apiWrapperMock.setup(api => api.getConfiguration(TypeMoq.It.isValue(constants.notebookConfigKey))).returns(() => workspaceConfigurtionMock.object);
|
||||
let bookTreeItemFormat1: BookTreeItemFormat = {
|
||||
root: '/temp/SubFolder/',
|
||||
tableOfContents: {
|
||||
sections: [
|
||||
{
|
||||
url: path.join(path.sep, 'sample', 'notebook')
|
||||
},
|
||||
{
|
||||
url: path.join(path.sep, 'sample', 'notebook2')
|
||||
}
|
||||
]
|
||||
},
|
||||
isUntitled: undefined,
|
||||
page: undefined,
|
||||
title: undefined,
|
||||
treeItemCollapsibleState: undefined,
|
||||
type: BookTreeItemType.Book
|
||||
};
|
||||
|
||||
let bookTreeItemFormat2: BookTreeItemFormat = {
|
||||
root: '/temp/SubFolder2/',
|
||||
tableOfContents: {
|
||||
sections: [
|
||||
{
|
||||
url: path.join(path.sep, 'sample', 'notebook')
|
||||
},
|
||||
{
|
||||
url: path.join(path.sep, 'sample', 'notebook2')
|
||||
}
|
||||
]
|
||||
},
|
||||
isUntitled: undefined,
|
||||
page: undefined,
|
||||
title: undefined,
|
||||
treeItemCollapsibleState: undefined,
|
||||
type: BookTreeItemType.Book
|
||||
};
|
||||
|
||||
let bookModel1Mock: TypeMoq.IMock<BookModel> = TypeMoq.Mock.ofType<BookModel>();
|
||||
bookModel1Mock.setup(model => model.bookItems).returns(() => [new BookTreeItem(bookTreeItemFormat1, undefined)]);
|
||||
bookModel1Mock.setup(model => model.getNotebook(TypeMoq.It.isValue(path.join(path.sep,'temp','SubFolder','content', 'sample', 'notebook.ipynb')))).returns((uri: string) => TypeMoq.Mock.ofType<BookTreeItem>().object);
|
||||
bookModel1Mock.setup(model => model.getNotebook(TypeMoq.It.isValue(path.join(path.sep,'temp','SubFolder','content', 'sample', 'notebook2.ipynb')))).returns((uri: string) => TypeMoq.Mock.ofType<BookTreeItem>().object);
|
||||
bookModel1Mock.setup(model => model.getNotebook(TypeMoq.It.isAnyString())).returns((uri: string) => undefined);
|
||||
|
||||
let bookModel2Mock: TypeMoq.IMock<BookModel> = TypeMoq.Mock.ofType<BookModel>();
|
||||
bookModel2Mock.setup(model => model.bookItems).returns(() => [new BookTreeItem(bookTreeItemFormat2, undefined)]);
|
||||
bookModel2Mock.setup(model => model.getNotebook(TypeMoq.It.isValue(path.join(path.sep,'temp','SubFolder2','content', 'sample', 'notebook.ipynb')))).returns((uri: string) => TypeMoq.Mock.ofType<BookTreeItem>().object);
|
||||
bookModel2Mock.setup(model => model.getNotebook(TypeMoq.It.isValue(path.join(path.sep,'temp','SubFolder2','content', 'sample', 'notebook2.ipynb')))).returns((uri: string) => TypeMoq.Mock.ofType<BookTreeItem>().object);
|
||||
bookModel2Mock.setup(model => model.getNotebook(TypeMoq.It.isAnyString())).returns((uri: string) => undefined);
|
||||
|
||||
books = [bookModel1Mock.object, bookModel2Mock.object];
|
||||
|
||||
bookTrustManager = new BookTrustManager(books, apiWrapperMock.object);
|
||||
});
|
||||
|
||||
it('should trust notebooks in a trusted book in a folder', async () => {
|
||||
bookTrustManager.setBookAsTrusted('/temp/SubFolder/');
|
||||
|
||||
let notebookUri1 = path.join(path.sep,'temp','SubFolder','content', 'sample', 'notebook.ipynb');
|
||||
let notebookUri2 = path.join(path.sep,'temp','SubFolder','content', 'sample', 'notebook2.ipynb');
|
||||
|
||||
let isNotebook1Trusted = bookTrustManager.isNotebookTrustedByDefault(notebookUri1);
|
||||
let isNotebook2Trusted = bookTrustManager.isNotebookTrustedByDefault(notebookUri2);
|
||||
|
||||
should(isNotebook1Trusted).be.true("Notebook 1 should be trusted");
|
||||
should(isNotebook2Trusted).be.true("Notebook 2 should be trusted");
|
||||
|
||||
});
|
||||
|
||||
it('should NOT trust a notebook in an untrusted book in a folder', async () => {
|
||||
let notebookUri = path.join(path.sep,'temp','SubFolder2','content', 'sample', 'notebook.ipynb');
|
||||
let isNotebookTrusted = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrusted).be.false("Notebook should be trusted");
|
||||
});
|
||||
|
||||
it('should trust notebook after book has been added to a folder', async () => {
|
||||
let notebookUri = path.join(path.sep,'temp','SubFolder2','content', 'sample','notebook.ipynb');
|
||||
let isNotebookTrustedBeforeChange = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrustedBeforeChange).be.false("Notebook should NOT be trusted");
|
||||
|
||||
bookTrustManager.setBookAsTrusted('/temp/SubFolder2/');
|
||||
|
||||
let isNotebookTrustedAfterChange = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrustedAfterChange).be.true("Notebook should be trusted");
|
||||
});
|
||||
|
||||
it('should NOT trust a notebook when untrusting a book in folder', async () => {
|
||||
bookTrustManager.setBookAsTrusted('/temp/SubFolder/');
|
||||
let notebookUri = path.join(path.sep,'temp','SubFolder','content', 'sample', 'notebook.ipynb');
|
||||
let isNotebookTrusted = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrusted).be.true("Notebook should be trusted");
|
||||
|
||||
trustedFolders = [];
|
||||
|
||||
let isNotebookTrustedAfterChange = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrustedAfterChange).be.false("Notebook should not be trusted after book removal");
|
||||
});
|
||||
|
||||
it('should NOT trust an unknown book', async () => {
|
||||
let notebookUri = path.join(path.sep, 'randomfolder', 'randomsubfolder', 'content', 'randomnotebook.ipynb');
|
||||
let isNotebookTrusted = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrusted).be.false("Random notebooks should not be trusted");
|
||||
});
|
||||
|
||||
it('should NOT trust notebook inside trusted subfolder when absent in table of contents ', async () => {
|
||||
bookTrustManager.setBookAsTrusted('/temp/SubFolder/');
|
||||
|
||||
let notebookUri = path.join(path.sep, 'temp', 'SubFolder', 'content', 'sample', 'notInToc.ipynb');
|
||||
let isNotebookTrusted = bookTrustManager.isNotebookTrustedByDefault(notebookUri);
|
||||
|
||||
should(isNotebookTrusted).be.false("Notebook should NOT be trusted");
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user