Skip to content

Commit a130dca

Browse files
authored
add dind to ci and handle them in testfixture
* configure daemons and clients to match github and local test environments * uses runners temp for certs * checkout in different path * reduce performance test asserts * let task some time to start monitoring
1 parent ed2041c commit a130dca

10 files changed

Lines changed: 362 additions & 170 deletions

.github/workflows/ci.yml

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
name: CI
22

33
on:
4-
workflow_dispatch:
54
pull_request:
65
branches:
76
- main
@@ -10,18 +9,28 @@ jobs:
109
build:
1110
runs-on: ubuntu-22.04
1211
services:
13-
docker:
12+
# Docker without TLS (plain TCP) !DEPRECATED! with next docker release
13+
docker-no-tls:
1414
image: docker:28.1-dind
1515
env:
1616
DOCKER_TLS_CERTDIR: ""
1717
ports:
1818
- 2375:2375
1919
options: >-
2020
--privileged
21-
--health-cmd "docker info || exit 1"
22-
--health-interval 10s
23-
--health-timeout 5s
24-
--health-retries 5
21+
22+
# Docker with TLS (secure TCP)
23+
docker-tls:
24+
image: docker:28.1-dind
25+
env:
26+
DOCKER_TLS_CERTDIR: /certs
27+
ports:
28+
- 2376:2376
29+
options: >-
30+
--privileged
31+
volumes:
32+
- ${{ github.workspace }}/certs:/certs
33+
2534
strategy:
2635
matrix:
2736
framework:
@@ -30,12 +39,53 @@ jobs:
3039
steps:
3140
- uses: actions/checkout@v4
3241
with:
42+
path: test
3343
fetch-depth: 0
3444
- name: Setup .NET Core
3545
uses: actions/setup-dotnet@v4
3646
with:
3747
dotnet-version: 9.x
3848
- name: Build
3949
run: dotnet build -c Release --framework ${{ matrix.framework }}
50+
working-directory: test
51+
52+
- name: Pack client cert, key, ca for C# docker client
53+
run: |
54+
mkdir -p ${{ github.workspace }}/certs
55+
sudo chmod 777 ${{ github.workspace }}/certs
56+
57+
# create pfx
58+
openssl pkcs12 -export -out ${{ github.workspace }}/certs/client.pfx -inkey ${{ github.workspace }}/certs/client/key.pem -in ${{ github.workspace }}/certs/client/cert.pem -certfile ${{ github.workspace }}/certs/client/ca.pem -passout pass:
59+
60+
- name: Wait for Docker (no TLS) to be healthy
61+
run: |
62+
for i in {1..10}; do
63+
if docker --host=tcp://localhost:2375 version; then
64+
echo "Docker (no TLS) is ready!"
65+
exit 0
66+
fi
67+
echo "Waiting for Docker (no TLS) to be ready..."
68+
sleep 3
69+
done
70+
echo "Docker (no TLS) did not become ready in time."
71+
exit 1
72+
73+
- name: Wait for Docker (with TLS) to be healthy
74+
run: |
75+
for i in {1..10}; do
76+
if docker --host=tcp://localhost:2376 --tlsverify \
77+
--tlscacert=${{ github.workspace }}/certs/client/ca.pem \
78+
--tlscert=${{ github.workspace }}/certs/client/cert.pem \
79+
--tlskey=${{ github.workspace }}/certs/client/key.pem version; then
80+
echo "Docker (TLS) is ready!"
81+
exit 0
82+
fi
83+
echo "Waiting for Docker (TLS) to be ready..."
84+
sleep 3
85+
done
86+
echo "Docker (TLS) did not become ready in time."
87+
exit 1
88+
4089
- name: Test
4190
run: dotnet test -c Release --framework ${{ matrix.framework }} --no-build --logger console
91+
working-directory: test

test/Docker.DotNet.Tests/IConfigOperationsTests.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@ public IConfigOperationsTests(TestFixture testFixture, ITestOutputHelper testOut
1313
}
1414

