Skip to content

Commit 867c8ad

Browse files
committed
Trying to figure out why transaction is in an uncommittable state.
1 parent c2e1bc4 commit 867c8ad

5 files changed

Lines changed: 381 additions & 11 deletions

File tree

Experiments/Debugging tSQLt.tdf

2.92 KB
Binary file not shown.
File renamed without changes.
Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
2+
EXEC tSQLt.NewTestClass 'NotInnerTests';
3+
GO
4+
CREATE PROCEDURE NotInnerTests.[test brittle transaction test]
5+
AS
6+
BEGIN
7+
BEGIN TRAN;
8+
END;
9+
GO
10+
11+
--EXEC tSQLt.Private_RunTest @TestName = 'NotInnerTests.[test brittle transaction test]';
12+
13+
14+
DROP TABLE IF EXISTS #TestMessage;
15+
DROP TABLE IF EXISTS #ExpectException;
16+
DROP TABLE IF EXISTS #SkipTest;
17+
DROP TABLE IF EXISTS #NoTransaction;
18+
DROP TABLE IF EXISTS #TableBackupLog;
19+
GO
20+
21+
DECLARE @TestName NVARCHAR(MAX) = 'NotInnerTests.[test brittle transaction test]';
22+
DECLARE @SetUp NVARCHAR(MAX) = NULL;
23+
DECLARE @CleanUp NVARCHAR(MAX) = NULL;
24+
25+
DECLARE @OuterPerimeterTrancount INT = @@TRANCOUNT;
26+
27+
DECLARE @Msg NVARCHAR(MAX); SET @Msg = '';
28+
DECLARE @Msg2 NVARCHAR(MAX); SET @Msg2 = '';
29+
DECLARE @TestClassName NVARCHAR(MAX); SET @TestClassName = '';
30+
DECLARE @TestProcName NVARCHAR(MAX); SET @TestProcName = '';
31+
DECLARE @Result NVARCHAR(MAX);
32+
DECLARE @TranName CHAR(32) = NULL;
33+
DECLARE @TestResultId INT;
34+
DECLARE @TestObjectId INT;
35+
DECLARE @TestEndTime DATETIME2 = NULL;
36+
37+
DECLARE @VerboseMsg NVARCHAR(MAX);
38+
DECLARE @Verbose BIT;
39+
SET @Verbose = ISNULL((SELECT CAST(Value AS BIT) FROM tSQLt.Private_GetConfiguration('Verbose')),0);
40+
41+
TRUNCATE TABLE tSQLt.CaptureOutputLog;
42+
CREATE TABLE #TestMessage(Msg NVARCHAR(MAX));
43+
CREATE TABLE #ExpectException(ExpectException INT,ExpectedMessage NVARCHAR(MAX), ExpectedSeverity INT, ExpectedState INT, ExpectedMessagePattern NVARCHAR(MAX), ExpectedErrorNumber INT, FailMessage NVARCHAR(MAX));
44+
CREATE TABLE #SkipTest(SkipTestMessage NVARCHAR(MAX) DEFAULT '');
45+
CREATE TABLE #NoTransaction(OrderId INT IDENTITY(1,1),CleanUpProcedureName NVARCHAR(MAX));
46+
CREATE TABLE #TableBackupLog(OriginalName NVARCHAR(MAX), BackupName NVARCHAR(MAX));
47+
48+
49+
SELECT @TestClassName = OBJECT_SCHEMA_NAME(OBJECT_ID(@TestName)),
50+
@TestProcName = tSQLt.Private_GetCleanObjectName(@TestName),
51+
@TestObjectId = OBJECT_ID(@TestName);
52+
53+
INSERT INTO tSQLt.TestResult(Class, TestCase, TranName, Result)
54+
SELECT @TestClassName, @TestProcName, @TranName, 'A severe error happened during test execution. Test did not finish.'
55+
OPTION(MAXDOP 1);
56+
SELECT @TestResultId = SCOPE_IDENTITY();
57+
58+
IF(@Verbose = 1)
59+
BEGIN
60+
SET @VerboseMsg = 'tSQLt.Run '''+@TestName+'''; --Starting';
61+
EXEC tSQLt.Private_Print @Message =@VerboseMsg, @Severity = 0;
62+
END;
63+
64+
65+
SET @Result = 'Success';
66+
DECLARE @SkipTestFlag BIT = 0;
67+
DECLARE @NoTransactionFlag BIT = 0;
68+
69+
--BEGIN TRY
70+
--EXEC tSQLt.Private_ProcessTestAnnotations @TestObjectId=@TestObjectId;
71+
--SET @SkipTestFlag = CASE WHEN EXISTS(SELECT 1 FROM #SkipTest) THEN 1 ELSE 0 END;
72+
--SET @NoTransactionFlag = CASE WHEN EXISTS(SELECT 1 FROM #NoTransaction) THEN 1 ELSE 0 END;
73+
74+
--IF(@SkipTestFlag = 0)
75+
--BEGIN
76+
-- IF(@NoTransactionFlag = 0)
77+
-- BEGIN
78+
-- EXEC tSQLt.GetNewTranName @TranName OUT;
79+
-- UPDATE tSQLt.TestResult SET TranName = @TranName WHERE Id = @TestResultId;
80+
-- END;
81+
--EXEC tSQLt.Private_RunTest_TestExecution
82+
-- @TestName,
83+
-- @SetUp,
84+
-- @CleanUp,
85+
-- @NoTransactionFlag,
86+
-- @TranName,
87+
-- @Result OUT,
88+
-- @Msg OUT,
89+
-- @TestEndTime OUT;
90+
IF (1=1)
91+
BEGIN
92+
DECLARE @TransactionStartedFlag BIT = 0;
93+
DECLARE @PreExecTrancount INT = NULL;
94+
DECLARE @TestExecutionCmd NVARCHAR(MAX) = 'EXEC ' + @TestName;
95+
DECLARE @CleanUpProcedureExecutionCmd NVARCHAR(MAX) = NULL;
96+
97+
BEGIN TRY
98+
99+
IF(@NoTransactionFlag = 0)
100+
BEGIN
101+
BEGIN TRAN;
102+
SET @TransactionStartedFlag = 1;
103+
SAVE TRAN @TranName;
104+
END;
105+
ELSE
106+
BEGIN
107+
SELECT object_id ObjectId, SCHEMA_NAME(schema_id) SchemaName, name ObjectName, type_desc ObjectType INTO #BeforeExecutionObjectSnapshot FROM sys.objects;
108+
EXEC tSQLt.Private_NoTransactionHandleTables @Action = 'Save';
109+
END;
110+
111+
SET @PreExecTrancount = @@TRANCOUNT;
112+
113+
DECLARE @TmpMsg NVARCHAR(MAX);
114+
SET @TestEndTime = NULL;
115+
BEGIN TRY
116+
IF (@SetUp IS NOT NULL)
117+
BEGIN
118+
EXEC @SetUp;
119+
END;
120+
121+
BEGIN TRY
122+
SELECT XACT_STATE(),@@TRANCOUNT,@TestExecutionCmd;
123+
EXEC (@TestExecutionCmd);
124+
END TRY
125+
BEGIN CATCH
126+
SELECT XACT_STATE(),@@TRANCOUNT,@TestExecutionCmd;
127+
THROW;
128+
END CATCH;
129+
130+
IF(EXISTS(SELECT 1 FROM #ExpectException WHERE ExpectException = 1))
131+
BEGIN
132+
SET @TmpMsg = COALESCE((SELECT FailMessage FROM #ExpectException)+' ','')+'Expected an error to be raised.';
133+
EXEC tSQLt.Fail @TmpMsg;
134+
END
135+
SET @TestEndTime = SYSDATETIME();
136+
END TRY
137+
BEGIN CATCH
138+
SET @TestEndTime = ISNULL(@TestEndTime,SYSDATETIME());
139+
IF ERROR_MESSAGE() LIKE '%tSQLt.Failure%'
140+
BEGIN
141+
SELECT @Msg = Msg FROM #TestMessage;
142+
SET @Result = 'Failure';
143+
END
144+
ELSE
145+
BEGIN
146+
DECLARE @ErrorInfo NVARCHAR(MAX);
147+
SELECT @ErrorInfo = FormattedError FROM tSQLt.Private_GetFormattedErrorInfo();
148+
149+
IF(EXISTS(SELECT 1 FROM #ExpectException))
150+
BEGIN
151+
DECLARE @ExpectException INT;
152+
DECLARE @ExpectedMessage NVARCHAR(MAX);
153+
DECLARE @ExpectedMessagePattern NVARCHAR(MAX);
154+
DECLARE @ExpectedSeverity INT;
155+
DECLARE @ExpectedState INT;
156+
DECLARE @ExpectedErrorNumber INT;
157+
DECLARE @FailMessage NVARCHAR(MAX);
158+
SELECT @ExpectException = ExpectException,
159+
@ExpectedMessage = ExpectedMessage,
160+
@ExpectedSeverity = ExpectedSeverity,
161+
@ExpectedState = ExpectedState,
162+
@ExpectedMessagePattern = ExpectedMessagePattern,
163+
@ExpectedErrorNumber = ExpectedErrorNumber,
164+
@FailMessage = FailMessage
165+
FROM #ExpectException;
166+
167+
IF(@ExpectException = 1)
168+
BEGIN
169+
SET @Result = 'Success';
170+
SET @TmpMsg = COALESCE(@FailMessage+' ','')+'Exception did not match expectation!';
171+
IF(ERROR_MESSAGE() <> @ExpectedMessage)
172+
BEGIN
173+
SET @TmpMsg = @TmpMsg +CHAR(13)+CHAR(10)+
174+
'Expected Message: <'+@ExpectedMessage+'>'+CHAR(13)+CHAR(10)+
175+
'Actual Message : <'+ERROR_MESSAGE()+'>';
176+
SET @Result = 'Failure';
177+
END
178+
IF(ERROR_MESSAGE() NOT LIKE @ExpectedMessagePattern)
179+
BEGIN
180+
SET @TmpMsg = @TmpMsg +CHAR(13)+CHAR(10)+
181+
'Expected Message to be like <'+@ExpectedMessagePattern+'>'+CHAR(13)+CHAR(10)+
182+
'Actual Message : <'+ERROR_MESSAGE()+'>';
183+
SET @Result = 'Failure';
184+
END
185+
IF(ERROR_NUMBER() <> @ExpectedErrorNumber)
186+
BEGIN
187+
SET @TmpMsg = @TmpMsg +CHAR(13)+CHAR(10)+
188+
'Expected Error Number: '+CAST(@ExpectedErrorNumber AS NVARCHAR(MAX))+CHAR(13)+CHAR(10)+
189+
'Actual Error Number : '+CAST(ERROR_NUMBER() AS NVARCHAR(MAX));
190+
SET @Result = 'Failure';
191+
END
192+
IF(ERROR_SEVERITY() <> @ExpectedSeverity)
193+
BEGIN
194+
SET @TmpMsg = @TmpMsg +CHAR(13)+CHAR(10)+
195+
'Expected Severity: '+CAST(@ExpectedSeverity AS NVARCHAR(MAX))+CHAR(13)+CHAR(10)+
196+
'Actual Severity : '+CAST(ERROR_SEVERITY() AS NVARCHAR(MAX));
197+
SET @Result = 'Failure';
198+
END
199+
IF(ERROR_STATE() <> @ExpectedState)
200+
BEGIN
201+
SET @TmpMsg = @TmpMsg +CHAR(13)+CHAR(10)+
202+
'Expected State: '+CAST(@ExpectedState AS NVARCHAR(MAX))+CHAR(13)+CHAR(10)+
203+
'Actual State : '+CAST(ERROR_STATE() AS NVARCHAR(MAX));
204+
SET @Result = 'Failure';
205+
END
206+
IF(@Result = 'Failure')
207+
BEGIN
208+
SET @Msg = @TmpMsg;
209+
END
210+
END
211+
ELSE
212+
BEGIN
213+
SET @Result = 'Failure';
214+
SET @Msg =
215+
COALESCE(@FailMessage+' ','')+
216+
'Expected no error to be raised. Instead this error was encountered:'+
217+
CHAR(13)+CHAR(10)+
218+
@ErrorInfo;
219+
END
220+
END;
221+
ELSE
222+
BEGIN
223+
SET @Result = 'Error';
224+
SET @Msg = @ErrorInfo;
225+
END;
226+
END;
227+
END CATCH;
228+
END TRY
229+
BEGIN CATCH
230+
SET @Result = 'Error';
231+
SET @Msg = ERROR_MESSAGE();
232+
END CATCH
233+
234+
--TODO:NoTran
235+
---- Compare @@Trancount, throw up arms if it doesn't match
236+
--TODO:NoTran
237+
BEGIN TRY
238+
IF(@TransactionStartedFlag = 1)
239+
BEGIN
240+
ROLLBACK TRAN @TranName;
241+
END;
242+
END TRY
243+
BEGIN CATCH
244+
DECLARE @PostExecTrancount INT;
245+
SET @PostExecTrancount = @PreExecTrancount - @@TRANCOUNT;
246+
IF (@@TRANCOUNT > 0) ROLLBACK;
247+
BEGIN TRAN;
248+
IF( @Result <> 'Success'
249+
OR @PostExecTrancount <> 0
250+
)
251+
BEGIN
252+
SELECT @Msg = COALESCE(@Msg, '<NULL>') + ' (There was also a ROLLBACK ERROR --> ' + FormattedError + ')' FROM tSQLt.Private_GetFormattedErrorInfo();
253+
SET @Result = 'Error';
254+
END;
255+
END CATCH;
256+
IF (@NoTransactionFlag = 1)
257+
BEGIN
258+
SET @CleanUpProcedureExecutionCmd = (
259+
(
260+
SELECT 'EXEC tSQLt.Private_CleanUpCmdHandler ''EXEC '+ REPLACE(NT.CleanUpProcedureName,'''','''''') +';'', @Result OUT, @Msg OUT;'
261+
FROM #NoTransaction NT
262+
ORDER BY OrderId
263+
FOR XML PATH(''),TYPE
264+
).value('.','NVARCHAR(MAX)')
265+
);
266+
IF(@CleanUpProcedureExecutionCmd IS NOT NULL)
267+
BEGIN
268+
EXEC sys.sp_executesql @CleanUpProcedureExecutionCmd, N'@Result NVARCHAR(MAX) OUTPUT, @Msg NVARCHAR(MAX) OUTPUT', @Result OUT, @Msg OUT;
269+
END;
270+
271+
IF(@CleanUp IS NOT NULL)
272+
BEGIN
273+
EXEC tSQLt.Private_CleanUpCmdHandler @CleanUp, @Result OUT, @Msg OUT;
274+
END;
275+
276+
DECLARE @CleanUpErrorMsg NVARCHAR(MAX);
277+
EXEC tSQLt.Private_CleanUp @FullTestName = @TestName, @Result = @Result OUT, @ErrorMsg = @CleanUpErrorMsg OUT;
278+
SET @Msg = @Msg + ISNULL(' ' + @CleanUpErrorMsg, '');
279+
280+
SELECT object_id ObjectId, SCHEMA_NAME(schema_id) SchemaName, name ObjectName, type_desc ObjectType INTO #AfterExecutionObjectSnapshot FROM sys.objects;
281+
EXEC tSQLt.Private_AssertNoSideEffects
282+
@BeforeExecutionObjectSnapshotTableName ='#BeforeExecutionObjectSnapshot',
283+
@AfterExecutionObjectSnapshotTableName = '#AfterExecutionObjectSnapshot',
284+
@TestResult = @Result OUT,
285+
@TestMsg = @Msg OUT
286+
END;
287+
IF(@TransactionStartedFlag = 1)
288+
BEGIN
289+
COMMIT;
290+
END;
291+
END;
292+
293+
--END;
294+
--ELSE
295+
--BEGIN
296+
-- DECLARE @TmpMsg NVARCHAR(MAX);
297+
-- SELECT
298+
-- @Result = 'Skipped',
299+
-- @Msg = ST.SkipTestMessage
300+
-- FROM #SkipTest AS ST;
301+
-- SET @TmpMsg = '-->'+@TestName+' skipped: '+@Msg;
302+
-- EXEC tSQLt.Private_Print @Message = @TmpMsg;
303+
-- SET @TestEndTime = SYSDATETIME();
304+
--END;
305+
--END TRY
306+
--BEGIN CATCH
307+
-- SET @Result = 'Error';
308+
-- SET @Msg = ISNULL(NULLIF(@Msg,'') + ' ','')+ERROR_MESSAGE();
309+
-- --SET @TestEndTime = SYSDATETIME();
310+
--END CATCH;
311+
------------------------------------------------------------------------------------------------
312+
-- If(@Result NOT IN ('Success','Skipped'))
313+
-- BEGIN
314+
-- SET @Msg2 = @TestName + ' failed: (' + @Result + ') ' + @Msg;
315+
-- EXEC tSQLt.Private_Print @Message = @Msg2, @Severity = 0;
316+
-- END;
317+
-- IF EXISTS(SELECT 1 FROM tSQLt.TestResult WHERE Id = @TestResultId)
318+
-- BEGIN
319+
-- UPDATE tSQLt.TestResult SET
320+
-- Result = @Result,
321+
-- Msg = @Msg,
322+
-- TestEndTime = @TestEndTime
323+
-- WHERE Id = @TestResultId;
324+
-- END;
325+
-- ELSE
326+
-- BEGIN
327+
-- INSERT tSQLt.TestResult(Class, TestCase, TranName, Result, Msg)
328+
-- SELECT @TestClassName,
329+
-- @TestProcName,
330+
-- '?',
331+
-- 'Error',
332+
-- 'TestResult entry is missing; Original outcome: ' + @Result + ', ' + @Msg;
333+
-- END;
334+
335+
-- IF(@Verbose = 1)
336+
-- BEGIN
337+
-- SET @VerboseMsg = 'tSQLt.Run '''+@TestName+'''; --Finished';
338+
-- EXEC tSQLt.Private_Print @Message =@VerboseMsg, @Severity = 0;
339+
-- --DECLARE @AsciiArtLine NVARCHAR(MAX) = CASE WHEN @Result<>'Success' THEN REPLICATE(CHAR(168),150)+' '+CHAR(155)+CHAR(155)+' '+@Result + ' ' +CHAR(139)+CHAR(139) ELSE '' END + CHAR(13)+CHAR(10) + CHAR(173);
340+
-- --EXEC tSQLt.Private_Print @Message = @AsciiArtLine, @Severity = 0;
341+
-- END;
342+
343+
-- IF(@Result = 'FATAL')
344+
-- BEGIN
345+
-- INSERT INTO tSQLt.Private_Seize VALUES(1);
346+
-- RAISERROR('The last test has invalidated the current installation of tSQLt. Please reinstall tSQLt.',16,10);
347+
-- END;
348+
-- IF(@Result = 'Abort')
349+
-- BEGIN
350+
-- RAISERROR('Aborting the current execution of tSQLt due to a severe error.', 16, 10);
351+
-- END;
352+
353+
-- IF(@OuterPerimeterTrancount != @@TRANCOUNT) RAISERROR('tSQLt is in an invalid state: Stopping Execution. (Mismatching TRANCOUNT: %i <> %i))',16,10,@OuterPerimeterTrancount, @@TRANCOUNT);

Source/Run_Methods.sql

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,15 @@ BEGIN
8181
BEGIN
8282
EXEC @SetUp;
8383
END;
84-
EXEC (@TestExecutionCmd);
84+
85+
BEGIN TRY
86+
SELECT XACT_STATE(),@@TRANCOUNT,@TestExecutionCmd;
87+
EXEC (@TestExecutionCmd);
88+
END TRY
89+
BEGIN CATCH
90+
SELECT XACT_STATE(),@@TRANCOUNT,@TestExecutionCmd;
91+
THROW;
92+
END CATCH;
8593

8694
IF(EXISTS(SELECT 1 FROM #ExpectException WHERE ExpectException = 1))
8795
BEGIN

0 commit comments

Comments
 (0)