diff --git a/src/AzureClient/AzureClient.cs b/src/AzureClient/AzureClient.cs
index ee639ec3e8..a282d18788 100644
--- a/src/AzureClient/AzureClient.cs
+++ b/src/AzureClient/AzureClient.cs
@@ -5,18 +5,20 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.IO;
+using System.Linq;
using System.Threading.Tasks;
+using Microsoft.Azure.Quantum;
using Microsoft.Azure.Quantum.Client;
+using Microsoft.Azure.Quantum.Client.Models;
+using Microsoft.Azure.Quantum.Storage;
+using Microsoft.Extensions.Logging;
using Microsoft.Identity.Client;
using Microsoft.Identity.Client.Extensions.Msal;
using Microsoft.Jupyter.Core;
-using Microsoft.Quantum.Simulation.Core;
+using Microsoft.Quantum.IQSharp.Common;
+using Microsoft.Quantum.Simulation.Common;
using Microsoft.Rest.Azure;
-using Microsoft.Azure.Quantum.Client.Models;
-using Microsoft.Azure.Quantum.Storage;
-using Microsoft.Azure.Quantum;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -25,6 +27,9 @@ namespace Microsoft.Quantum.IQSharp.AzureClient
///
public class AzureClient : IAzureClient
{
+ private ILogger Logger { get; }
+ private IReferences References { get; }
+ private IEntryPointGenerator EntryPointGenerator { get; }
private string ConnectionString { get; set; } = string.Empty;
private AzureExecutionTarget? ActiveTarget { get; set; }
private AuthenticationResult? AuthenticationResult { get; set; }
@@ -41,10 +46,20 @@ private string ValidExecutionTargetsDisplayText
: string.Join(", ", ValidExecutionTargets.Select(target => target.Id));
}
+ public AzureClient(
+ IReferences references,
+ IEntryPointGenerator entryPointGenerator,
+ ILogger logger,
+ IEventService eventService)
+ {
+ References = references;
+ EntryPointGenerator = entryPointGenerator;
+ Logger = logger;
+ eventService?.TriggerServiceInitialized(this);
+ }
///
- public async Task ConnectAsync(
- IChannel channel,
+ public async Task ConnectAsync(IChannel channel,
string subscriptionId,
string resourceGroupName,
string workspaceName,
@@ -127,7 +142,7 @@ public async Task ConnectAsync(
}
catch (Exception e)
{
- channel.Stderr(e.ToString());
+ Logger?.LogError(e, $"Failed to download providers list from Azure Quantum workspace: {e.Message}");
return AzureClientError.WorkspaceNotFound.ToExecutionResult();
}
@@ -151,11 +166,7 @@ public async Task GetConnectionStatusAsync(IChannel channel)
return ValidExecutionTargets.ToJupyterTable().ToExecutionResult();
}
- private async Task SubmitOrExecuteJobAsync(
- IChannel channel,
- IOperationResolver operationResolver,
- string operationName,
- bool execute)
+ private async Task SubmitOrExecuteJobAsync(IChannel channel, string operationName, Dictionary inputParameters, bool execute)
{
if (ActiveWorkspace == null)
{
@@ -176,7 +187,7 @@ private async Task SubmitOrExecuteJobAsync(
return AzureClientError.NoOperationName.ToExecutionResult();
}
- var machine = Azure.Quantum.QuantumMachineFactory.CreateMachine(ActiveWorkspace, ActiveTarget.TargetName, ConnectionString);
+ var machine = QuantumMachineFactory.CreateMachine(ActiveWorkspace, ActiveTarget.TargetName, ConnectionString);
if (machine == null)
{
// We should never get here, since ActiveTarget should have already been validated at the time it was set.
@@ -184,49 +195,81 @@ private async Task SubmitOrExecuteJobAsync(
return AzureClientError.InvalidTarget.ToExecutionResult();
}
- var operationInfo = operationResolver.Resolve(operationName);
- var entryPointInfo = new EntryPointInfo(operationInfo.RoslynType);
- var entryPointInput = QVoid.Instance;
+ channel.Stdout($"Submitting {operationName} to target {ActiveTarget.TargetName}...");
- if (execute)
+ IEntryPoint? entryPoint = null;
+ try
{
- channel.Stdout($"Executing {operationName} on target {ActiveTarget.TargetName}...");
- var output = await machine.ExecuteAsync(entryPointInfo, entryPointInput);
- MostRecentJobId = output.Job.Id;
-
- // TODO: Add encoder to visualize IEnumerable>
- return output.Histogram.ToExecutionResult();
+ entryPoint = EntryPointGenerator.Generate(operationName, ActiveTarget.TargetName);
}
- else
+ catch (UnsupportedOperationException e)
{
- channel.Stdout($"Submitting {operationName} to target {ActiveTarget.TargetName}...");
- var job = await machine.SubmitAsync(entryPointInfo, entryPointInput);
- channel.Stdout($"Job {job.Id} submitted successfully.");
+ channel.Stderr($"{operationName} is not a recognized Q# operation name.");
+ return AzureClientError.UnrecognizedOperationName.ToExecutionResult();
+ }
+ catch (CompilationErrorsException e)
+ {
+ channel.Stderr($"The Q# operation {operationName} could not be compiled as an entry point for job execution.");
+ foreach (var message in e.Errors) channel.Stderr(message);
+ return AzureClientError.InvalidEntryPoint.ToExecutionResult();
+ }
+ try
+ {
+ var job = await entryPoint.SubmitAsync(machine, inputParameters);
+ channel.Stdout($"Job {job.Id} submitted successfully.");
MostRecentJobId = job.Id;
+ }
+ catch (ArgumentException e)
+ {
+ channel.Stderr($"Failed to parse all expected parameters for Q# operation {operationName}.");
+ channel.Stderr(e.Message);
+ return AzureClientError.JobSubmissionFailed.ToExecutionResult();
+ }
+ catch (Exception e)
+ {
+ channel.Stderr($"Failed to submit Q# operation {operationName} for execution.");
+ channel.Stderr(e.InnerException?.Message ?? e.Message);
+ return AzureClientError.JobSubmissionFailed.ToExecutionResult();
+ }
- // TODO: Add encoder for IQuantumMachineJob rather than calling ToJupyterTable() here.
- return job.ToJupyterTable().ToExecutionResult();
+ if (!execute)
+ {
+ return await GetJobStatusAsync(channel, MostRecentJobId);
}
+
+ var timeoutInSeconds = 30;
+ channel.Stdout($"Waiting up to {timeoutInSeconds} seconds for Azure Quantum job to complete...");
+
+ using (var cts = new System.Threading.CancellationTokenSource(TimeSpan.FromSeconds(30)))
+ {
+ CloudJob? cloudJob = null;
+ do
+ {
+ // TODO: Once jupyter-core supports interrupt requests (https://github.com/microsoft/jupyter-core/issues/55),
+ // handle Jupyter kernel interrupt here and break out of this loop
+ var pollingIntervalInSeconds = 5;
+ await Task.Delay(TimeSpan.FromSeconds(pollingIntervalInSeconds));
+ if (cts.IsCancellationRequested) break;
+ cloudJob = await GetCloudJob(MostRecentJobId);
+ channel.Stdout($"[{DateTime.Now.ToLongTimeString()}] Current job status: {cloudJob?.Status ?? "Unknown"}");
+ }
+ while (cloudJob == null || cloudJob.InProgress);
+ }
+
+ return await GetJobResultAsync(channel, MostRecentJobId);
}
///
- public async Task SubmitJobAsync(
- IChannel channel,
- IOperationResolver operationResolver,
- string operationName) =>
- await SubmitOrExecuteJobAsync(channel, operationResolver, operationName, execute: false);
+ public async Task SubmitJobAsync(IChannel channel, string operationName, Dictionary inputParameters) =>
+ await SubmitOrExecuteJobAsync(channel, operationName, inputParameters, execute: false);
///
- public async Task ExecuteJobAsync(
- IChannel channel,
- IOperationResolver operationResolver,
- string operationName) =>
- await SubmitOrExecuteJobAsync(channel, operationResolver, operationName, execute: true);
+ public async Task ExecuteJobAsync(IChannel channel, string operationName, Dictionary inputParameters) =>
+ await SubmitOrExecuteJobAsync(channel, operationName, inputParameters, execute: true);
///
- public async Task GetActiveTargetAsync(
- IChannel channel)
+ public async Task GetActiveTargetAsync(IChannel channel)
{
if (AvailableProviders == null)
{
@@ -247,10 +290,7 @@ public async Task GetActiveTargetAsync(
}
///
- public async Task SetActiveTargetAsync(
- IChannel channel,
- IReferences references,
- string targetName)
+ public async Task SetActiveTargetAsync(IChannel channel, string targetName)
{
if (AvailableProviders == null)
{
@@ -279,15 +319,13 @@ public async Task SetActiveTargetAsync(
ActiveTarget = executionTarget;
channel.Stdout($"Loading package {ActiveTarget.PackageName} and dependencies...");
- await references.AddPackage(ActiveTarget.PackageName);
+ await References.AddPackage(ActiveTarget.PackageName);
return $"Active target is now {ActiveTarget.TargetName}".ToExecutionResult();
}
///
- public async Task GetJobResultAsync(
- IChannel channel,
- string jobId)
+ public async Task GetJobResultAsync(IChannel channel, string jobId)
{
if (ActiveWorkspace == null)
{
@@ -306,7 +344,7 @@ public async Task GetJobResultAsync(
jobId = MostRecentJobId;
}
- var job = ActiveWorkspace.GetJob(jobId);
+ var job = await GetCloudJob(jobId);
if (job == null)
{
channel.Stderr($"Job ID {jobId} not found in current Azure Quantum workspace.");
@@ -335,9 +373,7 @@ public async Task GetJobResultAsync(
}
///
- public async Task GetJobStatusAsync(
- IChannel channel,
- string jobId)
+ public async Task GetJobStatusAsync(IChannel channel, string jobId)
{
if (ActiveWorkspace == null)
{
@@ -356,20 +392,19 @@ public async Task GetJobStatusAsync(
jobId = MostRecentJobId;
}
- var job = ActiveWorkspace.GetJob(jobId);
+ var job = await GetCloudJob(jobId);
if (job == null)
{
channel.Stderr($"Job ID {jobId} not found in current Azure Quantum workspace.");
return AzureClientError.JobNotFound.ToExecutionResult();
}
- // TODO: Add encoder for CloudJob which calls ToJupyterTable() for display.
- return job.Details.ToExecutionResult();
+ // TODO: Add encoder for CloudJob rather than calling ToJupyterTable() here directly.
+ return job.ToJupyterTable().ToExecutionResult();
}
///
- public async Task GetJobListAsync(
- IChannel channel)
+ public async Task GetJobListAsync(IChannel channel)
{
if (ActiveWorkspace == null)
{
@@ -377,7 +412,7 @@ public async Task GetJobListAsync(
return AzureClientError.NotConnected.ToExecutionResult();
}
- var jobs = ActiveWorkspace.ListJobs();
+ var jobs = await GetCloudJobs();
if (jobs == null || jobs.Count() == 0)
{
channel.Stderr("No jobs found in current Azure Quantum workspace.");
@@ -385,7 +420,35 @@ public async Task GetJobListAsync(
}
// TODO: Add encoder for IEnumerable rather than calling ToJupyterTable() here directly.
- return jobs.Select(job => job.Details).ToJupyterTable().ToExecutionResult();
+ return jobs.ToJupyterTable().ToExecutionResult();
+ }
+
+ private async Task GetCloudJob(string jobId)
+ {
+ try
+ {
+ return await ActiveWorkspace.GetJobAsync(jobId);
+ }
+ catch (Exception e)
+ {
+ Logger?.LogError(e, $"Failed to retrieve the specified Azure Quantum job: {e.Message}");
+ }
+
+ return null;
+ }
+
+ private async Task?> GetCloudJobs()
+ {
+ try
+ {
+ return await ActiveWorkspace.ListJobsAsync();
+ }
+ catch (Exception e)
+ {
+ Logger?.LogError(e, $"Failed to retrieve the list of jobs from the Azure Quantum workspace: {e.Message}");
+ }
+
+ return null;
}
}
}
diff --git a/src/AzureClient/AzureClient.csproj b/src/AzureClient/AzureClient.csproj
index b2fc4b4554..995ae372bb 100644
--- a/src/AzureClient/AzureClient.csproj
+++ b/src/AzureClient/AzureClient.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/src/AzureClient/EntryPoint/EntryPoint.cs b/src/AzureClient/EntryPoint/EntryPoint.cs
new file mode 100644
index 0000000000..407f29d0d5
--- /dev/null
+++ b/src/AzureClient/EntryPoint/EntryPoint.cs
@@ -0,0 +1,90 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.Quantum.Runtime;
+using Microsoft.Quantum.Simulation.Core;
+
+namespace Microsoft.Quantum.IQSharp.AzureClient
+{
+ ///
+ internal class EntryPoint : IEntryPoint
+ {
+ private object EntryPointInfo { get; }
+ private Type InputType { get; }
+ private Type OutputType { get; }
+ private OperationInfo OperationInfo { get; }
+
+ ///
+ /// Creates an object used to submit jobs to Azure Quantum.
+ ///
+ /// Must be an object with type
+ /// parameters specified by the types in the entryPointInputbeginWords argument.
+ /// Specifies the input parameter type for the
+ /// object provided as the entryPointInfo argument.
+ /// Specifies the output parameter type for the
+ /// object provided as the entryPointInfo argument.
+ /// Information about the Q# operation to be used as the entry point.
+ public EntryPoint(object entryPointInfo, Type inputType, Type outputType, OperationInfo operationInfo)
+ {
+ EntryPointInfo = entryPointInfo;
+ InputType = inputType;
+ OutputType = outputType;
+ OperationInfo = operationInfo;
+ }
+
+ ///
+ public Task SubmitAsync(IQuantumMachine machine, Dictionary inputParameters)
+ {
+ var parameterTypes = new List();
+ var parameterValues = new List
diff --git a/src/Core/Loggers/QsharpLogger.cs b/src/Core/Loggers/QsharpLogger.cs
index 247227fc72..6afbb7ebb9 100644
--- a/src/Core/Loggers/QsharpLogger.cs
+++ b/src/Core/Loggers/QsharpLogger.cs
@@ -22,13 +22,12 @@ public class QSharpLogger : QsCompiler.Diagnostics.LogTracker
public List Logs { get; }
- public List ErrorCodesToIgnore { get; }
+ public List ErrorCodesToIgnore { get; } = new List();
- public QSharpLogger(ILogger logger, List errorCodesToIgnore = null)
+ public QSharpLogger(ILogger logger)
{
this.Logger = logger;
this.Logs = new List();
- this.ErrorCodesToIgnore = errorCodesToIgnore ?? new List();
}
public static LogLevel MapLevel(LSP.DiagnosticSeverity original)
diff --git a/src/Core/OperationInfo.cs b/src/Core/OperationInfo.cs
index caaeddbd5b..ebb9141f04 100644
--- a/src/Core/OperationInfo.cs
+++ b/src/Core/OperationInfo.cs
@@ -26,12 +26,14 @@ public class OperationInfo
{
private Lazy> _params;
private Lazy _roslynParams;
+ private Lazy _returnType;
internal OperationInfo(Type roslynType, CallableDeclarationHeader header)
{
this.Header = header ?? throw new ArgumentNullException(nameof(header));
RoslynType = roslynType;
_roslynParams = new Lazy(() => RoslynType?.GetMethod("Run").GetParameters().Skip(1).ToArray());
+ _returnType = new Lazy(() => RoslynType?.GetMethod("Run").ReturnType.GenericTypeArguments.Single());
_params = new Lazy>(() => RoslynParameters?.ToDictionary(p => p.Name, p => p.ParameterType.Name));
}
@@ -60,6 +62,12 @@ internal OperationInfo(Type roslynType, CallableDeclarationHeader header)
[JsonIgnore]
public ParameterInfo[] RoslynParameters => _roslynParams.Value;
+ ///
+ /// The return type for the underlying compiled .NET Type for this Q# operation
+ ///
+ [JsonIgnore]
+ public Type ReturnType => _returnType.Value;
+
public override string ToString() => FullName;
}
diff --git a/src/Core/Resolver/OperationResolver.cs b/src/Core/Resolver/OperationResolver.cs
index 8be04f2933..2bf52f5b16 100644
--- a/src/Core/Resolver/OperationResolver.cs
+++ b/src/Core/Resolver/OperationResolver.cs
@@ -71,11 +71,12 @@ private IEnumerable RelevantAssemblies()
/// Symbol names without a dot are resolved to the first symbol
/// whose base name matches the given name.
///
- public OperationInfo Resolve(string name)
+ public OperationInfo Resolve(string name) => ResolveFromAssemblies(name, RelevantAssemblies());
+
+ public static OperationInfo ResolveFromAssemblies(string name, IEnumerable assemblies)
{
var isQualified = name.Contains('.');
- var relevant = RelevantAssemblies();
- foreach (var operation in relevant.SelectMany(asm => asm.Operations))
+ foreach (var operation in assemblies.SelectMany(asm => asm.Operations))
{
if (name == (isQualified ? operation.FullName : operation.Header.QualifiedName.Name.Value))
{
diff --git a/src/Core/Snippets/ISnippets.cs b/src/Core/Snippets/ISnippets.cs
index f8393cb6b3..60e52fb2ea 100644
--- a/src/Core/Snippets/ISnippets.cs
+++ b/src/Core/Snippets/ISnippets.cs
@@ -55,6 +55,11 @@ public interface ISnippets
///
AssemblyInfo AssemblyInfo { get; }
+ ///
+ /// The list of currently available snippets.
+ ///
+ IEnumerable Items { get; set; }
+
///
/// Adds or updates a snippet of code. If successful, this updates the AssemblyInfo
/// with the new operations found in the Snippet and returns a new Snippet
diff --git a/src/Core/Snippets/Snippets.cs b/src/Core/Snippets/Snippets.cs
index bf3f0cf189..f6afa05204 100644
--- a/src/Core/Snippets/Snippets.cs
+++ b/src/Core/Snippets/Snippets.cs
@@ -104,7 +104,7 @@ private void OnWorkspaceReloaded(object sender, ReloadedEventArgs e)
///
/// The list of currently available snippets.
///
- internal IEnumerable Items { get; set; }
+ public IEnumerable Items { get; set; }
///
/// The list of Q# operations available across all snippets.
@@ -144,11 +144,7 @@ public Snippet Compile(string code)
if (string.IsNullOrWhiteSpace(code)) throw new ArgumentNullException(nameof(code));
var duration = Stopwatch.StartNew();
- var errorCodesToIgnore = new List()
- {
- QsCompiler.Diagnostics.ErrorCode.EntryPointInLibrary, // Ignore any @EntryPoint() attributes found in snippets.
- };
- var logger = new QSharpLogger(Logger, errorCodesToIgnore);
+ var logger = new QSharpLogger(Logger);
try
{
diff --git a/src/Core/Workspace/IWorkspace.cs b/src/Core/Workspace/IWorkspace.cs
index 4bc0e806ca..f950f1ca79 100644
--- a/src/Core/Workspace/IWorkspace.cs
+++ b/src/Core/Workspace/IWorkspace.cs
@@ -64,6 +64,11 @@ public interface IWorkspace
///
string Root { get; }
+ ///
+ /// Gets the source files to be built for this Workspace.
+ ///
+ public IEnumerable SourceFiles { get; }
+
///
/// The folder where the assembly is permanently saved for cache.
///
diff --git a/src/Tests/AzureClientEntryPointTests.cs b/src/Tests/AzureClientEntryPointTests.cs
new file mode 100644
index 0000000000..3aba6eb27a
--- /dev/null
+++ b/src/Tests/AzureClientEntryPointTests.cs
@@ -0,0 +1,184 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Quantum.IQSharp;
+using Microsoft.Quantum.IQSharp.AzureClient;
+using Microsoft.Quantum.IQSharp.Common;
+using Microsoft.Quantum.Runtime;
+using Microsoft.Quantum.Simulation.Common;
+using Microsoft.Quantum.Simulation.Core;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Tests.IQSharp
+{
+ [TestClass]
+ public class AzureClientEntryPointTests
+ {
+ private IEntryPointGenerator Init(string workspace, IEnumerable? codeSnippets = null)
+ {
+ var services = Startup.CreateServiceProvider(workspace);
+
+ if (codeSnippets != null)
+ {
+ var snippets = services.GetService();
+ snippets.Items = codeSnippets.Select(codeSnippet => new Snippet() { code = codeSnippet });
+ }
+
+ return services.GetService();
+ }
+
+ [TestMethod]
+ public async Task FromSnippet()
+ {
+ var entryPointGenerator = Init("Workspace", new string[] { SNIPPETS.HelloQ });
+ var entryPoint = entryPointGenerator.Generate("HelloQ", null);
+ Assert.IsNotNull(entryPoint);
+
+ var job = await entryPoint.SubmitAsync(new MockQuantumMachine(), new Dictionary());
+ Assert.IsNotNull(job);
+ }
+
+ [TestMethod]
+ public async Task FromBrokenSnippet()
+ {
+ var entryPointGenerator = Init("Workspace", new string[] { SNIPPETS.TwoErrors });
+ Assert.ThrowsException(() =>
+ entryPointGenerator.Generate("TwoErrors", null));
+ }
+
+ [TestMethod]
+ public async Task FromWorkspace()
+ {
+ var entryPointGenerator = Init("Workspace");
+ var entryPoint = entryPointGenerator.Generate("Tests.qss.HelloAgain", null);
+ Assert.IsNotNull(entryPoint);
+
+ var job = await entryPoint.SubmitAsync(new MockQuantumMachine(), new Dictionary() { { "count", "2" }, { "name", "test" } } );
+ Assert.IsNotNull(job);
+ }
+
+ [TestMethod]
+ public async Task FromWorkspaceMissingArgument()
+ {
+ var entryPointGenerator = Init("Workspace");
+ var entryPoint = entryPointGenerator.Generate("Tests.qss.HelloAgain", null);
+ Assert.IsNotNull(entryPoint);
+
+ Assert.ThrowsException(() =>
+ entryPoint.SubmitAsync(new MockQuantumMachine(), new Dictionary() { { "count", "2" } }));
+ }
+
+ [TestMethod]
+ public async Task FromWorkspaceIncorrectArgumentType()
+ {
+ var entryPointGenerator = Init("Workspace");
+ var entryPoint = entryPointGenerator.Generate("Tests.qss.HelloAgain", null);
+ Assert.IsNotNull(entryPoint);
+
+ Assert.ThrowsException(() =>
+ entryPoint.SubmitAsync(new MockQuantumMachine(), new Dictionary() { { "count", "NaN" }, { "name", "test" } }));
+ }
+
+ [TestMethod]
+ public async Task FromBrokenWorkspace()
+ {
+ var entryPointGenerator = Init("Workspace.Broken");
+ Assert.ThrowsException(() =>
+ entryPointGenerator.Generate("Tests.qss.HelloAgain", null));
+ }
+
+ [TestMethod]
+ public async Task FromSnippetDependsOnWorkspace()
+ {
+ var entryPointGenerator = Init("Workspace", new string[] { SNIPPETS.DependsOnWorkspace });
+ var entryPoint = entryPointGenerator.Generate("DependsOnWorkspace", null);
+ Assert.IsNotNull(entryPoint);
+
+ var job = await entryPoint.SubmitAsync(new MockQuantumMachine(), new Dictionary());
+ Assert.IsNotNull(job);
+ }
+
+ [TestMethod]
+ public async Task InvalidOperationName()
+ {
+ var entryPointGenerator = Init("Workspace");
+ Assert.ThrowsException(() =>
+ entryPointGenerator.Generate("InvalidOperationName", null));
+ }
+
+ [TestMethod]
+ public async Task InvalidEntryPointOperation()
+ {
+ var entryPointGenerator = Init("Workspace", new string[] { SNIPPETS.InvalidEntryPoint });
+ Assert.ThrowsException(() =>
+ entryPointGenerator.Generate("InvalidEntryPoint", null));
+ }
+ }
+
+ public class MockQuantumMachine : IQuantumMachine
+ {
+ public string ProviderId => throw new NotImplementedException();
+
+ public string Target => throw new NotImplementedException();
+
+ public Task> ExecuteAsync(EntryPointInfo info, TInput input)
+ => ExecuteAsync(info, input, null as IQuantumMachineSubmissionContext);
+
+ public Task> ExecuteAsync(EntryPointInfo info, TInput input, IQuantumMachineSubmissionContext submissionContext)
+ => ExecuteAsync(info, input, submissionContext, null as IQuantumMachine.ConfigureJob);
+
+ public Task> ExecuteAsync(EntryPointInfo info, TInput input, IQuantumMachineSubmissionContext submissionContext, IQuantumMachine.ConfigureJob configureJobCallback)
+ => ExecuteAsync(info, input, submissionContext, null, configureJobCallback);
+
+ public Task> ExecuteAsync(EntryPointInfo info, TInput input, IQuantumMachineExecutionContext executionContext)
+ => ExecuteAsync(info, input, null as IQuantumMachineExecutionContext);
+
+ public Task> ExecuteAsync(EntryPointInfo info, TInput input, IQuantumMachineExecutionContext executionContext, IQuantumMachine.ConfigureJob configureJobCallback)
+ => ExecuteAsync(info, input, executionContext, null as IQuantumMachine.ConfigureJob);
+
+ public Task> ExecuteAsync(EntryPointInfo info, TInput input, IQuantumMachineSubmissionContext submissionContext, IQuantumMachineExecutionContext executionContext)
+ => ExecuteAsync(info, input, submissionContext, executionContext, null);
+
+ public Task> ExecuteAsync(EntryPointInfo info, TInput input, IQuantumMachineSubmissionContext submissionContext, IQuantumMachineExecutionContext executionContext, IQuantumMachine.ConfigureJob configureJobCallback)
+ => throw new NotImplementedException();
+
+ public Task SubmitAsync(EntryPointInfo info, TInput input)
+ => SubmitAsync(info, input, null);
+
+ public Task SubmitAsync(EntryPointInfo info, TInput input, IQuantumMachineSubmissionContext submissionContext)
+ => SubmitAsync(info, input, null, null);
+
+ public Task SubmitAsync(EntryPointInfo info, TInput input, IQuantumMachineSubmissionContext submissionContext, IQuantumMachine.ConfigureJob configureJobCallback)
+ => Task.FromResult(new MockQuantumMachineJob() as IQuantumMachineJob);
+
+ public (bool IsValid, string Message) Validate(EntryPointInfo info, TInput input)
+ => throw new NotImplementedException();
+ }
+
+ public class MockQuantumMachineJob : IQuantumMachineJob
+ {
+ public bool Failed => throw new NotImplementedException();
+
+ public string Id => throw new NotImplementedException();
+
+ public bool InProgress => throw new NotImplementedException();
+
+ public string Status => throw new NotImplementedException();
+
+ public bool Succeeded => throw new NotImplementedException();
+
+ public Uri Uri => throw new NotImplementedException();
+
+ public Task CancelAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException();
+
+ public Task RefreshAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException();
+ }
+}
diff --git a/src/Tests/AzureClientMagicTests.cs b/src/Tests/AzureClientMagicTests.cs
index fbbc880253..a45f1eb6c0 100644
--- a/src/Tests/AzureClientMagicTests.cs
+++ b/src/Tests/AzureClientMagicTests.cs
@@ -85,8 +85,7 @@ public void TestSubmitMagic()
{
// no arguments
var azureClient = new MockAzureClient();
- var operationResolver = new MockOperationResolver();
- var submitMagic = new SubmitMagic(operationResolver, azureClient);
+ var submitMagic = new SubmitMagic(azureClient);
submitMagic.Test(string.Empty);
Assert.AreEqual(azureClient.LastAction, AzureClientAction.SubmitJob);
@@ -101,8 +100,7 @@ public void TestExecuteMagic()
{
// no arguments
var azureClient = new MockAzureClient();
- var operationResolver = new MockOperationResolver();
- var executeMagic = new ExecuteMagic(operationResolver, azureClient);
+ var executeMagic = new ExecuteMagic(azureClient);
executeMagic.Test(string.Empty);
Assert.AreEqual(azureClient.LastAction, AzureClientAction.ExecuteJob);
@@ -141,19 +139,15 @@ public void TestJobsMagic()
[TestMethod]
public void TestTargetMagic()
{
- var workspace = "Workspace";
- var services = Startup.CreateServiceProvider(workspace);
- var references = services.GetService();
-
// single argument - should set active target
var azureClient = new MockAzureClient();
- var targetMagic = new TargetMagic(azureClient, references);
+ var targetMagic = new TargetMagic(azureClient);
targetMagic.Test(targetName);
Assert.AreEqual(azureClient.LastAction, AzureClientAction.SetActiveTarget);
// no arguments - should print active target
azureClient = new MockAzureClient();
- targetMagic = new TargetMagic(azureClient, references);
+ targetMagic = new TargetMagic(azureClient);
targetMagic.Test(string.Empty);
Assert.AreEqual(azureClient.LastAction, AzureClientAction.GetActiveTarget);
}
@@ -182,7 +176,7 @@ public class MockAzureClient : IAzureClient
internal List SubmittedJobs = new List();
internal List ExecutedJobs = new List();
- public async Task SetActiveTargetAsync(IChannel channel, IReferences references, string targetName)
+ public async Task SetActiveTargetAsync(IChannel channel, string targetName)
{
LastAction = AzureClientAction.SetActiveTarget;
ActiveTargetName = targetName;
@@ -194,14 +188,14 @@ public async Task GetActiveTargetAsync(IChannel channel)
return ActiveTargetName.ToExecutionResult();
}
- public async Task SubmitJobAsync(IChannel channel, IOperationResolver operationResolver, string operationName)
+ public async Task SubmitJobAsync(IChannel channel, string operationName, Dictionary inputParameters)
{
LastAction = AzureClientAction.SubmitJob;
SubmittedJobs.Add(operationName);
return ExecuteStatus.Ok.ToExecutionResult();
}
- public async Task ExecuteJobAsync(IChannel channel, IOperationResolver operationResolver, string operationName)
+ public async Task ExecuteJobAsync(IChannel channel, string operationName, Dictionary inputParameters)
{
LastAction = AzureClientAction.ExecuteJob;
ExecutedJobs.Add(operationName);
diff --git a/src/Tests/AzureClientTests.cs b/src/Tests/AzureClientTests.cs
index af75ade1b8..2044b2116a 100644
--- a/src/Tests/AzureClientTests.cs
+++ b/src/Tests/AzureClientTests.cs
@@ -31,15 +31,14 @@ public void TestTargets()
{
var workspace = "Workspace";
var services = Startup.CreateServiceProvider(workspace);
- var references = services.GetService();
var azureClient = services.GetService();
// SetActiveTargetAsync with recognized target name, but not yet connected
- var result = azureClient.SetActiveTargetAsync(new MockChannel(), references, "ionq.simulator").GetAwaiter().GetResult();
+ var result = azureClient.SetActiveTargetAsync(new MockChannel(), "ionq.simulator").GetAwaiter().GetResult();
Assert.IsTrue(result.Status == ExecuteStatus.Error);
// SetActiveTargetAsync with unrecognized target name
- result = azureClient.SetActiveTargetAsync(new MockChannel(), references, "contoso.qpu").GetAwaiter().GetResult();
+ result = azureClient.SetActiveTargetAsync(new MockChannel(), "contoso.qpu").GetAwaiter().GetResult();
Assert.IsTrue(result.Status == ExecuteStatus.Error);
// GetActiveTargetAsync, but not yet connected
diff --git a/src/Tests/SNIPPETS.cs b/src/Tests/SNIPPETS.cs
index 8aff3f3214..ef29cf6628 100644
--- a/src/Tests/SNIPPETS.cs
+++ b/src/Tests/SNIPPETS.cs
@@ -207,6 +207,15 @@ operation InvalidFunctor(q: Qubit) : Unit {
}
";
+ public static string InvalidEntryPoint =
+@"
+ /// # Summary
+ /// This script has an operation that is not valid to be marked as an entry point.
+ operation InvalidEntryPoint(q : Qubit) : Unit {
+ H(q);
+ }
+";
+
public static string Reverse =
@"
/// # Summary
diff --git a/src/Tool/appsettings.json b/src/Tool/appsettings.json
index 3edf302854..f6975e9c6c 100644
--- a/src/Tool/appsettings.json
+++ b/src/Tool/appsettings.json
@@ -6,24 +6,24 @@
},
"AllowedHosts": "*",
"DefaultPackageVersions": [
- "Microsoft.Quantum.Compiler::0.11.2006.207",
+ "Microsoft.Quantum.Compiler::0.11.2006.403",
- "Microsoft.Quantum.CsharpGeneration::0.11.2006.207",
- "Microsoft.Quantum.Development.Kit::0.11.2006.207",
- "Microsoft.Quantum.Simulators::0.11.2006.207",
- "Microsoft.Quantum.Xunit::0.11.2006.207",
+ "Microsoft.Quantum.CsharpGeneration::0.11.2006.403",
+ "Microsoft.Quantum.Development.Kit::0.11.2006.403",
+ "Microsoft.Quantum.Simulators::0.11.2006.403",
+ "Microsoft.Quantum.Xunit::0.11.2006.403",
- "Microsoft.Quantum.Standard::0.11.2006.207",
- "Microsoft.Quantum.Chemistry::0.11.2006.207",
- "Microsoft.Quantum.Chemistry.Jupyter::0.11.2006.207",
- "Microsoft.Quantum.Numerics::0.11.2006.207",
+ "Microsoft.Quantum.Standard::0.11.2006.403",
+ "Microsoft.Quantum.Chemistry::0.11.2006.403",
+ "Microsoft.Quantum.Chemistry.Jupyter::0.11.2006.403",
+ "Microsoft.Quantum.Numerics::0.11.2006.403",
- "Microsoft.Quantum.Katas::0.11.2006.207",
+ "Microsoft.Quantum.Katas::0.11.2006.403",
- "Microsoft.Quantum.Research::0.11.2006.207",
+ "Microsoft.Quantum.Research::0.11.2006.403",
- "Microsoft.Quantum.Providers.IonQ::0.11.2006.207",
- "Microsoft.Quantum.Providers.Honeywell::0.11.2006.207",
- "Microsoft.Quantum.Providers.QCI::0.11.2006.207",
+ "Microsoft.Quantum.Providers.IonQ::0.11.2006.403",
+ "Microsoft.Quantum.Providers.Honeywell::0.11.2006.403",
+ "Microsoft.Quantum.Providers.QCI::0.11.2006.403",
]
}