这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
17e9aa7
add
akshita31 Jul 19, 2019
ea3a636
add logic to create the directory
akshita31 Jul 19, 2019
5cc75a5
copy the files
akshita31 Jul 19, 2019
1df0c75
add some logging
akshita31 Jul 19, 2019
6a348e8
merge
akshita31 Jul 19, 2019
7429fb6
clean up and add more assertions
akshita31 Jul 19, 2019
e49a6a8
merge
akshita31 Jul 19, 2019
94aba08
add interface
akshita31 Jul 20, 2019
570ba85
rename
akshita31 Jul 20, 2019
e08b06b
add test
akshita31 Jul 20, 2019
4a8ee40
add command line
akshita31 Jul 26, 2019
09010a0
refactoring to the jupyter command line
akshita31 Jul 26, 2019
645f6a5
use the directory accessor and test
akshita31 Jul 26, 2019
813addb
add the file.copy thing
akshita31 Jul 26, 2019
b084bcc
add methods to directory accessor
akshita31 Jul 29, 2019
c3c9264
move files to mls.agent and remove the environment variables stuff
akshita31 Jul 30, 2019
1551585
use python exe locattion
akshita31 Jul 30, 2019
2241c0f
pass the expected things from the test
akshita31 Jul 30, 2019
9ff64da
change the structure to use a helper
akshita31 Jul 30, 2019
e8cf00f
remove not needed copy method
akshita31 Jul 30, 2019
cdaa3a7
add the tests for helpers
akshita31 Jul 30, 2019
c405088
add ncrunch not ablr to build
akshita31 Jul 30, 2019
02a8c80
try to use the install command
akshita31 Jul 31, 2019
d08840b
add code to use the zip and the kernelspec install
akshita31 Jul 31, 2019
d29acc5
delete ununsed classes and rename
akshita31 Jul 31, 2019
0b930d5
clean up and all inmemory tests are passing
akshita31 Jul 31, 2019
b464aed
clean up
akshita31 Jul 31, 2019
01c0e9e
added a fact attribute
akshita31 Jul 31, 2019
1aaa80c
add list install
akshita31 Aug 1, 2019
6365501
add inmemory kernel specs
akshita31 Aug 1, 2019
3ad83f8
add test for the jupyter command line
akshita31 Aug 1, 2019
d374684
added the new fact attribues and all tests passing
akshita31 Aug 1, 2019
282b5f6
add the thing so that it gives error when the file is not found
akshita31 Aug 1, 2019
1209a75
clean up
akshita31 Aug 1, 2019
1c40d0a
clean up
akshita31 Aug 1, 2019
ec002a2
do not use the path, use the command directly
akshita31 Aug 1, 2019
8f77b95
clean up
akshita31 Aug 1, 2019
60c2e9f
make the test pass
akshita31 Aug 1, 2019
ae474b8
add comment
akshita31 Aug 1, 2019
68aaff5
remove async
akshita31 Aug 1, 2019
a19f7a6
make connection file optional and clean up
akshita31 Aug 1, 2019
b3b7e93
use which command to execute
akshita31 Aug 2, 2019
bb7c461
use Task.Run
akshita31 Aug 2, 2019
dc2101c
add --user
akshita31 Aug 2, 2019
af00826
skip the test
akshita31 Aug 2, 2019
b59b1f6
add timeout
akshita31 Aug 2, 2019
22b2318
rename the classes and add comment
akshita31 Aug 2, 2019
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
2 changes: 1 addition & 1 deletion MLS.Agent.Tests/CommandLine/CommandLineParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ public async Task jupyter_returns_error_if_connection_file_path_does_not_exits()
testConsole.Error.ToString().Should().Contain("File does not exist: not_exist.json");
}

