github.com/matrixorigin/matrixone@v1.2.0/pkg/util/trace/impl/motrace/mo_trace_test.go (about)

     1  // Copyright The OpenTelemetry Authors
     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  // Portions of this file are additionally subject to the following
    16  // copyright.
    17  //
    18  // Copyright (C) 2022 Matrix Origin.
    19  //
    20  // Modified the behavior and the interface of the step.
    21  
    22  package motrace
    23  
    24  import (
    25  	"context"
    26  	"fmt"
    27  	"io"
    28  	"os"
    29  	"path"
    30  	"path/filepath"
    31  	"runtime"
    32  	"sync"
    33  	"testing"
    34  	"time"
    35  
    36  	"github.com/matrixorigin/matrixone/pkg/util/export/table"
    37  	"github.com/matrixorigin/matrixone/pkg/util/trace"
    38  	"github.com/prashantv/gostub"
    39  	"github.com/stretchr/testify/assert"
    40  	"github.com/stretchr/testify/require"
    41  	"go.uber.org/zap"
    42  )
    43  
    44  var _1TxnID = [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1}
    45  var _1SesID = [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1}
    46  var _1TraceID trace.TraceID = [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1}
    47  var _2TraceID trace.TraceID = [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2}
    48  var _10F0TraceID trace.TraceID = [16]byte{0x09, 0x87, 0x65, 0x43, 0x21, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0}
    49  var _1SpanID trace.SpanID = [8]byte{0, 0, 0, 0, 0, 0, 0, 1}
    50  var _2SpanID trace.SpanID = [8]byte{0, 0, 0, 0, 0, 0, 0, 2}
    51  var _16SpanID trace.SpanID = [8]byte{0, 0, 0, 0, 0, 0x12, 0x34, 0x56}
    52  
    53  func TestMOTracer_Start(t *testing.T) {
    54  	if runtime.GOOS == `linux` {
    55  		t.Skip()
    56  		return
    57  	}
    58  	type fields struct {
    59  		Enable bool
    60  	}
    61  	type args struct {
    62  		ctx  context.Context
    63  		name string
    64  		opts []trace.SpanStartOption
    65  	}
    66  	rootCtx := trace.ContextWithSpanContext(context.Background(), trace.SpanContextWithIDs(_1TraceID, _1SpanID))
    67  	stmCtx := trace.ContextWithSpanContext(context.Background(), trace.SpanContextWithID(_1TraceID, trace.SpanKindStatement))
    68  	dAtA := make([]byte, 24)
    69  	span := trace.SpanFromContext(stmCtx)
    70  	c := span.SpanContext()
    71  	cnt, err := c.MarshalTo(dAtA)
    72  	require.Nil(t, err)
    73  	require.Equal(t, 24, cnt)
    74  	sc := &trace.SpanContext{}
    75  	err = sc.Unmarshal(dAtA)
    76  	require.Nil(t, err)
    77  	remoteCtx := trace.ContextWithSpanContext(context.Background(), *sc)
    78  	tests := []struct {
    79  		name             string
    80  		fields           fields
    81  		args             args
    82  		wantNewRoot      bool
    83  		wantTraceId      trace.TraceID
    84  		wantParentSpanId trace.SpanID
    85  		wantKind         trace.SpanKind
    86  	}{
    87  		{
    88  			name:             "normal",
    89  			fields:           fields{Enable: true},
    90  			args:             args{ctx: rootCtx, name: "normal", opts: []trace.SpanStartOption{}},
    91  			wantNewRoot:      false,
    92  			wantTraceId:      _1TraceID,
    93  			wantParentSpanId: _1SpanID,
    94  			wantKind:         trace.SpanKindInternal,
    95  		},
    96  		{
    97  			name:             "newRoot",
    98  			fields:           fields{Enable: true},
    99  			args:             args{ctx: rootCtx, name: "newRoot", opts: []trace.SpanStartOption{trace.WithNewRoot(true)}},
   100  			wantNewRoot:      true,
   101  			wantTraceId:      _1TraceID,
   102  			wantParentSpanId: _1SpanID,
   103  			wantKind:         trace.SpanKindInternal,
   104  		},
   105  		{
   106  			name:             "statement",
   107  			fields:           fields{Enable: true},
   108  			args:             args{ctx: stmCtx, name: "newStmt", opts: []trace.SpanStartOption{}},
   109  			wantNewRoot:      false,
   110  			wantTraceId:      _1TraceID,
   111  			wantParentSpanId: trace.NilSpanID,
   112  			wantKind:         trace.SpanKindStatement,
   113  		},
   114  		{
   115  			name:             "empty",
   116  			fields:           fields{Enable: true},
   117  			args:             args{ctx: context.Background(), name: "backgroundCtx", opts: []trace.SpanStartOption{}},
   118  			wantNewRoot:      true,
   119  			wantTraceId:      trace.NilTraceID,
   120  			wantParentSpanId: _1SpanID,
   121  			wantKind:         trace.SpanKindInternal,
   122  		},
   123  		{
   124  			name:             "remote",
   125  			fields:           fields{Enable: true},
   126  			args:             args{ctx: remoteCtx, name: "remoteCtx", opts: []trace.SpanStartOption{}},
   127  			wantNewRoot:      false,
   128  			wantTraceId:      _1TraceID,
   129  			wantParentSpanId: trace.NilSpanID,
   130  			wantKind:         trace.SpanKindRemote,
   131  		},
   132  	}
   133  	tracer := &MOTracer{
   134  		TracerConfig: trace.TracerConfig{Name: "motrace_test"},
   135  		provider:     defaultMOTracerProvider(),
   136  	}
   137  	for _, tt := range tests {
   138  		t.Run(tt.name, func(t1 *testing.T) {
   139  			tracer.provider.enable = tt.fields.Enable
   140  			newCtx, span := tracer.Start(tt.args.ctx, tt.args.name, tt.args.opts...)
   141  			if !tt.wantNewRoot {
   142  				require.Equal(t1, tt.wantTraceId, span.SpanContext().TraceID)
   143  				require.Equal(t1, tt.wantParentSpanId, span.ParentSpanContext().SpanID)
   144  				require.Equal(t1, tt.wantParentSpanId, trace.SpanFromContext(newCtx).ParentSpanContext().SpanID)
   145  			} else {
   146  				require.NotEqualf(t1, tt.wantTraceId, span.SpanContext().TraceID, "want %s, but got %s", tt.wantTraceId.String(), span.SpanContext().TraceID.String())
   147  				require.NotEqual(t1, tt.wantParentSpanId, span.ParentSpanContext().SpanID)
   148  				require.NotEqual(t1, tt.wantParentSpanId, trace.SpanFromContext(newCtx).ParentSpanContext().SpanID)
   149  			}
   150  			require.Equal(t1, tt.wantKind, trace.SpanFromContext(newCtx).ParentSpanContext().Kind)
   151  			require.Equal(t1, span, trace.SpanFromContext(newCtx))
   152  		})
   153  	}
   154  }
   155  
   156  func TestSpanContext_MarshalTo(t *testing.T) {
   157  	type fields struct {
   158  		TraceID trace.TraceID
   159  		SpanID  trace.SpanID
   160  	}
   161  	type args struct {
   162  		dAtA []byte
   163  	}
   164  	tests := []struct {
   165  		name      string
   166  		fields    fields
   167  		args      args
   168  		want      int
   169  		wantBytes []byte
   170  	}{
   171  		{
   172  			name: "normal",
   173  			fields: fields{
   174  				TraceID: trace.NilTraceID,
   175  				SpanID:  _16SpanID,
   176  			},
   177  			args: args{dAtA: make([]byte, 24)},
   178  			want: 24,
   179  			//                1  2  3  4  5  6  7  8, 1  2  3  4  5  6  7  8--1  2  3  4  5  6     7     8
   180  			wantBytes: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34, 0x56},
   181  		},
   182  		{
   183  			name: "not-zero",
   184  			fields: fields{
   185  				TraceID: _10F0TraceID,
   186  				SpanID:  _16SpanID,
   187  			},
   188  			args: args{dAtA: make([]byte, 24)},
   189  			want: 24,
   190  			//                1     2     3     4     5     6     7     8,    1  2  3  4  5  6  7  8--1  2  3  4  5  6     7     8
   191  			wantBytes: []byte{0x09, 0x87, 0x65, 0x43, 0x21, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34, 0x56},
   192  		},
   193  	}
   194  	for _, tt := range tests {
   195  		t.Run(tt.name, func(t *testing.T) {
   196  			c := &trace.SpanContext{
   197  				TraceID: tt.fields.TraceID,
   198  				SpanID:  tt.fields.SpanID,
   199  				Kind:    trace.SpanKindRemote,
   200  			}
   201  			got, err := c.MarshalTo(tt.args.dAtA)
   202  			require.Equal(t, nil, err)
   203  			require.Equal(t, got, tt.want)
   204  			require.Equal(t, tt.wantBytes, tt.args.dAtA)
   205  			newC := &trace.SpanContext{}
   206  			err = newC.Unmarshal(tt.args.dAtA)
   207  			require.Equal(t, nil, err)
   208  			require.Equal(t, c, newC)
   209  			require.Equal(t, tt.fields.TraceID, newC.TraceID)
   210  			require.Equal(t, tt.fields.SpanID, newC.SpanID)
   211  		})
   212  	}
   213  }
   214  
   215  func TestMOSpan_End(t *testing.T) {
   216  	if runtime.NumCPU() < 4 {
   217  		t.Skip("machine's performance too low to handle time sensitive case, issue #11669")
   218  		return
   219  	}
   220  
   221  	s := gostub.Stub(&freeMOSpan, func(span *MOSpan) {})
   222  	defer s.Reset()
   223  
   224  	ctx := context.TODO()
   225  	p := newMOTracerProvider(WithLongSpanTime(time.Hour), EnableTracer(true))
   226  	tracer := &MOTracer{
   227  		TracerConfig: trace.TracerConfig{Name: "test"},
   228  		provider:     p,
   229  	}
   230  
   231  	var WG sync.WaitGroup
   232  
   233  	// short time span
   234  	var shortTimeSpan trace.Span
   235  	WG.Add(1)
   236  	go func() {
   237  		_, shortTimeSpan = tracer.Start(ctx, "shortTimeSpan")
   238  		defer WG.Done()
   239  		defer shortTimeSpan.End()
   240  	}()
   241  	WG.Wait()
   242  	require.Equal(t, false, shortTimeSpan.(*MOSpan).needRecord)
   243  	require.Equal(t, 0, len(shortTimeSpan.(*MOSpan).ExtraFields))
   244  
   245  	// span with LongTimeThreshold
   246  	// and set ExtraFields
   247  	var longTimeSpan trace.Span
   248  	WG.Add(1)
   249  	extraFields := []zap.Field{zap.String("str", "field"), zap.Int64("int", 0)}
   250  	go func() {
   251  		_, longTimeSpan = tracer.Start(ctx, "longTimeSpan", trace.WithLongTimeThreshold(time.Millisecond))
   252  		defer WG.Done()
   253  		defer longTimeSpan.End()
   254  
   255  		longTimeSpan.AddExtraFields(extraFields...)
   256  
   257  		time.Sleep(10 * time.Millisecond)
   258  	}()
   259  	WG.Wait()
   260  	require.Equal(t, true, longTimeSpan.(*MOSpan).needRecord)
   261  	require.Equal(t, 2, len(longTimeSpan.(*MOSpan).ExtraFields))
   262  	require.Equal(t, false, longTimeSpan.(*MOSpan).doneProfile)
   263  	require.Equal(t, extraFields, longTimeSpan.(*MOSpan).ExtraFields)
   264  
   265  	// span with deadline context
   266  	deadlineCtx, cancel := context.WithTimeout(ctx, time.Millisecond)
   267  	defer cancel()
   268  	var deadlineSpan trace.Span
   269  	WG.Add(1)
   270  	go func() {
   271  		_, deadlineSpan = tracer.Start(deadlineCtx, "deadlineCtx")
   272  		defer WG.Done()
   273  		defer deadlineSpan.End()
   274  
   275  		time.Sleep(10 * time.Millisecond)
   276  	}()
   277  	WG.Wait()
   278  	require.Equal(t, true, deadlineSpan.(*MOSpan).needRecord)
   279  	require.Equal(t, 1, len(deadlineSpan.(*MOSpan).ExtraFields))
   280  	require.Equal(t, false, deadlineSpan.(*MOSpan).doneProfile)
   281  	require.Equal(t, []zap.Field{zap.Error(context.DeadlineExceeded)}, deadlineSpan.(*MOSpan).ExtraFields)
   282  
   283  	// span with deadline context (plus calling cancel2() before func return)
   284  	deadlineCtx2, cancel2 := context.WithTimeout(ctx, time.Millisecond)
   285  	var deadlineSpan2 trace.Span
   286  	WG.Add(1)
   287  	go func() {
   288  		_, deadlineSpan2 = tracer.Start(deadlineCtx2, "deadlineCtx")
   289  		defer WG.Done()
   290  		defer deadlineSpan2.End()
   291  
   292  		time.Sleep(10 * time.Millisecond)
   293  		cancel2()
   294  	}()
   295  	WG.Wait()
   296  	require.Equal(t, true, deadlineSpan2.(*MOSpan).needRecord)
   297  	require.Equal(t, 1, len(deadlineSpan2.(*MOSpan).ExtraFields))
   298  	require.Equal(t, false, deadlineSpan2.(*MOSpan).doneProfile)
   299  	require.Equal(t, []zap.Field{zap.Error(context.DeadlineExceeded)}, deadlineSpan2.(*MOSpan).ExtraFields)
   300  
   301  	// span with hung option, with Deadline situation
   302  	caseHungOptionWithDeadline := func() {
   303  		var hungSpan trace.Span
   304  		WG.Add(1)
   305  		go func() {
   306  			_, hungSpan = tracer.Start(ctx, "hungCtx", trace.WithHungThreshold(time.Millisecond))
   307  			defer WG.Done()
   308  			defer hungSpan.End()
   309  
   310  			time.Sleep(10 * time.Millisecond)
   311  		}()
   312  		WG.Wait()
   313  		require.Equal(t, true, hungSpan.(*MOHungSpan).needRecord)
   314  		require.Equal(t, 1, len(hungSpan.(*MOHungSpan).ExtraFields))
   315  		require.Equal(t, true, hungSpan.(*MOHungSpan).doneProfile)
   316  		require.Equal(t, []zap.Field{zap.Error(context.DeadlineExceeded)}, hungSpan.(*MOHungSpan).ExtraFields)
   317  	}
   318  	caseHungOptionWithDeadline()
   319  
   320  	// span with hung option, with NO Deadline situation
   321  	caseHungOptionWithoutDeadline := func() {
   322  		var hungSpan trace.Span
   323  		WG.Add(1)
   324  		go func() {
   325  			_, hungSpan = tracer.Start(ctx, "hungCtx", trace.WithHungThreshold(time.Minute))
   326  			defer WG.Done()
   327  			defer hungSpan.End()
   328  
   329  			time.Sleep(10 * time.Millisecond)
   330  		}()
   331  		WG.Wait()
   332  		require.Equal(t, false, hungSpan.(*MOHungSpan).needRecord)
   333  		require.Equal(t, 0, len(hungSpan.(*MOHungSpan).ExtraFields))
   334  		require.Equal(t, false, hungSpan.(*MOHungSpan).doneProfile)
   335  	}
   336  	caseHungOptionWithoutDeadline()
   337  
   338  }
   339  
   340  type dummyFileWriterFactory struct{}
   341  
   342  func (f *dummyFileWriterFactory) GetRowWriter(ctx context.Context, account string, tbl *table.Table, ts time.Time) table.RowWriter {
   343  	return &dummyStringWriter{}
   344  }
   345  func (f *dummyFileWriterFactory) GetWriter(ctx context.Context, fp string) io.WriteCloser {
   346  	selfDir, err := filepath.Abs(".")
   347  	if err != nil {
   348  		panic(err)
   349  	}
   350  	fmt.Printf("root: %s\n", selfDir)
   351  	dirname := path.Dir(fp)
   352  	if dirname != "." && dirname != "./" && dirname != "/" {
   353  		if err := os.Mkdir(dirname, os.ModeType|os.ModePerm); err != nil && !os.IsExist(err) {
   354  			panic(err)
   355  		}
   356  	}
   357  	fw, err := os.Create(fp)
   358  	if err != nil {
   359  		panic(err)
   360  	}
   361  	return fw
   362  }
   363  
   364  func TestMOSpan_doProfile(t *testing.T) {
   365  	type fields struct {
   366  		opts   []trace.SpanStartOption
   367  		ctx    context.Context
   368  		tracer *MOTracer
   369  	}
   370  
   371  	p := newMOTracerProvider(WithFSWriterFactory(&dummyFileWriterFactory{}), EnableTracer(true))
   372  	tracer := p.Tracer("test").(*MOTracer)
   373  	ctx := context.TODO()
   374  
   375  	prepareCheckCpu := func(t *testing.T) {
   376  		if runtime.NumCPU() < 4 {
   377  			t.Skip("machine's performance too low to handle time sensitive case, issue #11864")
   378  		}
   379  	}
   380  
   381  	tests := []struct {
   382  		name    string
   383  		fields  fields
   384  		prepare func(t *testing.T)
   385  		want    bool
   386  	}{
   387  		{
   388  			name: "normal",
   389  			fields: fields{
   390  				opts:   nil,
   391  				ctx:    ctx,
   392  				tracer: tracer,
   393  			},
   394  		},
   395  		{
   396  			name: "goroutine",
   397  			fields: fields{
   398  				opts:   []trace.SpanStartOption{trace.WithProfileGoroutine()}, // it will dump file into ETL folder.
   399  				ctx:    ctx,
   400  				tracer: tracer,
   401  			},
   402  			want: true,
   403  		},
   404  		{
   405  			name: "heap",
   406  			fields: fields{
   407  				opts:   []trace.SpanStartOption{trace.WithProfileHeap()},
   408  				ctx:    ctx,
   409  				tracer: tracer,
   410  			},
   411  			want: true,
   412  		},
   413  		{
   414  			name: "threadcreate",
   415  			fields: fields{
   416  				opts:   []trace.SpanStartOption{trace.WithProfileThreadCreate()},
   417  				ctx:    ctx,
   418  				tracer: tracer,
   419  			},
   420  			want: true,
   421  		},
   422  		{
   423  			name: "allocs",
   424  			fields: fields{
   425  				opts:   []trace.SpanStartOption{trace.WithProfileAllocs()},
   426  				ctx:    ctx,
   427  				tracer: tracer,
   428  			},
   429  			want: true,
   430  		},
   431  		{
   432  			name: "block",
   433  			fields: fields{
   434  				opts:   []trace.SpanStartOption{trace.WithProfileBlock()},
   435  				ctx:    ctx,
   436  				tracer: tracer,
   437  			},
   438  			want: true,
   439  		},
   440  		{
   441  			name: "mutex",
   442  			fields: fields{
   443  				opts:   []trace.SpanStartOption{trace.WithProfileMutex()},
   444  				ctx:    ctx,
   445  				tracer: tracer,
   446  			},
   447  			want: true,
   448  		},
   449  		{
   450  			name: "cpu",
   451  			fields: fields{
   452  				opts:   []trace.SpanStartOption{trace.WithProfileCpuSecs(time.Second)},
   453  				ctx:    ctx,
   454  				tracer: tracer,
   455  			},
   456  			prepare: prepareCheckCpu,
   457  			want:    true,
   458  		},
   459  		{
   460  			name: "trace",
   461  			fields: fields{
   462  				opts:   []trace.SpanStartOption{trace.WithProfileTraceSecs(time.Second)},
   463  				ctx:    ctx,
   464  				tracer: tracer,
   465  			},
   466  			prepare: prepareCheckCpu,
   467  			want:    true,
   468  		},
   469  	}
   470  	for _, tt := range tests {
   471  		t.Run(tt.name, func(t *testing.T) {
   472  			if tt.prepare != nil {
   473  				tt.prepare(t)
   474  			}
   475  			_, s := tt.fields.tracer.Start(tt.fields.ctx, "test", tt.fields.opts...)
   476  			ms, _ := s.(*MOSpan)
   477  			t.Logf("span.LongTimeThreshold: %v", ms.LongTimeThreshold)
   478  			time.Sleep(time.Millisecond)
   479  			s.End()
   480  			t.Logf("span.LongTimeThreshold: %v, duration: %v, needRecord: %v, needProfile: %v, doneProfile: %v",
   481  				ms.LongTimeThreshold, ms.Duration, ms.needRecord, ms.NeedProfile(), ms.doneProfile)
   482  			require.Equal(t, tt.want, s.(*MOSpan).doneProfile)
   483  		})
   484  	}
   485  }
   486  
   487  func TestMOHungSpan_EndBeforeDeadline_doProfile(t *testing.T) {
   488  
   489  	defer func() {
   490  		err := recover()
   491  		require.Nilf(t, err, "error: %s", err)
   492  	}()
   493  
   494  	p := newMOTracerProvider(WithFSWriterFactory(&dummyFileWriterFactory{}), EnableTracer(true))
   495  	tracer := p.Tracer("test").(*MOTracer)
   496  	ctx := context.TODO()
   497  
   498  	var ctrlWG sync.WaitGroup
   499  	ctrlWG.Add(1)
   500  
   501  	_, span := tracer.Start(ctx, "test_loop", trace.WithHungThreshold(100*time.Millisecond))
   502  	hungSpan := span.(*MOHungSpan)
   503  
   504  	hungSpan.mux.Lock()
   505  	// simulate the act of span.End()
   506  	// TIPs: remove trigger.Stop()
   507  	hungSpan.quitCancel()
   508  	hungSpan.stopped = true
   509  	hungSpan.MOSpan = nil
   510  	time.Sleep(300 * time.Millisecond)
   511  	t.Logf("hungSpan.quitCtx.Err: %s", hungSpan.quitCtx.Err())
   512  	// END > simulate
   513  	hungSpan.mux.Unlock()
   514  
   515  	// wait for goroutine to finish
   516  	// should not panic
   517  	time.Sleep(time.Second)
   518  }
   519  
   520  func TestContextDeadlineAndCancel(t *testing.T) {
   521  	if runtime.NumCPU() < 4 {
   522  		t.Skip("machine's performance too low to handle time sensitive case")
   523  		return
   524  	}
   525  	quitCtx, quitCancel := context.WithCancel(context.TODO())
   526  	deadlineCtx, deadlineCancel := context.WithTimeout(quitCtx, time.Microsecond)
   527  	defer deadlineCancel()
   528  
   529  	time.Sleep(time.Second)
   530  	t.Logf("deadlineCtx.Err: %s", deadlineCtx.Err())
   531  	quitCancel()
   532  	require.Equal(t, context.DeadlineExceeded, deadlineCtx.Err())
   533  }
   534  
   535  func TestMOTracer_FSSpanIsEnable(t *testing.T) {
   536  
   537  	tracer := &MOTracer{
   538  		TracerConfig: trace.TracerConfig{Name: "motrace_test"},
   539  		provider:     defaultMOTracerProvider(),
   540  	}
   541  	tracer.provider.enable = true
   542  
   543  	trace.InitMOCtledSpan()
   544  	trace.SetMoCtledSpanState("local", true, 0)
   545  
   546  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   547  	defer cancel()
   548  	_, span := tracer.Start(ctx, "test", trace.WithKind(
   549  		trace.SpanKindLocalFSVis))
   550  
   551  	_, ok := span.(trace.NoopSpan)
   552  
   553  	assert.True(t, tracer.IsEnable(trace.WithKind(trace.SpanKindLocalFSVis)))
   554  	assert.False(t, ok)
   555  	span.End()
   556  
   557  	_, span = tracer.Start(context.Background(), "test", trace.WithKind(
   558  		trace.SpanKindRemoteFSVis))
   559  	_, ok = span.(trace.NoopSpan)
   560  	assert.False(t, tracer.IsEnable(trace.WithKind(trace.SpanKindRemoteFSVis)))
   561  	assert.True(t, ok)
   562  	span.End()
   563  
   564  }
   565  
   566  func TestMOSpan_NeedRecord(t *testing.T) {
   567  	tracer := &MOTracer{
   568  		TracerConfig: trace.TracerConfig{Name: "motrace_test"},
   569  		provider:     defaultMOTracerProvider(),
   570  	}
   571  
   572  	tracer.provider.enable = true
   573  	tracer.provider.longSpanTime = time.Millisecond * 20
   574  	trace.InitMOCtledSpan()
   575  
   576  	// ctx has deadline
   577  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*1)
   578  	defer cancel()
   579  
   580  	_, span := tracer.Start(ctx, "normal span")
   581  	time.Sleep(time.Millisecond * 30)
   582  	// deadline not expired, no need to record
   583  	ret, _ := span.(*MOSpan).NeedRecord()
   584  	require.False(t, ret)
   585  	span.End()
   586  
   587  	_, span = tracer.Start(ctx, "normal span")
   588  	time.Sleep(time.Second)
   589  	span.(*MOSpan).EndTime = time.Now()
   590  	// ctx expired, record
   591  	ret, _ = span.(*MOSpan).NeedRecord()
   592  	require.True(t, ret)
   593  	span.End()
   594  
   595  	trace.SetMoCtledSpanState("statement", true, 0)
   596  	_, span = tracer.Start(ctx, "mo_ctl controlled span",
   597  		trace.WithKind(trace.SpanKindStatement))
   598  	// ctx expired, but not to record
   599  	trace.SetMoCtledSpanState("statement", false, 0)
   600  	ret, _ = span.(*MOSpan).NeedRecord()
   601  	require.False(t, ret)
   602  	span.End()
   603  
   604  	trace.SetMoCtledSpanState("statement", true, 0)
   605  	_, span = tracer.Start(ctx, "mo_ctl controlled span",
   606  		trace.WithKind(trace.SpanKindStatement))
   607  	// record
   608  	ret, _ = span.(*MOSpan).NeedRecord()
   609  	require.True(t, ret)
   610  	span.End()
   611  
   612  	// it won't record until this trace last more than 1000ms
   613  	trace.SetMoCtledSpanState("statement", true, 1000)
   614  	_, span = tracer.Start(ctx, "mo_ctl controlled span",
   615  		trace.WithKind(trace.SpanKindStatement))
   616  
   617  	span.(*MOSpan).Duration = time.Since(span.(*MOSpan).StartTime)
   618  
   619  	ret, _ = span.(*MOSpan).NeedRecord()
   620  	require.False(t, ret)
   621  	span.End()
   622  
   623  	trace.SetMoCtledSpanState("statement", true, 100)
   624  	_, span = tracer.Start(ctx, "mo_ctl controlled span",
   625  		trace.WithKind(trace.SpanKindStatement))
   626  	time.Sleep(time.Millisecond * 200)
   627  	// record
   628  
   629  	span.(*MOSpan).Duration = time.Since(span.(*MOSpan).StartTime)
   630  
   631  	ret, _ = span.(*MOSpan).NeedRecord()
   632  	require.True(t, ret)
   633  	span.End()
   634  }
   635  
   636  func TestMOCtledKindOverwrite(t *testing.T) {
   637  	tracer := &MOTracer{
   638  		TracerConfig: trace.TracerConfig{Name: "motrace_test"},
   639  		provider:     defaultMOTracerProvider(),
   640  	}
   641  	tracer.provider.enable = true
   642  
   643  	trace.InitMOCtledSpan()
   644  
   645  	fctx, fspan := tracer.Start(context.Background(), "test2", trace.WithKind(trace.SpanKindRemote))
   646  	defer fspan.End()
   647  	require.Equal(t, fspan.SpanContext().Kind, trace.SpanKindRemote)
   648  
   649  	trace.SetMoCtledSpanState("statement", true, 0)
   650  	// won't be overwritten
   651  	_, span := tracer.Start(fctx, "test3", trace.WithKind(trace.SpanKindStatement))
   652  	defer span.End()
   653  	require.NotEqual(t, span.SpanContext().Kind, fspan.SpanContext().Kind)
   654  	require.Equal(t, span.SpanContext().Kind, trace.SpanKindStatement)
   655  
   656  }
   657  
   658  func TestMOCtledKindPassDown(t *testing.T) {
   659  	tracer := &MOTracer{
   660  		TracerConfig: trace.TracerConfig{Name: "motrace_test"},
   661  		provider:     defaultMOTracerProvider(),
   662  	}
   663  	tracer.provider.enable = true
   664  
   665  	trace.InitMOCtledSpan()
   666  	trace.SetMoCtledSpanState("s3", true, 0)
   667  	specialCtx, specialSpan := tracer.Start(context.Background(), "special span",
   668  		trace.WithKind(trace.SpanKindRemoteFSVis))
   669  	defer specialSpan.End()
   670  	require.Equal(t, specialSpan.SpanContext().Kind, trace.SpanKindRemoteFSVis)
   671  
   672  	// won't pass down kind to child
   673  	_, span := tracer.Start(specialCtx, "child span")
   674  	defer span.End()
   675  	require.NotEqual(t, span.SpanContext().Kind, specialSpan.SpanContext().Kind)
   676  
   677  }