@@ -11,8 +11,10 @@ import (
1111
1212 networkTypes "github.com/docker/docker/api/types/network"
1313 "github.com/docker/docker/client"
14+ "github.com/docker/go-connections/nat"
1415 "github.com/pkg/errors"
1516 "github.com/smartcontractkit/chainlink-testing-framework/framework"
17+ "github.com/testcontainers/testcontainers-go"
1618 "github.com/testcontainers/testcontainers-go/modules/compose"
1719 "github.com/testcontainers/testcontainers-go/wait"
1820)
@@ -111,7 +113,9 @@ func New(in *Input) (*Output, error) {
111113 wait .ForListeningPort (DEFAULT_CHIP_INGRESS_GRPC_PORT ),
112114 ).WithDeadline (1 * time .Minute ),
113115 ).WaitForService (DEFAULT_RED_PANDA_SERVICE_NAME ,
114- wait .ForListeningPort (DEFAULT_RED_PANDA_KAFKA_PORT ).WithStartupTimeout (1 * time .Minute ),
116+ wait .ForAll (
117+ wait .ForListeningPort (DEFAULT_RED_PANDA_SCHEMA_REGISTRY_PORT ).WithStartupTimeout (1 * time .Minute ),
118+ wait .ForListeningPort (DEFAULT_RED_PANDA_KAFKA_PORT ).WithStartupTimeout (1 * time .Minute )),
115119 ).WaitForService (DEFAULT_RED_PANDA_CONSOLE_SERVICE_NAME ,
116120 wait .ForListeningPort (DEFAULT_RED_PANDA_CONSOLE_PORT ).WithStartupTimeout (1 * time .Minute ),
117121 )
@@ -130,41 +134,17 @@ func New(in *Input) (*Output, error) {
130134 }
131135 defer cli .Close ()
132136
133- timeout := time .After (1 * time .Minute )
134- tick := time .Tick (500 * time .Millisecond )
135-
136137 // so let's try to connect to a Docker network a couple of times, there must be a race condition in Docker
137138 // and even when network sandbox has been created and container is running, this call can still fail
138139 // retrying is simpler than trying to figure out how to correctly wait for the network sandbox to be ready
139- var connectNetwork = func (networkName string ) error {
140- for {
141- select {
142- case <- timeout :
143- return fmt .Errorf ("timeout while trying to connect chip-ingress to default network" )
144- case <- tick :
145- if networkErr := cli .NetworkConnect (
146- ctx ,
147- networkName ,
148- chipIngressContainer .ID ,
149- & networkTypes.EndpointSettings {
150- Aliases : []string {identifier },
151- },
152- ); networkErr != nil && ! strings .Contains (networkErr .Error (), "already exists in network" ) {
153- framework .L .Trace ().Msgf ("failed to connect to default network: %v" , networkErr )
154- continue
155- }
156- framework .L .Trace ().Msgf ("connected to %s network" , networkName )
157- return nil
158- }
159- }
160- }
161-
162140 networks := []string {framework .DefaultNetworkName }
163141 networks = append (networks , in .ExtraDockerNetworks ... )
164142
165143 for _ , networkName := range networks {
166144 framework .L .Debug ().Msgf ("Connecting chip-ingress to %s network" , networkName )
167- if connectErr := connectNetwork (networkName ); connectErr != nil {
145+ connectContex , connectCancel := context .WithTimeout (ctx , 30 * time .Second )
146+ defer connectCancel ()
147+ if connectErr := connectNetwork (connectContex , 30 * time .Second , cli , chipIngressContainer .ID , networkName , identifier ); connectErr != nil {
168148 return nil , errors .Wrapf (connectErr , "failed to connect chip-ingress to %s network" , networkName )
169149 }
170150 // verify that the container is connected to framework's network
@@ -177,14 +157,17 @@ func New(in *Input) (*Output, error) {
177157 if ! ok {
178158 return nil , fmt .Errorf ("container %s is NOT on network %s" , chipIngressContainer .ID , networkName )
179159 }
160+
161+ framework .L .Debug ().Msgf ("Container %s is connected to network %s" , chipIngressContainer .ID , networkName )
180162 }
181163
182164 // get hosts and ports for chip-ingress and redpanda
183165 chipIngressExternalHost , chipIngressExternalHostErr := chipIngressContainer .Host (ctx )
184166 if chipIngressExternalHostErr != nil {
185167 return nil , errors .Wrap (chipIngressExternalHostErr , "failed to get host for Chip Ingress" )
186168 }
187- chipIngressExternalPort , chipIngressExternalPortErr := chipIngressContainer .MappedPort (ctx , DEFAULT_CHIP_INGRESS_GRPC_PORT )
169+ // for some magical reason mapped port sometimes cannot be found, even though we wait for it to be ready, when starting the services
170+ chipIngressExternalPort , chipIngressExternalPortErr := findMappdePort (ctx , 20 * time .Second , chipIngressContainer , DEFAULT_CHIP_INGRESS_GRPC_PORT )
188171 if chipIngressExternalPortErr != nil {
189172 return nil , errors .Wrap (chipIngressExternalPortErr , "failed to get mapped port for Chip Ingress" )
190173 }
@@ -198,11 +181,11 @@ func New(in *Input) (*Output, error) {
198181 if redpandaExternalHostErr != nil {
199182 return nil , errors .Wrap (redpandaExternalHostErr , "failed to get host for Red Panda" )
200183 }
201- redpandaExternalKafkaPort , redpandaExternalKafkaPortErr := redpandaContainer . MappedPort (ctx , DEFAULT_RED_PANDA_KAFKA_PORT )
184+ redpandaExternalKafkaPort , redpandaExternalKafkaPortErr := findMappdePort (ctx , 20 * time . Second , redpandaContainer , DEFAULT_RED_PANDA_KAFKA_PORT )
202185 if redpandaExternalKafkaPortErr != nil {
203186 return nil , errors .Wrap (redpandaExternalKafkaPortErr , "failed to get mapped port for Red Panda" )
204187 }
205- redpandaExternalSchemaRegistryPort , redpandaExternalSchemaRegistryPortErr := redpandaContainer . MappedPort (ctx , DEFAULT_RED_PANDA_SCHEMA_REGISTRY_PORT )
188+ redpandaExternalSchemaRegistryPort , redpandaExternalSchemaRegistryPortErr := findMappdePort (ctx , 20 * time . Second , redpandaContainer , DEFAULT_RED_PANDA_SCHEMA_REGISTRY_PORT )
206189 if redpandaExternalSchemaRegistryPortErr != nil {
207190 return nil , errors .Wrap (redpandaExternalSchemaRegistryPortErr , "failed to get mapped port for Red Panda" )
208191 }
@@ -211,12 +194,11 @@ func New(in *Input) (*Output, error) {
211194 if redpandaConsoleErr != nil {
212195 return nil , errors .Wrap (redpandaConsoleErr , "failed to get redpanda-console container" )
213196 }
214-
215197 redpandaExternalConsoleHost , redpandaExternalConsoleHostErr := redpandaConsoleContainer .Host (ctx )
216198 if redpandaExternalConsoleHostErr != nil {
217199 return nil , errors .Wrap (redpandaExternalConsoleHostErr , "failed to get host for Red Panda Console" )
218200 }
219- redpandaExternalConsolePort , redpandaExternalConsolePortErr := redpandaConsoleContainer . MappedPort (ctx , DEFAULT_RED_PANDA_CONSOLE_PORT )
201+ redpandaExternalConsolePort , redpandaExternalConsolePortErr := findMappdePort (ctx , 20 * time . Second , redpandaConsoleContainer , DEFAULT_RED_PANDA_CONSOLE_PORT )
220202 if redpandaExternalConsolePortErr != nil {
221203 return nil , errors .Wrap (redpandaExternalConsolePortErr , "failed to get mapped port for Red Panda Console" )
222204 }
@@ -266,3 +248,59 @@ func composeFilePath(rawFilePath string) (string, error) {
266248
267249 return tempFile .Name (), nil
268250}
251+
252+ func findMappdePort (ctx context.Context , timeout time.Duration , container * testcontainers.DockerContainer , port nat.Port ) (nat.Port , error ) {
253+ forCtx , cancel := context .WithTimeout (ctx , timeout )
254+ defer cancel ()
255+
256+ tickerInterval := 5 * time .Second
257+ ticker := time .NewTicker (5 * time .Second )
258+ defer ticker .Stop ()
259+
260+ for {
261+ select {
262+ case <- forCtx .Done ():
263+ return "" , fmt .Errorf ("timeout while waiting for mapped port for %s" , port )
264+ case <- ticker .C :
265+ portCtx , portCancel := context .WithTimeout (ctx , tickerInterval )
266+ defer portCancel ()
267+ mappedPort , mappedPortErr := container .MappedPort (portCtx , port )
268+ if mappedPortErr != nil {
269+ return "" , errors .Wrapf (mappedPortErr , "failed to get mapped port for %s" , port )
270+ }
271+ if mappedPort .Port () == "" {
272+ return "" , fmt .Errorf ("mapped port for %s is empty" , port )
273+ }
274+ return mappedPort , nil
275+ }
276+ }
277+ }
278+
279+ func connectNetwork (connCtx context.Context , timeout time.Duration , dockerClient * client.Client , containerID , networkName , stackIdentifier string ) error {
280+ ticker := time .NewTicker (500 * time .Millisecond )
281+ defer ticker .Stop ()
282+
283+ networkCtx , networkCancel := context .WithTimeout (connCtx , timeout )
284+ defer networkCancel ()
285+
286+ for {
287+ select {
288+ case <- networkCtx .Done ():
289+ return fmt .Errorf ("timeout while trying to connect chip-ingress to default network" )
290+ case <- ticker .C :
291+ if networkErr := dockerClient .NetworkConnect (
292+ connCtx ,
293+ networkName ,
294+ containerID ,
295+ & networkTypes.EndpointSettings {
296+ Aliases : []string {stackIdentifier },
297+ },
298+ ); networkErr != nil && ! strings .Contains (networkErr .Error (), "already exists in network" ) {
299+ framework .L .Trace ().Msgf ("failed to connect to default network: %v" , networkErr )
300+ continue
301+ }
302+ framework .L .Trace ().Msgf ("connected to %s network" , networkName )
303+ return nil
304+ }
305+ }
306+ }
0 commit comments