@@ -21,10 +21,14 @@ function setupOnce(testCase)
2121 % add the utils folder to the path
2222 utilsfolder = fullfile(fileparts(mfilename(' fullpath' )), " utils" );
2323 testCase .applyFixture(matlab .unittest .fixtures .PathFixture(utilsfolder ));
24- % add the example folder to the path
24+ % add the example folders to the path
2525 example1folder = fullfile(fileparts(mfilename(' fullpath' )), " autotrace_examples" , " example1" );
2626 testCase .applyFixture(matlab .unittest .fixtures .PathFixture(example1folder ));
2727 commonSetupOnce(testCase );
28+
29+ % configure the global tracer provider
30+ tp = opentelemetry .sdk .trace .TracerProvider();
31+ setTracerProvider(tp );
2832 end
2933 end
3034
@@ -43,12 +47,7 @@ function teardown(testCase)
4347 methods (Test )
4448 function testBasic(testCase )
4549 % testBasic: instrument a simple example
46-
47- % configure the global tracer provider
48- tp = opentelemetry .sdk .trace .TracerProvider();
49- setTracerProvider(tp );
50- clear(" tp" );
51-
50+
5251 % set up AutoTrace
5352 at = opentelemetry .autoinstrument .AutoTrace(@example1 );
5453
@@ -59,11 +58,191 @@ function testBasic(testCase)
5958 results = readJsonResults(testCase );
6059 verifyNumElements(testCase , results , 3 );
6160
62- % check logger name, log body and severity, trace and span IDs
63- verifyEqual(testCase , string(results{1 }.resourceSpans.scopeSpans.scope.name), " AutoTrace" );
61+ % check tracer and span names
62+ verifyEqual(testCase , string(results{1 }.resourceSpans.scopeSpans.scope.name), " AutoTrace" ); % default name
6463 verifyEqual(testCase , string(results{1 }.resourceSpans.scopeSpans.spans.name), " generate_data" );
6564 verifyEqual(testCase , string(results{2 }.resourceSpans.scopeSpans.spans.name), " best_fit_line" );
6665 verifyEqual(testCase , string(results{3 }.resourceSpans.scopeSpans.spans.name), " example1" );
66+
67+ % check they belong to the same trace
68+ verifyEqual(testCase , results{1 }.resourceSpans.scopeSpans.spans.traceId, results{2 }.resourceSpans.scopeSpans.spans.traceId);
69+ verifyEqual(testCase , results{1 }.resourceSpans.scopeSpans.spans.traceId, results{3 }.resourceSpans.scopeSpans.spans.traceId);
70+
71+ % check parent children relationship
72+ verifyEqual(testCase , results{1 }.resourceSpans.scopeSpans.spans.parentSpanId, results{3 }.resourceSpans.scopeSpans.spans.spanId);
73+ verifyEqual(testCase , results{2 }.resourceSpans.scopeSpans.spans.parentSpanId, results{3 }.resourceSpans.scopeSpans.spans.spanId);
74+ end
75+
76+ function testIncludeExcludeFiles(testCase )
77+ % testIncludeExcludeFiles: AdditionalFiles and ExcludeFiles options
78+
79+ % set up AutoTrace
80+ at = opentelemetry .autoinstrument .AutoTrace(@example1 , ...
81+ " AdditionalFiles" , " polyfit" , " ExcludeFiles" , " generate_data" );
82+
83+ % run the example
84+ [~ ] = beginTrace(at , 100 );
85+
86+ % perform test comparisons
87+ results = readJsonResults(testCase );
88+ verifyNumElements(testCase , results , 3 );
89+
90+ % check span names
91+ verifyEqual(testCase , string(results{1 }.resourceSpans.scopeSpans.spans.name), " polyfit" );
92+ verifyEqual(testCase , string(results{2 }.resourceSpans.scopeSpans.spans.name), " best_fit_line" );
93+ verifyEqual(testCase , string(results{3 }.resourceSpans.scopeSpans.spans.name), " example1" );
94+
95+ % check parent children relationship
96+ verifyEqual(testCase , results{1 }.resourceSpans.scopeSpans.spans.parentSpanId, results{2 }.resourceSpans.scopeSpans.spans.spanId);
97+ verifyEqual(testCase , results{2 }.resourceSpans.scopeSpans.spans.parentSpanId, results{3 }.resourceSpans.scopeSpans.spans.spanId);
98+ end
99+
100+ function testDisableFileDetection(testCase )
101+ % testDisableFileDetection: AutoDetectFiles set to false
102+
103+ % set up AutoTrace
104+ at = opentelemetry .autoinstrument .AutoTrace(@example1 , ...
105+ " AutoDetectFiles" , false );
106+
107+ % run the example
108+ [~ ] = beginTrace(at , 100 );
109+
110+ % perform test comparisons
111+ results = readJsonResults(testCase );
112+
113+ % should only be 1 span
114+ verifyNumElements(testCase , results , 1 );
115+ verifyEqual(testCase , string(results{1 }.resourceSpans.scopeSpans.spans.name), " example1" );
116+ end
117+
118+ function testNonFileOptions(testCase )
119+ % testNonFileOptions: other options not related to files,
120+ % "TracerName", "TracerVersion", "TracerSchema", "Attributes",
121+ % "SpanKind"
122+
123+ tracername = " foo" ;
124+ tracerversion = " 1.1" ;
125+ tracerschema = " https://opentelemetry.io/schemas/1.28.0" ;
126+ spankind = " consumer" ;
127+ attrnames = [" foo" " bar" ];
128+ attrvalues = [1 2 ];
129+ attrs = dictionary(attrnames , attrvalues );
130+ % set up AutoTrace
131+ at = opentelemetry .autoinstrument .AutoTrace(@example1 , ...
132+ " TracerName" , tracername , " TracerVersion" , tracerversion , ...
133+ " TracerSchema" , tracerschema , " SpanKind" , spankind , " Attributes" , attrs );
134+
135+ % run the example
136+ [~ ] = beginTrace(at , 100 );
137+
138+ % perform test comparisons
139+ results = readJsonResults(testCase );
140+ verifyNumElements(testCase , results , 3 );
141+
142+ % check specified options in each span
143+ for i = 1 : numel(results )
144+ verifyEqual(testCase , string(results{i }.resourceSpans.scopeSpans.scope.name), tracername );
145+ verifyEqual(testCase , string(results{i }.resourceSpans.scopeSpans.scope.version), tracerversion );
146+ verifyEqual(testCase , string(results{i }.resourceSpans.scopeSpans.schemaUrl), tracerschema );
147+ verifyEqual(testCase , results{i }.resourceSpans.scopeSpans.spans.kind, 5 ); % SpanKind consumer
148+
149+ % attributes
150+ attrkeys = string({results{i }.resourceSpans.scopeSpans.spans.attributes.key});
151+
152+ for ii = 1 : numel(attrnames )
153+ attrnameii = attrnames(ii );
154+ idxii = find(attrkeys == attrnameii );
155+ verifyNotEmpty(testCase , idxii );
156+ verifyEqual(testCase , results{i }.resourceSpans.scopeSpans.spans.attributes(idxii ).value.doubleValue, ...
157+ attrvalues(ii ));
158+ end
159+ end
160+ end
161+
162+ function testError(testCase )
163+ % testError: handling error situation
164+
165+ % set up AutoTrace
166+ at = opentelemetry .autoinstrument .AutoTrace(@example1 );
167+
168+ % run the example with an invalid input, check for error
169+ verifyError(testCase , @()beginTrace(at , " invalid" ), " MATLAB:colon:inputsMustBeNumericCharLogical" );
170+
171+ % perform test comparisons
172+ results = readJsonResults(testCase );
173+ verifyNumElements(testCase , results , 2 );
174+
175+ % check span names
176+ verifyEqual(testCase , string(results{1 }.resourceSpans.scopeSpans.spans.name), " generate_data" );
177+ verifyEqual(testCase , string(results{2 }.resourceSpans.scopeSpans.spans.name), " example1" );
178+
179+ % check parent children relationship
180+ verifyEqual(testCase , results{1 }.resourceSpans.scopeSpans.spans.parentSpanId, results{2 }.resourceSpans.scopeSpans.spans.spanId);
181+
182+ % check error status
183+ verifyEqual(testCase , results{1 }.resourceSpans.scopeSpans.spans.status.code, 2 ); % error
184+ verifyEmpty(testCase , fieldnames(results{2 }.resourceSpans.scopeSpans.spans.status)); % ok, no error
185+ end
186+
187+ function testHandleError(testCase )
188+ % testHandleError: directly call handleError method rather than using
189+ % beginTrace method. This test should use example1_trycatch, which
190+ % wraps a try-catch in the input function and calls handleError
191+ % in the catch block.
192+
193+ % set up AutoTrace, using example1_trycatch
194+ at = opentelemetry .autoinstrument .AutoTrace(@example1_trycatch );
195+
196+ % call example directly instead of calling beginTrace, and pass
197+ % in an invalid input
198+ verifyError(testCase , @()example1_trycatch(at , " invalid" ), " MATLAB:colon:inputsMustBeNumericCharLogical" );
199+
200+ % perform test comparisons
201+ results = readJsonResults(testCase );
202+ verifyNumElements(testCase , results , 2 );
203+
204+ % check span names
205+ verifyEqual(testCase , string(results{1 }.resourceSpans.scopeSpans.spans.name), " generate_data" );
206+ verifyEqual(testCase , string(results{2 }.resourceSpans.scopeSpans.spans.name), " example1_trycatch" );
207+
208+ % check parent children relationship
209+ verifyEqual(testCase , results{1 }.resourceSpans.scopeSpans.spans.parentSpanId, results{2 }.resourceSpans.scopeSpans.spans.spanId);
210+
211+ % check error status
212+ verifyEqual(testCase , results{1 }.resourceSpans.scopeSpans.spans.status.code, 2 ); % error
213+ verifyEmpty(testCase , fieldnames(results{2 }.resourceSpans.scopeSpans.spans.status)); % ok, no error
214+ end
215+
216+ function testMultipleInstances(testCase )
217+ % testMultipleInstances: multiple overlapped instances should
218+ % return an error
219+
220+ % set up AutoTrace
221+ at = opentelemetry .autoinstrument .AutoTrace(@example1 ); % #ok<NASGU>
222+
223+ % set up another identical instance, check for error
224+ verifyError(testCase , @()opentelemetry .autoinstrument .AutoTrace(@example1 ), " opentelemetry:autoinstrument:AutoTrace:OverlappedInstances" );
225+ end
226+
227+ function testClearInstance(~)
228+ % testClearInstance: clear an instance and recreate a new instance
229+
230+ % create and instance and then clear
231+ at = opentelemetry .autoinstrument .AutoTrace(@example1 ); % #ok<NASGU>
232+ clear(" at" )
233+
234+ % create a new instance should not result in any error
235+ at = opentelemetry .autoinstrument .AutoTrace(@example1 ); % #ok<NASGU>
236+ end
237+
238+ function testInvalidInputFunction(testCase )
239+ % testInvalidInputFunction: negative test for invalid input
240+
241+ % anonymous function
242+ verifyError(testCase , @()opentelemetry .autoinstrument .AutoTrace(@()example1 ), " opentelemetry:autoinstrument:AutoTrace:AnonymousFunction" );
243+
244+ % builtin function
245+ verifyError(testCase , @()opentelemetry .autoinstrument .AutoTrace(@uplus ), " opentelemetry:autoinstrument:AutoTrace:InvalidMFile" );
67246 end
68247 end
69248end
0 commit comments