1515
public static IEnumerable<object[]> GetDockerClientTypes() =>
16-
Enum.GetValues(typeof(DockerClientType))
17-
.Cast<DockerClientType>()
18-
.Select(t => new object[] { t });
16+
TestFixture.GetDockerClientTypes();
1917

2018
[Theory]
2119
[MemberData(nameof(GetDockerClientTypes))]
22-
public async Task SwarmConfig_CanCreateAndRead(DockerClientType clientType)
20+
public async Task SwarmConfig_CanCreateAndRead(TestClientsEnum clientType)
2321
{
2422
var currentConfigs = await _testFixture.DockerClients[clientType].Configs.ListConfigsAsync();
2523

test/Docker.DotNet.Tests/IContainerOperationsTests.cs

Lines changed: 49 additions & 50 deletions
Large diffs are not rendered by default.

test/Docker.DotNet.Tests/IImageOperationsTests.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@ public IImageOperationsTests(TestFixture testFixture, ITestOutputHelper testOutp
1313
}
1414

1515
public static IEnumerable<object[]> GetDockerClientTypes() =>
16-
Enum.GetValues(typeof(DockerClientType))
17-
.Cast<DockerClientType>()
18-
.Select(t => new object[] { t });
16+
TestFixture.GetDockerClientTypes();
1917

2018
[Theory]
2119
[MemberData(nameof(GetDockerClientTypes))]
22-
public async Task CreateImageAsync_TaskCancelled_ThrowsTaskCanceledException(DockerClientType clientType)
20+
public async Task CreateImageAsync_TaskCancelled_ThrowsTaskCanceledException(TestClientsEnum clientType)
2321
{
2422
using var cts = CancellationTokenSource.CreateLinkedTokenSource(_testFixture.Cts.Token);
2523

@@ -55,7 +53,7 @@ await _testFixture.DockerClients[clientType].Images.TagImageAsync(
5553

5654
[Theory]
5755
[MemberData(nameof(GetDockerClientTypes))]
58-
public Task CreateImageAsync_ErrorResponse_ThrowsDockerApiException(DockerClientType clientType)
56+
public Task CreateImageAsync_ErrorResponse_ThrowsDockerApiException(TestClientsEnum clientType)
5957
{
6058
return Assert.ThrowsAsync<DockerApiException>(() => _testFixture.DockerClients[clientType].Images.CreateImageAsync(
6159
new ImagesCreateParameters
@@ -67,7 +65,7 @@ public Task CreateImageAsync_ErrorResponse_ThrowsDockerApiException(DockerClient
6765

6866
[Theory]
6967
[MemberData(nameof(GetDockerClientTypes))]
70-
public async Task DeleteImageAsync_RemovesImage(DockerClientType clientType)
68+
public async Task DeleteImageAsync_RemovesImage(TestClientsEnum clientType)
7169
{
7270
var newImageTag = Guid.NewGuid().ToString();
7371

test/Docker.DotNet.Tests/ISwarmOperationsTests.cs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@ public ISwarmOperationsTests(TestFixture testFixture, ITestOutputHelper testOutp
1313
}
1414

1515
public static IEnumerable<object[]> GetDockerClientTypes() =>
16-
Enum.GetValues(typeof(DockerClientType))
17-
.Cast<DockerClientType>()
18-
.Select(t => new object[] { t });
16+
TestFixture.GetDockerClientTypes();
1917

2018
[Theory]
2119
[MemberData(nameof(GetDockerClientTypes))]
22-
public async Task GetFilteredServicesByName_Succeeds(DockerClientType clientType)
20+
public async Task GetFilteredServicesByName_Succeeds(TestClientsEnum clientType)
2321
{
2422
var serviceName = $"service1-{Guid.NewGuid().ToString().Substring(1, 10)}";
2523

@@ -28,7 +26,7 @@ public async Task GetFilteredServicesByName_Succeeds(DockerClientType clientType
2826
Service = new ServiceSpec
2927
{
3028
Name = serviceName,
31-
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Image.ID } }
29+
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Images[TestFixture.GetDaemonForClient(clientType)].ID } }
3230
}
3331
})).ID;
3432

@@ -37,7 +35,7 @@ public async Task GetFilteredServicesByName_Succeeds(DockerClientType clientType
3735
Service = new ServiceSpec
3836
{
3937
Name = $"service2-{Guid.NewGuid().ToString().Substring(1, 10)}",
40-
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Image.ID } }
38+
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Images[TestFixture.GetDaemonForClient(clientType)].ID } }
4139
}
4240
})).ID;
4341

