< Summary - Kestrun — Combined Coverage

Information
Class: Kestrun.Scheduling.JobFactory
Assembly: Kestrun
File(s): /home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Scheduling/JobFactory.cs
Tag: Kestrun/Kestrun@0d738bf294e6281b936d031e1979d928007495ff
Line coverage
86%
Covered lines: 85
Uncovered lines: 13
Coverable lines: 98
Total lines: 144
Line coverage: 86.7%
Branch coverage
50%
Covered branches: 6
Total branches: 12
Branch coverage: 50%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 08/26/2025 - 14:53:17 Line coverage: 86.3% (82/95) Branch coverage: 50% (6/12) Total lines: 139 Tag: Kestrun/Kestrun@78d1e497d8ba989d121b57aa39aa3c6b22de743111/14/2025 - 12:29:34 Line coverage: 86.5% (84/97) Branch coverage: 50% (6/12) Total lines: 143 Tag: Kestrun/Kestrun@5e12b09a6838e68e704cd3dc975331b9e680a62612/18/2025 - 21:41:58 Line coverage: 86.7% (85/98) Branch coverage: 50% (6/12) Total lines: 144 Tag: Kestrun/Kestrun@0d738bf294e6281b936d031e1979d928007495ff 08/26/2025 - 14:53:17 Line coverage: 86.3% (82/95) Branch coverage: 50% (6/12) Total lines: 139 Tag: Kestrun/Kestrun@78d1e497d8ba989d121b57aa39aa3c6b22de743111/14/2025 - 12:29:34 Line coverage: 86.5% (84/97) Branch coverage: 50% (6/12) Total lines: 143 Tag: Kestrun/Kestrun@5e12b09a6838e68e704cd3dc975331b9e680a62612/18/2025 - 21:41:58 Line coverage: 86.7% (85/98) Branch coverage: 50% (6/12) Total lines: 144 Tag: Kestrun/Kestrun@0d738bf294e6281b936d031e1979d928007495ff

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_Host()100%11100%
get_Language()100%11100%
get_Code()100%11100%
get_Pool()100%11100%
get_ExtraImports()100%210%
get_ExtraRefs()100%210%
get_Locals()100%210%
get_LanguageVersion()100%210%
Create(...)37.5%10870%
CreateAsync()75%4488.88%
Create(...)100%11100%
PowerShellJob(...)100%1194.02%
RoslynJob(...)100%210%

File(s)

/home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Scheduling/JobFactory.cs

