vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/concatenate_test.go (about)

     1  /*
     2  Copyright 2020 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package engine
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"testing"
    24  
    25  	"vitess.io/vitess/go/test/utils"
    26  
    27  	"github.com/stretchr/testify/require"
    28  
    29  	"vitess.io/vitess/go/sqltypes"
    30  )
    31  
    32  func r(names, types string, rows ...string) *sqltypes.Result {
    33  	return sqltypes.MakeTestResult(sqltypes.MakeTestFields(names, types), rows...)
    34  }
    35  
    36  func TestConcatenate_NoErrors(t *testing.T) {
    37  	type testCase struct {
    38  		testName       string
    39  		inputs         []*sqltypes.Result
    40  		expectedResult *sqltypes.Result
    41  		expectedError  string
    42  		ignoreTypes    []int
    43  	}
    44  
    45  	r1 := r("id|col1|col2", "int64|varbinary|varbinary", "1|a1|b1", "2|a2|b2")
    46  	r2 := r("id|col1|col2", "int32|varbinary|varbinary", "1|a1|b1", "2|a2|b2")
    47  	combinedResult := r1
    48  	combinedResult.Rows = append(combinedResult.Rows, r2.Rows...)
    49  
    50  	testCases := []*testCase{{
    51  		testName: "empty results",
    52  		inputs: []*sqltypes.Result{
    53  			r("id1|col11|col12", "int64|varbinary|varbinary"),
    54  			r("id2|col21|col22", "int64|varbinary|varbinary"),
    55  			r("id3|col31|col32", "int64|varbinary|varbinary"),
    56  		},
    57  		expectedResult: r("id1|col11|col12", "int64|varbinary|varbinary"),
    58  	}, {
    59  		testName: "2 non empty result",
    60  		inputs: []*sqltypes.Result{
    61  			r("myid|mycol1|mycol2", "int64|varchar|varbinary", "11|m1|n1", "22|m2|n2"),
    62  			r("id|col1|col2", "int64|varchar|varbinary", "1|a1|b1", "2|a2|b2"),
    63  			r("id2|col2|col3", "int64|varchar|varbinary", "3|a3|b3"),
    64  			r("id2|col2|col3", "int64|varchar|varbinary", "4|a4|b4"),
    65  		},
    66  		expectedResult: r("myid|mycol1|mycol2", "int64|varchar|varbinary", "11|m1|n1", "22|m2|n2", "1|a1|b1", "2|a2|b2", "3|a3|b3", "4|a4|b4"),
    67  	}, {
    68  		testName: "mismatch field type",
    69  		inputs: []*sqltypes.Result{
    70  			r("id|col1|col2", "int64|varbinary|varbinary", "1|a1|b1", "2|a2|b2"),
    71  			r("id|col1|col2", "int64|varbinary|varbinary", "1|a1|b1", "2|a2|b2"),
    72  			r("id|col3|col4", "int64|varchar|varbinary", "1|a1|b1", "2|a2|b2"),
    73  		},
    74  		expectedError: "merging field of different types is not supported",
    75  	}, {
    76  		testName: "ignored field types - ignored",
    77  		inputs: []*sqltypes.Result{
    78  			r("id|col1|col2", "int64|varbinary|varbinary", "1|a1|b1", "2|a2|b2"),
    79  			r("id|col1|col2", "int32|varbinary|varbinary", "1|a1|b1", "2|a2|b2"),
    80  		},
    81  		expectedResult: combinedResult,
    82  		ignoreTypes:    []int{0},
    83  	}, {
    84  		testName: "input source has different column count",
    85  		inputs: []*sqltypes.Result{
    86  			r("id|col1|col2", "int64|varchar|varchar", "1|a1|b1", "2|a2|b2"),
    87  			r("id|col1|col2", "int64|varchar|varchar", "1|a1|b1", "2|a2|b2"),
    88  			r("id|col3|col4|col5", "int64|varchar|varchar|int32", "1|a1|b1|5", "2|a2|b2|6"),
    89  		},
    90  		expectedError: "The used SELECT statements have a different number of columns",
    91  	}, {
    92  		testName: "1 empty result and 1 non empty result",
    93  		inputs: []*sqltypes.Result{
    94  			r("myid|mycol1|mycol2", "int64|varchar|varbinary"),
    95  			r("id|col1|col2", "int64|varchar|varbinary", "1|a1|b1", "2|a2|b2"),
    96  		},
    97  		expectedResult: r("myid|mycol1|mycol2", "int64|varchar|varbinary", "1|a1|b1", "2|a2|b2"),
    98  	}}
    99  
   100  	for _, tc := range testCases {
   101  		var sources []Primitive
   102  		for _, input := range tc.inputs {
   103  			// input is added twice, since the first one is used by execute and the next by stream execute
   104  			sources = append(sources, &fakePrimitive{results: []*sqltypes.Result{input, input}})
   105  		}
   106  
   107  		concatenate := NewConcatenate(sources, tc.ignoreTypes)
   108  
   109  		t.Run(tc.testName+"-Execute", func(t *testing.T) {
   110  			qr, err := concatenate.TryExecute(context.Background(), &noopVCursor{}, nil, true)
   111  			if tc.expectedError == "" {
   112  				require.NoError(t, err)
   113  				require.Equal(t, tc.expectedResult, qr)
   114  			} else {
   115  				require.Error(t, err)
   116  				require.Contains(t, err.Error(), tc.expectedError)
   117  			}
   118  		})
   119  
   120  		t.Run(tc.testName+"-StreamExecute", func(t *testing.T) {
   121  			qr, err := wrapStreamExecute(concatenate, &noopVCursor{}, nil, true)
   122  			if tc.expectedError == "" {
   123  				require.NoError(t, err)
   124  				require.Equal(t, utils.SortString(fmt.Sprintf("%v", tc.expectedResult.Rows)), utils.SortString(fmt.Sprintf("%v", qr.Rows)))
   125  			} else {
   126  				require.Error(t, err)
   127  				require.Contains(t, err.Error(), tc.expectedError)
   128  			}
   129  		})
   130  	}
   131  }
   132  
   133  func TestConcatenate_WithErrors(t *testing.T) {
   134  	strFailed := "failed"
   135  
   136  	fake := r("id|col1|col2", "int64|varchar|varbinary", "1|a1|b1", "2|a2|b2")
   137  	concatenate := NewConcatenate(
   138  		[]Primitive{
   139  			&fakePrimitive{results: []*sqltypes.Result{fake, fake}},
   140  			&fakePrimitive{results: []*sqltypes.Result{nil, nil}, sendErr: errors.New(strFailed)},
   141  			&fakePrimitive{results: []*sqltypes.Result{fake, fake}},
   142  		}, nil,
   143  	)
   144  	_, err := concatenate.TryExecute(context.Background(), &noopVCursor{}, nil, true)
   145  	require.EqualError(t, err, strFailed)
   146  
   147  	_, err = wrapStreamExecute(concatenate, &noopVCursor{}, nil, true)
   148  	require.EqualError(t, err, strFailed)
   149  
   150  	concatenate = NewConcatenate(
   151  		[]Primitive{
   152  			&fakePrimitive{results: []*sqltypes.Result{fake, fake}},
   153  			&fakePrimitive{results: []*sqltypes.Result{nil, nil}, sendErr: errors.New(strFailed)},
   154  			&fakePrimitive{results: []*sqltypes.Result{fake, fake}},
   155  		}, nil)
   156  
   157  	_, err = concatenate.TryExecute(context.Background(), &noopVCursor{}, nil, true)
   158  	require.EqualError(t, err, strFailed)
   159  	_, err = wrapStreamExecute(concatenate, &noopVCursor{}, nil, true)
   160  	require.EqualError(t, err, strFailed)
   161  }