Merge pull request #20 from arthurbarr/master
Latest build and test changes
This commit is contained in:
@@ -13,17 +13,12 @@ before_install:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get -y install docker-ce
|
||||
- curl https://glide.sh/get | sh
|
||||
- curl -LO https://github.com/golang/dep/releases/download/v0.3.0/dep-linux-amd64.zip
|
||||
- unzip dep-linux-amd64.zip
|
||||
- sudo mv dep /usr/local/bin
|
||||
- rm dep-linux-amd64.zip
|
||||
- sudo curl -Lo /usr/local/bin/dep https://github.com/golang/dep/releases/download/v0.3.2/dep-linux-amd64
|
||||
- sudo chmod +x /usr/local/bin/dep
|
||||
|
||||
install:
|
||||
- echo nothing
|
||||
|
||||
before_script:
|
||||
- make deps
|
||||
|
||||
script:
|
||||
- make build-devserver
|
||||
- make test-devserver
|
||||
|
||||
60
Makefile
60
Makefile
@@ -16,7 +16,7 @@ BUILD_SERVER_CONTAINER=build-server
|
||||
DOCKER_TAG_ARCH ?= $(shell uname -m)
|
||||
# By default, all Docker client commands are run inside a Docker container.
|
||||
# This means that newer features of the client can be used, even with an older daemon.
|
||||
DOCKER ?= docker run --tty --interactive --rm --volume /var/run/docker.sock:/var/run/docker.sock --volume "$(CURDIR)":/var/src --workdir /var/src docker:stable docker
|
||||
DOCKER ?= docker
|
||||
DOCKER_TAG ?= latest-$(DOCKER_TAG_ARCH)
|
||||
DOCKER_REPO_DEVSERVER ?= mq-devserver
|
||||
DOCKER_REPO_ADVANCEDSERVER ?= mq-advancedserver
|
||||
@@ -43,6 +43,14 @@ TEST_OPTS_DOCKER ?=
|
||||
# Options to `go test` for the Kubernetes tests
|
||||
TEST_OPTS_KUBERNETES ?=
|
||||
TEST_IMAGE ?= $(DOCKER_FULL_ADVANCEDSERVER)
|
||||
NUM_CPU=$(shell docker info --format "{{ .NCPU }}")
|
||||
|
||||
.PHONY: vars
|
||||
vars:
|
||||
echo $(DOCKER_SERVER_VERSION_MAJOR)
|
||||
echo $(DOCKER_SERVER_VERSION_MINOR)
|
||||
echo $(DOCKER_CLIENT_VERSION_MAJOR)
|
||||
echo $(DOCKER_CLIENT_VERSION_MINOR)
|
||||
|
||||
.PHONY: default
|
||||
default: build-devserver test
|
||||
@@ -75,26 +83,37 @@ downloads: downloads/$(MQ_ARCHIVE_DEV)
|
||||
.PHONY: deps
|
||||
deps:
|
||||
glide install --strip-vendor
|
||||
|
||||
# Vendor Go dependencies for the Docker tests
|
||||
test/docker/vendor:
|
||||
cd test/docker && dep ensure -vendor-only
|
||||
|
||||
# Vendor Go dependencies for the Kubernetes tests
|
||||
test/kubernetes/vendor:
|
||||
cd test/docker && dep ensure -vendor-only
|
||||
cd test/kubernetes && dep ensure -vendor-only
|
||||
|
||||
.PHONY: build-cov
|
||||
build-cov:
|
||||
mkdir -p build
|
||||
cd build; go test -c -covermode=count ../cmd/runmqserver
|
||||
|
||||
# Shortcut to just run the unit tests
|
||||
.PHONY: test-unit
|
||||
test-unit:
|
||||
docker build --target builder --file Dockerfile-server .
|
||||
|
||||
.PHONY: test-advancedserver
|
||||
test-advancedserver:
|
||||
test-advancedserver: test/docker/vendor
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(DOCKER_FULL_ADVANCEDSERVER) on Docker"$(END)))
|
||||
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_ADVANCEDSERVER) go test $(TEST_OPTS_DOCKER)
|
||||
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_ADVANCEDSERVER) go test -parallel $(NUM_CPU) $(TEST_OPTS_DOCKER)
|
||||
|
||||
.PHONY: test-devserver
|
||||
test-devserver:
|
||||
test-devserver: test/docker/vendor
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(DOCKER_FULL_DEVSERVER) on Docker"$(END)))
|
||||
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_DEVSERVER) go test
|
||||
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_DEVSERVER) go test -parallel $(NUM_CPU)
|
||||
|
||||
.PHONY: test-advancedserver-cover
|
||||
test-advancedserver-cover:
|
||||
test-advancedserver-cover: test/docker/vendor
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(DOCKER_REPO_ADVANCEDSERVER) on Docker with code coverage"$(END)))
|
||||
rm -f ./coverage/unit*.cov
|
||||
# Run unit tests with coverage, for each package under 'internal'
|
||||
@@ -115,11 +134,11 @@ test-advancedserver-cover:
|
||||
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
|
||||
|
||||
.PHONY: test-kubernetes-devserver
|
||||
test-kubernetes-devserver:
|
||||
test-kubernetes-devserver: test/kubernetes/vendor
|
||||
$(call test-kubernetes,$(DOCKER_REPO_DEVSERVER),$(DOCKER_TAG),"../../charts/ibm-mqadvanced-server-dev")
|
||||
|
||||
.PHONY: test-kubernetes-advancedserver
|
||||
test-kubernetes-advancedserver:
|
||||
test-kubernetes-advancedserver: test/kubernetes/vendor
|
||||
$(call test-kubernetes,$(DOCKER_REPO_ADVANCEDSERVER),$(DOCKER_TAG),"../../charts/ibm-mqadvanced-server-prod")
|
||||
|
||||
define test-kubernetes
|
||||
@@ -139,9 +158,10 @@ define docker-build-mq
|
||||
--volume "$(realpath ./downloads/)":/usr/share/nginx/html:ro \
|
||||
--detach \
|
||||
nginx:alpine
|
||||
# Make sure we have the latest base image
|
||||
$(DOCKER) pull ubuntu:16.04
|
||||
# Build the new image
|
||||
$(DOCKER) build \
|
||||
--pull \
|
||||
--tag $1 \
|
||||
--file $2 \
|
||||
--network build \
|
||||
@@ -153,24 +173,30 @@ define docker-build-mq
|
||||
. ; $(DOCKER) kill $(BUILD_SERVER_CONTAINER) && $(DOCKER) network rm build
|
||||
endef
|
||||
|
||||
DOCKER_SERVER_VERSION=$(shell docker version --format "{{ .Server.Version }}")
|
||||
DOCKER_CLIENT_VERSION=$(shell docker version --format "{{ .Client.Version }}")
|
||||
.PHONY: docker-version
|
||||
docker-version:
|
||||
@test "$(word 1,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "17" || (echo "Error: Docker client 17.05 or greater is required" && exit 1)
|
||||
@test "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05" || (echo "Error: Docker client 17.05 or greater is required" && exit 1)
|
||||
@test "$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -ge "17" || (echo "Error: Docker server 17.05 or greater is required" && exit 1)
|
||||
@test "$(word 2,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -ge "05" || (echo "Error: Docker server 17.05 or greater is required" && exit 1)
|
||||
|
||||
.PHONY: build-advancedserver
|
||||
build-advancedserver: downloads/$(MQ_ARCHIVE)
|
||||
build-advancedserver: downloads/$(MQ_ARCHIVE) docker-version
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Build $(DOCKER_FULL_ADVANCEDSERVER)"$(END)))
|
||||
$(call docker-build-mq,$(DOCKER_FULL_ADVANCEDSERVER),Dockerfile-server,$(MQ_ARCHIVE),"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced",$(MQ_VERSION))
|
||||
$(DOCKER) tag $(DOCKER_FULL_ADVANCEDSERVER) $(DOCKER_REPO_ADVANCEDSERVER):$(MQ_VERSION)-$(DOCKER_TAG_ARCH)
|
||||
|
||||
.PHONY: build-devserver
|
||||
build-devserver: downloads/$(MQ_ARCHIVE_DEV)
|
||||
ifneq "x86_64" "$(shell uname -m)"
|
||||
$(error MQ Advanced for Developers is only available for x86_64 architecture)
|
||||
else
|
||||
build-devserver: downloads/$(MQ_ARCHIVE_DEV) docker-version
|
||||
@test "$(shell uname -m)" = "x86_64" || (echo "Error: MQ Advanced for Developers is only available for x86_64 architecture" && exit 1)
|
||||
$(info $(shell printf $(TITLE)"Build $(DOCKER_FULL_DEVSERVER)"$(END)))
|
||||
$(call docker-build-mq,$(DOCKER_FULL_DEVSERVER),Dockerfile-server,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)",$(MQ_VERSION))
|
||||
$(DOCKER) tag $(DOCKER_FULL_DEVSERVER) $(DOCKER_REPO_DEVSERVER):$(MQ_VERSION)-$(DOCKER_TAG_ARCH)
|
||||
endif
|
||||
|
||||
.PHONY: build-advancedserver-cover
|
||||
build-advancedserver-cover:
|
||||
build-advancedserver-cover: docker-version
|
||||
$(DOCKER) build -t $(DOCKER_REPO_ADVANCEDSERVER):cover -f Dockerfile-server.cover .
|
||||
|
||||
# .PHONY: build-web
|
||||
|
||||
@@ -36,7 +36,8 @@ func resolveLicenseFile() string {
|
||||
return "Chinese_TW.txt"
|
||||
case strings.HasPrefix(lang, "zh"):
|
||||
return "Chinese.txt"
|
||||
case strings.HasPrefix(lang, "cs"):
|
||||
// Differentiate Czech (cs) and Kashubian (csb)
|
||||
case strings.HasPrefix(lang, "cs") && !strings.HasPrefix(lang, "csb"):
|
||||
return "Czech.txt"
|
||||
case strings.HasPrefix(lang, "fr"):
|
||||
return "French.txt"
|
||||
@@ -50,7 +51,8 @@ func resolveLicenseFile() string {
|
||||
return "Italian.txt"
|
||||
case strings.HasPrefix(lang, "ja"):
|
||||
return "Japanese.txt"
|
||||
case strings.HasPrefix(lang, "ko"):
|
||||
// Differentiate Korean (ko) from Konkani (kok)
|
||||
case strings.HasPrefix(lang, "ko") && !strings.HasPrefix(lang, "kok"):
|
||||
return "Korean.txt"
|
||||
case strings.HasPrefix(lang, "lt"):
|
||||
return "Lithuanian.txt"
|
||||
|
||||
282
cmd/runmqserver/license_test.go
Normal file
282
cmd/runmqserver/license_test.go
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2017
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE_2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var licenseTests = []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"en_US.UTF_8", "English.txt"},
|
||||
{"en_US.ISO-8859-15", "English.txt"},
|
||||
{"es_GB", "Spanish.txt"},
|
||||
{"el_ES.UTF_8", "Greek.txt"},
|
||||
// Cover a wide variety of valid values
|
||||
{"af", "English.txt"},
|
||||
{"af_ZA", "English.txt"},
|
||||
{"ar", "English.txt"},
|
||||
{"ar_AE", "English.txt"},
|
||||
{"ar_BH", "English.txt"},
|
||||
{"ar_DZ", "English.txt"},
|
||||
{"ar_EG", "English.txt"},
|
||||
{"ar_IQ", "English.txt"},
|
||||
{"ar_JO", "English.txt"},
|
||||
{"ar_KW", "English.txt"},
|
||||
{"ar_LB", "English.txt"},
|
||||
{"ar_LY", "English.txt"},
|
||||
{"ar_MA", "English.txt"},
|
||||
{"ar_OM", "English.txt"},
|
||||
{"ar_QA", "English.txt"},
|
||||
{"ar_SA", "English.txt"},
|
||||
{"ar_SY", "English.txt"},
|
||||
{"ar_TN", "English.txt"},
|
||||
{"ar_YE", "English.txt"},
|
||||
{"az", "English.txt"},
|
||||
{"az_AZ", "English.txt"},
|
||||
{"az_AZ", "English.txt"},
|
||||
{"be", "English.txt"},
|
||||
{"be_BY", "English.txt"},
|
||||
{"bg", "English.txt"},
|
||||
{"bg_BG", "English.txt"},
|
||||
{"bs_BA", "English.txt"},
|
||||
{"ca", "English.txt"},
|
||||
{"ca_ES", "English.txt"},
|
||||
{"cs", "Czech.txt"},
|
||||
{"cs_CZ", "Czech.txt"},
|
||||
{"csb_PL", "English.txt"},
|
||||
{"cy", "English.txt"},
|
||||
{"cy_GB", "English.txt"},
|
||||
{"da", "English.txt"},
|
||||
{"da_DK", "English.txt"},
|
||||
{"de", "German.txt"},
|
||||
{"de_AT", "German.txt"},
|
||||
{"de_CH", "German.txt"},
|
||||
{"de_DE", "German.txt"},
|
||||
{"de_LI", "German.txt"},
|
||||
{"de_LU", "German.txt"},
|
||||
{"dv", "English.txt"},
|
||||
{"dv_MV", "English.txt"},
|
||||
{"el", "Greek.txt"},
|
||||
{"el_GR", "Greek.txt"},
|
||||
{"en", "English.txt"},
|
||||
{"en_AU", "English.txt"},
|
||||
{"en_BZ", "English.txt"},
|
||||
{"en_CA", "English.txt"},
|
||||
{"en_CB", "English.txt"},
|
||||
{"en_GB", "English.txt"},
|
||||
{"en_IE", "English.txt"},
|
||||
{"en_JM", "English.txt"},
|
||||
{"en_NZ", "English.txt"},
|
||||
{"en_PH", "English.txt"},
|
||||
{"en_TT", "English.txt"},
|
||||
{"en_US", "English.txt"},
|
||||
{"en_ZA", "English.txt"},
|
||||
{"en_ZW", "English.txt"},
|
||||
{"eo", "English.txt"},
|
||||
{"es", "Spanish.txt"},
|
||||
{"es_AR", "Spanish.txt"},
|
||||
{"es_BO", "Spanish.txt"},
|
||||
{"es_CL", "Spanish.txt"},
|
||||
{"es_CO", "Spanish.txt"},
|
||||
{"es_CR", "Spanish.txt"},
|
||||
{"es_DO", "Spanish.txt"},
|
||||
{"es_EC", "Spanish.txt"},
|
||||
{"es_ES", "Spanish.txt"},
|
||||
{"es_ES", "Spanish.txt"},
|
||||
{"es_GT", "Spanish.txt"},
|
||||
{"es_HN", "Spanish.txt"},
|
||||
{"es_MX", "Spanish.txt"},
|
||||
{"es_NI", "Spanish.txt"},
|
||||
{"es_PA", "Spanish.txt"},
|
||||
{"es_PE", "Spanish.txt"},
|
||||
{"es_PR", "Spanish.txt"},
|
||||
{"es_PY", "Spanish.txt"},
|
||||
{"es_SV", "Spanish.txt"},
|
||||
{"es_UY", "Spanish.txt"},
|
||||
{"es_VE", "Spanish.txt"},
|
||||
{"et", "English.txt"},
|
||||
{"et_EE", "English.txt"},
|
||||
{"eu", "English.txt"},
|
||||
{"eu_ES", "English.txt"},
|
||||
{"fa", "English.txt"},
|
||||
{"fa_IR", "English.txt"},
|
||||
{"fi", "English.txt"},
|
||||
{"fi_FI", "English.txt"},
|
||||
{"fo", "English.txt"},
|
||||
{"fo_FO", "English.txt"},
|
||||
{"fr", "French.txt"},
|
||||
{"fr_BE", "French.txt"},
|
||||
{"fr_CA", "French.txt"},
|
||||
{"fr_CH", "French.txt"},
|
||||
{"fr_FR", "French.txt"},
|
||||
{"fr_LU", "French.txt"},
|
||||
{"fr_MC", "French.txt"},
|
||||
{"gl", "English.txt"},
|
||||
{"gl_ES", "English.txt"},
|
||||
{"gu", "English.txt"},
|
||||
{"gu_IN", "English.txt"},
|
||||
{"he", "English.txt"},
|
||||
{"he_IL", "English.txt"},
|
||||
{"hi", "English.txt"},
|
||||
{"hi_IN", "English.txt"},
|
||||
{"hr", "English.txt"},
|
||||
{"hr_BA", "English.txt"},
|
||||
{"hr_HR", "English.txt"},
|
||||
{"hu", "English.txt"},
|
||||
{"hu_HU", "English.txt"},
|
||||
{"hy", "English.txt"},
|
||||
{"hy_AM", "English.txt"},
|
||||
{"id", "Indonesian.txt"},
|
||||
{"id_ID", "Indonesian.txt"},
|
||||
{"is", "English.txt"},
|
||||
{"is_IS", "English.txt"},
|
||||
{"it", "Italian.txt"},
|
||||
{"it_CH", "Italian.txt"},
|
||||
{"it_IT", "Italian.txt"},
|
||||
{"ja", "Japanese.txt"},
|
||||
{"ja_JP", "Japanese.txt"},
|
||||
{"ka", "English.txt"},
|
||||
{"ka_GE", "English.txt"},
|
||||
{"kk", "English.txt"},
|
||||
{"kk_KZ", "English.txt"},
|
||||
{"kn", "English.txt"},
|
||||
{"kn_IN", "English.txt"},
|
||||
{"ko", "Korean.txt"},
|
||||
{"ko_KR", "Korean.txt"},
|
||||
{"kok", "English.txt"},
|
||||
{"kok_IN", "English.txt"},
|
||||
{"ky", "English.txt"},
|
||||
{"ky_KG", "English.txt"},
|
||||
{"lt", "Lithuanian.txt"},
|
||||
{"lt_LT", "Lithuanian.txt"},
|
||||
{"lv", "English.txt"},
|
||||
{"lv_LV", "English.txt"},
|
||||
{"mi", "English.txt"},
|
||||
{"mi_NZ", "English.txt"},
|
||||
{"mk", "English.txt"},
|
||||
{"mk_MK", "English.txt"},
|
||||
{"mn", "English.txt"},
|
||||
{"mn_MN", "English.txt"},
|
||||
{"mr", "English.txt"},
|
||||
{"mr_IN", "English.txt"},
|
||||
{"ms", "English.txt"},
|
||||
{"ms_BN", "English.txt"},
|
||||
{"ms_MY", "English.txt"},
|
||||
{"mt", "English.txt"},
|
||||
{"mt_MT", "English.txt"},
|
||||
{"nb", "English.txt"},
|
||||
{"nb_NO", "English.txt"},
|
||||
{"nl", "English.txt"},
|
||||
{"nl_BE", "English.txt"},
|
||||
{"nl_NL", "English.txt"},
|
||||
{"nn_NO", "English.txt"},
|
||||
{"ns", "English.txt"},
|
||||
{"ns_ZA", "English.txt"},
|
||||
{"pa", "English.txt"},
|
||||
{"pa_IN", "English.txt"},
|
||||
{"pl", "Polish.txt"},
|
||||
{"pl_PL", "Polish.txt"},
|
||||
{"ps", "English.txt"},
|
||||
{"ps_AR", "English.txt"},
|
||||
{"pt", "Portugese.txt"},
|
||||
{"pt_BR", "Portugese.txt"},
|
||||
{"pt_PT", "Portugese.txt"},
|
||||
{"qu", "English.txt"},
|
||||
{"qu_BO", "English.txt"},
|
||||
{"qu_EC", "English.txt"},
|
||||
{"qu_PE", "English.txt"},
|
||||
{"ro", "English.txt"},
|
||||
{"ro_RO", "English.txt"},
|
||||
{"ru", "Russian.txt"},
|
||||
{"ru_RU", "Russian.txt"},
|
||||
{"sa", "English.txt"},
|
||||
{"sa_IN", "English.txt"},
|
||||
{"se", "English.txt"},
|
||||
{"se_FI", "English.txt"},
|
||||
{"se_FI", "English.txt"},
|
||||
{"se_FI", "English.txt"},
|
||||
{"se_NO", "English.txt"},
|
||||
{"se_NO", "English.txt"},
|
||||
{"se_NO", "English.txt"},
|
||||
{"se_SE", "English.txt"},
|
||||
{"se_SE", "English.txt"},
|
||||
{"se_SE", "English.txt"},
|
||||
{"sk", "English.txt"},
|
||||
{"sk_SK", "English.txt"},
|
||||
{"sl", "Slovenian.txt"},
|
||||
{"sl_SI", "Slovenian.txt"},
|
||||
{"sq", "English.txt"},
|
||||
{"sq_AL", "English.txt"},
|
||||
{"sr_BA", "English.txt"},
|
||||
{"sr_BA", "English.txt"},
|
||||
{"sr_SP", "English.txt"},
|
||||
{"sr_SP", "English.txt"},
|
||||
{"sv", "English.txt"},
|
||||
{"sv_FI", "English.txt"},
|
||||
{"sv_SE", "English.txt"},
|
||||
{"sw", "English.txt"},
|
||||
{"sw_KE", "English.txt"},
|
||||
{"syr", "English.txt"},
|
||||
{"syr_SY", "English.txt"},
|
||||
{"ta", "English.txt"},
|
||||
{"ta_IN", "English.txt"},
|
||||
{"te", "English.txt"},
|
||||
{"te_IN", "English.txt"},
|
||||
{"th", "English.txt"},
|
||||
{"th_TH", "English.txt"},
|
||||
{"tl", "English.txt"},
|
||||
{"tl_PH", "English.txt"},
|
||||
{"tn", "English.txt"},
|
||||
{"tn_ZA", "English.txt"},
|
||||
{"tr", "Turkish.txt"},
|
||||
{"tr_TR", "Turkish.txt"},
|
||||
{"tt", "English.txt"},
|
||||
{"tt_RU", "English.txt"},
|
||||
{"ts", "English.txt"},
|
||||
{"uk", "English.txt"},
|
||||
{"uk_UA", "English.txt"},
|
||||
{"ur", "English.txt"},
|
||||
{"ur_PK", "English.txt"},
|
||||
{"uz", "English.txt"},
|
||||
{"uz_UZ", "English.txt"},
|
||||
{"uz_UZ", "English.txt"},
|
||||
{"vi", "English.txt"},
|
||||
{"vi_VN", "English.txt"},
|
||||
{"xh", "English.txt"},
|
||||
{"xh_ZA", "English.txt"},
|
||||
{"zh", "Chinese.txt"},
|
||||
{"zh_CN", "Chinese.txt"},
|
||||
{"zh_HK", "Chinese.txt"},
|
||||
{"zh_MO", "Chinese.txt"},
|
||||
{"zh_SG", "Chinese.txt"},
|
||||
{"zh_TW", "Chinese_TW.txt"},
|
||||
{"zu", "English.txt"},
|
||||
{"zu_ZA", "English.txt"},
|
||||
}
|
||||
|
||||
func TestResolveLicenseFile(t *testing.T) {
|
||||
for _, table := range licenseTests {
|
||||
os.Setenv("LANG", table.in)
|
||||
f := resolveLicenseFile()
|
||||
if f != table.out {
|
||||
t.Errorf("resolveLicenseFile() with LANG=%v - expected %v, got %v", table.in, table.out, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
@@ -30,6 +31,20 @@ import (
|
||||
"github.com/ibm-messaging/mq-container/internal/name"
|
||||
)
|
||||
|
||||
var debug = false
|
||||
|
||||
func logDebug(msg string) {
|
||||
if debug {
|
||||
log.Printf("DEBUG: %v", msg)
|
||||
}
|
||||
}
|
||||
|
||||
func logDebugf(format string, args ...interface{}) {
|
||||
if debug {
|
||||
log.Printf("DEBUG: %v", fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
// createDirStructure creates the default MQ directory structure under /var/mqm
|
||||
func createDirStructure() error {
|
||||
out, _, err := command.Run("/opt/mqm/bin/crtmqdir", "-f", "-s")
|
||||
@@ -127,6 +142,10 @@ func stopQueueManager(name string) error {
|
||||
}
|
||||
|
||||
func doMain() error {
|
||||
debugEnv, ok := os.LookupEnv("DEBUG")
|
||||
if ok && (debugEnv == "true" || debugEnv == "1") {
|
||||
debug = true
|
||||
}
|
||||
accepted, err := checkLicense()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -50,11 +50,13 @@ func signalHandler(qmgr string) chan int {
|
||||
// End the goroutine
|
||||
return
|
||||
case <-reapSignals:
|
||||
logDebug("Received SIGCHLD signal")
|
||||
reapZombies()
|
||||
case job := <-control:
|
||||
switch {
|
||||
case job == startReaping:
|
||||
// Add SIGCHLD to the list of signals we're listening to
|
||||
logDebug("Listening for SIGCHLD signals")
|
||||
signal.Notify(reapSignals, syscall.SIGCHLD)
|
||||
case job == reapNow:
|
||||
reapZombies()
|
||||
@@ -75,5 +77,6 @@ func reapZombies() {
|
||||
if pid == 0 || err == unix.ECHILD {
|
||||
return
|
||||
}
|
||||
logDebugf("Reaped PID %v", pid)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
|
||||
## Prerequisites
|
||||
You need to ensure you have the following tools installed:
|
||||
* [Docker](https://www.docker.com/) V17.05 or later
|
||||
* [GNU make](https://www.gnu.org/software/make/)
|
||||
|
||||
* [Docker](https://www.docker.com/)
|
||||
You might also need the following tools installed:
|
||||
* [Go](https://golang.org/) - only needed for running the tests
|
||||
* [Glide](https://glide.sh/)
|
||||
* [dep](https://github.com/golang/dep) (official Go dependency management tool)
|
||||
* make
|
||||
* [Glide](https://glide.sh/) - only needed if you update the main dependencies
|
||||
* [dep](https://github.com/golang/dep) (official Go dependency management tool) - only needed to prepare for running the tests
|
||||
* [Helm](https://helm.sh) - only needed for running the Kubernetes tests
|
||||
|
||||
For running the Kubernetes tests, a Kubernetes environment is needed, for example [Minikube](https://github.com/kubernetes/minikube) or [IBM Cloud Private](https://www.ibm.com/cloud-computing/products/ibm-cloud-private/).
|
||||
@@ -24,6 +25,12 @@ You can build a different version of MQ by setting the `MQ_VERSION` environment
|
||||
MQ_VERSION=9.0.3.0 make build-advancedserver
|
||||
```
|
||||
|
||||
If you have an MQ archive file with a different file name, you can specify a particular file (which must be in the `downloads` directory). You should also specify the MQ version, so that the resulting image is tagged correctly, for example:
|
||||
|
||||
```bash
|
||||
MQ_ARCHIVE=mq-1.2.3.4.tar.gz MQ_VERSION=1.2.3.4 build-advancedserver
|
||||
```
|
||||
|
||||
## Running the tests
|
||||
There are three main sets of tests:
|
||||
|
||||
@@ -50,6 +57,12 @@ or:
|
||||
make test-advancedserver
|
||||
```
|
||||
|
||||
You can pass parameters to `go test` with an environment variable. For example, to run the "TestGoldenPath" test, run the following command::
|
||||
|
||||
```
|
||||
TEST_OPTS_DOCKER="-run TestGoldenPath" make test-advancedserver
|
||||
```
|
||||
|
||||
### Running the Docker tests with code coverage
|
||||
You can produce code coverage results from the Docker tests by running the following:
|
||||
|
||||
|
||||
@@ -87,12 +87,10 @@ find /opt/mqm -name '*.tar.gz' -delete
|
||||
rm -f /etc/apt/sources.list.d/IBM_MQ.list
|
||||
rm -rf ${DIR_EXTRACT}
|
||||
|
||||
# Apply any bug fixes not included in base Ubuntu or MQ image.
|
||||
#### Apply any bug fixes not included in base Ubuntu or MQ image.
|
||||
# Don't upgrade everything based on Docker best practices https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#run
|
||||
apt-get upgrade -y libkrb5-26-heimdal
|
||||
apt-get upgrade -y libexpat1
|
||||
|
||||
# End of bug fixes
|
||||
apt-get upgrade -y libdb5.3
|
||||
#### End of bug fixes
|
||||
|
||||
# Clean up cached apt files
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
@@ -17,8 +17,10 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
@@ -27,6 +29,7 @@ import (
|
||||
)
|
||||
|
||||
func TestLicenseNotSet(t *testing.T) {
|
||||
t.Parallel()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -41,6 +44,7 @@ func TestLicenseNotSet(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLicenseView(t *testing.T) {
|
||||
t.Parallel()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -61,23 +65,50 @@ func TestLicenseView(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestGoldenPath starts a queue manager successfully
|
||||
func TestGoldenPath(t *testing.T) {
|
||||
t.Parallel()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
containerConfig := container.Config{
|
||||
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||
//ExposedPorts: ports,
|
||||
ExposedPorts: nat.PortSet{
|
||||
"1414/tcp": struct{}{},
|
||||
},
|
||||
// ExposedPorts: nat.PortSet{
|
||||
// "1414/tcp": struct{}{},
|
||||
// },
|
||||
}
|
||||
id := runContainer(t, cli, &containerConfig)
|
||||
defer cleanContainer(t, cli, id)
|
||||
waitForReady(t, cli, id)
|
||||
}
|
||||
|
||||
// TestSecurityVulnerabilities checks for any vulnerabilities in the image, as reported
|
||||
// by Ubuntu
|
||||
func TestSecurityVulnerabilities(t *testing.T) {
|
||||
t.Parallel()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
containerConfig := container.Config{
|
||||
// Override the entrypoint to make "apt" only receive security updates, then check for updates
|
||||
Entrypoint: []string{"bash", "-c", "source /etc/os-release && echo \"deb http://security.ubuntu.com/ubuntu/ ${VERSION_CODENAME}-security main restricted\" > /etc/apt/sources.list && apt-get update 2>&1 >/dev/null && apt-get --simulate -qq upgrade"},
|
||||
}
|
||||
id := runContainer(t, cli, &containerConfig)
|
||||
defer cleanContainer(t, cli, id)
|
||||
// rc is the return code from apt-get
|
||||
rc := waitForContainer(t, cli, id, 10)
|
||||
if rc != 0 {
|
||||
t.Fatalf("Expected success, got %v", rc)
|
||||
}
|
||||
log := inspectLogs(t, cli, id)
|
||||
lines := strings.Split(strings.TrimSpace(log), "\n")
|
||||
if len(lines) > 0 && lines[0] != "" {
|
||||
t.Errorf("Expected no vulnerabilities, found the following:\n%v", log)
|
||||
}
|
||||
}
|
||||
|
||||
func utilTestNoQueueManagerName(t *testing.T, hostName string, expectedName string) {
|
||||
search := "QMNAME(" + expectedName + ")"
|
||||
cli, err := client.NewEnvClient()
|
||||
@@ -87,29 +118,29 @@ func utilTestNoQueueManagerName(t *testing.T, hostName string, expectedName stri
|
||||
containerConfig := container.Config{
|
||||
Env: []string{"LICENSE=accept"},
|
||||
Hostname: hostName,
|
||||
ExposedPorts: nat.PortSet{
|
||||
"1414/tcp": struct{}{},
|
||||
},
|
||||
}
|
||||
id := runContainer(t, cli, &containerConfig)
|
||||
defer cleanContainer(t, cli, id)
|
||||
waitForReady(t, cli, id)
|
||||
_, out := execContainer(t, cli, id, []string{"dspmq"})
|
||||
out := execContainerWithOutput(t, cli, id, "mqm", []string{"dspmq"})
|
||||
if !strings.Contains(out, search) {
|
||||
t.Errorf("Expected result of running dspmq to contain name=%v, got name=%v", search, out)
|
||||
}
|
||||
}
|
||||
func TestNoQueueManagerName(t *testing.T) {
|
||||
t.Parallel()
|
||||
utilTestNoQueueManagerName(t, "test", "test")
|
||||
}
|
||||
|
||||
func TestNoQueueManagerNameInvalidHostname(t *testing.T) {
|
||||
t.Parallel()
|
||||
utilTestNoQueueManagerName(t, "test-1", "test1")
|
||||
}
|
||||
|
||||
// TestWithVolume runs a container with a Docker volume, then removes that
|
||||
// container and starts a new one with same volume.
|
||||
func TestWithVolume(t *testing.T) {
|
||||
t.Parallel()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -148,17 +179,16 @@ func TestWithVolume(t *testing.T) {
|
||||
waitForReady(t, cli, ctr2.ID)
|
||||
}
|
||||
|
||||
// TestNoVolumeWithRestart ensures a queue manager container can be stopped
|
||||
// and restarted cleanly
|
||||
func TestNoVolumeWithRestart(t *testing.T) {
|
||||
t.Parallel()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
containerConfig := container.Config{
|
||||
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||
//ExposedPorts: ports,
|
||||
ExposedPorts: nat.PortSet{
|
||||
"1414/tcp": struct{}{},
|
||||
},
|
||||
}
|
||||
id := runContainer(t, cli, &containerConfig)
|
||||
defer cleanContainer(t, cli, id)
|
||||
@@ -168,8 +198,9 @@ func TestNoVolumeWithRestart(t *testing.T) {
|
||||
waitForReady(t, cli, id)
|
||||
}
|
||||
|
||||
// Test the case where `crtmqm` will fail
|
||||
// TestCreateQueueManagerFail causes a failure of `crtmqm`
|
||||
func TestCreateQueueManagerFail(t *testing.T) {
|
||||
t.Parallel()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -178,10 +209,6 @@ func TestCreateQueueManagerFail(t *testing.T) {
|
||||
oldEntrypoint := strings.Join(img.Config.Entrypoint, " ")
|
||||
containerConfig := container.Config{
|
||||
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||
//ExposedPorts: ports,
|
||||
ExposedPorts: nat.PortSet{
|
||||
"1414/tcp": struct{}{},
|
||||
},
|
||||
// Override the entrypoint to create the queue manager directory, but leave it empty.
|
||||
// This will cause `crtmqm` to return with an exit code of 2.
|
||||
Entrypoint: []string{"bash", "-c", "mkdir -p /mnt/mqm/data && mkdir -p /var/mqm/qmgrs/qm1 && exec " + oldEntrypoint},
|
||||
@@ -194,8 +221,9 @@ func TestCreateQueueManagerFail(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test the case where `strmqm` will fail
|
||||
// TestStartQueueManagerFail causes a failure of `strmqm`
|
||||
func TestStartQueueManagerFail(t *testing.T) {
|
||||
t.Parallel()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -204,10 +232,6 @@ func TestStartQueueManagerFail(t *testing.T) {
|
||||
oldEntrypoint := strings.Join(img.Config.Entrypoint, " ")
|
||||
containerConfig := container.Config{
|
||||
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||
//ExposedPorts: ports,
|
||||
ExposedPorts: nat.PortSet{
|
||||
"1414/tcp": struct{}{},
|
||||
},
|
||||
// Override the entrypoint to replace `crtmqm` with a no-op script.
|
||||
// This will cause `strmqm` to return with an exit code of 16.
|
||||
Entrypoint: []string{"bash", "-c", "echo '#!/bin/bash\n' > /opt/mqm/bin/crtmqm && exec " + oldEntrypoint},
|
||||
@@ -219,3 +243,87 @@ func TestStartQueueManagerFail(t *testing.T) {
|
||||
t.Errorf("Expected rc=1, got rc=%v", rc)
|
||||
}
|
||||
}
|
||||
|
||||
// TestVolumeUnmount runs a queue manager with a volume, and then forces an
|
||||
// unmount of the volume. The health check should then fail.
|
||||
// This simulates behaviour seen in some cloud environments, where network
|
||||
// attached storage gets unmounted.
|
||||
func TestVolumeUnmount(t *testing.T) {
|
||||
t.Parallel()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
vol := createVolume(t, cli)
|
||||
defer removeVolume(t, cli, vol.Name)
|
||||
containerConfig := container.Config{
|
||||
Image: imageName(),
|
||||
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||
}
|
||||
hostConfig := container.HostConfig{
|
||||
// SYS_ADMIN capability is required to unmount file systems
|
||||
CapAdd: []string{
|
||||
"SYS_ADMIN",
|
||||
},
|
||||
Binds: []string{
|
||||
coverageBind(t),
|
||||
vol.Name + ":/mnt/mqm",
|
||||
},
|
||||
}
|
||||
networkingConfig := network.NetworkingConfig{}
|
||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
startContainer(t, cli, ctr.ID)
|
||||
defer cleanContainer(t, cli, ctr.ID)
|
||||
waitForReady(t, cli, ctr.ID)
|
||||
// Unmount the volume as root
|
||||
rc := execContainerWithExitCode(t, cli, ctr.ID, "root", []string{"umount", "-l", "-f", "/mnt/mqm"})
|
||||
if rc != 0 {
|
||||
t.Fatalf("Expected umount to work with rc=0, got %v", rc)
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
rc = execContainerWithExitCode(t, cli, ctr.ID, "mqm", []string{"chkmqhealthy"})
|
||||
if rc == 0 {
|
||||
t.Errorf("Expected chkmqhealthy to fail")
|
||||
t.Logf(execContainerWithOutput(t, cli, ctr.ID, "mqm", []string{"df"}))
|
||||
t.Logf(execContainerWithOutput(t, cli, ctr.ID, "mqm", []string{"ps", "-ef"}))
|
||||
}
|
||||
}
|
||||
|
||||
// TestZombies starts a queue manager, then causes a zombie process to be
|
||||
// created, then checks that no zombies exist (runmqserver should reap them)
|
||||
func TestZombies(t *testing.T) {
|
||||
t.Parallel()
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
containerConfig := container.Config{
|
||||
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1", "DEBUG=true"},
|
||||
//ExposedPorts: ports,
|
||||
ExposedPorts: nat.PortSet{
|
||||
"1414/tcp": struct{}{},
|
||||
},
|
||||
}
|
||||
id := runContainer(t, cli, &containerConfig)
|
||||
defer cleanContainer(t, cli, id)
|
||||
waitForReady(t, cli, id)
|
||||
// Kill an MQ process with children. After it is killed, its children
|
||||
// will be adopted by PID 1, and should then be reaped when they die.
|
||||
out := execContainerWithOutput(t, cli, id, "mqm", []string{"pkill", "--signal", "kill", "-c", "amqzxma0"})
|
||||
if out == "0" {
|
||||
t.Fatalf("Expected pkill to kill a process, got %v", out)
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
// Create a zombie process for up to ten seconds
|
||||
out = execContainerWithOutput(t, cli, id, "mqm", []string{"bash", "-c", "ps -lA | grep '^. Z' | wc -l"})
|
||||
count, err := strconv.Atoi(out)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if count != 0 {
|
||||
t.Fatalf("Expected zombies=0, got %v", count)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -31,7 +32,7 @@ import (
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
)
|
||||
|
||||
func imageName() string {
|
||||
@@ -97,14 +98,14 @@ func runContainer(t *testing.T, cli *client.Client, containerConfig *container.C
|
||||
// if coverage
|
||||
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
||||
hostConfig := container.HostConfig{
|
||||
PortBindings: nat.PortMap{
|
||||
"1414/tcp": []nat.PortBinding{
|
||||
{
|
||||
HostIP: "0.0.0.0",
|
||||
HostPort: "1414",
|
||||
},
|
||||
},
|
||||
},
|
||||
// PortBindings: nat.PortMap{
|
||||
// "1414/tcp": []nat.PortBinding{
|
||||
// {
|
||||
// HostIP: "0.0.0.0",
|
||||
// HostPort: "1414",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
Binds: []string{
|
||||
coverageBind(t),
|
||||
},
|
||||
@@ -141,11 +142,11 @@ func getCoverageExitCode(t *testing.T, orig int64) int64 {
|
||||
f := filepath.Join(coverageDir(t), "exitCode")
|
||||
_, err := os.Stat(f)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
//t.Log(err)
|
||||
return orig
|
||||
}
|
||||
// Remove the file, ready for the next test
|
||||
//defer os.Remove(f)
|
||||
defer os.Remove(f)
|
||||
buf, err := ioutil.ReadFile(f)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
@@ -179,11 +180,45 @@ func waitForContainer(t *testing.T, cli *client.Client, ID string, timeout int64
|
||||
return rc
|
||||
}
|
||||
|
||||
// execContainer runs the specified command inside the container, returning the
|
||||
// exit code and the stdout/stderr string.
|
||||
func execContainer(t *testing.T, cli *client.Client, ID string, cmd []string) (int, string) {
|
||||
// execContainerWithExitCode runs a command in a running container, and returns the exit code
|
||||
// Note: due to a bug in Docker/Moby code, you always get an exit code of 0 if you attach to the
|
||||
// container to get output. This is why these are two separate commands.
|
||||
func execContainerWithExitCode(t *testing.T, cli *client.Client, ID string, user string, cmd []string) int {
|
||||
config := types.ExecConfig{
|
||||
User: "mqm",
|
||||
User: user,
|
||||
Privileged: false,
|
||||
Tty: false,
|
||||
AttachStdin: false,
|
||||
// Note that you still need to attach stdout/stderr, even though they're not wanted
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
Detach: false,
|
||||
Cmd: cmd,
|
||||
}
|
||||
resp, err := cli.ContainerExecCreate(context.Background(), ID, config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cli.ContainerExecStart(context.Background(), resp.ID, types.ExecStartCheck{
|
||||
Detach: false,
|
||||
Tty: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
inspect, err := cli.ContainerExecInspect(context.Background(), resp.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return inspect.ExitCode
|
||||
}
|
||||
|
||||
// execContainerWithOutput runs a command in a running container, and returns the output from stdout/stderr
|
||||
// Note: due to a bug in Docker/Moby code, you always get an exit code of 0 if you attach to the
|
||||
// container to get output. This is why these are two separate commands.
|
||||
func execContainerWithOutput(t *testing.T, cli *client.Client, ID string, user string, cmd []string) string {
|
||||
config := types.ExecConfig{
|
||||
User: user,
|
||||
Privileged: false,
|
||||
Tty: false,
|
||||
AttachStdin: false,
|
||||
@@ -207,46 +242,19 @@ func execContainer(t *testing.T, cli *client.Client, ID string, cmd []string) (i
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
inspect, err := cli.ContainerExecInspect(context.Background(), resp.ID)
|
||||
buf := new(bytes.Buffer)
|
||||
// Each output line has a header, which needs to be removed
|
||||
_, err = stdcopy.StdCopy(buf, buf, hijack.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
// TODO: For some reason, each line seems to start with an extra, random character
|
||||
buf, err := ioutil.ReadAll(hijack.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hijack.Close()
|
||||
return inspect.ExitCode, string(buf)
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
||||
|
||||
func waitForReady(t *testing.T, cli *client.Client, ID string) {
|
||||
for {
|
||||
resp, err := cli.ContainerExecCreate(context.Background(), ID, types.ExecConfig{
|
||||
User: "mqm",
|
||||
Privileged: false,
|
||||
Tty: false,
|
||||
AttachStdin: false,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
Detach: false,
|
||||
Cmd: []string{"chkmqready"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cli.ContainerExecStart(context.Background(), resp.ID, types.ExecStartCheck{
|
||||
Detach: false,
|
||||
Tty: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
inspect, err := cli.ContainerExecInspect(context.Background(), resp.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if inspect.ExitCode == 0 {
|
||||
rc := execContainerWithExitCode(t, cli, ID, "mqm", []string{"chkmqready"})
|
||||
if rc == 0 {
|
||||
t.Log("MQ is ready")
|
||||
return
|
||||
}
|
||||
@@ -313,8 +321,11 @@ func inspectLogs(t *testing.T, cli *client.Client, ID string) string {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(reader)
|
||||
// Each output line has a header, which needs to be removed
|
||||
_, err = stdcopy.StdCopy(buf, buf, reader)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user