build(deps): bump the golang group with 5 updates

Bumps the golang group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/Microsoft/hcsshim](https://github.com/Microsoft/hcsshim) | `0.11.4` | `0.12.0` |
| [github.com/alexflint/go-filemutex](https://github.com/alexflint/go-filemutex) | `1.2.0` | `1.3.0` |
| [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) | `2.13.2` | `2.16.0` |
| [github.com/onsi/gomega](https://github.com/onsi/gomega) | `1.30.0` | `1.31.1` |
| [golang.org/x/sys](https://github.com/golang/sys) | `0.15.0` | `0.17.0` |


Updates `github.com/Microsoft/hcsshim` from 0.11.4 to 0.12.0
- [Release notes](https://github.com/Microsoft/hcsshim/releases)
- [Commits](https://github.com/Microsoft/hcsshim/compare/v0.11.4...v0.12.0)

Updates `github.com/alexflint/go-filemutex` from 1.2.0 to 1.3.0
- [Release notes](https://github.com/alexflint/go-filemutex/releases)
- [Commits](https://github.com/alexflint/go-filemutex/compare/v1.2.0...v1.3.0)

Updates `github.com/onsi/ginkgo/v2` from 2.13.2 to 2.16.0
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.13.2...v2.16.0)

Updates `github.com/onsi/gomega` from 1.30.0 to 1.31.1
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.30.0...v1.31.1)

Updates `golang.org/x/sys` from 0.15.0 to 0.17.0
- [Commits](https://github.com/golang/sys/compare/v0.15.0...v0.17.0)

---
updated-dependencies:
- dependency-name: github.com/Microsoft/hcsshim
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
- dependency-name: github.com/alexflint/go-filemutex
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2024-03-11 15:54:46 +00:00
committed by GitHub
parent 0144de0fcf
commit 394ab0d149
376 changed files with 12902 additions and 33268 deletions

View File

@ -1,3 +1,65 @@
## 2.16.0
### Features
- add SpecContext to reporting nodes
### Fixes
- merge coverages instead of combining them (#1329) (#1340) [23f0cc5]
- core_dsl: disable Getwd() with environment variable (#1357) [cd418b7]
### Maintenance
- docs/index.md: Typo [2cebe8d]
- fix docs [06de431]
- chore: test with Go 1.22 (#1352) [898cba9]
- Bump golang.org/x/tools from 0.16.1 to 0.17.0 (#1336) [17ae120]
- Bump golang.org/x/sys from 0.15.0 to 0.16.0 (#1327) [5a179ed]
- Bump github.com/go-logr/logr from 1.3.0 to 1.4.1 (#1321) [a1e6b69]
- Bump github-pages and jekyll-feed in /docs (#1351) [d52951d]
- Fix docs for handling failures in goroutines (#1339) [4471b2e]
## 2.15.0
### Features
- JUnit reports now interpret Label(owner:X) and set owner to X. [8f3bd70]
- include cancellation reason when cancelling spec context [96e915c]
### Fixes
- emit output of failed go tool cover invocation so users can try to debug things for themselves [c245d09]
- fix outline when using nodot in ginkgo v2 [dca77c8]
- Document areas where GinkgoT() behaves differently from testing.T [dbaf18f]
- bugfix(docs): use Unsetenv instead of Clearenv (#1337) [6f67a14]
### Maintenance
- Bump to go 1.20 [4fcd0b3]
## 2.14.0
### Features
You can now use `GinkgoTB()` when you need an instance of `testing.TB` to pass to a library.
Prior to this release table testing only supported generating individual `It`s for each test entry. `DescribeTableSubtree` extends table testing support to entire testing subtrees - under the hood `DescrieTableSubtree` generates a new container for each entry and invokes your function to fill our the container. See the [docs](https://onsi.github.io/ginkgo/#generating-subtree-tables) to learn more.
- Introduce DescribeTableSubtree [65ec56d]
- add GinkgoTB() to docs [4a2c832]
- Add GinkgoTB() function (#1333) [92b6744]
### Fixes
- Fix typo in internal/suite.go (#1332) [beb9507]
- Fix typo in docs/index.md (#1319) [4ac3a13]
- allow wasm to compile with ginkgo present (#1311) [b2e5bc5]
### Maintenance
- Bump golang.org/x/tools from 0.16.0 to 0.16.1 (#1316) [465a8ec]
- Bump actions/setup-go from 4 to 5 (#1313) [eab0e40]
- Bump github/codeql-action from 2 to 3 (#1317) [fbf9724]
- Bump golang.org/x/crypto (#1318) [3ee80ee]
- Bump golang.org/x/tools from 0.14.0 to 0.16.0 (#1306) [123e1d5]
- Bump github.com/onsi/gomega from 1.29.0 to 1.30.0 (#1297) [558f6e0]
- Bump golang.org/x/net from 0.17.0 to 0.19.0 (#1307) [84ff7f3]
## 2.13.2
### Fixes

View File

@ -292,7 +292,7 @@ func RunSpecs(t GinkgoTestingT, description string, args ...interface{}) bool {
err = global.Suite.BuildTree()
exitIfErr(err)
suitePath, err := os.Getwd()
suitePath, err := getwd()
exitIfErr(err)
suitePath, err = filepath.Abs(suitePath)
exitIfErr(err)
@ -345,6 +345,15 @@ func extractSuiteConfiguration(args []interface{}) Labels {
return suiteLabels
}
func getwd() (string, error) {
if !strings.EqualFold(os.Getenv("GINKGO_PRESERVE_CACHE"), "true") {
// Getwd calls os.Getenv("PWD"), which breaks test caching if the cache
// is shared between two different directories with the same test code.
return os.Getwd()
}
return "", nil
}
/*
PreviewSpecs walks the testing tree and produces a report without actually invoking the specs.
See http://onsi.github.io/ginkgo/#previewing-specs for more information.
@ -369,7 +378,7 @@ func PreviewSpecs(description string, args ...any) Report {
err = global.Suite.BuildTree()
exitIfErr(err)
suitePath, err := os.Getwd()
suitePath, err := getwd()
exitIfErr(err)
suitePath, err = filepath.Abs(suitePath)
exitIfErr(err)

View File

@ -0,0 +1,129 @@
// Copyright (c) 2015, Wade Simmons
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Package gocovmerge takes the results from multiple `go test -coverprofile`
// runs and merges them into one profile
// this file was originally taken from the gocovmerge project
// see also: https://go.shabbyrobe.org/gocovmerge
package internal
import (
"fmt"
"io"
"sort"
"golang.org/x/tools/cover"
)
func AddCoverProfile(profiles []*cover.Profile, p *cover.Profile) []*cover.Profile {
i := sort.Search(len(profiles), func(i int) bool { return profiles[i].FileName >= p.FileName })
if i < len(profiles) && profiles[i].FileName == p.FileName {
MergeCoverProfiles(profiles[i], p)
} else {
profiles = append(profiles, nil)
copy(profiles[i+1:], profiles[i:])
profiles[i] = p
}
return profiles
}
func DumpCoverProfiles(profiles []*cover.Profile, out io.Writer) error {
if len(profiles) == 0 {
return nil
}
if _, err := fmt.Fprintf(out, "mode: %s\n", profiles[0].Mode); err != nil {
return err
}
for _, p := range profiles {
for _, b := range p.Blocks {
if _, err := fmt.Fprintf(out, "%s:%d.%d,%d.%d %d %d\n", p.FileName, b.StartLine, b.StartCol, b.EndLine, b.EndCol, b.NumStmt, b.Count); err != nil {
return err
}
}
}
return nil
}
func MergeCoverProfiles(into *cover.Profile, merge *cover.Profile) error {
if into.Mode != merge.Mode {
return fmt.Errorf("cannot merge profiles with different modes")
}
// Since the blocks are sorted, we can keep track of where the last block
// was inserted and only look at the blocks after that as targets for merge
startIndex := 0
for _, b := range merge.Blocks {
var err error
startIndex, err = mergeProfileBlock(into, b, startIndex)
if err != nil {
return err
}
}
return nil
}
func mergeProfileBlock(p *cover.Profile, pb cover.ProfileBlock, startIndex int) (int, error) {
sortFunc := func(i int) bool {
pi := p.Blocks[i+startIndex]
return pi.StartLine >= pb.StartLine && (pi.StartLine != pb.StartLine || pi.StartCol >= pb.StartCol)
}
i := 0
if sortFunc(i) != true {
i = sort.Search(len(p.Blocks)-startIndex, sortFunc)
}
i += startIndex
if i < len(p.Blocks) && p.Blocks[i].StartLine == pb.StartLine && p.Blocks[i].StartCol == pb.StartCol {
if p.Blocks[i].EndLine != pb.EndLine || p.Blocks[i].EndCol != pb.EndCol {
return i, fmt.Errorf("gocovmerge: overlapping merge %v %v %v", p.FileName, p.Blocks[i], pb)
}
switch p.Mode {
case "set":
p.Blocks[i].Count |= pb.Count
case "count", "atomic":
p.Blocks[i].Count += pb.Count
default:
return i, fmt.Errorf("gocovmerge: unsupported covermode '%s'", p.Mode)
}
} else {
if i > 0 {
pa := p.Blocks[i-1]
if pa.EndLine >= pb.EndLine && (pa.EndLine != pb.EndLine || pa.EndCol > pb.EndCol) {
return i, fmt.Errorf("gocovmerge: overlap before %v %v %v", p.FileName, pa, pb)
}
}
if i < len(p.Blocks)-1 {
pa := p.Blocks[i+1]
if pa.StartLine <= pb.StartLine && (pa.StartLine != pb.StartLine || pa.StartCol < pb.StartCol) {
return i, fmt.Errorf("gocovmerge: overlap after %v %v %v", p.FileName, pa, pb)
}
}
p.Blocks = append(p.Blocks, cover.ProfileBlock{})
copy(p.Blocks[i+1:], p.Blocks[i:])
p.Blocks[i] = pb
}
return i + 1, nil
}

View File

@ -1,7 +1,6 @@
package internal
import (
"bytes"
"fmt"
"os"
"os/exec"
@ -12,6 +11,7 @@ import (
"github.com/google/pprof/profile"
"github.com/onsi/ginkgo/v2/reporters"
"github.com/onsi/ginkgo/v2/types"
"golang.org/x/tools/cover"
)
func AbsPathForGeneratedAsset(assetName string, suite TestSuite, cliConfig types.CLIConfig, process int) string {
@ -144,38 +144,26 @@ func FinalizeProfilesAndReportsForSuites(suites TestSuites, cliConfig types.CLIC
return messages, nil
}
//loads each profile, combines them, deletes them, stores them in destination
// loads each profile, merges them, deletes them, stores them in destination
func MergeAndCleanupCoverProfiles(profiles []string, destination string) error {
combined := &bytes.Buffer{}
modeRegex := regexp.MustCompile(`^mode: .*\n`)
for i, profile := range profiles {
contents, err := os.ReadFile(profile)
var merged []*cover.Profile
for _, file := range profiles {
parsedProfiles, err := cover.ParseProfiles(file)
if err != nil {
return fmt.Errorf("Unable to read coverage file %s:\n%s", profile, err.Error())
return err
}
os.Remove(profile)
// remove the cover mode line from every file
// except the first one
if i > 0 {
contents = modeRegex.ReplaceAll(contents, []byte{})
}
_, err = combined.Write(contents)
// Add a newline to the end of every file if missing.
if err == nil && len(contents) > 0 && contents[len(contents)-1] != '\n' {
_, err = combined.Write([]byte("\n"))
}
if err != nil {
return fmt.Errorf("Unable to append to coverprofile:\n%s", err.Error())
os.Remove(file)
for _, p := range parsedProfiles {
merged = AddCoverProfile(merged, p)
}
}
err := os.WriteFile(destination, combined.Bytes(), 0666)
dst, err := os.OpenFile(destination, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return fmt.Errorf("Unable to create combined cover profile:\n%s", err.Error())
return err
}
err = DumpCoverProfiles(merged, dst)
if err != nil {
return err
}
return nil
}
@ -184,7 +172,7 @@ func GetCoverageFromCoverProfile(profile string) (float64, error) {
cmd := exec.Command("go", "tool", "cover", "-func", profile)
output, err := cmd.CombinedOutput()
if err != nil {
return 0, fmt.Errorf("Could not process Coverprofile %s: %s", profile, err.Error())
return 0, fmt.Errorf("Could not process Coverprofile %s: %s - %s", profile, err.Error(), string(output))
}
re := regexp.MustCompile(`total:\s*\(statements\)\s*(\d*\.\d*)\%`)
matches := re.FindStringSubmatch(string(output))

View File

@ -1,10 +1,11 @@
package outline
import (
"github.com/onsi/ginkgo/v2/types"
"go/ast"
"go/token"
"strconv"
"github.com/onsi/ginkgo/v2/types"
)
const (

View File

@ -28,14 +28,7 @@ func packageNameForImport(f *ast.File, path string) *string {
}
name := spec.Name.String()
if name == "<nil>" {
// If the package name is not explicitly specified,
// make an educated guess. This is not guaranteed to be correct.
lastSlash := strings.LastIndex(path, "/")
if lastSlash == -1 {
name = path
} else {
name = path[lastSlash+1:]
}
name = "ginkgo"
}
if name == "." {
name = ""

View File

@ -1,7 +1,10 @@
package ginkgo
import (
"testing"
"github.com/onsi/ginkgo/v2/internal/testingtproxy"
"github.com/onsi/ginkgo/v2/types"
)
/*
@ -12,10 +15,15 @@ GinkgoT() is analogous to *testing.T and implements the majority of *testing.T's
GinkgoT() takes an optional offset argument that can be used to get the
correct line number associated with the failure - though you do not need to use this if you call GinkgoHelper() or GinkgoT().Helper() appropriately
GinkgoT() attempts to mimic the behavior of `testing.T` with the exception of the following:
- Error/Errorf: failures in Ginkgo always immediately stop execution and there is no mechanism to log a failure without aborting the test. As such Error/Errorf are equivalent to Fatal/Fatalf.
- Parallel() is a no-op as Ginkgo's multi-process parallelism model is substantially different from go test's in-process model.
You can learn more here: https://onsi.github.io/ginkgo/#using-third-party-libraries
*/
func GinkgoT(optionalOffset ...int) FullGinkgoTInterface {
offset := 3
offset := 1
if len(optionalOffset) > 0 {
offset = optionalOffset[0]
}
@ -41,21 +49,21 @@ The portion of the interface returned by GinkgoT() that maps onto methods in the
type GinkgoTInterface interface {
Cleanup(func())
Setenv(kev, value string)
Error(args ...interface{})
Errorf(format string, args ...interface{})
Error(args ...any)
Errorf(format string, args ...any)
Fail()
FailNow()
Failed() bool
Fatal(args ...interface{})
Fatalf(format string, args ...interface{})
Fatal(args ...any)
Fatalf(format string, args ...any)
Helper()
Log(args ...interface{})
Logf(format string, args ...interface{})
Log(args ...any)
Logf(format string, args ...any)
Name() string
Parallel()
Skip(args ...interface{})
Skip(args ...any)
SkipNow()
Skipf(format string, args ...interface{})
Skipf(format string, args ...any)
Skipped() bool
TempDir() string
}
@ -71,9 +79,9 @@ type FullGinkgoTInterface interface {
AddReportEntryVisibilityNever(name string, args ...any)
//Prints to the GinkgoWriter
Print(a ...interface{})
Printf(format string, a ...interface{})
Println(a ...interface{})
Print(a ...any)
Printf(format string, a ...any)
Println(a ...any)
//Provides access to Ginkgo's color formatting, correctly configured to match the color settings specified in the invocation of ginkgo
F(format string, args ...any) string
@ -92,3 +100,81 @@ type FullGinkgoTInterface interface {
AttachProgressReporter(func() string) func()
}
/*
GinkgoTB() implements a wrapper that exactly matches the testing.TB interface.
In go 1.18 a new private() function was added to the testing.TB interface. Any function which accepts testing.TB as input needs to be passed in something that directly implements testing.TB.
This wrapper satisfies the testing.TB interface and intended to be used as a drop-in replacement with third party libraries that accept testing.TB.
Similar to GinkgoT(), GinkgoTB() takes an optional offset argument that can be used to get the
correct line number associated with the failure - though you do not need to use this if you call GinkgoHelper() or GinkgoT().Helper() appropriately
*/
func GinkgoTB(optionalOffset ...int) *GinkgoTBWrapper {
offset := 2
if len(optionalOffset) > 0 {
offset = optionalOffset[0]
}
return &GinkgoTBWrapper{GinkgoT: GinkgoT(offset)}
}
type GinkgoTBWrapper struct {
testing.TB
GinkgoT FullGinkgoTInterface
}
func (g *GinkgoTBWrapper) Cleanup(f func()) {
g.GinkgoT.Cleanup(f)
}
func (g *GinkgoTBWrapper) Error(args ...any) {
g.GinkgoT.Error(args...)
}
func (g *GinkgoTBWrapper) Errorf(format string, args ...any) {
g.GinkgoT.Errorf(format, args...)
}
func (g *GinkgoTBWrapper) Fail() {
g.GinkgoT.Fail()
}
func (g *GinkgoTBWrapper) FailNow() {
g.GinkgoT.FailNow()
}
func (g *GinkgoTBWrapper) Failed() bool {
return g.GinkgoT.Failed()
}
func (g *GinkgoTBWrapper) Fatal(args ...any) {
g.GinkgoT.Fatal(args...)
}
func (g *GinkgoTBWrapper) Fatalf(format string, args ...any) {
g.GinkgoT.Fatalf(format, args...)
}
func (g *GinkgoTBWrapper) Helper() {
types.MarkAsHelper(1)
}
func (g *GinkgoTBWrapper) Log(args ...any) {
g.GinkgoT.Log(args...)
}
func (g *GinkgoTBWrapper) Logf(format string, args ...any) {
g.GinkgoT.Logf(format, args...)
}
func (g *GinkgoTBWrapper) Name() string {
return g.GinkgoT.Name()
}
func (g *GinkgoTBWrapper) Setenv(key, value string) {
g.GinkgoT.Setenv(key, value)
}
func (g *GinkgoTBWrapper) Skip(args ...any) {
g.GinkgoT.Skip(args...)
}
func (g *GinkgoTBWrapper) SkipNow() {
g.GinkgoT.SkipNow()
}
func (g *GinkgoTBWrapper) Skipf(format string, args ...any) {
g.GinkgoT.Skipf(format, args...)
}
func (g *GinkgoTBWrapper) Skipped() bool {
return g.GinkgoT.Skipped()
}
func (g *GinkgoTBWrapper) TempDir() string {
return g.GinkgoT.TempDir()
}

View File

@ -5,9 +5,8 @@ import (
"fmt"
"reflect"
"sort"
"time"
"sync"
"time"
"github.com/onsi/ginkgo/v2/types"
)
@ -16,8 +15,8 @@ var _global_node_id_counter = uint(0)
var _global_id_mutex = &sync.Mutex{}
func UniqueNodeID() uint {
//There's a reace in the internal integration tests if we don't make
//accessing _global_node_id_counter safe across goroutines.
// There's a reace in the internal integration tests if we don't make
// accessing _global_node_id_counter safe across goroutines.
_global_id_mutex.Lock()
defer _global_id_mutex.Unlock()
_global_node_id_counter += 1
@ -44,8 +43,8 @@ type Node struct {
SynchronizedAfterSuiteProc1Body func(SpecContext)
SynchronizedAfterSuiteProc1BodyHasContext bool
ReportEachBody func(types.SpecReport)
ReportSuiteBody func(types.Report)
ReportEachBody func(SpecContext, types.SpecReport)
ReportSuiteBody func(SpecContext, types.Report)
MarkedFocus bool
MarkedPending bool
@ -209,7 +208,7 @@ func NewNode(deprecationTracker *types.DeprecationTracker, nodeType types.NodeTy
args = unrollInterfaceSlice(args)
remainingArgs := []interface{}{}
//First get the CodeLocation up-to-date
// First get the CodeLocation up-to-date
for _, arg := range args {
switch v := arg.(type) {
case Offset:
@ -225,11 +224,11 @@ func NewNode(deprecationTracker *types.DeprecationTracker, nodeType types.NodeTy
trackedFunctionError := false
args = remainingArgs
remainingArgs = []interface{}{}
//now process the rest of the args
// now process the rest of the args
for _, arg := range args {
switch t := reflect.TypeOf(arg); {
case t == reflect.TypeOf(float64(0)):
break //ignore deprecated timeouts
break // ignore deprecated timeouts
case t == reflect.TypeOf(Focus):
node.MarkedFocus = bool(arg.(focusType))
if !nodeType.Is(types.NodeTypesForContainerAndIt) {
@ -325,7 +324,12 @@ func NewNode(deprecationTracker *types.DeprecationTracker, nodeType types.NodeTy
node.Body = func(SpecContext) { body() }
} else if nodeType.Is(types.NodeTypeReportBeforeEach | types.NodeTypeReportAfterEach) {
if node.ReportEachBody == nil {
node.ReportEachBody = arg.(func(types.SpecReport))
if fn, ok := arg.(func(types.SpecReport)); ok {
node.ReportEachBody = func(_ SpecContext, r types.SpecReport) { fn(r) }
} else {
node.ReportEachBody = arg.(func(SpecContext, types.SpecReport))
node.HasContext = true
}
} else {
appendError(types.GinkgoErrors.MultipleBodyFunctions(node.CodeLocation, nodeType))
trackedFunctionError = true
@ -333,7 +337,12 @@ func NewNode(deprecationTracker *types.DeprecationTracker, nodeType types.NodeTy
}
} else if nodeType.Is(types.NodeTypeReportBeforeSuite | types.NodeTypeReportAfterSuite) {
if node.ReportSuiteBody == nil {
node.ReportSuiteBody = arg.(func(types.Report))
if fn, ok := arg.(func(types.Report)); ok {
node.ReportSuiteBody = func(_ SpecContext, r types.Report) { fn(r) }
} else {
node.ReportSuiteBody = arg.(func(SpecContext, types.Report))
node.HasContext = true
}
} else {
appendError(types.GinkgoErrors.MultipleBodyFunctions(node.CodeLocation, nodeType))
trackedFunctionError = true
@ -395,7 +404,7 @@ func NewNode(deprecationTracker *types.DeprecationTracker, nodeType types.NodeTy
}
}
//validations
// validations
if node.MarkedPending && node.MarkedFocus {
appendError(types.GinkgoErrors.InvalidDeclarationOfFocusedAndPending(node.CodeLocation, nodeType))
}

View File

@ -0,0 +1,7 @@
//go:build wasm
package internal
func NewOutputInterceptor() OutputInterceptor {
return &NoopOutputInterceptor{}
}

View File

@ -0,0 +1,10 @@
//go:build wasm
package internal
import (
"os"
"syscall"
)
var PROGRESS_SIGNALS = []os.Signal{syscall.SIGUSR1}

View File

@ -17,7 +17,7 @@ type specContext struct {
context.Context
*ProgressReporterManager
cancel context.CancelFunc
cancel context.CancelCauseFunc
suite *Suite
}
@ -30,7 +30,7 @@ Note that while SpecContext is used to enforce deadlines by Ginkgo it is not con
This is because Ginkgo needs finer control over when the context is canceled. Specifically, Ginkgo needs to generate a ProgressReport before it cancels the context to ensure progress is captured where the spec is currently running. The only way to avoid a race here is to manually control the cancellation.
*/
func NewSpecContext(suite *Suite) *specContext {
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancelCause(context.Background())
sc := &specContext{
cancel: cancel,
suite: suite,

View File

@ -79,7 +79,7 @@ func NewSuite() *Suite {
func (suite *Suite) Clone() (*Suite, error) {
if suite.phase != PhaseBuildTopLevel {
return nil, fmt.Errorf("cnanot clone suite after tree has been built")
return nil, fmt.Errorf("cannot clone suite after tree has been built")
}
return &Suite{
tree: &TreeNode{},
@ -594,8 +594,8 @@ func (suite *Suite) reportEach(spec Spec, nodeType types.NodeType) {
suite.writer.Truncate()
suite.outputInterceptor.StartInterceptingOutput()
report := suite.currentSpecReport
nodes[i].Body = func(SpecContext) {
nodes[i].ReportEachBody(report)
nodes[i].Body = func(ctx SpecContext) {
nodes[i].ReportEachBody(ctx, report)
}
state, failure := suite.runNode(nodes[i], time.Time{}, spec.Nodes.BestTextFor(nodes[i]))
@ -762,7 +762,7 @@ func (suite *Suite) runReportSuiteNode(node Node, report types.Report) {
report = report.Add(aggregatedReport)
}
node.Body = func(SpecContext) { node.ReportSuiteBody(report) }
node.Body = func(ctx SpecContext) { node.ReportSuiteBody(ctx, report) }
suite.currentSpecReport.State, suite.currentSpecReport.Failure = suite.runNode(node, time.Time{}, "")
suite.currentSpecReport.EndTime = time.Now()
@ -840,7 +840,7 @@ func (suite *Suite) runNode(node Node, specDeadline time.Time, text string) (typ
timeoutInPlay = "node"
}
if (!deadline.IsZero() && deadline.Before(now)) || interruptStatus.Interrupted() {
//we're out of time already. let's wait for a NodeTimeout if we have it, or GracePeriod if we don't
// we're out of time already. let's wait for a NodeTimeout if we have it, or GracePeriod if we don't
if node.NodeTimeout > 0 {
deadline = now.Add(node.NodeTimeout)
timeoutInPlay = "node"
@ -858,7 +858,7 @@ func (suite *Suite) runNode(node Node, specDeadline time.Time, text string) (typ
}
sc := NewSpecContext(suite)
defer sc.cancel()
defer sc.cancel(fmt.Errorf("spec has finished"))
suite.selectiveLock.Lock()
suite.currentSpecContext = sc
@ -918,9 +918,9 @@ func (suite *Suite) runNode(node Node, specDeadline time.Time, text string) (typ
if outcomeFromRun != types.SpecStatePassed {
additionalFailure := types.AdditionalFailure{
State: outcomeFromRun,
Failure: failure, //we make a copy - this will include all the configuration set up above...
Failure: failure, // we make a copy - this will include all the configuration set up above...
}
//...and then we update the failure with the details from failureFromRun
// ...and then we update the failure with the details from failureFromRun
additionalFailure.Failure.Location, additionalFailure.Failure.ForwardedPanic, additionalFailure.Failure.TimelineLocation = failureFromRun.Location, failureFromRun.ForwardedPanic, failureFromRun.TimelineLocation
additionalFailure.Failure.ProgressReport = types.ProgressReport{}
if outcome == types.SpecStateTimedout {
@ -958,8 +958,8 @@ func (suite *Suite) runNode(node Node, specDeadline time.Time, text string) (typ
// tell the spec to stop. it's important we generate the progress report first to make sure we capture where
// the spec is actually stuck
sc.cancel()
//and now we wait for the grace period
sc.cancel(fmt.Errorf("%s timeout occurred", timeoutInPlay))
// and now we wait for the grace period
gracePeriodChannel = time.After(gracePeriod)
case <-interruptStatus.Channel:
interruptStatus = suite.interruptHandler.Status()
@ -985,7 +985,7 @@ func (suite *Suite) runNode(node Node, specDeadline time.Time, text string) (typ
}
progressReport = progressReport.WithoutOtherGoroutines()
sc.cancel()
sc.cancel(fmt.Errorf(interruptStatus.Message()))
if interruptStatus.Level == interrupt_handler.InterruptLevelBailOut {
if interruptStatus.ShouldIncludeProgressReport() {

View File

@ -15,6 +15,7 @@ import (
"fmt"
"os"
"path"
"regexp"
"strings"
"github.com/onsi/ginkgo/v2/config"
@ -104,6 +105,8 @@ type JUnitProperty struct {
Value string `xml:"value,attr"`
}
var ownerRE = regexp.MustCompile(`(?i)^owner:(.*)$`)
type JUnitTestCase struct {
// Name maps onto the full text of the spec - equivalent to "[SpecReport.LeafNodeType] SpecReport.FullText()"
Name string `xml:"name,attr"`
@ -113,6 +116,8 @@ type JUnitTestCase struct {
Status string `xml:"status,attr"`
// Time is the time in seconds to execute the spec - maps onto SpecReport.RunTime
Time float64 `xml:"time,attr"`
// Owner is the owner the spec - is set if a label matching Label("owner:X") is provided. The last matching label is used as the owner, thereby allowing specs to override owners specified in container nodes.
Owner string `xml:"owner,attr,omitempty"`
//Skipped is populated with a message if the test was skipped or pending
Skipped *JUnitSkipped `xml:"skipped,omitempty"`
//Error is populated if the test panicked or was interrupted
@ -195,6 +200,12 @@ func GenerateJUnitReportWithConfig(report types.Report, dst string, config Junit
if len(labels) > 0 && !config.OmitSpecLabels {
name = name + " [" + strings.Join(labels, ", ") + "]"
}
owner := ""
for _, label := range labels {
if matches := ownerRE.FindStringSubmatch(label); len(matches) == 2 {
owner = matches[1]
}
}
name = strings.TrimSpace(name)
test := JUnitTestCase{
@ -202,6 +213,7 @@ func GenerateJUnitReportWithConfig(report types.Report, dst string, config Junit
Classname: report.SuiteDescription,
Status: spec.State.String(),
Time: spec.RunTime.Seconds(),
Owner: owner,
}
if !spec.State.Is(config.OmitTimelinesForSpecState) {
test.SystemErr = systemErrForUnstructuredReporters(spec)

View File

@ -74,12 +74,21 @@ func AddReportEntry(name string, args ...interface{}) {
/*
ReportBeforeEach nodes are run for each spec, even if the spec is skipped or pending. ReportBeforeEach nodes take a function that
receives a SpecReport. They are called before the spec starts.
receives a SpecReport or both SpecContext and Report for interruptible behavior. They are called before the spec starts.
Example:
ReportBeforeEach(func(report SpecReport) { // process report })
ReportBeforeEach(func(ctx SpecContext, report SpecReport) {
// process report
}), NodeTimeout(1 * time.Minute))
You cannot nest any other Ginkgo nodes within a ReportBeforeEach node's closure.
You can learn more about ReportBeforeEach here: https://onsi.github.io/ginkgo/#generating-reports-programmatically
You can learn about interruptible nodes here: https://onsi.github.io/ginkgo/#spec-timeouts-and-interruptible-nodes
*/
func ReportBeforeEach(body func(SpecReport), args ...interface{}) bool {
func ReportBeforeEach(body any, args ...any) bool {
combinedArgs := []interface{}{body}
combinedArgs = append(combinedArgs, args...)
@ -87,13 +96,23 @@ func ReportBeforeEach(body func(SpecReport), args ...interface{}) bool {
}
/*
ReportAfterEach nodes are run for each spec, even if the spec is skipped or pending. ReportAfterEach nodes take a function that
receives a SpecReport. They are called after the spec has completed and receive the final report for the spec.
ReportAfterEach nodes are run for each spec, even if the spec is skipped or pending.
ReportAfterEach nodes take a function that receives a SpecReport or both SpecContext and Report for interruptible behavior.
They are called after the spec has completed and receive the final report for the spec.
Example:
ReportAfterEach(func(report SpecReport) { // process report })
ReportAfterEach(func(ctx SpecContext, report SpecReport) {
// process report
}), NodeTimeout(1 * time.Minute))
You cannot nest any other Ginkgo nodes within a ReportAfterEach node's closure.
You can learn more about ReportAfterEach here: https://onsi.github.io/ginkgo/#generating-reports-programmatically
You can learn about interruptible nodes here: https://onsi.github.io/ginkgo/#spec-timeouts-and-interruptible-nodes
*/
func ReportAfterEach(body func(SpecReport), args ...interface{}) bool {
func ReportAfterEach(body any, args ...any) bool {
combinedArgs := []interface{}{body}
combinedArgs = append(combinedArgs, args...)
@ -101,7 +120,15 @@ func ReportAfterEach(body func(SpecReport), args ...interface{}) bool {
}
/*
ReportBeforeSuite nodes are run at the beginning of the suite. ReportBeforeSuite nodes take a function that receives a suite Report.
ReportBeforeSuite nodes are run at the beginning of the suite. ReportBeforeSuite nodes take a function
that can either receive Report or both SpecContext and Report for interruptible behavior.
Example Usage:
ReportBeforeSuite(func(r Report) { // process report })
ReportBeforeSuite(func(ctx SpecContext, r Report) {
// process report
}, NodeTimeout(1 * time.Minute))
They are called at the beginning of the suite, before any specs have run and any BeforeSuite or SynchronizedBeforeSuite nodes, and are passed in the initial report for the suite.
ReportBeforeSuite nodes must be created at the top-level (i.e. not nested in a Context/Describe/When node)
@ -112,18 +139,28 @@ You cannot nest any other Ginkgo nodes within a ReportAfterSuite node's closure.
You can learn more about ReportAfterSuite here: https://onsi.github.io/ginkgo/#generating-reports-programmatically
You can learn more about Ginkgo's reporting infrastructure, including generating reports with the CLI here: https://onsi.github.io/ginkgo/#generating-machine-readable-reports
You can learn about interruptible nodes here: https://onsi.github.io/ginkgo/#spec-timeouts-and-interruptible-nodes
*/
func ReportBeforeSuite(body func(Report), args ...interface{}) bool {
func ReportBeforeSuite(body any, args ...any) bool {
combinedArgs := []interface{}{body}
combinedArgs = append(combinedArgs, args...)
return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeReportBeforeSuite, "", combinedArgs...))
}
/*
ReportAfterSuite nodes are run at the end of the suite. ReportAfterSuite nodes take a function that receives a suite Report.
ReportAfterSuite nodes are run at the end of the suite. ReportAfterSuite nodes execute at the suite's conclusion,
and accept a function that can either receive Report or both SpecContext and Report for interruptible behavior.
Example Usage:
ReportAfterSuite("Non-interruptible ReportAfterSuite", func(r Report) { // process report })
ReportAfterSuite("Interruptible ReportAfterSuite", func(ctx SpecContext, r Report) {
// process report
}, NodeTimeout(1 * time.Minute))
They are called at the end of the suite, after all specs have run and any AfterSuite or SynchronizedAfterSuite nodes, and are passed in the final report for the suite.
ReportAftersuite nodes must be created at the top-level (i.e. not nested in a Context/Describe/When node)
ReportAfterSuite nodes must be created at the top-level (i.e. not nested in a Context/Describe/When node)
When running in parallel, Ginkgo ensures that only one of the parallel nodes runs the ReportAfterSuite and that it is passed a report that is aggregated across
all parallel nodes
@ -134,8 +171,10 @@ You cannot nest any other Ginkgo nodes within a ReportAfterSuite node's closure.
You can learn more about ReportAfterSuite here: https://onsi.github.io/ginkgo/#generating-reports-programmatically
You can learn more about Ginkgo's reporting infrastructure, including generating reports with the CLI here: https://onsi.github.io/ginkgo/#generating-machine-readable-reports
You can learn about interruptible nodes here: https://onsi.github.io/ginkgo/#spec-timeouts-and-interruptible-nodes
*/
func ReportAfterSuite(text string, body func(Report), args ...interface{}) bool {
func ReportAfterSuite(text string, body any, args ...interface{}) bool {
combinedArgs := []interface{}{body}
combinedArgs = append(combinedArgs, args...)
return pushNode(internal.NewNode(deprecationTracker, types.NodeTypeReportAfterSuite, text, combinedArgs...))

View File

@ -46,7 +46,7 @@ And can explore some Table patterns here: https://onsi.github.io/ginkgo/#table-s
*/
func DescribeTable(description string, args ...interface{}) bool {
GinkgoHelper()
generateTable(description, args...)
generateTable(description, false, args...)
return true
}
@ -56,7 +56,7 @@ You can focus a table with `FDescribeTable`. This is equivalent to `FDescribe`.
func FDescribeTable(description string, args ...interface{}) bool {
GinkgoHelper()
args = append(args, internal.Focus)
generateTable(description, args...)
generateTable(description, false, args...)
return true
}
@ -66,7 +66,7 @@ You can mark a table as pending with `PDescribeTable`. This is equivalent to `P
func PDescribeTable(description string, args ...interface{}) bool {
GinkgoHelper()
args = append(args, internal.Pending)
generateTable(description, args...)
generateTable(description, false, args...)
return true
}
@ -75,6 +75,71 @@ You can mark a table as pending with `XDescribeTable`. This is equivalent to `X
*/
var XDescribeTable = PDescribeTable
/*
DescribeTableSubtree describes a table-driven spec that generates a set of tests for each entry.
For example:
DescribeTableSubtree("a subtree table",
func(url string, code int, message string) {
var resp *http.Response
BeforeEach(func() {
var err error
resp, err = http.Get(url)
Expect(err).NotTo(HaveOccurred())
DeferCleanup(resp.Body.Close)
})
It("should return the expected status code", func() {
Expect(resp.StatusCode).To(Equal(code))
})
It("should return the expected message", func() {
body, err := ioutil.ReadAll(resp.Body)
Expect(err).NotTo(HaveOccurred())
Expect(string(body)).To(Equal(message))
})
},
Entry("default response", "example.com/response", http.StatusOK, "hello world"),
Entry("missing response", "example.com/missing", http.StatusNotFound, "wat?"),
)
Note that you **must** place define an It inside the body function.
You can learn more about DescribeTableSubtree here: https://onsi.github.io/ginkgo/#table-specs
And can explore some Table patterns here: https://onsi.github.io/ginkgo/#table-specs-patterns
*/
func DescribeTableSubtree(description string, args ...interface{}) bool {
GinkgoHelper()
generateTable(description, true, args...)
return true
}
/*
You can focus a table with `FDescribeTableSubtree`. This is equivalent to `FDescribe`.
*/
func FDescribeTableSubtree(description string, args ...interface{}) bool {
GinkgoHelper()
args = append(args, internal.Focus)
generateTable(description, true, args...)
return true
}
/*
You can mark a table as pending with `PDescribeTableSubtree`. This is equivalent to `PDescribe`.
*/
func PDescribeTableSubtree(description string, args ...interface{}) bool {
GinkgoHelper()
args = append(args, internal.Pending)
generateTable(description, true, args...)
return true
}
/*
You can mark a table as pending with `XDescribeTableSubtree`. This is equivalent to `XDescribe`.
*/
var XDescribeTableSubtree = PDescribeTableSubtree
/*
TableEntry represents an entry in a table test. You generally use the `Entry` constructor.
*/
@ -131,14 +196,14 @@ var XEntry = PEntry
var contextType = reflect.TypeOf(new(context.Context)).Elem()
var specContextType = reflect.TypeOf(new(SpecContext)).Elem()
func generateTable(description string, args ...interface{}) {
func generateTable(description string, isSubtree bool, args ...interface{}) {
GinkgoHelper()
cl := types.NewCodeLocation(0)
containerNodeArgs := []interface{}{cl}
entries := []TableEntry{}
var itBody interface{}
var itBodyType reflect.Type
var internalBody interface{}
var internalBodyType reflect.Type
var tableLevelEntryDescription interface{}
tableLevelEntryDescription = func(args ...interface{}) string {
@ -166,11 +231,11 @@ func generateTable(description string, args ...interface{}) {
case t.Kind() == reflect.Func && t.NumOut() == 1 && t.Out(0) == reflect.TypeOf(""):
tableLevelEntryDescription = arg
case t.Kind() == reflect.Func:
if itBody != nil {
if internalBody != nil {
exitIfErr(types.GinkgoErrors.MultipleEntryBodyFunctionsForTable(cl))
}
itBody = arg
itBodyType = reflect.TypeOf(itBody)
internalBody = arg
internalBodyType = reflect.TypeOf(internalBody)
default:
containerNodeArgs = append(containerNodeArgs, arg)
}
@ -200,39 +265,47 @@ func generateTable(description string, args ...interface{}) {
err = types.GinkgoErrors.InvalidEntryDescription(entry.codeLocation)
}
itNodeArgs := []interface{}{entry.codeLocation}
itNodeArgs = append(itNodeArgs, entry.decorations...)
internalNodeArgs := []interface{}{entry.codeLocation}
internalNodeArgs = append(internalNodeArgs, entry.decorations...)
hasContext := false
if itBodyType.NumIn() > 0. {
if itBodyType.In(0).Implements(specContextType) {
if internalBodyType.NumIn() > 0. {
if internalBodyType.In(0).Implements(specContextType) {
hasContext = true
} else if itBodyType.In(0).Implements(contextType) && (len(entry.parameters) == 0 || !reflect.TypeOf(entry.parameters[0]).Implements(contextType)) {
} else if internalBodyType.In(0).Implements(contextType) && (len(entry.parameters) == 0 || !reflect.TypeOf(entry.parameters[0]).Implements(contextType)) {
hasContext = true
}
}
if err == nil {
err = validateParameters(itBody, entry.parameters, "Table Body function", entry.codeLocation, hasContext)
err = validateParameters(internalBody, entry.parameters, "Table Body function", entry.codeLocation, hasContext)
}
if hasContext {
itNodeArgs = append(itNodeArgs, func(c SpecContext) {
internalNodeArgs = append(internalNodeArgs, func(c SpecContext) {
if err != nil {
panic(err)
}
invokeFunction(itBody, append([]interface{}{c}, entry.parameters...))
invokeFunction(internalBody, append([]interface{}{c}, entry.parameters...))
})
if isSubtree {
exitIfErr(types.GinkgoErrors.ContextsCannotBeUsedInSubtreeTables(cl))
}
} else {
itNodeArgs = append(itNodeArgs, func() {
internalNodeArgs = append(internalNodeArgs, func() {
if err != nil {
panic(err)
}
invokeFunction(itBody, entry.parameters)
invokeFunction(internalBody, entry.parameters)
})
}
pushNode(internal.NewNode(deprecationTracker, types.NodeTypeIt, description, itNodeArgs...))
internalNodeType := types.NodeTypeIt
if isSubtree {
internalNodeType = types.NodeTypeContainer
}
pushNode(internal.NewNode(deprecationTracker, internalNodeType, description, internalNodeArgs...))
}
})

View File

@ -505,6 +505,15 @@ func (g ginkgoErrors) IncorrectVariadicParameterTypeToTableFunction(expected, ac
}
}
func (g ginkgoErrors) ContextsCannotBeUsedInSubtreeTables(cl CodeLocation) error {
return GinkgoError{
Heading: "Contexts cannot be used in subtree tables",
Message: "You''ve defined a subtree body function that accepts a context but did not provide one in the table entry. Ginkgo SpecContexts can only be passed in to subject and setup nodes - so if you are trying to implement a spec timeout you should request a context in the It function within your subtree body function, not in the subtree body function itself.",
CodeLocation: cl,
DocLink: "table-specs",
}
}
/* Parallel Synchronization errors */
func (g ginkgoErrors) AggregatedReportUnavailableDueToNodeDisappearing() error {

View File

@ -1,3 +1,3 @@
package types
const VERSION = "2.13.2"
const VERSION = "2.16.0"