Skip to content

Commit 3522921

Browse files
committed
Add -MaxParallelism and -MaxParallelismPerTarget parameters to Invoke- commands.
1 parent b27ca76 commit 3522921

34 files changed

Lines changed: 1509 additions & 417 deletions

PSql.Deploy.Engine.Tests/Core/DeploymentSessionOptionsTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,36 @@ namespace PSql.Deploy;
66
[TestFixture]
77
public class DeploymentSessionOptionsTests
88
{
9+
[Test]
10+
public void MaxParallelism_Get_Default()
11+
{
12+
new TestDeploymentSessionOptions().MaxParallelism.ShouldBe(int.MaxValue);
13+
}
14+
15+
[Test]
16+
public void MaxParallelism_Set_OutOfRange()
17+
{
18+
Should.Throw<ArgumentOutOfRangeException>(() =>
19+
{
20+
new TestDeploymentSessionOptions().MaxParallelism = 0;
21+
});
22+
}
23+
24+
[Test]
25+
public void MaxParallelismPerTarget_Get_Default()
26+
{
27+
new TestDeploymentSessionOptions().MaxParallelismPerTarget.ShouldBe(int.MaxValue);
28+
}
29+
30+
[Test]
31+
public void MaxParallelismPerTarget_Set_OutOfRange()
32+
{
33+
Should.Throw<ArgumentOutOfRangeException>(() =>
34+
{
35+
new TestDeploymentSessionOptions().MaxParallelismPerTarget = 0;
36+
});
37+
}
38+
939
[Test]
1040
public void MaxErrorCount_Set_OutOfRange()
1141
{

PSql.Deploy.Engine.Tests/Core/DeploymentSessionTests.cs

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ private IDeploymentSessionInternal SessionInternal
2424
=> SessionMock.Object;
2525

2626
private static readonly Target
27-
TargetA = new Target("Server=sql.example.com;Database=a"),
28-
TargetB = new Target("Server=sql.example.com;Database=b"),
29-
TargetC = new Target("Server=sql.example.com;Database=c");
27+
TargetA = new("Server=sql.example.com;Database=a"),
28+
TargetB = new("Server=sql.example.com;Database=b"),
29+
TargetC = new("Server=sql.example.com;Database=c");
3030

3131
[Test]
3232
public void Construct_NullOptions()
@@ -37,6 +37,22 @@ public void Construct_NullOptions()
3737
});
3838
}
3939

