forked from redhat-developer/s2i-dotnetcore
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun
More file actions
executable file
·597 lines (491 loc) · 18.9 KB
/
run
File metadata and controls
executable file
·597 lines (491 loc) · 18.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
#!/bin/bash
#
# The 'run' script performs simple tests that verifies usability
# of the image
#
# IMAGE_NAME specifies a name of the candidate image used for testing.
# The image has to be available before this script is executed. It may be a
# short image name such as 'foobar', or it may be a fully qualified name in the
# form of example.com/project/repository/image@sha256:hashinhex
#
# OPENSHIFT_ONLY environment variable, if 'true', only tests features used by
# OpenShift's try-it feature.
#
# TEST_PORT specifies the port on the docker host to be used for testing.
# The container application will still use 8080, but this port will be bound
# to the running container when testing asp.net projects.
#
# DEBUG environment variable, if not empty, makes 'run' to log every step
# of testing.
#
# STOP_ON_ERROR determines if the tests should exit on encountering
# the first error, or keep going and list all failed tests at the end.
# Defaults to 'true', can be set to 'false'.
#
# SKIP_VERSION_CHECK environment variable, if 'true', versions are not checked.
#
# Example usage: $ sudo ./test/run
STOP_ON_ERROR=${STOP_ON_ERROR:-true}
IMAGE_OS=${IMAGE_OS:-RHEL8}
IMAGE_NAME=${IMAGE_NAME:-localhost/ubi9/dotnet-100}
# Infer runtime image from SDK image when it is not explicitly set
OPENSHIFT_ONLY=${OPENSHIFT_ONLY:-false}
test_dir="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")")"
source "${test_dir}/testcommon"
dotnet_version_series="10.0"
sample_app_url="https://github.com/redhat-developer/s2i-dotnetcore-ex.git"
s2i_build_and_run() {
local app="$1"
local image=$(s2i_build ${app})
local output=$(docker_run ${image})
docker_rmi ${image}
echo "$output"
}
test_s2i_usage_projfile()
{
# startup_project_not_found contains two project files
# but doesn't set DOTNET_STARTUP_PROJECT to select one.
local app=startup_project_not_found
# build image
local image=$(s2i_image_tag ${app})
local s2i_build=$(s2i_build_output_log ${app} ${image})
# cleanup
docker_rmi ${image}
# verify usage instructions
local expected="error: DOTNET_STARTUP_PROJECT has no project file
You can specify the startup project by adding an '.s2i/environment' file to the source repository.
The source repository contains the following projects:
- proj1/proj1.csproj
- proj2/proj2.fsproj
Update the '.s2i/environment' file to specify the project you want to publish, for example DOTNET_STARTUP_PROJECT=proj1/proj1.csproj."
assert_contains_multiline "${s2i_build}" "${expected}"
}
test_s2i_usage() {
local output=$(s2i_usage ${IMAGE_NAME} 2>&1)
# s2i usage refers to the sample app
assert_contains "$output" "${sample_app_url}"
}
test_usage() {
test_start
test_s2i_usage
test_s2i_usage_projfile
}
test_default_cmd() {
test_start
# verify the default command is bash.
local container=$(docker_run_withargs $IMAGE_NAME -td) # use '-t' to stop bash from exiting.
local processes=$(docker top $container)
# cleanup
docker_rm ${container}
# Ensure there is a single bash process.
# The output of 'docker top' looks like
# USER PID PPID %CPU ELAPSED TTY TIME COMMAND
# root 1 0 0.000 16m30.479579703s pts/0 0s /bin/bash
assert_equal $(echo "$processes" | wc -l) "2"
assert_contains_multiline "$processes" "/bin/bash"
}
test_image() {
test_start
# verify dotnet is available
assert_contains $(docker_run ${IMAGE_NAME} dotnet --version) "$dotnet_version_series"
# Like Microsoft images, we set set DOTNET_SDK_VERSION.
# Its value get checked during the build.
# This is to ensure it is provided as environment variables.
assert_contains $(docker_get_env $IMAGE_NAME DOTNET_SDK_VERSION) "$dotnet_version_series"
# DOTNET_DEFAULT_CMD
assert_equal $(docker_get_env $IMAGE_NAME DOTNET_DEFAULT_CMD) "default-cmd.sh"
# DOTNET_APP_PATH
assert_equal $(docker_get_env $IMAGE_NAME DOTNET_APP_PATH) "/opt/app-root/app"
# Verify $HOME != $CWD. See https://github.com/redhat-developer/s2i-dotnetcore/issues/28
local working_dir=$(docker_run ${IMAGE_NAME} pwd)
assert_equal "${working_dir}" "/opt/app-root/src"
local env=$(docker_run ${IMAGE_NAME} env)
assert_contains "${env}" "HOME=/opt/app-root$"
# Verify the `dotnet watch` command can detect file changes in the container.
assert_contains "${env}" "DOTNET_USE_POLLING_FILE_WATCHER=true$"
# verify no 'Welcome' message appears, due to running first time actions in build Dockerfile.
local dotnet_help=$(docker_run ${IMAGE_NAME} dotnet help)
assert_not_contains "${dotnet_help}" "Welcome"
# Certificate folders created by the 1001 user are not accepted by .NET
# when the image runs on OpenShift as another user.
# Ensure there are no certificate store folders.
# This also ensures the image doesn't include an ASP.NET Core developer certificate.
local certificate_stores=$(docker run --rm ${IMAGE_NAME} stat /opt/app-root/.dotnet/corefx/cryptography/x509stores 2>&1)
assert_contains "${certificate_stores}" "No such file or directory"
}
test_port() {
test_start
# Port 8080 is exposed (for s2i based apps)
assert_equal $(docker_get_exposedports $IMAGE_NAME) '{"8080/tcp":{}}'
}
test_consoleapp() {
test_start
# helloworld is a C# console application
# application returns expected output
assert_contains "$(s2i_build_and_run helloworld)" "Hello World!"
}
test_multiframework() {
test_start
# hw_framework_config targets both: net451 and netcoreapp
# this test verifies we are building and able to run the .NET target.
# application returns expected output
assert_contains "$(s2i_build_and_run hw_framework_config)" "Hello World!"
}
test_fsharp() {
test_start
# helloworld-fs is an F# console application
# application returns expected output
assert_contains "$(s2i_build_and_run helloworld-fs)" "Hello World from F#!"
}
test_vb() {
test_start
# helloworld-vb is a VB console application
# application returns expected output
assert_contains "$(s2i_build_and_run helloworld-vb)" "Hello World from VB!"
}
test_published_files() {
test_start
# qotd has an appsettings.json and quotes.txt files that must
# be published with the app and found at runtime.
# application returns expected output
assert_contains "$(s2i_build_and_run qotd)" "QOTD"
}
test_aspnetapp() {
test_start
# asp-net-hello-world is an ASP.NET Core application
local app=asp-net-hello-world
# build image
local image=$(s2i_build ${app})
# start container
local container=$(docker_run_d ${image})
local url=$(container_url ${container})
# request
local response_base=$(curl_retry ${url}/)
local response_file=$(curl_retry ${url}/TextFile.txt)
local pid1_process=$(docker_exec ${container} /bin/bash -c 'ps --no-headers -o args 1')
# cleanup
docker_rm ${container}
docker_rmi ${image}
# Check response by ASP.NET pipeline
assert_equal "${response_base}" "Hello world"
# Check response by file middleware
assert_equal "${response_file}" "A text file."
# Verify dotnet runs as PID 1
assert_equal "${pid1_process}" "dotnet asp-net-hello-world.dll"
}
test_user() {
test_start
local app=asp-net-hello-world
# user to run the app (30002) is different than user that built the app (1001).
local run_user=30002
# build image
local image=$(s2i_build ${app})
# start container
local container=$(docker_run_as_d ${image} ${run_user})
local url=$(container_url ${container})
# request
local response=$(curl_retry ${url}/)
# cleanup
docker_rm ${container}
docker_rmi ${image}
docker_rmi ${image}-as-${run_user} # image created on podman systems by docker_run_as_d
# app is working
assert_equal "${response}" "Hello world"
}
test_template()
{
local template=$1
info " template: $template"
# newweb creates instantiates the 'dotnet new mvc' template
# in the assemble script.
local app=newtemplate
# build image
local image=$(s2i_build ${app} -e TEMPLATE=$template)
# start container
local container=$(docker_run_d ${image})
local url=$(container_url ${container})
# request
local response=$(curl_retry ${url}/)
# cleanup
docker_rm ${container}
docker_rmi ${image}
# app is working
assert_contains "${response}" "html"
}
test_templates() {
test_start
# mvc is a pure ASP.NET Core MVC web application
local templates=(mvc)
for template in ${templates[@]}; do
test_template $template
done
}
test_config_configuration() {
# DOTNET_CONFIGURATION=Debug
assert_contains "$(s2i_build_and_run dotnet-configuration-debug)" "Debug"
# DOTNET_CONFIGURATION=Release
assert_contains "$(s2i_build_and_run dotnet-configuration-release)" "Release"
}
test_config_1() {
# groups envvar tests which are performed against asp-net-hello-world-envvar
local app=asp-net-hello-world-envvar
# build image
local image=$(s2i_image_tag ${app})
local s2i_build=$(s2i_build_output_log ${app} ${image})
# find gulp and packed all
local watch_path=$(docker_run ${image} bash -c "command -v dotnet-symbol")
local dotnetrpm_path=$(docker_run ${image} bash -c "command -v dotnet-rpm")
local packed_app=$(docker_run ${image} ls /opt/app-root/app.tar.gz)
local src_folder_content=$(docker_run ${image} ls -a /opt/app-root/src)
# start container
local container=$(docker_run_d ${image})
local url=$(container_url ${container})
# request
local response=$(curl_retry ${url}/)
local container_log=$(docker logs ${container})
# cleanup
docker_rm ${container}
docker_rmi ${image}
# DOTNET_STARTUP_PROJECT=src/app
assert_equal "${response}" "Hello world"
# DOTNET_TEST_PROJECTS=test/test1 test/test2
assert_contains "${s2i_build}" "Passed!.*test1"
assert_contains "${s2i_build}" "Passed!.*test2"
# DOTNET_TEST_CONFIGURATION=Debug
assert_contains "${s2i_build}" "test1/bin/Debug"
assert_contains "${s2i_build}" "test2/bin/Debug"
# DOTNET_ASSEMBLY_NAME=SampleApp
assert_contains "${s2i_build}" "/opt/app-root/src/src/app/bin/Debug/net10.0/SampleApp.dll"
# DOTNET_RESTORE_SOURCES=https://api.nuget.org/v3/index.json https://www.myget.org/F/s2i-dotnetcore
assert_contains "${s2i_build}" 'Restored /opt/app-root/src/src/app/app.csproj \([^)]+\)\.' # Includes S2iDotNetCoreDummy from myget.org.
# DOTNET_PACK=true
assert_contains "${s2i_build}" "Packing application..."
assert_equal "${packed_app}" "/opt/app-root/app.tar.gz"
# DOTNET_TOOLS=dotnet-symbol@1.0.5 dotnet-serve
assert_equal "${watch_path}" "/opt/app-root/.dotnet/tools/dotnet-symbol"
assert_equal "${dotnetrpm_path}" "/opt/app-root/.dotnet/tools/dotnet-rpm"
assert_contains "${s2i_build}" "Tool 'dotnet-symbol' \(version '1.0.5'\) was successfully installed."
# DOTNET_RM_SRC=true
# The application folder contains a file and folder that starts with a '.', we verify that *all* files are removed.
assert_contains "${s2i_build}" "Removing sources..."
assert_not_contains "${src_folder_content}" "[^.]"
# DOTNET_INFO=true
assert_contains "${s2i_build}" ".NET information:"
assert_contains "${s2i_build}" "Heap Size:"
assert_contains "${container_log}" ".NET information:"
assert_contains "${container_log}" "Heap Size:"
}
test_config_2() {
# groups envvar tests which are performed against asp-net-hello-world-envvar2
local app=asp-net-hello-world-envvar2
# build image
local image=$(s2i_image_tag ${app})
local s2i_build=$(s2i_build_output_log ${app} ${image})
# start container
local container=$(docker_run_d ${image})
local url=$(container_url ${container})
# request
local response=$(curl_retry ${url}/)
# cleanup
docker_rm ${container}
docker_rmi ${image}
# DOTNET_STARTUP_PROJECT=src/app/app.csproj
# DOTNET_RESTORE_CONFIGFILE=src/app/NuGet.Config.s2i
# The config file was used to restore S2iDotNetCoreDummy and didn't cause issues for the test and tool install.
assert_equal "${response}" "Hello world"
# DOTNET_TEST_PROJECTS=test/test1/test1.csproj test/test2
assert_contains "${s2i_build}" "Finished: test1"
assert_contains "${s2i_build}" "Finished: test2"
# DOTNET_TEST_CONFIGURATION=Release
assert_contains "${s2i_build}" "test1/bin/Release"
assert_contains "${s2i_build}" "test2/bin/Release"
# DOTNET_VERBOSITY=normal
## Environment
assert_contains "${s2i_build}" "Environment:"
assert_contains "${s2i_build}" "DOTNET_VERBOSITY=normal"
assert_contains "${s2i_build}" ".NET information:"
assert_contains "${s2i_build}" "Heap Size:"
## Test project restore
assert_contains "${s2i_build}" 'Project "/opt/app-root/src/test/test1/test1.csproj" on node 1 \(Restore target\(s\)\).'
## Test project test
assert_contains "${s2i_build}" 'Project "/opt/app-root/src/test/test1/test1.csproj" on node 1 \(VSTest target\(s\)\).'
## App project restore
assert_contains "${s2i_build}" 'Project "/opt/app-root/src/src/app/app.csproj" on node 1 \(Restore target\(s\)\).'
## App project publish
assert_contains "${s2i_build}" 'Project "/opt/app-root/src/src/app/app.csproj" on node 1 \(Publish target\(s\)\).'
# DOTNET_PUBLISH_READYTORUN=true
if [ "$(uname -m)" == "s390x" -o "$(uname -m)" == "ppc64le" ]; then
assert_contains "${s2i_build}" 'DOTNET_PUBLISH_READYTORUN is not supported on'
else
assert_contains "${s2i_build}" '_CreateR2RImages'
fi
}
test_config_3() {
# groups envvar tests which are performed against dotnet-configuration-debug
local app=dotnet-configuration-debug
# build image
local image=$(s2i_image_tag ${app})
local s2i_build=$(s2i_build_output_log ${app} ${image})
# cleanup
docker_rmi ${image}
# DOTNET_RESTORE_DISABLE_PARALLEL=true
assert_contains "${s2i_build}" "Running non-parallel restore"
}
test_config() {
test_start
test_config_configuration
test_config_1
test_config_2
test_config_3
}
test_imagestream_sample() {
test_start
# test the sample app defined with the imagestreams:
# "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git",
# "sampleContextDir": "app",
# "sampleRef": "dotnet-10.0"
# build image
local image=$(s2i_image_tag sample)
docker_rmi ${tag}
local s2i_build=$(s2i_build_core ${image} --pull-policy=always --context-dir=app --ref=dotnet-10.0 https://github.com/redhat-developer/s2i-dotnetcore-ex.git 2>&1)
# start container
local container=$(docker_run_d ${image})
local url=$(container_url ${container})
# request
local response=$(curl_retry ${url}/)
# cleanup
docker_rm ${container}
docker_rmi ${image}
# app is working
assert_contains "${response}" "html"
}
test_binary()
{
test_start
# precompiled contains 2 pre-compiled .net console applications
# console.dll: prints out "Hello World!"
# world2/console.dll: prints out "Hello World2!"
local app=precompiled
# verify the console.dll entry point assembly is detected and ran
local image=$(s2i_build ${app})
local output=$(docker_run ${image})
docker_rmi ${image}
assert_contains "${output}" "Hello World!"
# verify we can run world2/console.dll by setting DOTNET_STARTUP_ASSEMBLY
image=$(s2i_build ${app} -e DOTNET_STARTUP_ASSEMBLY=world2/console.dll)
output=$(docker_run ${image})
docker_rmi ${image}
assert_contains "${output}" "Hello World2!"
}
test_incremental()
{
test_start
# asp-net-hello-world-envvar2 is an ASP.NET Core application
local app=asp-net-hello-world-envvar2
# perform a first build, with the incremental flag
local image=$(s2i_image_tag ${app})
docker_rmi ${image}
local s2i_build=$(s2i_build_output_log ${app} ${image} -e DOTNET_INCREMENTAL=true)
# verify packages are installed
assert_contains "${s2i_build}" "GET https://api.nuget.org/v3-flatcontainer/newtonsoft.json/13.0.1/newtonsoft.json.13.0.1.nupkg"
# verify the build completes succesfully
assert_completed_build ${image} "${s2i_build}"
# perform a second build, with the incremental flag
s2i_build=$(s2i_build_output_log ${app} ${image} --incremental -e DOTNET_INCREMENTAL=true)
# verify NO other packages are installed
assert_not_contains "${s2i_build}" "GET https://api.nuget.org/v3-flatcontainer/newtonsoft.json/13.0.1/newtonsoft.json.13.0.1.nupkg"
# verify the build completes succesfully
assert_completed_build ${image} "${s2i_build}"
# cleanup
docker_rmi ${image}
}
test_incremental_without_packages()
{
test_start
# asp-net-hello-world-envvar2 is an ASP.NET Core application
local app=asp-net-hello-world-envvar2
# perform a first build without keeping packages
local image=$(s2i_image_tag ${app})
local s2i_build=$(s2i_build_output_log ${app} ${image} -e DOTNET_INCREMENTAL=false)
# verify packages are installed
assert_contains "${s2i_build}" "GET https://api.nuget.org/v3-flatcontainer/newtonsoft.json/13.0.1/newtonsoft.json.13.0.1.nupkg"
# verify the build completes succesfully
assert_completed_build ${image} "${s2i_build}"
# perform a second build, with the incremental flag
s2i_build=$(s2i_build_output_log ${app} ${image} --incremental)
# verify NO incremental packages are installed
assert_not_contains "${s2i_build}" "Installing artifacts from incremental build"
# verify the build completes succesfully
assert_completed_build ${image} "${s2i_build}"
# cleanup
docker_rmi ${image}
}
test_repos() {
test_start
local output=$(docker_run_as $IMAGE_NAME 0 bash -c 'microdnf install -y zlib-devel || dnf install -y zlib-devel')
assert_contains "$output" "Complete"
}
test_rm_tmp_dotnet() {
test_start
# rm-tmp-dotnet creates a directory at /tmp/.dotnet/shm during assemble.
local app=rm-tmp-dotnet
# build image
local image=$(s2i_image_tag ${app})
local s2i_build=$(s2i_build_output_log ${app} ${image})
local tmp_dotnet=$(docker run --rm ${image} stat /tmp/.dotnet 2>&1)
# cleanup
docker_rmi ${image}
# verify /tmp/.dotnet was removed
assert_contains "${tmp_dotnet}" "No such file or directory"
}
test_msbuild_exec_task() {
test_start
# msbuild-exec-task uses an MSBuild Exec Task.
# MSBuild Exec sets the en_US locale. This test verifies the locale doesn't cause issues in the container image.
# See https://github.com/redhat-developer/s2i-dotnetcore/issues/478.
local app=msbuild-exec-task
# build image
local image=$(s2i_image_tag ${app})
local s2i_build=$(s2i_build_output_log ${app} ${image})
# cleanup
docker_rmi ${image}
# verify the Exec task ran
assert_contains "${s2i_build}" "Running RunExecTask"
# verify the build did not fail
assert_completed_build ${image} "${s2i_build}"
}
info "Testing ${IMAGE_NAME}"
if [ ${OPENSHIFT_ONLY} != true ]; then
test_image
test_port
test_config
test_usage
test_default_cmd
test_repos
test_rm_tmp_dotnet
test_consoleapp
test_multiframework
test_fsharp
test_vb
test_published_files
test_aspnetapp
test_templates
test_user
test_binary
test_incremental
test_incremental_without_packages
test_msbuild_exec_task
else
test_imagestream_sample
fi
if [ "$STOP_ON_ERROR" != "true" ]; then
failures=(${TEST_FAILURES})
if [ ${#failures[@]} -gt 0 ]; then
echo "[ERROR] Tests failed: ${#failures[@]}"
for item in ${failures[@]}; do
echo " ${item}"
done
exit 1
fi
fi
info "All tests finished successfully."