github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/colflow/vectorized_panic_propagation_test.go (about)

     1  // Copyright 2019 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package colflow_test
    12  
    13  import (
    14  	"context"
    15  	"testing"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/col/coldata"
    18  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/colexec"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/colexecbase"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/colexecbase/colexecerror"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/execinfra"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/execinfrapb"
    24  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    25  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    26  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  // TestVectorizedInternalPanic verifies that materializers successfully
    31  // handle panics coming from exec package. It sets up the following chain:
    32  // RowSource -> columnarizer -> test panic emitter -> materializer,
    33  // and makes sure that a panic doesn't occur yet the error is propagated.
    34  func TestVectorizedInternalPanic(t *testing.T) {
    35  	defer leaktest.AfterTest(t)()
    36  	ctx := context.Background()
    37  	st := cluster.MakeTestingClusterSettings()
    38  	evalCtx := tree.MakeTestingEvalContext(st)
    39  	defer evalCtx.Stop(ctx)
    40  
    41  	flowCtx := execinfra.FlowCtx{
    42  		EvalCtx: &evalCtx,
    43  		Cfg:     &execinfra.ServerConfig{Settings: cluster.MakeTestingClusterSettings()},
    44  	}
    45  
    46  	nRows, nCols := 1, 1
    47  	types := sqlbase.OneIntCol
    48  	input := execinfra.NewRepeatableRowSource(types, sqlbase.MakeIntRows(nRows, nCols))
    49  
    50  	col, err := colexec.NewColumnarizer(ctx, testAllocator, &flowCtx, 0 /* processorID */, input)
    51  	if err != nil {
    52  		t.Fatal(err)
    53  	}
    54  
    55  	vee := newTestVectorizedInternalPanicEmitter(col)
    56  	mat, err := colexec.NewMaterializer(
    57  		&flowCtx,
    58  		1, /* processorID */
    59  		vee,
    60  		types,
    61  		nil, /* output */
    62  		nil, /* metadataSourceQueue */
    63  		nil, /* toClose */
    64  		nil, /* outputStatsToTrace */
    65  		nil, /* cancelFlow */
    66  	)
    67  	if err != nil {
    68  		t.Fatal(err)
    69  	}
    70  	mat.Start(ctx)
    71  
    72  	var meta *execinfrapb.ProducerMetadata
    73  	require.NotPanics(t, func() { _, meta = mat.Next() }, "InternalError was not caught")
    74  	require.NotNil(t, meta.Err, "InternalError was not propagated as metadata")
    75  }
    76  
    77  // TestNonVectorizedPanicPropagation verifies that materializers do not handle
    78  // panics coming not from exec package. It sets up the following chain:
    79  // RowSource -> columnarizer -> test panic emitter -> materializer,
    80  // and makes sure that a panic is emitted all the way through the chain.
    81  func TestNonVectorizedPanicPropagation(t *testing.T) {
    82  	defer leaktest.AfterTest(t)()
    83  	ctx := context.Background()
    84  	st := cluster.MakeTestingClusterSettings()
    85  	evalCtx := tree.MakeTestingEvalContext(st)
    86  	defer evalCtx.Stop(ctx)
    87  
    88  	flowCtx := execinfra.FlowCtx{
    89  		EvalCtx: &evalCtx,
    90  		Cfg:     &execinfra.ServerConfig{Settings: cluster.MakeTestingClusterSettings()},
    91  	}
    92  
    93  	nRows, nCols := 1, 1
    94  	types := sqlbase.OneIntCol
    95  	input := execinfra.NewRepeatableRowSource(types, sqlbase.MakeIntRows(nRows, nCols))
    96  
    97  	col, err := colexec.NewColumnarizer(ctx, testAllocator, &flowCtx, 0 /* processorID */, input)
    98  	if err != nil {
    99  		t.Fatal(err)
   100  	}
   101  
   102  	nvee := newTestNonVectorizedPanicEmitter(col)
   103  	mat, err := colexec.NewMaterializer(
   104  		&flowCtx,
   105  		1, /* processorID */
   106  		nvee,
   107  		types,
   108  		nil, /* output */
   109  		nil, /* metadataSourceQueue */
   110  		nil, /* toClose */
   111  		nil, /* outputStatsToTrace */
   112  		nil, /* cancelFlow */
   113  	)
   114  	if err != nil {
   115  		t.Fatal(err)
   116  	}
   117  	mat.Start(ctx)
   118  
   119  	require.Panics(t, func() { mat.Next() }, "NonVectorizedPanic was caught by the operators")
   120  }
   121  
   122  // testVectorizedInternalPanicEmitter is an colexec.Operator that panics with
   123  // colexecerror.InternalError on every odd-numbered invocation of Next()
   124  // and returns the next batch from the input on every even-numbered (i.e. it
   125  // becomes a noop for those iterations). Used for tests only.
   126  type testVectorizedInternalPanicEmitter struct {
   127  	colexec.OneInputNode
   128  	emitBatch bool
   129  }
   130  
   131  var _ colexecbase.Operator = &testVectorizedInternalPanicEmitter{}
   132  
   133  func newTestVectorizedInternalPanicEmitter(input colexecbase.Operator) colexecbase.Operator {
   134  	return &testVectorizedInternalPanicEmitter{
   135  		OneInputNode: colexec.NewOneInputNode(input),
   136  	}
   137  }
   138  
   139  // Init is part of exec.Operator interface.
   140  func (e *testVectorizedInternalPanicEmitter) Init() {
   141  	e.Input().Init()
   142  }
   143  
   144  // Next is part of exec.Operator interface.
   145  func (e *testVectorizedInternalPanicEmitter) Next(ctx context.Context) coldata.Batch {
   146  	if !e.emitBatch {
   147  		e.emitBatch = true
   148  		colexecerror.InternalError("")
   149  	}
   150  
   151  	e.emitBatch = false
   152  	return e.Input().Next(ctx)
   153  }
   154  
   155  // testNonVectorizedPanicEmitter is the same as
   156  // testVectorizedInternalPanicEmitter but it panics with the builtin panic
   157  // function. Used for tests only. It is the only colexec.Operator panics from
   158  // which are not caught.
   159  type testNonVectorizedPanicEmitter struct {
   160  	colexec.OneInputNode
   161  	emitBatch bool
   162  }
   163  
   164  var _ colexecbase.Operator = &testVectorizedInternalPanicEmitter{}
   165  
   166  func newTestNonVectorizedPanicEmitter(input colexecbase.Operator) colexecbase.Operator {
   167  	return &testNonVectorizedPanicEmitter{
   168  		OneInputNode: colexec.NewOneInputNode(input),
   169  	}
   170  }
   171  
   172  // Init is part of exec.Operator interface.
   173  func (e *testNonVectorizedPanicEmitter) Init() {
   174  	e.Input().Init()
   175  }
   176  
   177  // Next is part of exec.Operator interface.
   178  func (e *testNonVectorizedPanicEmitter) Next(ctx context.Context) coldata.Batch {
   179  	if !e.emitBatch {
   180  		e.emitBatch = true
   181  		panic("")
   182  	}
   183  
   184  	e.emitBatch = false
   185  	return e.Input().Next(ctx)
   186  }