github.com/buildpack/pack@v0.5.0/app/run_test.go (about) 1 package app_test 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "io/ioutil" 8 "math/rand" 9 "net/http" 10 "strings" 11 "testing" 12 "time" 13 14 "github.com/docker/docker/client" 15 "github.com/heroku/color" 16 "github.com/sclevine/spec" 17 "github.com/sclevine/spec/report" 18 19 "github.com/buildpack/pack/app" 20 "github.com/buildpack/pack/internal/fakes" 21 h "github.com/buildpack/pack/testhelpers" 22 ) 23 24 func TestApp(t *testing.T) { 25 h.RequireDocker(t) 26 color.Disable(true) 27 defer func() { color.Disable(false) }() 28 rand.Seed(time.Now().UTC().UnixNano()) 29 spec.Run(t, "app", testApp, spec.Sequential(), spec.Report(report.Terminal{})) 30 } 31 32 func testApp(t *testing.T, when spec.G, it spec.S) { 33 when("#Run", func() { 34 var ( 35 subject *app.Image 36 docker *client.Client 37 err error 38 errBuf bytes.Buffer 39 repo string 40 ) 41 42 it.Before(func() { 43 docker, err = client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38")) 44 h.AssertNil(t, err) 45 46 repo = "some-org/" + h.RandString(10) 47 48 logger := fakes.NewFakeLogger(&errBuf) 49 50 subject = &app.Image{ 51 RepoName: repo, 52 Logger: logger, 53 } 54 }) 55 56 it.After(func() { 57 h.AssertNil(t, h.DockerRmi(docker, repo, "hashicorp/http-echo")) 58 }) 59 60 when("there is no exposed or provided ports", func() { 61 it.Before(func() { 62 h.CreateImageOnLocal( 63 t, 64 docker, 65 repo, 66 "FROM hashicorp/http-echo\nCMD [\"-text=hello world\"]", 67 ) 68 }) 69 70 it("runs an image", func() { 71 assertOnRunningContainer(t, subject, nil, &errBuf, docker, func() bool { 72 return strings.Contains(errBuf.String(), "listening") 73 }) 74 }) 75 }) 76 77 when("a port is exposed", func() { 78 var containerPort string 79 80 it.Before(func() { 81 containerPort, err = h.GetFreePort() 82 h.AssertNil(t, err) 83 h.CreateImageOnLocal( 84 t, 85 docker, 86 repo, 87 fmt.Sprintf( 88 "FROM hashicorp/http-echo\nEXPOSE %s\nCMD [\"-listen=:%s\",\"-text=hello world\"]", 89 containerPort, 90 containerPort, 91 ), 92 ) 93 }) 94 95 it("gets exposed ports from the image", func() { 96 assertOnRunningContainer(t, subject, nil, &errBuf, docker, func() bool { 97 resp, err := http.Get("http://localhost:" + containerPort) 98 if err != nil { 99 t.Log(err) 100 return false 101 } 102 defer resp.Body.Close() 103 104 body, err := ioutil.ReadAll(resp.Body) 105 if err != nil { 106 t.Log(err) 107 return false 108 } 109 if !strings.Contains(string(body), "hello world") { 110 t.Log("got response body:", string(body)) 111 return false 112 } 113 return true 114 }) 115 }) 116 }) 117 118 when("custom ports bindings are defined", func() { 119 var ( 120 containerPort string 121 err error 122 ) 123 124 it.Before(func() { 125 containerPort, err = h.GetFreePort() 126 h.AssertNil(t, err) 127 h.CreateImageOnLocal( 128 t, 129 docker, 130 repo, 131 fmt.Sprintf("FROM hashicorp/http-echo\nCMD [\"-listen=:%s\",\"-text=hello world\"]", containerPort), 132 ) 133 }) 134 135 it("binds simple ports from localhost to the container on the same port", func() { 136 assertOnRunningContainer(t, subject, []string{containerPort}, &errBuf, docker, func() bool { 137 resp, err := http.Get("http://localhost:" + containerPort) 138 if err != nil { 139 t.Log(err) 140 return false 141 } 142 defer resp.Body.Close() 143 144 body, err := ioutil.ReadAll(resp.Body) 145 if err != nil { 146 t.Log(err) 147 return false 148 } 149 if !strings.Contains(string(body), "hello world") { 150 t.Log("got response body:", string(body)) 151 return false 152 } 153 return true 154 }) 155 }) 156 157 it("binds each port to the container", func() { 158 hostPort, err := h.GetFreePort() 159 h.AssertNil(t, err) 160 161 assertOnRunningContainer( 162 t, 163 subject, 164 []string{fmt.Sprintf("127.0.0.1:%s:%s/tcp", hostPort, containerPort)}, 165 &errBuf, 166 docker, 167 func() bool { 168 resp, err := http.Get("http://localhost:" + hostPort) 169 if err != nil { 170 t.Log(err) 171 return false 172 } 173 defer resp.Body.Close() 174 175 body, err := ioutil.ReadAll(resp.Body) 176 if err != nil { 177 t.Log(err) 178 return false 179 } 180 if !strings.Contains(string(body), "hello world") { 181 t.Log("got response body:", string(body)) 182 return false 183 } 184 return true 185 }) 186 }) 187 }) 188 }) 189 } 190 191 func assertOnRunningContainer(t *testing.T, subject *app.Image, port []string, errBuf *bytes.Buffer, docker *client.Client, testFunc func() bool) { 192 ctx, cancel := context.WithCancel(context.Background()) 193 194 done := make(chan error) 195 go func() { 196 done <- subject.Run(ctx, docker, port) 197 }() 198 199 ticker := time.NewTicker(time.Second) 200 defer ticker.Stop() 201 timer := time.NewTimer(time.Second * 5) 202 defer timer.Stop() 203 204 loop: 205 for { 206 select { 207 case <-timer.C: 208 cancel() 209 t.Fatalf("timed out: %s", errBuf.String()) 210 case <-ticker.C: 211 if testFunc() { 212 break loop 213 } 214 } 215 } 216 cancel() 217 if err := <-done; !strings.Contains(err.Error(), context.Canceled.Error()) { 218 t.Fatalf("expected canceled context, failed with a different error: %s", err) 219 } 220 }