github.com/matrixorigin/matrixone@v1.2.0/pkg/frontend/export_test.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package frontend
    16  
    17  import (
    18  	"bufio"
    19  	"context"
    20  	"os"
    21  	"testing"
    22  
    23  	"github.com/prashantv/gostub"
    24  	"github.com/smartystreets/goconvey/convey"
    25  
    26  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    27  	"github.com/matrixorigin/matrixone/pkg/container/types"
    28  	"github.com/matrixorigin/matrixone/pkg/defines"
    29  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    30  )
    31  
    32  var colName1, colName2 = "DATABASE()", "VARIABLE_VALUE"
    33  
    34  func Test_initExportFileParam(t *testing.T) {
    35  	var oq = &outputQueue{
    36  		mrs: &MysqlResultSet{},
    37  		ep: &ExportConfig{
    38  			userConfig: &tree.ExportParam{
    39  				Lines: &tree.Lines{
    40  					TerminatedBy: &tree.Terminated{},
    41  				},
    42  				Fields: &tree.Fields{
    43  					Terminated: &tree.Terminated{},
    44  					EnclosedBy: &tree.EnclosedBy{},
    45  					EscapedBy:  &tree.EscapedBy{},
    46  				},
    47  			},
    48  		},
    49  	}
    50  	initExportFileParam(oq.ep, oq.mrs)
    51  
    52  	col1 := new(MysqlColumn)
    53  	col1.SetName(colName1)
    54  	col2 := new(MysqlColumn)
    55  	col2.SetName(colName2)
    56  	oq.mrs.AddColumn(col1)
    57  	oq.mrs.AddColumn(col2)
    58  
    59  	oq.ep.userConfig.ForceQuote = append(oq.ep.userConfig.ForceQuote, colName1)
    60  	oq.mrs.Name2Index[colName1] = 0
    61  	initExportFileParam(oq.ep, oq.mrs)
    62  }
    63  
    64  func Test_openNewFile(t *testing.T) {
    65  	convey.Convey("openNewFile failed", t, func() {
    66  		var oq = &outputQueue{
    67  			mrs: &MysqlResultSet{},
    68  			ep: &ExportConfig{
    69  				userConfig: &tree.ExportParam{
    70  					Lines: &tree.Lines{
    71  						TerminatedBy: &tree.Terminated{},
    72  					},
    73  					Fields: &tree.Fields{
    74  						Terminated: &tree.Terminated{},
    75  						EnclosedBy: &tree.EnclosedBy{},
    76  						EscapedBy:  &tree.EscapedBy{},
    77  					},
    78  					Header:   true,
    79  					FilePath: "test/export.csv",
    80  				},
    81  			},
    82  		}
    83  		stubs := gostub.StubFunc(&OpenFile, nil, moerr.NewInternalError(context.TODO(), "can not open file"))
    84  		defer stubs.Reset()
    85  		convey.So(openNewFile(context.TODO(), oq.ep, oq.mrs), convey.ShouldNotBeNil)
    86  	})
    87  
    88  	convey.Convey("openNewFile succ", t, func() {
    89  		var oq = &outputQueue{
    90  			mrs: &MysqlResultSet{},
    91  			ep: &ExportConfig{
    92  				userConfig: &tree.ExportParam{
    93  					Lines: &tree.Lines{
    94  						TerminatedBy: &tree.Terminated{},
    95  					},
    96  					Fields: &tree.Fields{
    97  						Terminated: &tree.Terminated{},
    98  						EnclosedBy: &tree.EnclosedBy{},
    99  						EscapedBy:  &tree.EscapedBy{},
   100  					},
   101  					Header:   true,
   102  					FilePath: "test/export.csv",
   103  				},
   104  				LineSize: 1,
   105  			},
   106  		}
   107  		col1 := new(MysqlColumn)
   108  		col1.SetName(colName1)
   109  		col2 := new(MysqlColumn)
   110  		col2.SetName(colName2)
   111  		oq.mrs.AddColumn(col1)
   112  		oq.mrs.AddColumn(col2)
   113  
   114  		var file = &os.File{}
   115  		stubs := gostub.StubFunc(&OpenFile, file, nil)
   116  		defer stubs.Reset()
   117  
   118  		stubs = gostub.StubFunc(&writeDataToCSVFile, nil)
   119  		defer stubs.Reset()
   120  
   121  		convey.So(openNewFile(context.TODO(), oq.ep, oq.mrs), convey.ShouldBeNil)
   122  	})
   123  }
   124  
   125  func Test_formatOutputString(t *testing.T) {
   126  	convey.Convey("openNewFile failed", t, func() {
   127  		var oq = &outputQueue{
   128  			mrs: &MysqlResultSet{},
   129  			ep: &ExportConfig{
   130  				userConfig: &tree.ExportParam{
   131  					Lines: &tree.Lines{
   132  						TerminatedBy: &tree.Terminated{},
   133  					},
   134  					Fields: &tree.Fields{
   135  						Terminated: &tree.Terminated{},
   136  						EnclosedBy: &tree.EnclosedBy{},
   137  						EscapedBy:  &tree.EscapedBy{},
   138  					},
   139  					Header:   true,
   140  					FilePath: "test/export.csv",
   141  				},
   142  				LineSize: 1,
   143  			},
   144  		}
   145  		stubs := gostub.StubFunc(&writeDataToCSVFile, moerr.NewInternalError(context.TODO(), "write err"))
   146  		defer stubs.Reset()
   147  		convey.So(formatOutputString(oq, nil, nil, '\n', true), convey.ShouldNotBeNil)
   148  
   149  		stubs = gostub.StubFunc(&writeDataToCSVFile, nil)
   150  		defer stubs.Reset()
   151  		convey.So(formatOutputString(oq, nil, nil, '\n', true), convey.ShouldBeNil)
   152  	})
   153  }
   154  
   155  func Test_writeToCSVFile(t *testing.T) {
   156  	convey.Convey("writeToCSVFile case", t, func() {
   157  		var oq = &outputQueue{
   158  			mrs: &MysqlResultSet{},
   159  			ep: &ExportConfig{
   160  				userConfig: &tree.ExportParam{
   161  					Lines: &tree.Lines{
   162  						TerminatedBy: &tree.Terminated{},
   163  					},
   164  					Fields: &tree.Fields{
   165  						Terminated: &tree.Terminated{},
   166  						EnclosedBy: &tree.EnclosedBy{},
   167  						EscapedBy:  &tree.EscapedBy{},
   168  					},
   169  					Header:   true,
   170  					FilePath: "test/export.csv",
   171  				},
   172  				LineSize: 1,
   173  				Writer:   &bufio.Writer{},
   174  			},
   175  		}
   176  		var output = []byte{'1', '2'}
   177  		oq.ep.userConfig.MaxFileSize = 1
   178  
   179  		convey.So(writeToCSVFile(oq, output), convey.ShouldNotBeNil)
   180  
   181  		oq.ep.Rows = 1
   182  		stubs := gostub.StubFunc(&Flush, moerr.NewInternalError(context.TODO(), "Flush error"))
   183  		defer stubs.Reset()
   184  
   185  		convey.So(writeToCSVFile(oq, output), convey.ShouldNotBeNil)
   186  
   187  		stubs = gostub.StubFunc(&Flush, nil)
   188  		defer stubs.Reset()
   189  
   190  		stubs = gostub.StubFunc(&Seek, int64(0), moerr.NewInternalError(context.TODO(), "Seek error"))
   191  		defer stubs.Reset()
   192  		convey.So(writeToCSVFile(oq, output), convey.ShouldNotBeNil)
   193  
   194  		stubs = gostub.StubFunc(&Seek, int64(0), nil)
   195  		defer stubs.Reset()
   196  		stubs = gostub.StubFunc(&Read, 0, moerr.NewInternalError(context.TODO(), "Read error"))
   197  		defer stubs.Reset()
   198  		convey.So(writeToCSVFile(oq, output), convey.ShouldNotBeNil)
   199  
   200  		stubs = gostub.StubFunc(&Read, 1, nil)
   201  		defer stubs.Reset()
   202  
   203  		stubs = gostub.StubFunc(&Truncate, moerr.NewInternalError(context.TODO(), "Truncate error"))
   204  		defer stubs.Reset()
   205  		convey.So(writeToCSVFile(oq, output), convey.ShouldNotBeNil)
   206  
   207  		stubs = gostub.StubFunc(&Truncate, nil)
   208  		defer stubs.Reset()
   209  		stubs = gostub.StubFunc(&Close, moerr.NewInternalError(context.TODO(), "Close error"))
   210  		defer stubs.Reset()
   211  		convey.So(writeToCSVFile(oq, output), convey.ShouldNotBeNil)
   212  
   213  		stubs = gostub.StubFunc(&Close, nil)
   214  		defer stubs.Reset()
   215  		stubs = gostub.StubFunc(&openNewFile, moerr.NewInternalError(context.TODO(), "openNewFile error"))
   216  		defer stubs.Reset()
   217  		convey.So(writeToCSVFile(oq, output), convey.ShouldNotBeNil)
   218  
   219  		stubs = gostub.StubFunc(&openNewFile, nil)
   220  		defer stubs.Reset()
   221  		stubs = gostub.StubFunc(&writeDataToCSVFile, moerr.NewInternalError(context.TODO(), "writeDataToCSVFile error"))
   222  		defer stubs.Reset()
   223  		convey.So(writeToCSVFile(oq, output), convey.ShouldNotBeNil)
   224  
   225  		stubs = gostub.StubFunc(&writeDataToCSVFile, nil)
   226  		defer stubs.Reset()
   227  		convey.So(writeToCSVFile(oq, output), convey.ShouldBeNil)
   228  	})
   229  }
   230  
   231  func Test_writeDataToCSVFile(t *testing.T) {
   232  	convey.Convey("writeDataToCSVFile case", t, func() {
   233  		var oq = &outputQueue{
   234  			mrs: &MysqlResultSet{},
   235  			ep: &ExportConfig{
   236  				userConfig: &tree.ExportParam{
   237  					Lines: &tree.Lines{
   238  						TerminatedBy: &tree.Terminated{},
   239  					},
   240  					Fields: &tree.Fields{
   241  						Terminated: &tree.Terminated{},
   242  						EnclosedBy: &tree.EnclosedBy{},
   243  						EscapedBy:  &tree.EscapedBy{},
   244  					},
   245  					Header:   true,
   246  					FilePath: "test/export.csv",
   247  				},
   248  				LineSize: 1,
   249  				Writer:   &bufio.Writer{},
   250  			},
   251  		}
   252  		var output = []byte{'1', '2'}
   253  		stubs := gostub.StubFunc(&Write, 0, moerr.NewInternalError(context.TODO(), "writeDataToCSVFile error"))
   254  		defer stubs.Reset()
   255  
   256  		convey.So(writeDataToCSVFile(oq.ep, output), convey.ShouldNotBeNil)
   257  
   258  		stubs = gostub.StubFunc(&Write, len(output), nil)
   259  		defer stubs.Reset()
   260  		convey.So(writeDataToCSVFile(oq.ep, output), convey.ShouldBeNil)
   261  
   262  	})
   263  }
   264  
   265  func Test_exportDataToCSVFile(t *testing.T) {
   266  	convey.Convey("exportDataToCSVFile succ", t, func() {
   267  		var oq = &outputQueue{
   268  			mrs: &MysqlResultSet{},
   269  			ep: &ExportConfig{
   270  				userConfig: &tree.ExportParam{
   271  					Lines: &tree.Lines{
   272  						TerminatedBy: &tree.Terminated{},
   273  					},
   274  					Fields: &tree.Fields{
   275  						Terminated: &tree.Terminated{},
   276  						EnclosedBy: &tree.EnclosedBy{},
   277  						EscapedBy:  &tree.EscapedBy{},
   278  					},
   279  					Header:   true,
   280  					FilePath: "test/export.csv",
   281  				},
   282  				LineSize: 1,
   283  				Writer:   &bufio.Writer{},
   284  			},
   285  		}
   286  
   287  		var col = make([]MysqlColumn, 13)
   288  		col[5].flag = 0
   289  		col[6].flag = 1 << 5
   290  		var colType = []defines.MysqlType{defines.MYSQL_TYPE_YEAR, defines.MYSQL_TYPE_YEAR, defines.MYSQL_TYPE_YEAR, defines.MYSQL_TYPE_SHORT, defines.MYSQL_TYPE_DOUBLE,
   291  			defines.MYSQL_TYPE_LONGLONG, defines.MYSQL_TYPE_LONGLONG, defines.MYSQL_TYPE_VARCHAR, defines.MYSQL_TYPE_DATE, defines.MYSQL_TYPE_DATETIME,
   292  			defines.MYSQL_TYPE_BOOL, defines.MYSQL_TYPE_DECIMAL, defines.MYSQL_TYPE_JSON}
   293  		for i := 0; i < len(col); i++ {
   294  			col[i].SetColumnType(colType[i])
   295  			oq.mrs.AddColumn(&col[i])
   296  		}
   297  		var data = make([]interface{}, len(col))
   298  		data[1] = 0
   299  		data[2] = 1
   300  		data[3] = 1
   301  		data[4] = 1.0
   302  		data[5] = 1
   303  		data[6] = 1
   304  		data[7] = []byte{1}
   305  		data[8] = types.Date(1)
   306  		data[9] = "2022-02-28 23:59:59.9999"
   307  		data[10] = true
   308  		data[11] = 1.2
   309  		data[12], _ = types.ParseStringToByteJson(`{"a":1}`)
   310  
   311  		oq.mrs.AddRow(data)
   312  
   313  		oq.ep.Symbol = make([][]byte, len(col))
   314  		oq.ep.ColumnFlag = make([]bool, len(col))
   315  
   316  		stubs := gostub.StubFunc(&formatOutputString, nil)
   317  		defer stubs.Reset()
   318  
   319  		convey.So(exportDataToCSVFile(oq), convey.ShouldBeNil)
   320  	})
   321  
   322  	convey.Convey("exportDataToCSVFile fail", t, func() {
   323  		var oq = &outputQueue{
   324  			mrs: &MysqlResultSet{},
   325  			ep: &ExportConfig{
   326  				userConfig: &tree.ExportParam{
   327  					Lines: &tree.Lines{
   328  						TerminatedBy: &tree.Terminated{},
   329  					},
   330  					Fields: &tree.Fields{
   331  						Terminated: &tree.Terminated{},
   332  						EnclosedBy: &tree.EnclosedBy{},
   333  						EscapedBy:  &tree.EscapedBy{},
   334  					},
   335  					Header:   true,
   336  					FilePath: "test/export.csv",
   337  				},
   338  				LineSize: 1,
   339  				Writer:   &bufio.Writer{},
   340  			},
   341  		}
   342  		var col = make([]MysqlColumn, 1)
   343  		var colType = []defines.MysqlType{defines.MYSQL_TYPE_TIMESTAMP}
   344  		for i := 0; i < len(col); i++ {
   345  			col[i].SetColumnType(colType[i])
   346  			oq.mrs.AddColumn(&col[i])
   347  		}
   348  
   349  		var data = make([]interface{}, len(col))
   350  		data[0] = 1
   351  		oq.mrs.AddRow(data)
   352  		oq.ep.Symbol = make([][]byte, len(col))
   353  		oq.ep.ColumnFlag = make([]bool, len(col))
   354  
   355  		stubs := gostub.StubFunc(&formatOutputString, nil)
   356  		defer stubs.Reset()
   357  
   358  		convey.So(exportDataToCSVFile(oq), convey.ShouldBeNil)
   359  	})
   360  }