@@ -46,7 +44,7 @@ public async Task GetFilteredServicesByName_Succeeds(DockerClientType clientType
4644
Service = new ServiceSpec
4745
{
4846
Name = $"service3-{Guid.NewGuid().ToString().Substring(1, 10)}",
49-
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Image.ID } }
47+
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Images[TestFixture.GetDaemonForClient(clientType)].ID } }
5048
}
5149
})).ID;
5250

@@ -70,14 +68,14 @@ public async Task GetFilteredServicesByName_Succeeds(DockerClientType clientType
7068

7169
[Theory]
7270
[MemberData(nameof(GetDockerClientTypes))]
73-
public async Task GetFilteredServicesById_Succeeds(DockerClientType clientType)
71+
public async Task GetFilteredServicesById_Succeeds(TestClientsEnum clientType)
7472
{
7573
var firstServiceId = (await _testFixture.DockerClients[clientType].Swarm.CreateServiceAsync(new ServiceCreateParameters
7674
{
7775
Service = new ServiceSpec
7876
{
7977
Name = $"service1-{Guid.NewGuid().ToString().Substring(1, 10)}",
80-
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Image.ID } }
78+
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Images[TestFixture.GetDaemonForClient(clientType)].ID } }
8179
}
8280
})).ID;
8381

@@ -86,7 +84,7 @@ public async Task GetFilteredServicesById_Succeeds(DockerClientType clientType)
8684
Service = new ServiceSpec
8785
{
8886
Name = $"service2-{Guid.NewGuid().ToString().Substring(1, 10)}",
89-
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Image.ID } }
87+
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Images[TestFixture.GetDaemonForClient(clientType)].ID } }
9088
}
9189
})).ID;
9290

@@ -95,7 +93,7 @@ public async Task GetFilteredServicesById_Succeeds(DockerClientType clientType)
9593
Service = new ServiceSpec
9694
{
9795
Name = $"service3-{Guid.NewGuid().ToString().Substring(1, 10)}",
98-
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Image.ID } }
96+
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Images[TestFixture.GetDaemonForClient(clientType)].ID } }
9997
}
10098
})).ID;
10199

@@ -119,7 +117,7 @@ public async Task GetFilteredServicesById_Succeeds(DockerClientType clientType)
119117

120118
[Theory]
121119
[MemberData(nameof(GetDockerClientTypes))]
122-
public async Task GetServices_Succeeds(DockerClientType clientType)
120+
public async Task GetServices_Succeeds(TestClientsEnum clientType)
123121
{
124122
var initialServiceCount = (await _testFixture.DockerClients[clientType].Swarm.ListServicesAsync(cancellationToken: CancellationToken.None)).Count();
125123

@@ -128,7 +126,7 @@ public async Task GetServices_Succeeds(DockerClientType clientType)
128126
Service = new ServiceSpec
129127
{
130128
Name = $"service1-{Guid.NewGuid().ToString().Substring(1, 10)}",
131-
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Image.ID } }
129+
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Images[TestFixture.GetDaemonForClient(clientType)].ID } }
132130
}
133131
})).ID;
134132

@@ -137,7 +135,7 @@ public async Task GetServices_Succeeds(DockerClientType clientType)
137135
Service = new ServiceSpec
138136
{
139137
Name = $"service2-{Guid.NewGuid().ToString().Substring(1, 10)}",
140-
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Image.ID } }
138+
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Images[TestFixture.GetDaemonForClient(clientType)].ID } }
141139
}
142140
})).ID;
143141

