Commit 395063f1 authored by Tomasz Maczukin's avatar Tomasz Maczukin 🌴

Add tests for PatchTrace; fix RangeMissmatch handling error

parent b106580b
......@@ -3,6 +3,7 @@ v 1.6.0 (unreleased)
- Update YAML parser library !307
- Add parameter `volumes_from` for docker containers created by runners !236
- Add RC tags support in CI configuration !312
- Fix range mismatch handling error while patch tracing !319
v 1.5.3
- Fix Caret-escape parentheses when not inside double quotes for Windows cmd
......
......@@ -15,7 +15,7 @@ const (
UpdateNotFound
UpdateAbort
UpdateFailed
UpdateRangeMissmatch
UpdateRangeMismatch
)
const (
......
......@@ -35,6 +35,10 @@ func (tp *tracePatch) Limit() int {
}
func (tp *tracePatch) SetNewOffset(newOffset int) {
if (newOffset > tp.limit) {
newOffset = tp.limit
}
tp.offset = newOffset
}
......@@ -228,7 +232,7 @@ func (c *clientBuildTrace) incrementalUpdate() common.UpdateState {
return update
}
if update == common.UpdateRangeMissmatch {
if update == common.UpdateRangeMismatch {
update = c.resendPatch(c.buildCredentials.ID, c.config, c.buildCredentials, tracePatch)
}
......@@ -244,7 +248,7 @@ func (c *clientBuildTrace) resendPatch(id int, config common.RunnerConfig, build
config.Log().Warningln(id, "Resending trace patch due to range mismatch")
update = c.client.PatchTrace(config, buildCredentials, tracePatch)
if update == common.UpdateRangeMissmatch {
if update == common.UpdateRangeMismatch {
config.Log().Errorln(id, "Appending trace to coordinator...", "failed due to range mismatch")
update = common.UpdateFailed
}
......
......@@ -269,7 +269,7 @@ func (n *GitLabClient) PatchTrace(config common.RunnerConfig, buildCredentials *
newOffset, _ := strconv.Atoi(remoteRange[1])
tracePatch.SetNewOffset(newOffset)
return common.UpdateRangeMissmatch
return common.UpdateRangeMismatch
case clientError:
log.Errorln("Appending trace to coordinator...", "error")
return common.UpdateAbort
......
package network
import (
"bytes"
"encoding/json"
"fmt"
"github.com/stretchr/testify/assert"
......@@ -9,6 +10,8 @@ import (
"net/http"
"net/http/httptest"
"os"
"strings"
"strconv"
"testing"
)
......@@ -488,3 +491,173 @@ func TestArtifactsUpload(t *testing.T) {
state = c.UploadArtifacts(invalidToken, tempFile.Name())
assert.Equal(t, UploadForbidden, state, "Artifacts should be rejected if invalid token")
}
var patchToken = "token"
var patchTraceString = "trace trace trace"
func getPatchServer(t *testing.T, handler func(w http.ResponseWriter, r *http.Request, body string, offset, limit int)) (*httptest.Server, GitLabClient, RunnerConfig) {
patchHandler := func(w http.ResponseWriter, r *http.Request) {
if r.Method != "PATCH" {
w.WriteHeader(406)
return
}
assert.Equal(t, patchToken, r.Header.Get("BUILD-TOKEN"))
body, err := ioutil.ReadAll(r.Body)
assert.NoError(t, err)
contentRange := r.Header.Get("Content-Range")
ranges := strings.Split(contentRange, "-")
offset, err := strconv.Atoi(ranges[0])
assert.NoError(t, err)
limit, err := strconv.Atoi(ranges[1])
assert.NoError(t, err)
handler(w, r, string(body), offset, limit)
}
server := httptest.NewServer(http.HandlerFunc(patchHandler))
config := RunnerConfig{
RunnerCredentials: RunnerCredentials{
URL: server.URL,
},
}
return server, GitLabClient{}, config
}
func getTracePatch(traceString string, offset int) *tracePatch {
trace := bytes.Buffer{}
trace.WriteString(traceString)
tracePatch, _ := newTracePatch(trace, offset)
return tracePatch
}
func TestUnknownPatchTrace(t *testing.T) {
handler := func(w http.ResponseWriter, r *http.Request, body string, offset, limit int) {
w.WriteHeader(404)
}
server, client, config := getPatchServer(t, handler)
defer server.Close()
tracePatch := getTracePatch(patchTraceString, 0)
state := client.PatchTrace(config, &BuildCredentials{ID: 1, Token: patchToken}, tracePatch)
assert.Equal(t, UpdateNotFound, state)
}
func TestForbiddenPatchTrace(t *testing.T) {
handler := func(w http.ResponseWriter, r *http.Request, body string, offset, limit int) {
w.WriteHeader(403)
}
server, client, config := getPatchServer(t, handler)
defer server.Close()
tracePatch := getTracePatch(patchTraceString, 0)
state := client.PatchTrace(config, &BuildCredentials{ID: 1, Token: patchToken}, tracePatch)
assert.Equal(t, UpdateAbort, state)
}
func TestPatchTrace(t *testing.T) {
handler := func(w http.ResponseWriter, r *http.Request, body string, offset, limit int) {
assert.Equal(t, patchTraceString[offset:limit], body)
w.WriteHeader(202)
}
server, client, config := getPatchServer(t, handler)
defer server.Close()
tracePatch := getTracePatch(patchTraceString, 0)
state := client.PatchTrace(config, &BuildCredentials{ID: 1, Token: patchToken}, tracePatch)
assert.Equal(t, UpdateSucceeded, state)
tracePatch = getTracePatch(patchTraceString, 3)
state = client.PatchTrace(config, &BuildCredentials{ID: 1, Token: patchToken}, tracePatch)
assert.Equal(t, UpdateSucceeded, state)
tracePatch = getTracePatch(patchTraceString[:10], 3)
state = client.PatchTrace(config, &BuildCredentials{ID: 1, Token: patchToken}, tracePatch)
assert.Equal(t, UpdateSucceeded, state)
}
func TestRangeMismatchPatchTrace(t *testing.T) {
handler := func(w http.ResponseWriter, r *http.Request, body string, offset, limit int) {
if (offset > 10) {
w.Header().Set("Range", "0-10")
w.WriteHeader(416)
}
w.WriteHeader(202)
}
server, client, config := getPatchServer(t, handler)
defer server.Close()
tracePatch := getTracePatch(patchTraceString, 11)
state := client.PatchTrace(config, &BuildCredentials{ID: 1, Token: patchToken}, tracePatch)
assert.Equal(t, UpdateRangeMismatch, state)
tracePatch = getTracePatch(patchTraceString, 15)
state = client.PatchTrace(config, &BuildCredentials{ID: 1, Token: patchToken}, tracePatch)
assert.Equal(t, UpdateRangeMismatch, state)
tracePatch = getTracePatch(patchTraceString, 5)
state = client.PatchTrace(config, &BuildCredentials{ID: 1, Token: patchToken}, tracePatch)
assert.Equal(t, UpdateSucceeded, state)
}
func TestResendPatchTrace(t *testing.T) {
handler := func(w http.ResponseWriter, r *http.Request, body string, offset, limit int) {
if (offset > 10) {
w.Header().Set("Range", "0-10")
w.WriteHeader(416)
}
w.WriteHeader(202)
}
server, client, config := getPatchServer(t, handler)
defer server.Close()
tracePatch := getTracePatch(patchTraceString, 11)
state := client.PatchTrace(config, &BuildCredentials{ID: 1, Token: patchToken}, tracePatch)
assert.Equal(t, UpdateRangeMismatch, state)
state = client.PatchTrace(config, &BuildCredentials{ID: 1, Token: patchToken}, tracePatch)
assert.Equal(t, UpdateSucceeded, state)
}
// We've had a situation where the same build was triggered second time by GItLab. In GitLab the build trace
// was 17041 bytes long while the repeated build trace was only 66 bytes long. We've had a `RangeMismatch`
// response, so the offset was updated (to 17041) and `client.PatchTrace` was repeated, at it was planned.
// Unfortunately the `tracePatch` struct was not resistant to a situation when the offset is set to a
// value bigger than trace's length. This test simulates such situation.
func TestResendDoubledBuildPatchTrace(t *testing.T) {
handler := func(w http.ResponseWriter, r *http.Request, body string, offset, limit int) {
if (offset > 10) {
w.Header().Set("Range", "0-100")
w.WriteHeader(416)
}
w.WriteHeader(202)
}
server, client, config := getPatchServer(t, handler)
defer server.Close()
tracePatch := getTracePatch(patchTraceString, 11)
state := client.PatchTrace(config, &BuildCredentials{ID: 1, Token: patchToken}, tracePatch)
assert.Equal(t, UpdateRangeMismatch, state)
state = client.PatchTrace(config, &BuildCredentials{ID: 1, Token: patchToken}, tracePatch)
assert.Equal(t, UpdateRangeMismatch, state)
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment