diff --git a/go.mod b/go.mod index 2fe9a182..b9840863 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/streamnative/pulsarctl go 1.12 require ( - github.com/davecgh/go-spew v1.1.1 github.com/dgrijalva/jwt-go v3.2.0+incompatible + github.com/docker/go-connections v0.4.0 github.com/fatih/color v1.7.0 // indirect github.com/golang/protobuf v1.3.1 github.com/google/go-cmp v0.3.1 // indirect @@ -16,7 +16,7 @@ require ( github.com/pkg/errors v0.8.1 github.com/spf13/cobra v0.0.5 github.com/spf13/pflag v1.0.3 - github.com/stretchr/objx v0.2.0 // indirect github.com/stretchr/testify v1.3.0 + github.com/testcontainers/testcontainers-go v0.0.10 gopkg.in/yaml.v2 v2.2.2 ) diff --git a/go.sum b/go.sum index 8182d15c..f7eda5a0 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,17 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/hcsshim v0.8.6 h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -9,16 +21,49 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible h1:dvc1KSkIYTVjZgHf/CTC2diTYC8PzhaA5sFISRfNVrE= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190506211059-b20a14b54661 h1:ZuxGvIvF01nfc/G9RJ5Q7Va1zQE2WJyG18Zv3DqCEf4= +github.com/docker/docker v0.7.3-0.20190506211059-b20a14b54661/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-redis/redis v6.15.6+incompatible h1:H9evprGPLI8+ci7fxQx6WNZHJSb7be8FqJQRhdQZ5Sg= +github.com/go-redis/redis v6.15.6+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kris-nova/logger v0.0.0-20181127235838-fd0d87064b06 h1:vN4d3jSss3ExzUn2cE0WctxztfOgiKvMKnDrydBsg00= github.com/kris-nova/logger v0.0.0-20181127235838-fd0d87064b06/go.mod h1:++9BgZujZd4v0ZTZCb5iPsaomXdZWyxotIAh1IiDm44= github.com/kris-nova/lolgopher v0.0.0-20180921204813-313b3abb0d9b h1:xYEM2oBUhBEhQjrV+KJ9lEWDWYZoNVZUaBF++Wyljq4= @@ -32,14 +77,32 @@ github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE= +github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= @@ -49,21 +112,54 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/testcontainers/testcontainers-go v0.0.10 h1:WP99DOGWmkr+RXHURyAXnvZqZO0x3VXkRYAzQ+mwtpQ= +github.com/testcontainers/testcontainers-go v0.0.10/go.mod h1:2kePcwMHd3ix/BU3cTDuhvggUgMBAit+qcWwadeMXok= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180810170437-e96c4e24768d/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.17.0 h1:TRJYBgMclJvGYn2rIMjj+h9KtMt5r1Ij7ODVRIZkwhk= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools v0.0.0-20181223230014-1083505acf35 h1:zpdCK+REwbk+rqjJmHhiCN6iBIigrZ39glqSF0P3KF0= +gotest.tools v0.0.0-20181223230014-1083505acf35/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/test/base_container.go b/pkg/test/base_container.go new file mode 100644 index 00000000..4476a017 --- /dev/null +++ b/pkg/test/base_container.go @@ -0,0 +1,138 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 test + +import ( + "context" + + "github.com/docker/go-connections/nat" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" +) + +// BaseContainer provide the basic operations for a container. +type BaseContainer struct { + containerRequest testcontainers.GenericContainerRequest + container testcontainers.Container +} + +// NewContainer creates a container using the image. +func NewContainer(image string) *BaseContainer { + gcr := testcontainers.GenericContainerRequest{ + ContainerRequest: testcontainers.ContainerRequest{ + Image: image, + }, + } + + return &BaseContainer{ + containerRequest: gcr, + } +} + +// WithNetwork uses a existent network for the container. +func (bc *BaseContainer) WithNetwork(network []string) *BaseContainer { + bc.containerRequest.Networks = append(bc.containerRequest.Networks, network...) + return bc +} + +// WithNetworkAliases creates some aliases for the container. +func (bc *BaseContainer) WithNetworkAliases(aliases map[string][]string) *BaseContainer { + if bc.containerRequest.NetworkAliases == nil { + bc.containerRequest.NetworkAliases = make(map[string][]string) + } + for k, v := range aliases { + bc.containerRequest.NetworkAliases[k] = append(bc.containerRequest.NetworkAliases[k], v...) + } + return bc +} + +// WithCmd sets the containers start up commands. +func (bc *BaseContainer) WithCmd(cmd []string) *BaseContainer { + bc.containerRequest.Cmd = append(bc.containerRequest.Cmd, cmd...) + return bc +} + +// WithEnv sets the environment variable to the container. +func (bc *BaseContainer) WithEnv(env map[string]string) *BaseContainer { + if bc.containerRequest.Env == nil { + bc.containerRequest.Env = make(map[string]string) + } + for k, v := range env { + bc.containerRequest.Env[k] = v + } + return bc +} + +// ExposedPorts exposes the ports from the container. +func (bc *BaseContainer) ExposedPorts(ports []string) *BaseContainer { + bc.containerRequest.ExposedPorts = append(bc.containerRequest.ExposedPorts, ports...) + return bc +} + +// WaitForPort waits for the container ports exposed. +func (bc *BaseContainer) WaitForPort(port string) *BaseContainer { + bc.containerRequest.WaitingFor = wait.ForListeningPort(nat.Port(port)) + return bc +} + +// WaitForLog waits for the log string appear. +func (bc *BaseContainer) WaitForLog(log string) *BaseContainer { + bc.containerRequest.WaitingFor = wait.ForLog(log) + return bc +} + +// WaitForHTTPPath waits for the path can be used. The Default access port is 80. +// TODO: support the specified path with a port. +func (bc *BaseContainer) WaitForHTTPPath(path string) *BaseContainer { + bc.containerRequest.WaitingFor = wait.ForHTTP(path) + return bc +} + +// Start starts the container. +func (bc *BaseContainer) Start(ctx context.Context) error { + c, err := testcontainers.GenericContainer(ctx, bc.containerRequest) + if err != nil { + return err + } + bc.container = c + err = c.Start(ctx) + return err +} + +// ExecCmd executes a command in the container. +func (bc *BaseContainer) ExecCmd(ctx context.Context, cmd []string) (int, error) { + return bc.container.Exec(ctx, cmd) +} + +// Stop stops the container. +func (bc *BaseContainer) Stop(ctx context.Context) error { + if bc.container != nil { + return bc.container.Terminate(ctx) + } + return nil +} + +// GetContainerID gets the container ID. +func (bc *BaseContainer) GetContainerID() string { + return bc.container.GetContainerID() +} + +// MappedPort gets the outside port. +func (bc *BaseContainer) MappedPort(ctx context.Context, port string) (nat.Port, error) { + return bc.container.MappedPort(ctx, nat.Port(port)) +} diff --git a/pkg/test/pulsar/cluster.go b/pkg/test/pulsar/cluster.go new file mode 100644 index 00000000..92e25c11 --- /dev/null +++ b/pkg/test/pulsar/cluster.go @@ -0,0 +1,235 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 pulsar + +import ( + "context" + "fmt" + "strconv" + + "github.com/streamnative/pulsarctl/pkg/test" + "github.com/streamnative/pulsarctl/pkg/test/pulsar/containers" + + "github.com/pkg/errors" + "github.com/testcontainers/testcontainers-go" +) + +var ( + InvalidPort = -1 + DefaultZKPort = 2181 + DefaultBookiePort = 3181 + DefaultBrokerPort = 6650 + DefaultBrokerHTTPPort = 8080 + + LatestImage = "apachepulsar/pulsar:latest" +) + +type ClusterDef struct { + clusterSpec *ClusterSpec + network testcontainers.Network + zkContainer *test.BaseContainer + proxyContainer *test.BaseContainer + bookieContainers map[string]*test.BaseContainer + brokerContainers map[string]*test.BaseContainer +} + +type Cluster interface { + // Start a pulsar cluster. + Start(ctx context.Context) error + + // Stop a pulsar cluster. + Stop(ctx context.Context) error + + // GetPlainTextServiceURL gets the pulsar service connect string. + GetPlainTextServiceURL(ctx context.Context) (string, error) + + // GetHTTPServiceURL gets the pulsar HTTP service connect string. + GetHTTPServiceURL(ctx context.Context) (string, error) + + // Close closes resources used for starting the cluster. + Close(ctx context.Context) +} + +// DefaultPulsarCluster creates a pulsar cluster using the default cluster spec. +func DefaultPulsarCluster() (Cluster, error) { + return NewPulsarCluster(DefaultClusterSpec()) +} + +// NewPulsarCluster creates a pulsar cluster using the spec. +func NewPulsarCluster(spec *ClusterSpec) (Cluster, error) { + networkName := spec.ClusterName + network, err := test.NewNetwork(networkName) + if err != nil { + return nil, err + } + + zookeeper := containers.NewZookeeperContainer(LatestImage, networkName) + bookies := getBookieContainers(networkName, spec.NumBookies) + brokers := getBrokerContainers(spec.ClusterName, networkName, spec.NumBrokers) + broker := getABrokerNetAlias(brokers) + proxy := containers.NewProxyContainer(LatestImage, networkName).WithEnv(map[string]string{ + "webServicePort": strconv.Itoa(spec.ProxyHTTPServicePort), + "servicePort": strconv.Itoa(spec.ProxyServicePort), + "brokerServiceURL": fmt.Sprintf("pulsar://%s:%d", broker, spec.BrokerServicePort), + "brokerWebServiceURL": fmt.Sprintf("http://%s:%d", broker, spec.BrokerHTTPServicePort), + }) + + return &ClusterDef{ + network: network, + clusterSpec: spec, + zkContainer: zookeeper, + proxyContainer: proxy, + bookieContainers: bookies, + brokerContainers: brokers, + }, nil +} + +func getBookieContainers(network string, num int) map[string]*test.BaseContainer { + bookies := make(map[string]*test.BaseContainer) + for i := 0; i < num; i++ { + name := fmt.Sprintf("%s-%d", containers.BookieName, i) + bookies[name] = containers.NewBookieContainer(LatestImage, network).WithEnv(map[string]string{ + "zkServers": containers.ZookeeperName, + }).WithNetworkAliases(map[string][]string{ + network: {name}, + }) + } + return bookies +} + +func getBrokerContainers(clusterName, network string, num int) map[string]*test.BaseContainer { + brokers := make(map[string]*test.BaseContainer) + for i := 0; i < num; i++ { + name := fmt.Sprintf("%s-%d", containers.BrokerName, i) + brokers[name] = containers.NewBrokerContainer(LatestImage, network).WithEnv(map[string]string{ + "zookeeperServers": containers.ZookeeperName, + "clusterName": clusterName, + }).WithNetworkAliases(map[string][]string{ + network: {name}, + }) + } + return brokers +} + +func getABrokerNetAlias(brokers map[string]*test.BaseContainer) string { + for k := range brokers { + return k + } + return containers.BrokerName +} + +func (c *ClusterDef) Start(ctx context.Context) error { + err := c.zkContainer.Start(ctx) + if err != nil { + return errors.WithMessage(err, "encountered errors when starting the zookeeper") + } + fmt.Printf("Zookeeper %s:%s started.\n", containers.ZookeeperName, c.zkContainer.GetContainerID()) + + init := InitCluster(&InitConf{ + ClusterName: c.clusterSpec.ClusterName, + ConfigurationStore: fmt.Sprintf("%s:%d", containers.ZookeeperName, DefaultZKPort), + Zookeeper: fmt.Sprintf("%s:%d", containers.ZookeeperName, DefaultZKPort), + Broker: fmt.Sprintf("%s:%d", + getABrokerNetAlias(c.brokerContainers), c.clusterSpec.BrokerHTTPServicePort), + }, LatestImage, c.clusterSpec.ClusterName) + err = init.Start(ctx) + if err != nil { + return errors.WithMessage(err, "encountered errors when initializing the pulsar cluster") + } + fmt.Printf("Initialize pulsar cluster %s successfully.\n", c.clusterSpec.ClusterName) + + for k, v := range c.bookieContainers { + err = v.Start(ctx) + if err != nil { + return errors.WithMessagef(err, "encountered errors when starting the bookie %s", k) + } + fmt.Printf("Bookie %s:%s started.\n", k, v.GetContainerID()) + } + + for k, v := range c.brokerContainers { + err = v.Start(ctx) + if err != nil { + return errors.WithMessagef(err, "encountered errors when starting the bookie %s", k) + } + fmt.Printf("Broker %s:%s started.\n", k, v.GetContainerID()) + } + + err = c.proxyContainer.Start(ctx) + if err != nil { + return errors.WithMessage(err, "encountered errors when starting the proxy") + } + fmt.Printf("Proxy %s:%s started.\n", containers.ProxyName, c.proxyContainer.GetContainerID()) + + return nil +} + +func (c *ClusterDef) Stop(ctx context.Context) error { + if c.zkContainer != nil { + err := c.zkContainer.Stop(ctx) + if err != nil { + return err + } + } + + if c.bookieContainers != nil { + for _, v := range c.bookieContainers { + err := v.Stop(ctx) + if err != nil { + return err + } + } + } + + if c.brokerContainers != nil { + for _, v := range c.brokerContainers { + err := v.Stop(ctx) + if err != nil { + return err + } + } + } + + if c.proxyContainer != nil { + err := c.proxyContainer.Stop(ctx) + if err != nil { + return err + } + } + + return nil +} + +func (c *ClusterDef) GetPlainTextServiceURL(ctx context.Context) (string, error) { + port, err := c.proxyContainer.MappedPort(ctx, strconv.Itoa(c.clusterSpec.BrokerHTTPServicePort)) + if err != nil { + return "", err + } + return "pulsar://localhost:" + port.Port(), nil +} + +func (c *ClusterDef) GetHTTPServiceURL(ctx context.Context) (string, error) { + port, err := c.proxyContainer.MappedPort(ctx, strconv.Itoa(c.clusterSpec.ProxyHTTPServicePort)) + if err != nil { + return "", err + } + return "http://localhost:" + port.Port(), nil +} + +func (c *ClusterDef) Close(ctx context.Context) { + c.network.Remove(ctx) +} diff --git a/pkg/test/pulsar/cluster_script.go b/pkg/test/pulsar/cluster_script.go new file mode 100644 index 00000000..160ed473 --- /dev/null +++ b/pkg/test/pulsar/cluster_script.go @@ -0,0 +1,45 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 pulsar + +import ( + "fmt" + + "github.com/streamnative/pulsarctl/pkg/test" +) + +// InitConf is a configuration for the initialization of the pulsar cluster. +type InitConf struct { + ClusterName string + ConfigurationStore string + Zookeeper string + Broker string +} + +// InitCluster returns a container for executing init pulsar cluster. +func InitCluster(conf *InitConf, image, network string) *test.BaseContainer { + pulsarInit := test.NewContainer(image) + pulsarInit.WithNetwork([]string{network}) + pulsarInit.WaitForLog(fmt.Sprintf("Cluster metadata for '%s' setup correctly", conf.ClusterName)) + pulsarInit.WithCmd([]string{ + "bash", "-c", + fmt.Sprintf("bin/pulsar initialize-cluster-metadata -c %s -cs %s -uw %s -zk %s", + conf.ClusterName, conf.ConfigurationStore, conf.Broker, conf.Zookeeper), + }) + return pulsarInit +} diff --git a/pkg/test/pulsar/cluster_spec.go b/pkg/test/pulsar/cluster_spec.go new file mode 100644 index 00000000..73f4bb9f --- /dev/null +++ b/pkg/test/pulsar/cluster_spec.go @@ -0,0 +1,48 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 pulsar + +// ClusterSpec is to build a pulsar cluster. +type ClusterSpec struct { + Image string + ClusterName string + BookiePort int + NumBookies int + BrokerServicePort int + BrokerHTTPServicePort int + NumBrokers int + ProxyServicePort int + ProxyHTTPServicePort int + NumProxies int +} + +// DefaultClusterSpec returns default configuration of a cluster. +func DefaultClusterSpec() *ClusterSpec { + return &ClusterSpec{ + Image: LatestImage, + ClusterName: "default-cluster", + BookiePort: DefaultBookiePort, + NumBookies: 2, + BrokerServicePort: DefaultBrokerPort, + BrokerHTTPServicePort: DefaultBrokerHTTPPort, + NumBrokers: 2, + ProxyServicePort: DefaultBrokerPort, + ProxyHTTPServicePort: DefaultBrokerHTTPPort, + NumProxies: 1, + } +} diff --git a/pkg/test/pulsar/cluster_test.go b/pkg/test/pulsar/cluster_test.go new file mode 100644 index 00000000..d896cf9c --- /dev/null +++ b/pkg/test/pulsar/cluster_test.go @@ -0,0 +1,56 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 pulsar + +import ( + "context" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDefaultPulsarCluster(t *testing.T) { + ctx := context.Background() + pulsar, err := DefaultPulsarCluster() + // nolint + defer pulsar.Close(ctx) + if err != nil { + t.Fatal(err) + } + + err = pulsar.Start(ctx) + defer pulsar.Stop(ctx) + if err != nil { + t.Fatal(err) + } + + path, err := pulsar.GetHTTPServiceURL(ctx) + if err != nil { + t.Fatal(err) + } + + resp, err := http.Get(path + "/admin/v2/tenants") + // nolint + defer resp.Body.Close() + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, 200, resp.StatusCode) +} diff --git a/pkg/test/pulsar/containers/bookie.go b/pkg/test/pulsar/containers/bookie.go new file mode 100644 index 00000000..0fe81379 --- /dev/null +++ b/pkg/test/pulsar/containers/bookie.go @@ -0,0 +1,34 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 containers + +import "github.com/streamnative/pulsarctl/pkg/test" + +const BookieName = "bookie" + +func NewBookieContainer(image, network string) *test.BaseContainer { + bk := test.NewContainer(image) + bk.WithNetwork([]string{network}) + bk.WithNetworkAliases(map[string][]string{network: {BookieName}}) + bk.WithCmd([]string{ + "bash", "-c", + "bin/apply-config-from-env.py conf/bookkeeper.conf && bin/pulsar bookie", + }) + bk.WaitForLog("Started component bookie-server") + return bk +} diff --git a/pkg/test/pulsar/containers/broker.go b/pkg/test/pulsar/containers/broker.go new file mode 100644 index 00000000..3a6af955 --- /dev/null +++ b/pkg/test/pulsar/containers/broker.go @@ -0,0 +1,35 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 containers + +import "github.com/streamnative/pulsarctl/pkg/test" + +const BrokerName = "broker" + +func NewBrokerContainer(image, network string) *test.BaseContainer { + broker := test.NewContainer(image) + broker.WithNetwork([]string{network}) + broker.WithNetworkAliases(map[string][]string{network: {BrokerName}}) + broker.ExposedPorts([]string{"8080", "6650"}) + broker.WithCmd([]string{ + "bash", "-c", + "bin/apply-config-from-env.py conf/broker.conf && bin/pulsar broker", + }) + broker.WaitForPort("8080") + return broker +} diff --git a/pkg/test/pulsar/containers/proxy.go b/pkg/test/pulsar/containers/proxy.go new file mode 100644 index 00000000..44424352 --- /dev/null +++ b/pkg/test/pulsar/containers/proxy.go @@ -0,0 +1,35 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 containers + +import "github.com/streamnative/pulsarctl/pkg/test" + +const ProxyName = "proxy" + +func NewProxyContainer(image, network string) *test.BaseContainer { + proxy := test.NewContainer(image) + proxy.WithNetwork([]string{network}) + proxy.WithNetworkAliases(map[string][]string{network: {ProxyName}}) + proxy.ExposedPorts([]string{"8080", "6650"}) + proxy.WithCmd([]string{ + "bash", "-c", + "bin/apply-config-from-env.py conf/proxy.conf && bin/pulsar proxy", + }) + proxy.WaitForLog("Server started at end point") + return proxy +} diff --git a/pkg/test/pulsar/containers/zookeeper.go b/pkg/test/pulsar/containers/zookeeper.go new file mode 100644 index 00000000..75f543d2 --- /dev/null +++ b/pkg/test/pulsar/containers/zookeeper.go @@ -0,0 +1,34 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 containers + +import "github.com/streamnative/pulsarctl/pkg/test" + +const ZookeeperName = "zookeeper" + +func NewZookeeperContainer(image, network string) *test.BaseContainer { + zookeeper := test.NewContainer(image) + zookeeper.WithNetwork([]string{network}) + zookeeper.WithNetworkAliases(map[string][]string{network: {ZookeeperName}}) + zookeeper.ExposedPorts([]string{"2181"}) + zookeeper.WithCmd([]string{ + "bin/pulsar", "zookeeper", + }) + zookeeper.WaitForPort("2181") + return zookeeper +} diff --git a/pkg/test/pulsar/standalone.go b/pkg/test/pulsar/standalone.go new file mode 100644 index 00000000..492fc18c --- /dev/null +++ b/pkg/test/pulsar/standalone.go @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 pulsar + +import "github.com/streamnative/pulsarctl/pkg/test" + +func NewStandalone(image string) *test.BaseContainer { + s := test.NewContainer(image) + s.ExposedPorts([]string{"8080", "6650"}) + s.WithCmd([]string{ + "bin/pulsar", "standalone", + }) + s.WaitForPort("8080") + return s +} diff --git a/pkg/test/pulsar/standalone_test.go b/pkg/test/pulsar/standalone_test.go new file mode 100644 index 00000000..0593c3c1 --- /dev/null +++ b/pkg/test/pulsar/standalone_test.go @@ -0,0 +1,53 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 pulsar + +import ( + "context" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewStandalone(t *testing.T) { + ctx := context.Background() + standalone := NewStandalone("apachepulsar/pulsar:latest") + err := standalone.Start(ctx) + // nolint + defer standalone.Stop(ctx) + if err != nil { + t.Fatal(err) + } + + port, err := standalone.MappedPort(ctx, "8080") + if err != nil { + t.Fatal(err) + } + path := "http://localhost:" + port.Port() + "/admin/v2/tenants" + + resp, err := http.Get(path) + // nolint + defer resp.Body.Close() + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, 200, resp.StatusCode) + +} diff --git a/pkg/test/utils.go b/pkg/test/utils.go new file mode 100644 index 00000000..0d542555 --- /dev/null +++ b/pkg/test/utils.go @@ -0,0 +1,39 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 test + +import ( + "context" + + "github.com/testcontainers/testcontainers-go" +) + +// NewNetwork creates a network. +func NewNetwork(name string) (testcontainers.Network, error) { + ctx := context.Background() + dp, err := testcontainers.NewDockerProvider() + if err != nil { + return nil, err + } + + net, err := dp.CreateNetwork(ctx, testcontainers.NetworkRequest{ + Name: name, + CheckDuplicate: true, + }) + return net, err +}