#LineLine coverage
 1using System.Management.Automation;
 2using System.Reflection;
 3using Kestrun.Hosting;
 4using Kestrun.Scripting;
 5using Kestrun.Utilities;
 6using Microsoft.CodeAnalysis.CSharp;
 7using Serilog.Events;
 8using Kestrun.Languages;
 9
 10namespace Kestrun.Scheduling;
 11
 12internal static class JobFactory
 13{
 1214    internal record JobConfig(
 1415          KestrunHost Host,
 1716          ScriptLanguage Language,
 4317          string Code,
 3918          KestrunRunspacePoolManager? Pool = null,
 019          string[]? ExtraImports = null,
 020          Assembly[]? ExtraRefs = null,
 021            IReadOnlyDictionary<string, object?>? Locals = null,
 022          LanguageVersion LanguageVersion = LanguageVersion.CSharp12
 1223          );
 24
 25    internal static Func<CancellationToken, Task> Create(JobConfig config)
 26    {
 1227        return config.Language switch
 1228        {
 1229            ScriptLanguage.PowerShell =>
 1230                config.Pool is null
 1231                    ? throw new InvalidOperationException("PowerShell runspace pool must be provided for PowerShell jobs
 1232                    : PowerShellJob(config),
 033            ScriptLanguage.CSharp => RoslynJob(config),
 034            ScriptLanguage.VBNet => RoslynJob(config),
 035            _ => throw new NotSupportedException($"Language {config.Language} not supported.")
 1236        };
 37    }
 38
 39    public static async Task<Func<CancellationToken, Task>> CreateAsync(
 40     JobConfig config, FileInfo fileInfo, CancellationToken ct = default)
 41    {
 542        var log = config.Host.Logger;
 543        ArgumentNullException.ThrowIfNull(fileInfo);
 544        if (!fileInfo.Exists)
 45        {
 046            throw new FileNotFoundException(fileInfo.FullName);
 47        }
 48
 549        var updatedConfig = config with { Code = await File.ReadAllTextAsync(fileInfo.FullName, ct) };
 550        if (log.IsEnabled(LogEventLevel.Debug))
 51        {
 552            log.Debug("Creating job for {File} with language {Lang}", fileInfo.FullName, updatedConfig.Language);
 53        }
 54
 555        return Create(updatedConfig);
 556    }
 57
 58    public static Func<CancellationToken, Task> Create(
 259        JobConfig config, FileInfo fileInfo) => CreateAsync(config, fileInfo).GetAwaiter().GetResult();
 60
 61    /* ----------------  PowerShell  ---------------- */
 62    private static Func<CancellationToken, Task> PowerShellJob(
 63       JobConfig config)
 64    {
 1165        return async ct =>
 1166        {
 967            var log = config.Host.Logger;
 968            if (log.IsEnabled(LogEventLevel.Debug))
 1169            {
 970                log.Debug("Building PowerShell delegate, script length={Length}", config.Code?.Length);
 1171            }
 1172
 973            if (config.Pool is null)
 1174            {
 075                throw new InvalidOperationException("PowerShell runspace pool must be provided for PowerShell jobs.");
 1176            }
 1177
 978            var runspace = config.Pool.Acquire();
 1179            try
 1180            {
 981                using var ps = PowerShell.Create();
 982                ps.Runspace = runspace;
 983                _ = ps.AddScript(config.Code);
 984                if (log.IsEnabled(LogEventLevel.Debug))
 1185                {
 986                    log.Debug("Executing PowerShell script with {RunspaceId} - {Preview}", runspace.Id, config.Code?[..M
 1187                }
 1188
 1189                // Register cancellation
 1090                using var reg = ct.Register(() => ps.Stop());
 1191
 1192                // Wait for the PowerShell script to complete
 1193                //  var psResults = await ps.InvokeAsync().WaitAsync(ct).ConfigureAwait(false);
 994                var psResults = await ps.InvokeAsync(log, ct).ConfigureAwait(false);
 1195
 896                log.Verbose($"PowerShell script executed with {psResults.Count} results.");
 897                if (log.IsEnabled(LogEventLevel.Debug))
 1198                {
 899                    log.Debug("PowerShell script output:");
 20100                    foreach (var r in psResults.Take(10))      // first 10 only
 11101                    {
 2102                        log.Debug("   • {Result}", r);
 11103                    }
 11104
 8105                    if (psResults.Count > 10)
 11106                    {
 0107                        log.Debug("   … {Count} more", psResults.Count - 10);
 11108                    }
 11109                }
 11110
 8111                if (ps.HadErrors || ps.Streams.Error.Count != 0 || ps.Streams.Verbose.Count > 0 || ps.Streams.Debug.Coun
 11112                {
 0113                    log.Verbose("PowerShell script completed with verbose/debug/warning/info messages.");
 0114                    log.Verbose(BuildError.Text(ps));
 11115                }
 8116            }
 1117            catch (Exception ex)
 11118            {
 1119                log.Error(ex, "PowerShell job failed - {Preview}", config.Code?[..Math.Min(40, config.Code.Length)]);
 1120                throw;
 11121            }
 11122            finally
 11123            {
 9124                if (log.IsEnabled(LogEventLevel.Debug))
 11125                {
 9126                    log.Debug("PowerShell job completed, releasing runspace back to pool.");
 11127                }
 11128                // Ensure we release the runspace back to the pool
 9129                config.Pool.Release(runspace);
 11130            }
 19131        };
 132    }
 133
 134    /// <summary>
 135    /// Creates a C# or VB.NET job using Roslyn compilation.
 136    /// </summary>
 137    /// <param name="config">The job configuration containing code, logger, and other parameters.</param>
 138    /// <returns>A function that executes the job.</returns>
 139    /// <remarks>
 140    /// This method uses Roslyn to compile and execute C# or VB.NET code.
 141    /// </remarks>
 142    private static Func<CancellationToken, Task> RoslynJob(JobConfig config) =>
 0143    RoslynJobFactory.Build(config.Host, config.Code, config.ExtraImports, config.ExtraRefs, config.Locals, config.Langua
 144}