github.com/etecs-ru/gnomock@v0.13.2/gnomock_test.go (about) 1 package gnomock_test 2 3 import ( 4 "context" 5 "crypto/tls" 6 "errors" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "net/http" 11 "testing" 12 "time" 13 14 "github.com/etecs-ru/gnomock" 15 "github.com/etecs-ru/gnomock/internal/testutil" 16 "github.com/stretchr/testify/require" 17 ) 18 19 func TestGnomock_happyFlow(t *testing.T) { 20 t.Parallel() 21 22 namedPorts := gnomock.NamedPorts{ 23 "web80": gnomock.TCP(testutil.GoodPort80), 24 "web8080": gnomock.TCP(testutil.GoodPort8080), 25 } 26 container, err := gnomock.StartCustom( 27 testutil.TestImage, namedPorts, 28 gnomock.WithHealthCheckInterval(time.Microsecond*500), 29 gnomock.WithHealthCheck(testutil.Healthcheck), 30 gnomock.WithInit(initf), 31 gnomock.WithContext(context.Background()), 32 gnomock.WithTimeout(time.Second*30), 33 gnomock.WithEnv("GNOMOCK_TEST_1=foo"), 34 gnomock.WithEnv("GNOMOCK_TEST_2=bar"), 35 ) 36 37 require.NoError(t, err) 38 require.NotNil(t, container) 39 40 addr := fmt.Sprintf("http://%s/", container.Address("web80")) 41 requireResponse(t, addr, "80") 42 43 addr = fmt.Sprintf("http://%s/", container.Address("web8080")) 44 requireResponse(t, addr, "8080") 45 46 t.Run("default address is empty when no default port set", func(t *testing.T) { 47 require.Empty(t, container.DefaultAddress()) 48 }) 49 50 t.Run("wrong port not found", func(t *testing.T) { 51 _, err := container.Ports.Find("tcp", 1234) 52 require.True(t, errors.Is(err, gnomock.ErrPortNotFound)) 53 }) 54 55 t.Run("default port is zero when no default port set", func(t *testing.T) { 56 require.Zero(t, container.DefaultPort()) 57 }) 58 59 require.NoError(t, gnomock.Stop(container)) 60 } 61 62 func TestGnomock_wrongPort(t *testing.T) { 63 t.Parallel() 64 65 container, err := gnomock.StartCustom( 66 testutil.TestImage, gnomock.DefaultTCP(testutil.BadPort), 67 gnomock.WithTimeout(time.Millisecond*50), 68 ) 69 require.Error(t, err) 70 require.Nil(t, container) 71 require.NoError(t, gnomock.Stop(container)) 72 } 73 74 func TestGnomock_cancellation(t *testing.T) { 75 t.Parallel() 76 77 ctx, cancel := context.WithCancel(context.Background()) 78 79 go func() { 80 time.Sleep(time.Millisecond * 100) 81 cancel() 82 }() 83 84 container, err := gnomock.StartCustom( 85 testutil.TestImage, gnomock.DefaultTCP(testutil.BadPort), 86 gnomock.WithContext(ctx), 87 ) 88 require.True(t, errors.Is(err, context.Canceled)) 89 require.Nil(t, container) 90 require.NoError(t, gnomock.Stop(container)) 91 } 92 93 func TestGnomock_customHealthcheck(t *testing.T) { 94 t.Parallel() 95 96 container, err := gnomock.StartCustom( 97 testutil.TestImage, gnomock.DefaultTCP(testutil.BadPort), 98 gnomock.WithTimeout(time.Second*10), 99 gnomock.WithHealthCheck(failingHealthcheck), 100 ) 101 102 defer func() { 103 require.NoError(t, gnomock.Stop(container)) 104 }() 105 106 require.Error(t, err) 107 } 108 109 func TestGnomock_initError(t *testing.T) { 110 t.Parallel() 111 112 errNope := fmt.Errorf("nope") 113 initWithErr := func(context.Context, *gnomock.Container) error { 114 return errNope 115 } 116 117 container, err := gnomock.StartCustom( 118 testutil.TestImage, gnomock.DefaultTCP(testutil.GoodPort80), 119 gnomock.WithInit(initWithErr), 120 ) 121 require.True(t, errors.Is(err, errNope)) 122 require.Nil(t, container) 123 require.NoError(t, gnomock.Stop(container)) 124 } 125 126 func TestGnomock_cantStart(t *testing.T) { 127 t.Parallel() 128 129 container, err := gnomock.StartCustom( 130 "docker.io/orlangure/noimage", 131 gnomock.DefaultTCP(testutil.GoodPort80), 132 ) 133 require.Error(t, err) 134 require.Nil(t, container) 135 require.NoError(t, gnomock.Stop(container)) 136 } 137 138 func TestGnomock_withLogWriter(t *testing.T) { 139 t.Parallel() 140 141 r, w := io.Pipe() 142 143 container, err := gnomock.StartCustom( 144 testutil.TestImage, gnomock.DefaultTCP(testutil.GoodPort80), 145 gnomock.WithLogWriter(w), 146 ) 147 require.NoError(t, err) 148 149 signal := make(chan struct{}) 150 151 go func() { 152 defer close(signal) 153 154 log, err := ioutil.ReadAll(r) 155 require.NoError(t, err) 156 require.Contains(t, string(log), "starting with env1 = '', env2 = ''\n") 157 }() 158 159 require.NoError(t, gnomock.Stop(container)) 160 161 require.NoError(t, w.Close()) 162 <-signal 163 require.NoError(t, r.Close()) 164 } 165 166 func TestGnomock_withCommand(t *testing.T) { 167 t.Parallel() 168 169 r, w := io.Pipe() 170 171 container, err := gnomock.StartCustom( 172 testutil.TestImage, gnomock.DefaultTCP(testutil.GoodPort80), 173 gnomock.WithLogWriter(w), 174 gnomock.WithCommand("foo", "bar"), 175 ) 176 require.NoError(t, err) 177 178 signal := make(chan struct{}) 179 180 go func() { 181 defer close(signal) 182 183 log, err := ioutil.ReadAll(r) 184 require.NoError(t, err) 185 require.Contains(t, string(log), "[foo bar]") 186 }() 187 188 require.NoError(t, gnomock.Stop(container)) 189 190 require.NoError(t, w.Close()) 191 <-signal 192 require.NoError(t, r.Close()) 193 } 194 195 func initf(context.Context, *gnomock.Container) error { 196 return nil 197 } 198 199 func requireResponse(t *testing.T, url string, expected string) { 200 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) 201 defer cancel() 202 203 client := &http.Client{ 204 Transport: &http.Transport{ 205 TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 206 }, 207 } 208 209 req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) 210 require.NoError(t, err) 211 212 resp, err := client.Do(req) 213 require.NoError(t, err) 214 215 defer func() { 216 require.NoError(t, resp.Body.Close()) 217 }() 218 219 require.Equal(t, http.StatusOK, resp.StatusCode) 220 221 body, err := io.ReadAll(resp.Body) 222 223 require.NoError(t, err) 224 require.Equal(t, expected, string(body)) 225 } 226 227 func failingHealthcheck(ctx context.Context, c *gnomock.Container) error { 228 return fmt.Errorf("this container should not start") 229 }