40+
[Test]
41+
public void MaxParallelism_Get()
42+
{
43+
_options.MaxParallelism = 3;
44+
45+
Session.MaxParallelism.ShouldBe(3);
46+
}
47+
48+
[Test]
49+
public void MaxParallelismPerTarget_Get()
50+
{
51+
_options.MaxParallelismPerTarget = 3;
52+
53+
Session.MaxParallelismPerTarget.ShouldBe(3);
54+
}
55+
4056
[Test]
4157
public void MaxErrorCount_Get()
4258
{
@@ -81,11 +97,28 @@ public void BeginApplying_Group_NullTarget()
8197
[Test]
8298
public async Task Apply_Target_Ok()
8399
{
84-
static void AssertParallelism(Target t, Parallelism p)
100+
static void AssertParallelism(Target t, TargetParallelism p)
85101
{
86-
p.MaxParallelTargets .ShouldBe(1);
87-
p.MaxParallelCommands .ShouldBe(4);
88-
p.MaxCommandsPerTarget.ShouldBe(4);
102+
p.MaxActions.ShouldBe(4);
103+
}
104+
105+
ExpectGetMaxParallelTargets(g => g.Targets.Single() == TargetA, result: 1);
106+
ExpectApplyCore(TargetA, AssertParallelism);
107+
108+
Session.BeginApplying(TargetA, maxParallelism: 4);
109+
110+
await Session.CompleteApplyingAsync(Cancellation.Token);
111+
}
112+
113+
[Test]
114+
public async Task Apply_Target_GlobalParallelismLimits()
115+
{
116+
_options.MaxParallelism = 3;
117+
_options.MaxParallelismPerTarget = 2;
118+
119+
static void AssertParallelism(Target t, TargetParallelism p)
120+
{
121+
p.MaxActions.ShouldBe(2); // limited by global max per target
89122
}
90123

91124
ExpectGetMaxParallelTargets(g => g.Targets.Single() == TargetA, result: 1);
@@ -101,15 +134,39 @@ public async Task Apply_Group_Ok()
101134
{
102135
var group = new TargetGroup(
103136
[TargetA, TargetB],
104-
maxParallelism: 8,
137+
maxParallelism: 8,
105138
maxParallelismPerTarget: 1
106139
);
107140

108-
static void AssertParallelism(Target t, Parallelism p)
141+
static void AssertParallelism(Target t, TargetParallelism p)
142+
{
143+
p.MaxActions.ShouldBe(1);
144+
}
145+
146+
ExpectGetMaxParallelTargets(g => g == group, result: 6);
147+
ExpectApplyCore(TargetA, AssertParallelism);
148+
ExpectApplyCore(TargetB, AssertParallelism);
149+
150+
Session.BeginApplying(group);
151+
152+
await Session.CompleteApplyingAsync(Cancellation.Token);
153+
}
154+
155+
[Test]
156+
public async Task Apply_Group_GlobalParallelismLimits()
157+
{
158+
_options.MaxParallelism = 3;
159+
_options.MaxParallelismPerTarget = 2;
160+
161+
var group = new TargetGroup(
162+
[TargetA, TargetB],
163+
maxParallelism: 8,
164+
maxParallelismPerTarget: 4
165+
);
166+
167+
static void AssertParallelism(Target t, TargetParallelism p)
109168
{
110-
p.MaxParallelTargets .ShouldBe(6);
111-
p.MaxParallelCommands .ShouldBe(8);
112-
p.MaxCommandsPerTarget.ShouldBe(1);
169+
p.MaxActions.ShouldBe(2);
113170
}
114171

115172
ExpectGetMaxParallelTargets(g => g == group, result: 6);
@@ -241,12 +298,12 @@ private void ExpectGetMaxParallelTargets(
241298
.Verifiable();
242299
}
243300

244-
private void ExpectApplyCore(Target target, Action<Target, Parallelism>? callback = null)
301+
private void ExpectApplyCore(Target target, Action<Target, TargetParallelism>? callback = null)
245302
{
246-
static void Nop(Target t, Parallelism p) { }
303+
static void Nop(Target t, TargetParallelism p) { }
247304

248305
SessionMock
249-
.Setup(s => s.ApplyCoreAsync_Public(target, It.IsNotNull<Parallelism>()))
306+
.Setup(s => s.ApplyCoreAsync_Public(target, It.IsNotNull<TargetParallelism>()))
250307
.Callback(callback ?? Nop)
251308
.Returns(Task.CompletedTask)
252309
.Verifiable();
@@ -298,13 +355,13 @@ public TestDeploymentSession(TestDeploymentSessionOptions options)
298355
protected sealed override int GetMaxParallelTargets(TargetGroup group)
299356
=> PublicGetMaxParallelTargets_Public(group);
300357

301-
protected sealed override Task ApplyCoreAsync(Target target, Parallelism parallelism)
358+
protected sealed override Task ApplyCoreAsync(Target target, TargetParallelism parallelism)
302359
=> ApplyCoreAsync_Public(target, parallelism);
303360

304361
public virtual int PublicGetMaxParallelTargets_Public(TargetGroup group)
305362
=> 4;
306363

307-
public virtual Task ApplyCoreAsync_Public(Target target, Parallelism parallelism)
364+
public virtual Task ApplyCoreAsync_Public(Target target, TargetParallelism parallelism)
308365
=> Task.CompletedTask;
309366
}
310367

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright Subatomix Research Inc.
2+
// SPDX-License-Identifier: MIT
3+
4+
namespace PSql.Deploy;
5+
6+
[TestFixture]
7+
[FixtureLifeCycle(LifeCycle.SingleInstance)]
8+
public class GlobalParallelismTests
9+
{
10+
[Test]
11+
public void Construct_MaxActionsOutOfRange()
12+
{
13+
Should.Throw<ArgumentOutOfRangeException>(() =>
14+
{
15+
_ = new GlobalParallelism(maxActions: 0, maxActionsPerTarget: 4);
16+
});
17+
}
18+
19+
[Test]
20+
public void Construct_MaxActionsPerTargetOutOfRange()
21+
{
22+
Should.Throw<ArgumentOutOfRangeException>(() =>
23+
{
24+
_ = new GlobalParallelism(maxActions: 8, maxActionsPerTarget: 0);
25+
});
26+
}
27+
28+
[Test]
29+
public void ActionLimiter_Get()
30+
{
31+
using var parallelism = new GlobalParallelism(maxActions: 8, maxActionsPerTarget: 4);
32+
33+
parallelism
34+
.ActionLimiter .ShouldBeOfType<ParallelismLimiter>()
35+
.EffectiveLimit.ShouldBe(8);
36+
}
37+
38+
[Test]
39+
public void MaxActions_Get()
40+
{
41+
using var parallelism = new GlobalParallelism(maxActions: 8, maxActionsPerTarget: 4);
42+
43+
parallelism.MaxActions.ShouldBe(8);
44+
}
45+
46+
[Test]
47+
public void MaxActionsPerTarget_Get()
48+
{
49+
using var parallelism = new GlobalParallelism(maxActions: 8, maxActionsPerTarget: 4);
50+
51+
parallelism.MaxActionsPerTarget.ShouldBe(4);
52+
}
53+
54+
[Test]
55+
public void MaxActionsPerTarget_Get_Clamped()
56+
{
57+
using var parallelism = new GlobalParallelism(maxActions: 3, maxActionsPerTarget: 4);
58+
59+
parallelism.MaxActionsPerTarget.ShouldBe(3);
60+
}
61+
62+
[Test]
63+
public void ForGroup_NullGroup()
64+
{
65+
using var parallelism = new GlobalParallelism(maxActions: 8, maxActionsPerTarget: 4);
66+
67+
Should.Throw<ArgumentNullException>(() =>
68+
{
69+
parallelism.ForGroup(group: null!, maxTargets: 2);
70+
});
71+
}
72+
73+
[Test]
74+
public void ForGroup_MaxTargetsOutOfRange()
75+
{
76+
using var parallelism = new GlobalParallelism(maxActions: 8, maxActionsPerTarget: 4);
77+
78+
var group = new TargetGroup([new("Server=s; Database=d")]);
79+
80+
Should.Throw<ArgumentOutOfRangeException>(() =>
81+
{
82+
parallelism.ForGroup(group, maxTargets: 0);
83+
});
84+
}
85+
86+
[Test]
87+
public void ForGroup_Ok()
88+
{
89+
using var parallelism = new GlobalParallelism(maxActions: 8, maxActionsPerTarget: 4);
90+
91+
var group = new TargetGroup([new("Server=s; Database=d")]);
92+
93+
using var forGroup = parallelism.ForGroup(group, maxTargets: 2);
94+
95+
forGroup .ShouldBeOfType<TargetGroupParallelism>();
96+
forGroup.MaxTargets .ShouldBe(2);
97+
forGroup.MaxActionsPerTarget.ShouldBe(4);
98+
}
99+
100+
[Test]
101+
public void Dispose()
102+
{
103+
var parallelism = new GlobalParallelism(maxActions: 8, maxActionsPerTarget: 4);
104+
105+
parallelism.Dispose();
106+
107+
// Verify limiter got disposed
108+
Should.Throw<ObjectDisposedException>(() =>
109+
{
110+
parallelism.ActionLimiter.AcquireAsync(default).GetAwaiter().GetResult();
111+
});
112+
113+
// Test multiple disposal
114+
parallelism.Dispose();
115+
}
116+
}

0 commit comments

Comments
 (0)