Skip to content

Commit

Permalink
Added integration tests for transactions.
Browse files Browse the repository at this point in the history
Added isolation levels to api.
  • Loading branch information
digitalBush committed Sep 1, 2017
1 parent ee93373 commit 1476156
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 7 deletions.
4 changes: 4 additions & 0 deletions spec/integration/sql/transaction-setup.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DROP TABLE IF EXISTS dbo.MutationTests;
CREATE TABLE dbo.MutationTests(
id int
);
86 changes: 86 additions & 0 deletions spec/integration/transaction.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
const { config } = testHelpers;

const skwell = require( "src/" );
describe( "Transaction - Integration", () => {
let sql;
before( () => {
sql = skwell.connect( config );
return sql.execute( sql.fromFile( "sql/transaction-setup.sql" ) );
} );

beforeEach( async () => {
await sql.execute( "DELETE FROM MutationTests" );
} );

after( () => {
return sql.dispose();
} );

describe( "isolation levels", () => {
const isolationLevelQuery = `
SELECT CASE transaction_isolation_level
WHEN 0 THEN 'Unspecified'
WHEN 1 THEN 'ReadUncommitted'
WHEN 2 THEN 'ReadCommitted'
WHEN 3 THEN 'Repeatable'
WHEN 4 THEN 'Serializable'
WHEN 5 THEN 'Snapshot' END AS level
FROM sys.dm_exec_sessions
where session_id = @@SPID`;

it( "should default to read committed isolation level", async () => {
await sql.transaction( async tx => {
return tx.queryValue( isolationLevelQuery );
} ).should.eventually.equal( "ReadCommitted" );
} );

it( "should set isolation level", async () => {
await sql.transaction( sql.read_uncommitted, async tx => {
return tx.queryValue( isolationLevelQuery );
} ).should.eventually.equal( "ReadUncommitted" );
} );
} );

describe( "rollback", () => {
it( "should roll back transaction when sql fails", async () => {
const expectedError = "Automatic Rollback. Failed Because: Invalid object name 'fake_table'.";

await sql.transaction( async tx => {
await tx.execute( "insert into MutationTests(id) values (1)" );
await tx.query( "select lol from fake_table" );
} ).should.eventually.be.rejectedWith( expectedError );

const vals = await sql.query( "select * from MutationTests" );
vals.length.should.equal( 0 );
} );

it( "should roll back transaction when an error is thrown", async () => {
await sql.transaction( async tx => {
await tx.execute( "insert into MutationTests(id) values (1)" );
throw new Error( "NOPE" );
} ).should.eventually.be.rejectedWith( "NOPE" );

const vals = await sql.query( "select * from MutationTests" );
vals.length.should.equal( 0 );
} );

it( "should roll back transaction when manually calling rollback", async () => {
await sql.transaction( async tx => {
await tx.execute( "insert into MutationTests(id) values (1)" );
await tx.rollback();
} ).should.eventually.be.rejectedWith( "Manual Rollback" );

const vals = await sql.query( "select * from MutationTests" );
vals.length.should.equal( 0 );
} );
} );

it( "should commit transaction when promise resolves", async () => {
await sql.transaction( async tx => {
await tx.execute( "insert into MutationTests(id) values (1)" );
} );

const vals = await sql.query( "select * from MutationTests" );
vals.should.deep.equal( [ { id: 1 } ] );
} );
} );
8 changes: 7 additions & 1 deletion src/api.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const Request = require( "tedious" ).Request;
const { Request, ISOLATION_LEVEL } = require( "tedious" );
const Readable = require( "readable-stream" ).Readable;

const parameterBuilder = require( "./parameterBuilder" );
Expand Down Expand Up @@ -108,5 +108,11 @@ class Api {
}

Object.assign( Api.prototype, types );

Object.keys( ISOLATION_LEVEL ).forEach( k => {
Api.prototype[ k.toLowerCase() ] = ISOLATION_LEVEL[ k ];
} );

Api.prototype.fromFile = fileLoader;

module.exports = Api;
5 changes: 0 additions & 5 deletions src/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ class Transaction extends Api {
// TODO: wrap err instead of mangling message
err.message = `Automatic Rollback. Failed Because: ${ err.message }`;
await tx.rollback( err );
throw err;
}
}

Expand All @@ -43,10 +42,6 @@ class Transaction extends Api {
}

async rollback( err ) {
if ( this[ _state ].rolledBack ) {
return;
}

await this[ _state ].connection.rollbackTransaction();
this[ _state ].rolledBack = true;
throw err;
Expand Down
2 changes: 1 addition & 1 deletion src/types.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { TYPES } = require( "tedious" );
const { TYPES, ISOLATION_LEVEL } = require( "tedious" );

const TypeWrapper = require( "./TypeWrapper" );

Expand Down

0 comments on commit 1476156

Please sign in to comment.