log.go ×27

Frontier kind: Joint frontier

unlabeled · c_dae9af747261

1 test · 136 LOC · 2 files · introduces 1 test · 113 LOC · 2 files

Introduces — evidence that enters the hierarchy at this concept

Code
28 ranges113 lines · 2 files
Tests
1 test

Contains — complete concept membership

All code (extent)
38 ranges136 lines · 2 files · Browse complete extent
All tests (intent)
1 testBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

1 test introduced at this concept.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

2 files ranked by introduced lines: 113 introduced LOC across 28 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

go.temporal.io/server/tools/testrunner/log.go 112 introduced LOC · 27 ranges

Open complete file

120 // alerts such as data races and panics. It returns a slice of alerts in the
121 // order they were encountered.
122 > func parseAlerts(stdout string) []alert { log.go
123 > lines := strings.Split(strings.ReplaceAll(stdout, "\r\n", "\n"), "\n")
124 > var alerts []alert
125 >
126 > for i := 0; i < len(lines); i++ {
127 > line := lines[i]
128 >
129 > if a, next, ok := tryParseDataRace(lines, i, line); ok {
130 > alerts = append(alerts, a)
131 > i = next
132 > continue
133 }
134 > if a, next, ok := tryParsePanic(lines, i, line); ok { log.go
135 > alerts = append(alerts, a)
136 > i = next
137 > continue
138 }
139 > if a, next, ok := tryParseFatal(lines, i, line); ok { log.go
140 alerts = append(alerts, a)
141 i = next
144 }
145
146 > return alerts log.go
147 }
148
149 // extractTestNames tries to identify Go test function names from a log block.
150 // It looks for fully-qualified names like pkg.TestXxx(...) and Go test failure lines.
151 > func extractTestNames(block string) []string { log.go
152 > var tests []string
153 > seen := make(map[string]struct{})
154 > for line := range strings.SplitSeq(block, "\n") {
155 > l := strings.TrimSpace(line)
156 > if l == "" {
157 > continue
158 }
159 > if name, ok := parseTripleDashTestName(l); ok { log.go
160 addUniqueTest(&tests, seen, name)
161 continue
162 }
163 > if name, ok := parseFullyQualifiedTestName(l); ok { log.go
164 > addUniqueTest(&tests, seen, name)
165 > continue
166 }
167 > if name, ok := parsePlainTestName(l); ok { log.go
168 addUniqueTest(&tests, seen, name)
169 }
170 }
171 > return tests log.go
172 }
173
184 func parseTripleDashTestName(line string) (string, bool) {
185 if !strings.HasPrefix(line, goTestFailLinePrefix) {
186 > return "", false log.go
187 > }
188 name := strings.TrimSpace(strings.TrimPrefix(line, goTestFailLinePrefix))
189 name, _, _ = strings.Cut(name, " ")
195
196 // parseFullyQualifiedTestName extracts names like "pkg/path.TestName" from a line.
197 > func parseFullyQualifiedTestName(line string) (string, bool) { log.go
198 > idx := strings.Index(line, ".Test")
199 > if idx < 0 {
200 > return "", false
201 > }
202 // Include the package/path qualifier preceding ".Test"
203 > start := 0 log.go
204 > if sp := strings.LastIndex(line[:idx], " "); sp >= 0 {
205 start = sp + 1
206 }
207 > if p := strings.Index(line[idx:], "("); p > 0 { log.go
208 > return line[start : idx+p], true
209 > }
210 return "", false
211 }
212
213 // parsePlainTestName extracts a leading "TestName(" form.
214 > func parsePlainTestName(line string) (string, bool) { log.go
215 > if !strings.HasPrefix(line, "Test") || !strings.Contains(line, "(") {
216 > return "", false
217 > }
218 name := line
219 if p := strings.Index(name, "("); p > 0 {
224
225 // tryParseDataRace parses a data race alert at position i if present.
226 > func tryParseDataRace(lines []string, i int, line string) (alert, int, bool) { log.go
227 > if !strings.HasPrefix(line, "WARNING: DATA RACE") {
228 > return alert{}, i, false
229 > }
230 > start := findRaceBlockStart(lines, i)
231 > // Merge contiguous race-report sections into a single alert. The Go race
232 > // detector may emit multiple "WARNING: DATA RACE" blocks back-to-back,
233 > // each wrapped by a line of ==================. Treat adjacent sections as
234 > // a single logical alert until we either hit a test boundary or a race
235 > // boundary that is not followed by another race section.
236 > block, end := collectBlock(lines, start, func(curLine string, idx, start int) bool {
237 > // Stop at PASS/FAIL boundaries always.
238 > if isTestResultBoundary(curLine) {
239 return true
240 }
241 // If we hit a race boundary after we've started, only stop if the next
242 // non-current line does not continue the race report.
243 > if idx > start && isRaceBoundary(curLine) { log.go
244 > if idx+1 < len(lines) {
245 > next := strings.TrimSpace(lines[idx+1])
246 > if isRaceBoundary(next) || strings.HasPrefix(next, "WARNING: DATA RACE") {
247 > return false
248 > }
249 }
250 > return true log.go
251 }
252 > return false log.go
253 })
254 > return alert{ log.go
255 > Type: failureTypeDataRace,
256 > Summary: "Data race detected",
257 > Details: block,
258 > Tests: extractTestNames(block),
259 > }, end, true
260 }
261
262 // tryParsePanic parses a non-timeout panic alert at position i if present.
263 > func tryParsePanic(lines []string, i int, line string) (alert, int, bool) { log.go
264 > if !strings.HasPrefix(line, "panic: ") || strings.HasPrefix(line, "panic: test timed out after") {
265 > return alert{}, i, false
266 > }
267 > block, end := collectBlock(lines, i, shouldStopOnTestBoundary)
268 > return alert{
269 > Type: failureTypePanic,
270 > Summary: strings.TrimSpace(strings.TrimPrefix(line, "panic: ")),
271 > Details: block,
272 > Tests: extractTestNames(block),
273 > }, end, true
274 }
275
276 // tryParseFatal parses a runtime fatal error alert at position i if present.
277 > func tryParseFatal(lines []string, i int, line string) (alert, int, bool) { log.go
278 > if !strings.HasPrefix(line, "fatal error: ") {
279 > return alert{}, i, false
280 > }
281 block, end := collectBlock(lines, i, shouldStopOnTestBoundary)
282 return alert{
289
290 // findRaceBlockStart searches upward for the race report delimiter.
291 > func findRaceBlockStart(lines []string, i int) int { log.go
292 > start := i
293 > for j := i - 1; j >= 0; j-- {
294 > if isRaceBoundary(lines[j]) {
295 > start = j
296 > break
297 }
298 }
299 > return start log.go
300 }
301
302 // collectBlock builds a block from start until the stop condition is met.
303 > func collectBlock(lines []string, start int, stop func(line string, idx, start int) bool) (string, int) { log.go
304 > var b strings.Builder
305 > for j := start; j < len(lines); j++ {
306 > b.WriteString(lines[j])
307 > b.WriteByte('\n')
308 > if stop(lines[j], j, start) {
309 > return b.String(), j
310 > }
311 }
312 return b.String(), len(lines) - 1
313 }
314
315 > func isRaceBoundary(line string) bool { log.go
316 > return strings.HasPrefix(strings.TrimSpace(line), "==================")
317 > }
318
319 > func isTestResultBoundary(line string) bool { log.go
320 > return strings.HasPrefix(line, "FAIL") || strings.HasPrefix(line, "PASS")
321 > }
322
323 > func shouldStopOnTestBoundary(line string, _ int, _ int) bool { log.go
324 > return isTestResultBoundary(line)
325 > }
326
327 // parseFailedTestsFromOutput extracts failing test names from gotestsum stdout.
go.temporal.io/server/tools/testrunner/junit.go 1 introduced LOC · 1 range

Open complete file

207 key := string(a.Type) + "\n" + a.Details
208 if _, ok := seen[key]; ok {
209 > continue junit.go
210 }
211 seen[key] = struct{}{}