[Fact]
[Fact(Skip ="Skipped until System.CommandLine allows subcommands to skip the arguments from the main command")]
public async Task jupyter_returns_error_if_connection_file_path_is_not_passed()
{
var testConsole = new TestConsole();
Expand Down
45 changes: 45 additions & 0 deletions MLS.Agent.Tests/FactDependsOnJupyterNotOnPathAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;
using System.IO;
using WorkspaceServer;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace MLS.Agent.Tests
{
[XunitTestCaseDiscoverer("MLS.Agent.Tests.JupyterNotInstalledTestCaseDiscover", "MLS.Agent.Tests")]
public class FactDependsOnJupyterNotOnPathAttribute : FactAttribute
{
}

public class JupyterNotInstalledTestCaseDiscover : IXunitTestCaseDiscoverer
{
private readonly IMessageSink messageSink;

public JupyterNotInstalledTestCaseDiscover(IMessageSink messageSink)
{
this.messageSink = messageSink;
}

public IEnumerable<IXunitTestCase> Discover(
ITestFrameworkDiscoveryOptions discoveryOptions,
ITestMethod testMethod,
IAttributeInfo factAttribute)
{
if (testMethod.TestClass.Class.Name.Contains("Integration") && FileSystemJupyterKernelSpec.CheckIfJupyterKernelSpecExists())
{
yield break;
}

yield return new XunitTestCase(
messageSink,
TestMethodDisplay.ClassAndMethod,
new TestMethodDisplayOptions(),
testMethod
);
}
}
}
45 changes: 45 additions & 0 deletions MLS.Agent.Tests/FactDependsOnJupyterOnPathAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;
using System.IO;
using WorkspaceServer;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace MLS.Agent.Tests
{
[XunitTestCaseDiscoverer("MLS.Agent.Tests.JupyterInstalledTestCaseDiscoverer", "MLS.Agent.Tests")]
public class FactDependsOnJupyterOnPathAttribute : FactAttribute
{
}

public class JupyterInstalledTestCaseDiscoverer : IXunitTestCaseDiscoverer
{
private readonly IMessageSink messageSink;

public JupyterInstalledTestCaseDiscoverer(IMessageSink messageSink)
{
this.messageSink = messageSink;
}

public IEnumerable<IXunitTestCase> Discover(
ITestFrameworkDiscoveryOptions discoveryOptions,
ITestMethod testMethod,
IAttributeInfo factAttribute)
{
if (testMethod.TestClass.Class.Name.Contains("Integration") && !FileSystemJupyterKernelSpec.CheckIfJupyterKernelSpecExists())
{
yield break;
}

yield return new XunitTestCase(
messageSink,
TestMethodDisplay.ClassAndMethod,
new TestMethodDisplayOptions(),
testMethod
);
}
}
}
39 changes: 39 additions & 0 deletions MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using MLS.Agent.Tools;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace MLS.Agent.Tests
{
public class InMemoryJupyterKernelSpec : IJupyterKernelSpec
{
private bool _successfulInstall;

public InMemoryJupyterKernelSpec(bool successfulInstall)
{
_successfulInstall = successfulInstall;
}

public Task<CommandLineResult> ExecuteCommand(string command, string args = "")
{
throw new NotImplementedException();
}

public async Task<CommandLineResult> InstallKernel(DirectoryInfo sourceDirectory)
{
if(_successfulInstall)
{
var installPath = Path.Combine(Directory.GetCurrentDirectory(), sourceDirectory.Name.ToLower());
return new CommandLineResult(0, error: new List<string> { $"[InstallKernelSpec] Installed kernelspec {sourceDirectory.Name} in {installPath}" });
}

return new CommandLineResult(1);
}
}
}
32 changes: 32 additions & 0 deletions MLS.Agent.Tests/JupyterCommandLineTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using FluentAssertions;
using System.CommandLine;
using System.Threading.Tasks;
using Xunit;

namespace MLS.Agent.Tests
{
public class JupyterCommandLineTests
{
[Fact]
public async Task Returns_error_when_jupyter_paths_could_not_be_obtained()
{
var console = new TestConsole();
var jupyterCommandLine = new JupyterCommandLine(console, new InMemoryJupyterKernelSpec(false));
await jupyterCommandLine.InvokeAsync();
console.Error.ToString().Should().Contain(".NET kernel installation failed");
}

[Fact]
public async Task Prints_to_console_when_kernel_installation_succeded()
{
var console = new TestConsole();
var jupyterCommandLine = new JupyterCommandLine(console, new InMemoryJupyterKernelSpec(true));
await jupyterCommandLine.InvokeAsync();
console.Out.ToString().Should().MatchEquivalentOf($"*[InstallKernelSpec] Installed kernelspec .net in *.net *");
console.Out.ToString().Should().Contain(".NET kernel installation succeded");
}
}
}
81 changes: 81 additions & 0 deletions MLS.Agent.Tests/JupyterKernelSpecTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using FluentAssertions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using WorkspaceServer.Tests;
using Xunit;

namespace MLS.Agent.Tests
{
public abstract class JupyterKernelSpecTests: IAsyncDisposable
{
protected List<string> _installedKernels;

public JupyterKernelSpecTests()
{
_installedKernels = new List<string>();
}

public abstract IJupyterKernelSpec GetJupyterKernelSpec(bool success);

[FactDependsOnJupyterOnPath]
public async Task Returns_sucess_output_when_kernel_installation_succeded()
{
//For the FileSystemJupyterKernelSpec, this fact needs jupyter to be on the path
//To run this test for FileSystemJupyterKernelSpec open Visual Studio inside anaconda prompt or in a terminal with
//path containing the environment variables for jupyter

var kernelSpec = GetJupyterKernelSpec(true);
var kernelDir = Create.EmptyWorkspace().Directory;

var result = await kernelSpec.InstallKernel(kernelDir);
result.ExitCode.Should().Be(0);
_installedKernels.Add(kernelDir.Name.ToLower());

//The actual jupyter instance is returning the output in the error field
result.Error.First().Should().MatchEquivalentOf($"[InstallKernelSpec] Installed kernelspec {kernelDir.Name} in *{kernelDir.Name}");
}

[FactDependsOnJupyterNotOnPath]
public async Task Returns_failure_when_kernel_installation_did_not_succeed()
{
var kernelSpec = GetJupyterKernelSpec(false);
var kernelDir = Create.EmptyWorkspace().Directory;

var result = await kernelSpec.InstallKernel(kernelDir);
result.ExitCode.Should().Be(1);
}


public async ValueTask DisposeAsync()
{
var kernelSpec = GetJupyterKernelSpec(true);
foreach (var kernel in _installedKernels)
{
await kernelSpec.ExecuteCommand("uninstall", kernel);
}
}
}

public class FileSystemJupyterKernelSpecIntegrationTests : JupyterKernelSpecTests
{

public override IJupyterKernelSpec GetJupyterKernelSpec(bool success)
{
return new FileSystemJupyterKernelSpec();
}
}

public class InMemoryJupyterKernelSpecTests : JupyterKernelSpecTests
{
public override IJupyterKernelSpec GetJupyterKernelSpec(bool success)
{
return new InMemoryJupyterKernelSpec(success);
}
}
}
11 changes: 10 additions & 1 deletion MLS.Agent/CommandLine/CommandLineParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,8 @@ Command Jupyter()
};
var connectionFileArgument = new Argument<FileInfo>
{
Name = "ConnectionFile"
Name = "ConnectionFile",
Arity = ArgumentArity.ZeroOrOne //should be removed once the commandlineapi allows subcommands to not have arguments from the main command
}.ExistingOnly();
jupyterCommand.AddArgument(connectionFileArgument);

Expand Down Expand Up @@ -392,6 +393,14 @@ Command Jupyter()
return jupyter(options, console, startServer, context);
});

var installCommand = new Command("install", "Install the .NET kernel for Jupyter");
installCommand.Handler = CommandHandler.Create<IConsole>((console) =>
{
return new JupyterCommandLine(console, new FileSystemJupyterKernelSpec()).InvokeAsync();
});

jupyterCommand.AddCommand(installCommand);

return jupyterCommand;
}

Expand Down
44 changes: 44 additions & 0 deletions MLS.Agent/FileSystemJupyterKernelSpec.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using MLS.Agent.Tools;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Clockwise;

namespace MLS.Agent
{
public class FileSystemJupyterKernelSpec : IJupyterKernelSpec
{
public async Task<CommandLineResult> ExecuteCommand(string command, string args = "")
{
if (!CheckIfJupyterKernelSpecExists())
{
return new CommandLineResult(1, new List<string>() { "Could not find jupyter kernelspec module" });
}

return await Tools.CommandLine.Execute("jupyter", $"kernelspec {command} {args}");
}

public Task<CommandLineResult> InstallKernel(DirectoryInfo sourceDirectory)
{
return ExecuteCommand($"install {sourceDirectory.FullName}", "--user");
}

public static bool CheckIfJupyterKernelSpecExists()
{
var command = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "where" : "which";
bool jupyterKernelSpecExists = false ;

Task.Run(async ()=> {
var result = await Tools.CommandLine.Execute(command, "jupyter-kernelspec");
jupyterKernelSpecExists = result.ExitCode == 0;
}).Wait(2000);

return jupyterKernelSpecExists;
}
}
}
16 changes: 16 additions & 0 deletions MLS.Agent/IJupyterKernelSpec.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using MLS.Agent.Tools;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace MLS.Agent
{
public interface IJupyterKernelSpec
{
Task<CommandLineResult> ExecuteCommand(string command, string args="");
Task<CommandLineResult> InstallKernel(DirectoryInfo sourceDirectory);
}
}
Loading