(t *testing.T)
| 67 | } |
| 68 | |
| 69 | func TestSnapshotHandler_LargeMemory(t *testing.T) { |
| 70 | // Try to create a stack frame over 1MiB in size when serialized to string. |
| 71 | // This is tricky since this is dependent on many factors out of our control. |
| 72 | // Do this by starting a lot of callbacks with a lot of arguments. |
| 73 | wg := sync.WaitGroup{} |
| 74 | ctx, cancel := context.WithCancel(context.Background()) |
| 75 | defer cancel() |
| 76 | a := 0 |
| 77 | alive := make(chan struct{}) |
| 78 | // Assuming >400 bytes per goroutine, 2500 parallel goroutines is enough to |
| 79 | // use more than 1MiB of call stack. We must not put it too high or it'll |
| 80 | // crash on Travis. |
| 81 | const parallel = 2500 |
| 82 | for i := 0; i < parallel; i++ { |
| 83 | wg.Add(1) |
| 84 | go func() { |
| 85 | defer wg.Done() |
| 86 | alive <- struct{}{} |
| 87 | dummy(ctx, &a, &a, &a, &a, &a, &a, &a, &a, &a) |
| 88 | }() |
| 89 | } |
| 90 | for i := 0; i < parallel; i++ { |
| 91 | <-alive |
| 92 | } |
| 93 | |
| 94 | // Normal. |
| 95 | req := httptest.NewRequest("GET", "/debug", nil) |
| 96 | w := httptest.NewRecorder() |
| 97 | SnapshotHandler(w, req) |
| 98 | if w.Code != 200 { |
| 99 | t.Fatalf("%d\n%s", w.Code, w.Body.String()) |
| 100 | } |
| 101 | |
| 102 | // Cut off. That's 1<<20 + 1 |
| 103 | req = httptest.NewRequest("GET", "/debug?maxmem=1048577", nil) |
| 104 | w = httptest.NewRecorder() |
| 105 | SnapshotHandler(w, req) |
| 106 | // It can result in a 500 because the cut off is arbitrary, making parsing to |
| 107 | // fail. |
| 108 | if w.Code != 200 && w.Code != 500 { |
| 109 | t.Fatalf("%d\n%s", w.Code, w.Body.String()) |
| 110 | } |
| 111 | |
| 112 | cancel() |
| 113 | wg.Wait() |
| 114 | } |
| 115 | |
| 116 | func BenchmarkSnapshotHandle(b *testing.B) { |
| 117 | // TODO(maruel): We should hook runtime.Stack() to make it a deterministic |
nothing calls this directly
no test coverage detected
searching dependent graphs…