@@ -146,7 +144,7 @@ public async Task GetServices_Succeeds(DockerClientType clientType)
146144
Service = new ServiceSpec
147145
{
148146
Name = $"service3-{Guid.NewGuid().ToString().Substring(1, 10)}",
149-
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Image.ID } }
147+
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Images[TestFixture.GetDaemonForClient(clientType)].ID } }
150148
}
151149
})).ID;
152150

@@ -161,7 +159,7 @@ public async Task GetServices_Succeeds(DockerClientType clientType)
161159

162160
[Theory]
163161
[MemberData(nameof(GetDockerClientTypes))]
164-
public async Task GetServiceLogs_Succeeds(DockerClientType clientType)
162+
public async Task GetServiceLogs_Succeeds(TestClientsEnum clientType)
165163
{
166164
var cts = new CancellationTokenSource();
167165
var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(_testFixture.Cts.Token, cts.Token);
@@ -172,7 +170,7 @@ public async Task GetServiceLogs_Succeeds(DockerClientType clientType)
172170
Service = new ServiceSpec
173171
{
174172
Name = serviceName,
175-
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Image.ID, Command = CommonCommands.EchoToStdoutAndStderr } }
173+
TaskTemplate = new TaskSpec { ContainerSpec = new ContainerSpec { Image = _testFixture.Images[TestFixture.GetDaemonForClient(clientType)].ID, Command = CommonCommands.EchoToStdoutAndStderr } }
176174
}
177175
})).ID;
178176

test/Docker.DotNet.Tests/ISystemOperations.Tests.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ public ISystemOperationsTests(TestFixture testFixture, ITestOutputHelper testOut
1313
}
1414

1515
public static IEnumerable<object[]> GetDockerClientTypes() =>
16-
Enum.GetValues(typeof(DockerClientType))
17-
.Cast<DockerClientType>()
18-
.Select(t => new object[] { t });
16+
TestFixture.GetDockerClientTypes();
1917

2018
[Fact]
2119
public void Docker_IsRunning()
@@ -30,23 +28,23 @@ public void Docker_IsRunning()
3028

3129
[Theory]
3230
[MemberData(nameof(GetDockerClientTypes))]
33-
public async Task GetSystemInfoAsync_Succeeds(DockerClientType clientType)
31+
public async Task GetSystemInfoAsync_Succeeds(TestClientsEnum clientType)
3432
{
3533
var info = await _testFixture.DockerClients[clientType].System.GetSystemInfoAsync();
3634
Assert.NotNull(info.Architecture);
3735
}
3836

3937
[Theory]
4038
[MemberData(nameof(GetDockerClientTypes))]
41-
public async Task GetVersionAsync_Succeeds(DockerClientType clientType)
39+
public async Task GetVersionAsync_Succeeds(TestClientsEnum clientType)
4240
{
4341
var version = await _testFixture.DockerClients[clientType].System.GetVersionAsync();
4442
Assert.NotNull(version.APIVersion);
4543
}
4644

4745
[Theory]
4846
[MemberData(nameof(GetDockerClientTypes))]
49-
public async Task MonitorEventsAsync_EmptyContainersList_CanBeCancelled(DockerClientType clientType)
47+
public async Task MonitorEventsAsync_EmptyContainersList_CanBeCancelled(TestClientsEnum clientType)
5048
{
5149
var progress = new Progress<Message>();
5250

@@ -60,21 +58,21 @@ public async Task MonitorEventsAsync_EmptyContainersList_CanBeCancelled(DockerCl
6058

6159
[Theory]
6260
[MemberData(nameof(GetDockerClientTypes))]
63-
public async Task MonitorEventsAsync_NullParameters_Throws(DockerClientType clientType)
61+
public async Task MonitorEventsAsync_NullParameters_Throws(TestClientsEnum clientType)
6462
{
6563
await Assert.ThrowsAsync<ArgumentNullException>(() => _testFixture.DockerClients[clientType].System.MonitorEventsAsync(null, null));
6664
}
6765

6866
[Theory]
6967
[MemberData(nameof(GetDockerClientTypes))]
70-
public async Task MonitorEventsAsync_NullProgress_Throws(DockerClientType clientType)
68+
public async Task MonitorEventsAsync_NullProgress_Throws(TestClientsEnum clientType)
7169
{
7270
await Assert.ThrowsAsync<ArgumentNullException>(() => _testFixture.DockerClients[clientType].System.MonitorEventsAsync(new ContainerEventsParameters(), null));
7371
}
7472

7573
[Theory]
7674
[MemberData(nameof(GetDockerClientTypes))]
77-
public async Task MonitorEventsAsync_Succeeds(DockerClientType clientType)
75+
public async Task MonitorEventsAsync_Succeeds(TestClientsEnum clientType)
7876
{
7977
var newTag = $"MonitorTests-{Guid.NewGuid().ToString().Substring(1, 10)}";
8078

@@ -116,7 +114,7 @@ await _testFixture.DockerClients[clientType].Images.DeleteImageAsync(
116114

117115
[Theory]
118116
[MemberData(nameof(GetDockerClientTypes))]
119-
public async Task MonitorEventsAsync_IsCancelled_NoStreamCorruption(DockerClientType clientType)
117+
public async Task MonitorEventsAsync_IsCancelled_NoStreamCorruption(TestClientsEnum clientType)
120118
{
121119
var rand = new Random();
122120
var sw = new Stopwatch();
@@ -181,7 +179,7 @@ await _testFixture.DockerClients[clientType].Images.TagImageAsync(
181179

182180
[Theory]
183181
[MemberData(nameof(GetDockerClientTypes))]
184-
public async Task MonitorEventsFiltered_Succeeds(DockerClientType clientType)
182+
public async Task MonitorEventsFiltered_Succeeds(TestClientsEnum clientType)
185183
{
186184
string newTag = $"MonitorTests-{Guid.NewGuid().ToString().Substring(1, 10)}";
187185
string newImageRepositoryName = Guid.NewGuid().ToString();
@@ -247,6 +245,8 @@ await _testFixture.DockerClients[clientType].Images.TagImageAsync(
247245
using var cts = CancellationTokenSource.CreateLinkedTokenSource(_testFixture.Cts.Token);
248246
var task = Task.Run(() => _testFixture.DockerClients[clientType].System.MonitorEventsAsync(eventsParams, progress, cts.Token));
249247

248+
await Task.Delay(TimeSpan.FromSeconds(1));
249+
250250
await _testFixture.DockerClients[clientType].Images.TagImageAsync($"{_testFixture.Repository}:{_testFixture.Tag}", new ImageTagParameters { RepositoryName = _testFixture.Repository, Tag = newTag });
251251
await _testFixture.DockerClients[clientType].Images.DeleteImageAsync($"{_testFixture.Repository}:{newTag}", new ImageDeleteParameters());
252252

@@ -264,7 +264,7 @@ await _testFixture.DockerClients[clientType].Images.TagImageAsync(
264264

265265
[Theory]
266266
[MemberData(nameof(GetDockerClientTypes))]
267-
public async Task PingAsync_Succeeds(DockerClientType clientType)
267+
public async Task PingAsync_Succeeds(TestClientsEnum clientType)
268268
{
269269
await _testFixture.DockerClients[clientType].System.PingAsync();
270270
}

test/Docker.DotNet.Tests/IVolumeOperationsTests.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@ public IVolumeOperationsTests(TestFixture testFixture, ITestOutputHelper testOut
1313
}
1414

1515
public static IEnumerable<object[]> GetDockerClientTypes() =>
16-
Enum.GetValues(typeof(DockerClientType))
17-
.Cast<DockerClientType>()
18-
.Select(t => new object[] { t });
16+
TestFixture.GetDockerClientTypes();
1917

2018
[Theory]
2119
[MemberData(nameof(GetDockerClientTypes))]
22-
public async Task ListAsync_VolumeExists_Succeeds(DockerClientType clientType)
20+
public async Task ListAsync_VolumeExists_Succeeds(TestClientsEnum clientType)
2321
{
2422
const string volumeName = "docker-dotnet-test-volume";
2523

0 commit comments

Comments
 (0)